From 34b582ba4efe5216d268ee5a050eb496d8e910cd Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 16 Oct 2018 16:30:05 +0200 Subject: [PATCH] Use official OGDF repository as submodule Signed-off-by: Sven Strickroth --- .gitmodules | 3 + appveyor.yml | 2 +- ext/OGDF | 1 + ext/OGDF/LICENSE.txt | 32 - ext/OGDF/LICENSE_GPL_v2.txt | 339 -- ext/OGDF/LICENSE_GPL_v3.txt | 674 ---- ext/OGDF/Makefile.README | 20 - ext/OGDF/Makefile.header | 22 - ext/OGDF/README.txt | 89 - ext/OGDF/config/ogdf.dll.vcproj.vs2005.template | 312 -- ext/OGDF/config/ogdf.dll.vcproj.vs2008.template | 312 -- ext/OGDF/config/ogdf.dll.vcxproj.vs2010.template | 176 - ext/OGDF/config/ogdf.dll.vcxproj.vs2012.template | 181 - ext/OGDF/config/ogdf.vcproj.vs2003.template | 164 - ext/OGDF/config/ogdf.vcproj.vs2005.template | 300 -- ext/OGDF/config/ogdf.vcproj.vs2008.template | 300 -- ext/OGDF/config/ogdf.vcxproj.filters.template | 16 - ext/OGDF/config/ogdf.vcxproj.vs2010.template | 160 - ext/OGDF/config/ogdf.vcxproj.vs2012.template | 165 - ext/OGDF/doc/build-ogdf-docs.bat | 2 - ext/OGDF/doc/build-ogdf-docs.sh | 10 - ext/OGDF/doc/govisual-footer.html | 16 - ext/OGDF/doc/govisual-header.html | 75 - ext/OGDF/doc/govisual.css | 1189 ------ ext/OGDF/doc/images/ftv2doc.png | Bin 628 -> 0 bytes ext/OGDF/doc/images/ftv2folderclosed.png | Bin 339 -> 0 bytes ext/OGDF/doc/images/ftv2folderopen.png | Bin 408 -> 0 bytes ext/OGDF/doc/images/insertEdgePathEmbedded.png | Bin 43916 -> 0 bytes ext/OGDF/doc/images/insertEdgePathEmbedded.svg | 108 - ext/OGDF/doc/ogdf-doxygen.cfg | 1801 --------- ext/OGDF/makeMakefile.config | 76 - ext/OGDF/makeMakefile.py | 231 -- ext/OGDF/makeMakefile.sh | 2 - ext/OGDF/makeVCProj.config | 25 - ext/OGDF/makeVCProj.py | 192 - ext/OGDF/makeVCXProj.config | 29 - ext/OGDF/makeVCXProj.py | 244 -- ext/OGDF/makeVCXProjPython3.py | 244 -- ext/OGDF/ogdf/augmentation/DfsMakeBiconnected.h | 82 - ext/OGDF/ogdf/augmentation/PlanarAugmentation.h | 305 -- ext/OGDF/ogdf/augmentation/PlanarAugmentationFix.h | 225 -- ext/OGDF/ogdf/basic/AdjEntryArray.h | 224 -- ext/OGDF/ogdf/basic/Array.h | 587 --- ext/OGDF/ogdf/basic/Array2D.h | 325 -- ext/OGDF/ogdf/basic/ArrayBuffer.h | 240 -- ext/OGDF/ogdf/basic/Barrier.h | 258 -- ext/OGDF/ogdf/basic/BinaryHeap.h | 243 -- ext/OGDF/ogdf/basic/BinaryHeap2.h | 526 --- ext/OGDF/ogdf/basic/BoundedQueue.h | 203 - ext/OGDF/ogdf/basic/BoundedStack.h | 209 - ext/OGDF/ogdf/basic/CombinatorialEmbedding.h | 484 --- ext/OGDF/ogdf/basic/Constraints.h | 209 - ext/OGDF/ogdf/basic/CriticalSection.h | 161 - ext/OGDF/ogdf/basic/DisjointSets.h | 579 --- ext/OGDF/ogdf/basic/DualGraph.h | 120 - ext/OGDF/ogdf/basic/EFreeList.h | 150 - ext/OGDF/ogdf/basic/EList.h | 507 --- ext/OGDF/ogdf/basic/EdgeArray.h | 256 -- ext/OGDF/ogdf/basic/EdgeComparer.h | 122 - ext/OGDF/ogdf/basic/EdgeComparerSimple.h | 82 - ext/OGDF/ogdf/basic/FaceArray.h | 221 -- ext/OGDF/ogdf/basic/FaceSet.h | 271 -- ext/OGDF/ogdf/basic/Graph.h | 72 - ext/OGDF/ogdf/basic/GraphAttributes.h | 860 ---- ext/OGDF/ogdf/basic/GraphCopy.h | 642 --- ext/OGDF/ogdf/basic/GraphCopyAttributes.h | 116 - ext/OGDF/ogdf/basic/GraphObserver.h | 144 - ext/OGDF/ogdf/basic/Graph_d.h | 1557 -------- ext/OGDF/ogdf/basic/GridLayout.h | 195 - ext/OGDF/ogdf/basic/GridLayoutMapped.h | 126 - ext/OGDF/ogdf/basic/HashArray.h | 176 - ext/OGDF/ogdf/basic/HashArray2D.h | 166 - ext/OGDF/ogdf/basic/HashIterator2D.h | 120 - ext/OGDF/ogdf/basic/Hashing.h | 517 --- ext/OGDF/ogdf/basic/HeapBase.h | 129 - ext/OGDF/ogdf/basic/HyperGraph.h | 913 ----- ext/OGDF/ogdf/basic/IncNodeInserter.h | 95 - ext/OGDF/ogdf/basic/Layout.h | 176 - ext/OGDF/ogdf/basic/List.h | 1631 -------- ext/OGDF/ogdf/basic/Logger.h | 229 -- ext/OGDF/ogdf/basic/Math.h | 147 - ext/OGDF/ogdf/basic/MinHeap.h | 341 -- ext/OGDF/ogdf/basic/MinPriorityQueue.h | 222 -- ext/OGDF/ogdf/basic/Module.h | 95 - ext/OGDF/ogdf/basic/ModuleOption.h | 100 - ext/OGDF/ogdf/basic/NearestRectangleFinder.h | 161 - ext/OGDF/ogdf/basic/NodeArray.h | 224 -- ext/OGDF/ogdf/basic/NodeComparer.h | 99 - ext/OGDF/ogdf/basic/NodeSet.h | 269 -- ext/OGDF/ogdf/basic/PreprocessorLayout.h | 123 - ext/OGDF/ogdf/basic/Queue.h | 230 -- ext/OGDF/ogdf/basic/SList.h | 1044 ----- ext/OGDF/ogdf/basic/Skiplist.h | 230 -- ext/OGDF/ogdf/basic/Stack.h | 249 -- ext/OGDF/ogdf/basic/String.h | 229 -- ext/OGDF/ogdf/basic/System.h | 324 -- ext/OGDF/ogdf/basic/Thread.h | 236 -- ext/OGDF/ogdf/basic/Timeouter.h | 107 - ext/OGDF/ogdf/basic/TopologyModule.h | 232 -- ext/OGDF/ogdf/basic/UMLGraph.h | 320 -- ext/OGDF/ogdf/basic/basic.h | 637 --- ext/OGDF/ogdf/basic/comparer.h | 285 -- ext/OGDF/ogdf/basic/exceptions.h | 304 -- ext/OGDF/ogdf/basic/extended_graph_alg.h | 421 -- ext/OGDF/ogdf/basic/geometry.h | 791 ---- ext/OGDF/ogdf/basic/graph_generators.h | 330 -- ext/OGDF/ogdf/basic/memory.h | 123 - ext/OGDF/ogdf/basic/precondition.h | 177 - ext/OGDF/ogdf/basic/simple_graph_alg.h | 800 ---- ext/OGDF/ogdf/basic/tuples.h | 271 -- ext/OGDF/ogdf/cluster/CPlanarEdgeInserter.h | 160 - ext/OGDF/ogdf/cluster/CPlanarSubClusteredGraph.h | 93 - ext/OGDF/ogdf/cluster/CconnectClusterPlanar.h | 129 - ext/OGDF/ogdf/cluster/CconnectClusterPlanarEmbed.h | 262 -- ext/OGDF/ogdf/cluster/ClusterArray.h | 242 -- ext/OGDF/ogdf/cluster/ClusterGraph.h | 822 ---- ext/OGDF/ogdf/cluster/ClusterGraphAttributes.h | 435 -- ext/OGDF/ogdf/cluster/ClusterGraphCopyAttributes.h | 162 - ext/OGDF/ogdf/cluster/ClusterGraphObserver.h | 110 - ext/OGDF/ogdf/cluster/ClusterOrthoLayout.h | 206 - ext/OGDF/ogdf/cluster/ClusterOrthoShaper.h | 302 -- ext/OGDF/ogdf/cluster/ClusterPlanRep.h | 218 - ext/OGDF/ogdf/cluster/ClusterPlanarizationLayout.h | 187 - ext/OGDF/ogdf/cluster/ClusterSet.h | 267 -- ext/OGDF/ogdf/cluster/MaximumCPlanarSubgraph.h | 278 -- ext/OGDF/ogdf/decomposition/BCTree.h | 611 --- ext/OGDF/ogdf/decomposition/DynamicBCTree.h | 326 -- .../ogdf/decomposition/DynamicPlanarSPQRTree.h | 122 - ext/OGDF/ogdf/decomposition/DynamicSPQRForest.h | 400 -- ext/OGDF/ogdf/decomposition/DynamicSPQRTree.h | 271 -- ext/OGDF/ogdf/decomposition/DynamicSkeleton.h | 149 - ext/OGDF/ogdf/decomposition/PertinentGraph.h | 171 - ext/OGDF/ogdf/decomposition/PlanarSPQRTree.h | 164 - ext/OGDF/ogdf/decomposition/SPQRTree.h | 250 -- ext/OGDF/ogdf/decomposition/Skeleton.h | 170 - ext/OGDF/ogdf/decomposition/StaticPlanarSPQRTree.h | 124 - ext/OGDF/ogdf/decomposition/StaticSPQRTree.h | 273 -- ext/OGDF/ogdf/decomposition/StaticSkeleton.h | 163 - ext/OGDF/ogdf/energybased/CoinTutteLayout.h | 127 - ext/OGDF/ogdf/energybased/DavidsonHarel.h | 137 - ext/OGDF/ogdf/energybased/DavidsonHarelLayout.h | 161 - ext/OGDF/ogdf/energybased/FMMMLayout.h | 1388 ------- ext/OGDF/ogdf/energybased/FastMultipoleEmbedder.h | 221 -- ext/OGDF/ogdf/energybased/GEMLayout.h | 314 -- ext/OGDF/ogdf/energybased/MultilevelLayout.h | 97 - ext/OGDF/ogdf/energybased/SpringEmbedderFR.h | 261 -- ext/OGDF/ogdf/energybased/SpringEmbedderFRExact.h | 223 -- ext/OGDF/ogdf/energybased/SpringEmbedderKK.h | 337 -- .../ogdf/energybased/StressMajorizationSimple.h | 400 -- .../energybased/multilevelmixer/BarycenterPlacer.h | 69 - .../energybased/multilevelmixer/CirclePlacer.h | 79 - .../energybased/multilevelmixer/EdgeCoverMerger.h | 70 - .../multilevelmixer/IndependentSetMerger.h | 72 - .../energybased/multilevelmixer/InitialPlacer.h | 75 - .../multilevelmixer/LocalBiconnectedMerger.h | 84 - .../multilevelmixer/MMMExampleFastLayout.h | 83 - .../multilevelmixer/MMMExampleNiceLayout.h | 83 - .../multilevelmixer/MMMExampleNoTwistLayout.h | 84 - .../energybased/multilevelmixer/MatchingMerger.h | 69 - .../energybased/multilevelmixer/MedianPlacer.h | 65 - .../energybased/multilevelmixer/MixedForceLayout.h | 73 - .../multilevelmixer/ModularMultilevelMixer.h | 206 - .../multilevelmixer/MultilevelBuilder.h | 99 - .../energybased/multilevelmixer/RandomMerger.h | 68 - .../energybased/multilevelmixer/RandomPlacer.h | 69 - .../energybased/multilevelmixer/ScalingLayout.h | 166 - .../ogdf/energybased/multilevelmixer/SolarMerger.h | 93 - .../ogdf/energybased/multilevelmixer/SolarPlacer.h | 65 - .../ogdf/energybased/multilevelmixer/ZeroPlacer.h | 69 - ext/OGDF/ogdf/external/abacus.h | 73 - ext/OGDF/ogdf/external/coin.h | 110 - ext/OGDF/ogdf/fileformats/DinoLineBuffer.h | 244 -- ext/OGDF/ogdf/fileformats/DinoTools.h | 84 - ext/OGDF/ogdf/fileformats/DinoUmlDiagramGraph.h | 196 - ext/OGDF/ogdf/fileformats/DinoUmlModelGraph.h | 119 - .../ogdf/fileformats/DinoUmlToGraphConverter.h | 334 -- ext/OGDF/ogdf/fileformats/DinoXmlParser.h | 461 --- ext/OGDF/ogdf/fileformats/DinoXmlScanner.h | 163 - ext/OGDF/ogdf/fileformats/GmlParser.h | 230 -- ext/OGDF/ogdf/fileformats/Ogml.h | 365 -- ext/OGDF/ogdf/fileformats/OgmlParser.h | 287 -- ext/OGDF/ogdf/fileformats/SteinLibParser.h | 223 -- ext/OGDF/ogdf/fileformats/XmlObject.h | 129 - ext/OGDF/ogdf/fileformats/XmlParser.h | 172 - ext/OGDF/ogdf/fileformats/simple_graph_load.h | 332 -- ext/OGDF/ogdf/graphalg/CliqueFinder.h | 171 - ext/OGDF/ogdf/graphalg/Clusterer.h | 148 - ext/OGDF/ogdf/graphalg/ConvexHull.h | 85 - ext/OGDF/ogdf/graphalg/Dijkstra.h | 125 - ext/OGDF/ogdf/graphalg/GraphReduction.h | 98 - ext/OGDF/ogdf/graphalg/MinCostFlowReinelt.h | 166 - ext/OGDF/ogdf/graphalg/MinimumCut.h | 119 - ext/OGDF/ogdf/graphalg/PageRank.h | 128 - ext/OGDF/ogdf/graphalg/ShortestPathWithBFM.h | 82 - ext/OGDF/ogdf/internal/augmentation/PALabel.h | 174 - .../ogdf/internal/basic/MallocMemoryAllocator.h | 115 - ext/OGDF/ogdf/internal/basic/PoolMemoryAllocator.h | 188 - ext/OGDF/ogdf/internal/basic/intrinsics.h | 77 - ext/OGDF/ogdf/internal/basic/list_templates.h | 98 - .../ogdf/internal/cluster/CPlanarSubClusteredST.h | 220 -- .../ogdf/internal/cluster/ClusterPQContainer.h | 188 - .../internal/cluster/Cluster_ChunkConnection.h | 111 - .../ogdf/internal/cluster/Cluster_CutConstraint.h | 89 - ext/OGDF/ogdf/internal/cluster/Cluster_EdgeVar.h | 94 - .../ogdf/internal/cluster/Cluster_MaxPlanarEdges.h | 85 - .../ogdf/internal/cluster/KuratowskiConstraint.h | 92 - ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Master.h | 342 -- .../cluster/MaxCPlanar_MinimalClusterConnection.h | 86 - ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Sub.h | 297 -- ext/OGDF/ogdf/internal/cluster/basics.h | 91 - .../ogdf/internal/energybased/AdjacencyOracle.h | 77 - ext/OGDF/ogdf/internal/energybased/Attraction.h | 89 - .../ogdf/internal/energybased/EdgeAttributes.h | 118 - .../ogdf/internal/energybased/EnergyFunction.h | 114 - .../internal/energybased/FruchtermanReingold.h | 105 - .../internal/energybased/IntersectionRectangle.h | 209 - .../ogdf/internal/energybased/MultilevelGraph.h | 177 - ext/OGDF/ogdf/internal/energybased/NMM.h | 513 --- .../ogdf/internal/energybased/NodeAttributes.h | 181 - .../ogdf/internal/energybased/NodePairEnergy.h | 103 - ext/OGDF/ogdf/internal/energybased/Overlap.h | 76 - ext/OGDF/ogdf/internal/energybased/ParticleInfo.h | 150 - ext/OGDF/ogdf/internal/energybased/Planarity.h | 113 - ext/OGDF/ogdf/internal/energybased/PlanarityGrid.h | 86 - ext/OGDF/ogdf/internal/energybased/QuadTreeNM.h | 159 - .../ogdf/internal/energybased/QuadTreeNodeNM.h | 188 - ext/OGDF/ogdf/internal/energybased/Repulsion.h | 73 - ext/OGDF/ogdf/internal/energybased/UniformGrid.h | 164 - ext/OGDF/ogdf/internal/lpsolver/LPSolver_coin.h | 125 - ext/OGDF/ogdf/internal/orthogonal/NodeInfo.h | 302 -- ext/OGDF/ogdf/internal/orthogonal/RoutingChannel.h | 160 - .../ogdf/internal/planarity/BoyerMyrvoldInit.h | 165 - .../ogdf/internal/planarity/BoyerMyrvoldPlanar.h | 470 --- .../ogdf/internal/planarity/ConnectedSubgraph.h | 424 -- ext/OGDF/ogdf/internal/planarity/EmbedIndicator.h | 105 - ext/OGDF/ogdf/internal/planarity/EmbedPQTree.h | 162 - .../planarity/EmbedderMaxFaceBiconnectedGraphs.h | 1906 --------- .../EmbedderMaxFaceBiconnectedGraphsLayers.h | 2688 ------------- ext/OGDF/ogdf/internal/planarity/FindKuratowskis.h | 354 -- ext/OGDF/ogdf/internal/planarity/IndInfo.h | 80 - .../ogdf/internal/planarity/MDMFLengthAttribute.h | 99 - .../ogdf/internal/planarity/MaxSequencePQTree.h | 1936 --------- ext/OGDF/ogdf/internal/planarity/PQBasicKey.h | 205 - ext/OGDF/ogdf/internal/planarity/PQBasicKeyRoot.h | 79 - ext/OGDF/ogdf/internal/planarity/PQInternalKey.h | 110 - ext/OGDF/ogdf/internal/planarity/PQInternalNode.h | 293 -- ext/OGDF/ogdf/internal/planarity/PQLeaf.h | 261 -- ext/OGDF/ogdf/internal/planarity/PQLeafKey.h | 141 - ext/OGDF/ogdf/internal/planarity/PQNode.h | 651 --- ext/OGDF/ogdf/internal/planarity/PQNodeKey.h | 104 - ext/OGDF/ogdf/internal/planarity/PQNodeRoot.h | 102 - ext/OGDF/ogdf/internal/planarity/PQTree.h | 3968 ------------------- ext/OGDF/ogdf/internal/planarity/PlanarLeafKey.h | 87 - ext/OGDF/ogdf/internal/planarity/PlanarPQTree.h | 95 - .../ogdf/internal/planarity/PlanarSubgraphPQTree.h | 118 - ext/OGDF/ogdf/internal/planarity/whaInfo.h | 162 - .../ogdf/internal/steinertree/EdgeWeightedGraph.h | 110 - .../internal/steinertree/EdgeWeightedGraphCopy.h | 186 - ext/OGDF/ogdf/labeling/ELabelInterface.h | 305 -- ext/OGDF/ogdf/labeling/ELabelPosSimple.h | 81 - ext/OGDF/ogdf/labeling/EdgeLabel.h | 451 --- ext/OGDF/ogdf/layered/BarycenterHeuristic.h | 80 - ext/OGDF/ogdf/layered/CoffmanGrahamRanking.h | 168 - ext/OGDF/ogdf/layered/CrossingsMatrix.h | 99 - ext/OGDF/ogdf/layered/DfsAcyclicSubgraph.h | 98 - ext/OGDF/ogdf/layered/ExtendedNestingGraph.h | 458 --- ext/OGDF/ogdf/layered/FastHierarchyLayout.h | 232 -- ext/OGDF/ogdf/layered/FastSimpleHierarchyLayout.h | 226 -- ext/OGDF/ogdf/layered/GreedyCycleRemoval.h | 85 - ext/OGDF/ogdf/layered/GreedyInsertHeuristic.h | 82 - ext/OGDF/ogdf/layered/GreedySwitchHeuristic.h | 80 - ext/OGDF/ogdf/layered/Hierarchy.h | 231 -- ext/OGDF/ogdf/layered/Level.h | 160 - ext/OGDF/ogdf/layered/LongestPathRanking.h | 240 -- ext/OGDF/ogdf/layered/MedianHeuristic.h | 80 - .../ogdf/layered/OptimalHierarchyClusterLayout.h | 243 -- ext/OGDF/ogdf/layered/OptimalHierarchyLayout.h | 210 - ext/OGDF/ogdf/layered/OptimalRanking.h | 174 - ext/OGDF/ogdf/layered/SiftingHeuristic.h | 98 - ext/OGDF/ogdf/layered/SplitHeuristic.h | 83 - ext/OGDF/ogdf/layered/SugiyamaLayout.h | 484 --- ext/OGDF/ogdf/lpsolver/LPSolver.h | 61 - ext/OGDF/ogdf/misclayout/BalloonLayout.h | 172 - ext/OGDF/ogdf/misclayout/CircularLayout.h | 179 - ext/OGDF/ogdf/misclayout/ProcrustesSubLayout.h | 197 - ext/OGDF/ogdf/module/AcyclicSubgraphModule.h | 124 - ext/OGDF/ogdf/module/AugmentationModule.h | 125 - ext/OGDF/ogdf/module/CCLayoutPackModule.h | 192 - ext/OGDF/ogdf/module/CPlanarSubgraphModule.h | 110 - ext/OGDF/ogdf/module/ClustererModule.h | 169 - ext/OGDF/ogdf/module/CrossingMinimizationModule.h | 163 - ext/OGDF/ogdf/module/EdgeInsertionModule.h | 253 -- ext/OGDF/ogdf/module/EmbedderModule.h | 88 - ext/OGDF/ogdf/module/FUPSModule.h | 110 - ext/OGDF/ogdf/module/ForceLayoutModule.h | 115 - ext/OGDF/ogdf/module/GridLayoutModule.h | 334 -- .../ogdf/module/HierarchyClusterLayoutModule.h | 103 - ext/OGDF/ogdf/module/HierarchyLayoutModule.h | 138 - ext/OGDF/ogdf/module/LayoutClusterPlanRepModule.h | 127 - ext/OGDF/ogdf/module/LayoutModule.h | 101 - ext/OGDF/ogdf/module/LayoutPlanRepModule.h | 131 - .../ogdf/module/MMCrossingMinimizationModule.h | 159 - ext/OGDF/ogdf/module/MMEdgeInsertionModule.h | 128 - ext/OGDF/ogdf/module/MinCostFlowModule.h | 202 - .../module/MixedModelCrossingsBeautifierModule.h | 128 - ext/OGDF/ogdf/module/MultilevelLayoutModule.h | 126 - ext/OGDF/ogdf/module/PlanarSubgraphModule.h | 179 - ext/OGDF/ogdf/module/PlanarityModule.h | 98 - ext/OGDF/ogdf/module/RankingModule.h | 104 - ext/OGDF/ogdf/module/ShellingOrderModule.h | 114 - ext/OGDF/ogdf/module/ShortestPathModule.h | 146 - ext/OGDF/ogdf/module/TwoLayerCrossMin.h | 115 - ext/OGDF/ogdf/module/UMLLayoutModule.h | 93 - ext/OGDF/ogdf/module/UPRLayoutModule.h | 100 - ext/OGDF/ogdf/module/UpwardEdgeInserterModule.h | 165 - ext/OGDF/ogdf/module/UpwardPlanarSubgraphModule.h | 104 - ext/OGDF/ogdf/module/UpwardPlanarizerModule.h | 154 - .../ogdf/orthogonal/CompactionConstraintGraph.h | 1719 -------- ext/OGDF/ogdf/orthogonal/EdgeRouter.h | 294 -- ext/OGDF/ogdf/orthogonal/FlowCompaction.h | 173 - ext/OGDF/ogdf/orthogonal/LongestPathCompaction.h | 155 - ext/OGDF/ogdf/orthogonal/MinimumEdgeDistances.h | 118 - ext/OGDF/ogdf/orthogonal/OrthoLayout.h | 215 - ext/OGDF/ogdf/orthogonal/OrthoRep.h | 499 --- ext/OGDF/ogdf/orthogonal/OrthoShaper.h | 259 -- ext/OGDF/ogdf/packing/ComponentSplitterLayout.h | 97 - ext/OGDF/ogdf/packing/TileToRowsCCPacker.h | 121 - ext/OGDF/ogdf/planarity/BoothLueker.h | 141 - ext/OGDF/ogdf/planarity/BoyerMyrvold.h | 288 -- ext/OGDF/ogdf/planarity/EdgeTypePatterns.h | 97 - ext/OGDF/ogdf/planarity/EmbedderMaxFace.h | 164 - ext/OGDF/ogdf/planarity/EmbedderMaxFaceLayers.h | 169 - ext/OGDF/ogdf/planarity/EmbedderMinDepth.h | 186 - ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFace.h | 190 - .../ogdf/planarity/EmbedderMinDepthMaxFaceLayers.h | 195 - ext/OGDF/ogdf/planarity/EmbedderMinDepthPiTa.h | 327 -- ext/OGDF/ogdf/planarity/ExtractKuratowskis.h | 474 --- ext/OGDF/ogdf/planarity/FastPlanarSubgraph.h | 138 - ext/OGDF/ogdf/planarity/FixedEmbeddingInserter.h | 230 -- ext/OGDF/ogdf/planarity/KuratowskiSubdivision.h | 63 - ext/OGDF/ogdf/planarity/MMFixedEmbeddingInserter.h | 376 -- ext/OGDF/ogdf/planarity/MMSubgraphPlanarizer.h | 99 - .../ogdf/planarity/MMVariableEmbeddingInserter.h | 326 -- .../ogdf/planarity/MaximalPlanarSubgraphSimple.h | 88 - ext/OGDF/ogdf/planarity/MaximumPlanarSubgraph.h | 105 - ext/OGDF/ogdf/planarity/MultiEdgeApproxInserter.h | 202 - ext/OGDF/ogdf/planarity/NodeTypePatterns.h | 97 - ext/OGDF/ogdf/planarity/NonPlanarCore.h | 102 - ext/OGDF/ogdf/planarity/PlanRep.h | 770 ---- ext/OGDF/ogdf/planarity/PlanRepExpansion.h | 509 --- ext/OGDF/ogdf/planarity/PlanRepInc.h | 194 - ext/OGDF/ogdf/planarity/PlanRepUML.h | 201 - ext/OGDF/ogdf/planarity/PlanarizationGridLayout.h | 240 -- ext/OGDF/ogdf/planarity/PlanarizationLayout.h | 449 --- ext/OGDF/ogdf/planarity/SimpleEmbedder.h | 85 - ext/OGDF/ogdf/planarity/SimpleIncNodeInserter.h | 125 - ext/OGDF/ogdf/planarity/SubgraphPlanarizer.h | 175 - .../ogdf/planarity/VariableEmbeddingInserter.h | 214 - .../ogdf/planarity/VariableEmbeddingInserter2.h | 161 - .../ogdf/planarlayout/BiconnectedShellingOrder.h | 83 - ext/OGDF/ogdf/planarlayout/FPPLayout.h | 104 - ext/OGDF/ogdf/planarlayout/MMCBBase.h | 81 - ext/OGDF/ogdf/planarlayout/MMCBDoubleGrid.h | 78 - ext/OGDF/ogdf/planarlayout/MMCBLocalStretch.h | 78 - ext/OGDF/ogdf/planarlayout/MixedModelLayout.h | 192 - ext/OGDF/ogdf/planarlayout/PlanarDrawLayout.h | 242 -- ext/OGDF/ogdf/planarlayout/PlanarStraightLayout.h | 224 -- ext/OGDF/ogdf/planarlayout/SchnyderLayout.h | 115 - ext/OGDF/ogdf/planarlayout/ShellingOrder.h | 263 -- .../ogdf/planarlayout/TriconnectedShellingOrder.h | 82 - ext/OGDF/ogdf/simultaneous/SimDraw.h | 229 -- ext/OGDF/ogdf/simultaneous/SimDrawCaller.h | 130 - ext/OGDF/ogdf/simultaneous/SimDrawColorizer.h | 166 - ext/OGDF/ogdf/simultaneous/SimDrawCreator.h | 126 - ext/OGDF/ogdf/simultaneous/SimDrawCreatorSimple.h | 93 - .../ogdf/simultaneous/SimDrawManipulatorModule.h | 102 - .../ogdf/simultaneous/TwoLayerCrossMinSimDraw.h | 81 - ext/OGDF/ogdf/tree/RadialTreeLayout.h | 225 -- ext/OGDF/ogdf/tree/TreeLayout.h | 302 -- ext/OGDF/ogdf/upward/DominanceLayout.h | 136 - ext/OGDF/ogdf/upward/ExpansionGraph.h | 163 - ext/OGDF/ogdf/upward/FUPSSimple.h | 139 - ext/OGDF/ogdf/upward/FaceSinkGraph.h | 221 -- .../ogdf/upward/FeasibleUpwardPlanarSubgraph.h | 135 - .../ogdf/upward/FixedEmbeddingUpwardEdgeInserter.h | 171 - .../ogdf/upward/FixedUpwardEmbeddingInserter.h | 153 - ext/OGDF/ogdf/upward/LayerBasedUPRLayout.h | 232 -- ext/OGDF/ogdf/upward/SubgraphUpwardPlanarizer.h | 132 - ext/OGDF/ogdf/upward/UpwardPlanRep.h | 233 -- ext/OGDF/ogdf/upward/UpwardPlanarModule.h | 280 -- ext/OGDF/ogdf/upward/UpwardPlanarSubgraphSimple.h | 98 - ext/OGDF/ogdf/upward/UpwardPlanarizationLayout.h | 127 - ext/OGDF/ogdf/upward/VisibilityLayout.h | 135 - ext/OGDF/src/augmentation/DfsMakeBiconnected.cpp | 58 - ext/OGDF/src/augmentation/PlanarAugmentation.cpp | 1446 ------- .../src/augmentation/PlanarAugmentationFix.cpp | 1102 ------ ext/OGDF/src/basic/CliqueFinder.cpp | 1030 ----- ext/OGDF/src/basic/CombinatorialEmbedding.cpp | 630 --- ext/OGDF/src/basic/Constraint.cpp | 83 - ext/OGDF/src/basic/ConstraintManager.cpp | 67 - ext/OGDF/src/basic/DisjointSets.cpp | 52 - ext/OGDF/src/basic/DualGraph.cpp | 127 - ext/OGDF/src/basic/EdgeComparer.cpp | 381 -- ext/OGDF/src/basic/EdgeComparerSimple.cpp | 153 - ext/OGDF/src/basic/Graph.cpp | 1481 ------- ext/OGDF/src/basic/GraphAttributes.cpp | 1256 ------ ext/OGDF/src/basic/GraphConstraints.cpp | 72 - ext/OGDF/src/basic/GraphCopy.cpp | 677 ---- ext/OGDF/src/basic/GridLayout.cpp | 458 --- ext/OGDF/src/basic/GridLayoutModule.cpp | 189 - ext/OGDF/src/basic/Hashing.cpp | 207 - ext/OGDF/src/basic/Logger.cpp | 63 - ext/OGDF/src/basic/Math.cpp | 112 - ext/OGDF/src/basic/NearestRectangleFinder.cpp | 383 -- ext/OGDF/src/basic/PoolMemoryAllocator.cpp | 448 --- ext/OGDF/src/basic/PreprocessorLayout.cpp | 127 - ext/OGDF/src/basic/String.cpp | 219 -- ext/OGDF/src/basic/System.cpp | 443 --- ext/OGDF/src/basic/UMLGraph.cpp | 717 ---- ext/OGDF/src/basic/basic.cpp | 357 -- ext/OGDF/src/basic/extended_graph_alg.cpp | 583 --- ext/OGDF/src/basic/geometry.cpp | 804 ---- ext/OGDF/src/basic/graph_generators.cpp | 1205 ------ ext/OGDF/src/basic/modules.cpp | 78 - ext/OGDF/src/basic/random_hierarchy.cpp | 237 -- ext/OGDF/src/basic/simple_graph_alg.cpp | 1056 ----- ext/OGDF/src/basic/stNumber.cpp | 348 -- ext/OGDF/src/cluster/CPlanarEdgeInserter.cpp | 853 ---- ext/OGDF/src/cluster/CPlanarSubCLusteredST.cpp | 242 -- ext/OGDF/src/cluster/CPlanarSubClusteredGraph.cpp | 165 - ext/OGDF/src/cluster/CconnectClusterPlanar.cpp | 737 ---- .../src/cluster/CconnectClusterPlanarEmbed.cpp | 2303 ----------- ext/OGDF/src/cluster/ClusterGraph.cpp | 1775 --------- ext/OGDF/src/cluster/ClusterGraphAttributes.cpp | 740 ---- .../src/cluster/ClusterPlanarizationLayout.cpp | 525 --- ext/OGDF/src/cluster/Cluster_ChunkConnection.cpp | 92 - ext/OGDF/src/cluster/Cluster_CutConstraint.cpp | 76 - ext/OGDF/src/cluster/Cluster_EdgeVar.cpp | 83 - ext/OGDF/src/cluster/Cluster_MaxPlanarEdges.cpp | 89 - ext/OGDF/src/cluster/Clusterer.cpp | 587 --- ext/OGDF/src/cluster/KuratowskiConstraint.cpp | 77 - ext/OGDF/src/cluster/MaxCPlanar_Master.cpp | 1034 ----- .../MaxCPlanar_MinimalClusterConnection.cpp | 85 - ext/OGDF/src/cluster/MaxCPlanar_Sub.cpp | 2573 ------------ ext/OGDF/src/cluster/MaximumCPlanarSubgraph.cpp | 547 --- ext/OGDF/src/decomposition/BCTree.cpp | 309 -- ext/OGDF/src/decomposition/DynamicBCTree.cpp | 288 -- ext/OGDF/src/decomposition/DynamicSPQRForest.cpp | 837 ---- ext/OGDF/src/decomposition/DynamicSPQRTree.cpp | 306 -- ext/OGDF/src/decomposition/NonPlanarCore.cpp | 325 -- ext/OGDF/src/decomposition/PlanarSPQRTree.cpp | 407 -- ext/OGDF/src/decomposition/StaticSPQRTree.cpp | 272 -- ext/OGDF/src/decomposition/TricComp.cpp | 1194 ------ ext/OGDF/src/decomposition/TricComp.h | 216 - ext/OGDF/src/energybased/AdjacencyOracle.cpp | 91 - ext/OGDF/src/energybased/ArrayGraph.cpp | 249 -- ext/OGDF/src/energybased/ArrayGraph.h | 354 -- ext/OGDF/src/energybased/Attraction.cpp | 99 - ext/OGDF/src/energybased/CoinTutteLayout.cpp | 384 -- ext/OGDF/src/energybased/ComplexDouble.h | 479 --- ext/OGDF/src/energybased/DavidsonHarel.cpp | 365 -- ext/OGDF/src/energybased/DavidsonHarelLayout.cpp | 229 -- ext/OGDF/src/energybased/Edge.h | 154 - ext/OGDF/src/energybased/EdgeAttributes.cpp | 87 - ext/OGDF/src/energybased/EnergyFunction.cpp | 98 - ext/OGDF/src/energybased/FMEFunc.h | 1047 ----- ext/OGDF/src/energybased/FMEFunctional.h | 236 -- ext/OGDF/src/energybased/FMEKernel.cpp | 741 ---- ext/OGDF/src/energybased/FMEKernel.h | 290 -- ext/OGDF/src/energybased/FMEMultipoleKernel.cpp | 650 --- ext/OGDF/src/energybased/FMEMultipoleKernel.h | 216 - ext/OGDF/src/energybased/FMEThread.cpp | 151 - ext/OGDF/src/energybased/FMEThread.h | 199 - ext/OGDF/src/energybased/FMMMLayout.cpp | 1644 -------- ext/OGDF/src/energybased/FastMultipoleEmbedder.cpp | 478 --- ext/OGDF/src/energybased/FastUtils.h | 616 --- ext/OGDF/src/energybased/FruchtermanReingold.cpp | 269 -- ext/OGDF/src/energybased/GEMLayout.cpp | 363 -- ext/OGDF/src/energybased/GalaxyMultilevel.cpp | 249 -- ext/OGDF/src/energybased/GalaxyMultilevel.h | 169 - ext/OGDF/src/energybased/IntersectionRectangle.cpp | 198 - ext/OGDF/src/energybased/LinearQuadtree.cpp | 166 - ext/OGDF/src/energybased/LinearQuadtree.h | 810 ---- ext/OGDF/src/energybased/LinearQuadtreeBuilder.cpp | 147 - ext/OGDF/src/energybased/LinearQuadtreeBuilder.h | 141 - .../src/energybased/LinearQuadtreeExpansion.cpp | 259 -- ext/OGDF/src/energybased/LinearQuadtreeExpansion.h | 118 - ext/OGDF/src/energybased/MAARPacking.cpp | 420 -- ext/OGDF/src/energybased/MAARPacking.h | 157 - ext/OGDF/src/energybased/Multilevel.cpp | 885 ----- ext/OGDF/src/energybased/Multilevel.h | 244 -- ext/OGDF/src/energybased/MultilevelGraph.cpp | 834 ---- ext/OGDF/src/energybased/MultilevelLayout.cpp | 118 - ext/OGDF/src/energybased/NMM.cpp | 2867 -------------- ext/OGDF/src/energybased/Node.h | 96 - ext/OGDF/src/energybased/NodeAttributes.cpp | 143 - ext/OGDF/src/energybased/NodePairEnergy.cpp | 169 - ext/OGDF/src/energybased/Overlap.cpp | 68 - ext/OGDF/src/energybased/PQueue.h | 173 - ext/OGDF/src/energybased/PackingRowInfo.h | 102 - ext/OGDF/src/energybased/Planarity.cpp | 197 - ext/OGDF/src/energybased/PlanarityGrid.cpp | 110 - ext/OGDF/src/energybased/QuadTreeNM.cpp | 288 -- ext/OGDF/src/energybased/QuadTreeNodeNM.cpp | 193 - ext/OGDF/src/energybased/Rectangle.h | 205 - ext/OGDF/src/energybased/Repulsion.cpp | 81 - ext/OGDF/src/energybased/Set.cpp | 241 -- ext/OGDF/src/energybased/Set.h | 128 - ext/OGDF/src/energybased/SpringEmbedderFR.cpp | 420 -- ext/OGDF/src/energybased/SpringEmbedderFRExact.cpp | 599 --- ext/OGDF/src/energybased/SpringEmbedderKK.cpp | 644 --- .../src/energybased/StressMajorizationSimple.cpp | 613 --- ext/OGDF/src/energybased/UniformGrid.cpp | 736 ---- ext/OGDF/src/energybased/WSPD.cpp | 93 - ext/OGDF/src/energybased/WSPD.h | 229 -- .../multilevelmixer/BarycenterPlacer.cpp | 97 - .../energybased/multilevelmixer/CirclePlacer.cpp | 117 - .../multilevelmixer/EdgeCoverMerger.cpp | 180 - .../multilevelmixer/IndependentSetMerger.cpp | 239 -- .../multilevelmixer/LocalBiconnectedMerger.cpp | 373 -- .../multilevelmixer/MMMExampleFastLayout.cpp | 107 - .../multilevelmixer/MMMExampleNiceLayout.cpp | 115 - .../multilevelmixer/MMMExampleNoTwistLayout.cpp | 110 - .../energybased/multilevelmixer/MatchingMerger.cpp | 150 - .../energybased/multilevelmixer/MedianPlacer.cpp | 87 - .../multilevelmixer/MixedForceLayout.cpp | 77 - .../multilevelmixer/ModularMultilevelMixer.cpp | 185 - .../energybased/multilevelmixer/RandomMerger.cpp | 119 - .../energybased/multilevelmixer/RandomPlacer.cpp | 99 - .../energybased/multilevelmixer/ScalingLayout.cpp | 203 - .../energybased/multilevelmixer/SolarMerger.cpp | 444 --- .../energybased/multilevelmixer/SolarPlacer.cpp | 92 - .../src/energybased/multilevelmixer/ZeroPlacer.cpp | 78 - ext/OGDF/src/energybased/numexcept.cpp | 214 - ext/OGDF/src/energybased/numexcept.h | 101 - ext/OGDF/src/external/coin.cpp | 240 -- ext/OGDF/src/fileformats/DinoLineBuffer.cpp | 424 -- ext/OGDF/src/fileformats/DinoTools.cpp | 114 - ext/OGDF/src/fileformats/DinoUmlDiagramGraph.cpp | 192 - ext/OGDF/src/fileformats/DinoUmlModelGraph.cpp | 111 - .../src/fileformats/DinoUmlToGraphConverter.cpp | 1034 ----- ext/OGDF/src/fileformats/DinoXmlParser.cpp | 913 ----- ext/OGDF/src/fileformats/DinoXmlScanner.cpp | 448 --- ext/OGDF/src/fileformats/GmlParser.cpp | 1315 ------- ext/OGDF/src/fileformats/Ogml.cpp | 303 -- ext/OGDF/src/fileformats/OgmlParser.cpp | 3937 ------------------- ext/OGDF/src/fileformats/XmlParser.cpp | 1204 ------ ext/OGDF/src/fileformats/simple_graph_load.cpp | 710 ---- ext/OGDF/src/graphalg/ConvexHull.cpp | 454 --- ext/OGDF/src/graphalg/MinCostFlowModule.cpp | 162 - ext/OGDF/src/graphalg/MinCostFlowReinelt.cpp | 1030 ----- ext/OGDF/src/graphalg/MinimumCut.cpp | 343 -- ext/OGDF/src/graphalg/PageRank.cpp | 135 - ext/OGDF/src/graphalg/ShortestPathsWithBFM.cpp | 93 - ext/OGDF/src/graphalg/mcf_front_reinelt.cpp | 180 - ext/OGDF/src/incremental/SimpleIncNodeInserter.cpp | 665 ---- ext/OGDF/src/labeling/ELabelPosSimple.cpp | 177 - ext/OGDF/src/layered/CoffmanGrahamRanking.cpp | 264 -- ext/OGDF/src/layered/CrossingsMatrix.cpp | 172 - ext/OGDF/src/layered/FastHierarchyLayout.cpp | 1254 ------ ext/OGDF/src/layered/FastSimpleHierarchyLayout.cpp | 469 --- ext/OGDF/src/layered/HierarchyLayoutModule.cpp | 551 --- .../src/layered/OptimalHierarchyClusterLayout.cpp | 897 ----- ext/OGDF/src/layered/OptimalHierarchyLayout.cpp | 647 --- ext/OGDF/src/layered/OptimalRanking.cpp | 218 - ext/OGDF/src/layered/SplitHeuristic.cpp | 125 - ext/OGDF/src/layered/acyclic_subgraph.cpp | 351 -- ext/OGDF/src/layered/heuristics.cpp | 265 -- ext/OGDF/src/layered/ranking.cpp | 475 --- ext/OGDF/src/layered/sugiyama-cluster.cpp | 1928 --------- ext/OGDF/src/layered/sugiyama.cpp | 1293 ------ ext/OGDF/src/lpsolver/LPSolver_coin.cpp | 206 - ext/OGDF/src/misclayout/BalloonLayout.cpp | 738 ---- ext/OGDF/src/misclayout/CircularLayout.cpp | 1968 ---------- ext/OGDF/src/misclayout/ProcrustesSubLayout.cpp | 287 -- ext/OGDF/src/orthogonal/ClusterOrthoLayout.cpp | 355 -- ext/OGDF/src/orthogonal/ClusterOrthoShaper.cpp | 1347 ------- .../src/orthogonal/CompactionConstraintGraph.cpp | 678 ---- ext/OGDF/src/orthogonal/EdgeLabel-impl.h | 2925 -------------- ext/OGDF/src/orthogonal/EdgeRouter.cpp | 4145 -------------------- ext/OGDF/src/orthogonal/FlowCompaction.cpp | 770 ---- ext/OGDF/src/orthogonal/LongestPathCompaction.cpp | 372 -- ext/OGDF/src/orthogonal/NodeInfo.cpp | 153 - ext/OGDF/src/orthogonal/OrthoLayout.cpp | 411 -- ext/OGDF/src/orthogonal/OrthoRep.cpp | 1238 ------ ext/OGDF/src/orthogonal/OrthoShaper.cpp | 1746 --------- ext/OGDF/src/packing/CCLayoutPackModule.cpp | 93 - ext/OGDF/src/packing/ComponentSplitterLayout.cpp | 385 -- ext/OGDF/src/packing/TileToRowsCCPacker.cpp | 231 -- ext/OGDF/src/planarity/BoothLueker.cpp | 582 --- ext/OGDF/src/planarity/BoyerMyrvold.cpp | 376 -- ext/OGDF/src/planarity/BoyerMyrvoldInit.cpp | 269 -- ext/OGDF/src/planarity/BoyerMyrvoldPlanar.cpp | 927 ----- ext/OGDF/src/planarity/ClusterPlanRep.cpp | 573 --- ext/OGDF/src/planarity/EdgeInsertionModule.cpp | 83 - ext/OGDF/src/planarity/EmbedPQTree.cpp | 608 --- ext/OGDF/src/planarity/EmbedderMaxFace.cpp | 467 --- ext/OGDF/src/planarity/EmbedderMaxFaceLayers.cpp | 646 --- ext/OGDF/src/planarity/EmbedderMinDepth.cpp | 810 ---- ext/OGDF/src/planarity/EmbedderMinDepthMaxFace.cpp | 958 ----- .../planarity/EmbedderMinDepthMaxFaceLayers.cpp | 1123 ------ ext/OGDF/src/planarity/EmbedderMinDepthPiTa.cpp | 1558 -------- ext/OGDF/src/planarity/ExtractKuratowskis.cpp | 1847 --------- ext/OGDF/src/planarity/FastPlanarSubgraph.cpp | 309 -- ext/OGDF/src/planarity/FindKuratowskis.cpp | 790 ---- ext/OGDF/src/planarity/FixedEmbeddingInserter.cpp | 862 ---- ext/OGDF/src/planarity/GraphReduction.cpp | 146 - ext/OGDF/src/planarity/Layout.cpp | 119 - ext/OGDF/src/planarity/LayoutPlanRepModule.cpp | 106 - ext/OGDF/src/planarity/MDMFLengthAttribute.cpp | 173 - .../src/planarity/MMCrossingMinimizationModule.cpp | 194 - .../src/planarity/MMFixedEmbeddingInserter.cpp | 1421 ------- ext/OGDF/src/planarity/MMSubgraphPlanarizer.cpp | 131 - .../src/planarity/MMVariableEmbeddingInserter.cpp | 1893 --------- .../src/planarity/MaximalPlanarSubgraphSimple.cpp | 101 - ext/OGDF/src/planarity/MaximumPlanarSubgraph.cpp | 179 - ext/OGDF/src/planarity/MultiEdgeApproxInserter.cpp | 1743 -------- ext/OGDF/src/planarity/PlanRep.cpp | 972 ----- ext/OGDF/src/planarity/PlanRepExpansion.cpp | 1201 ------ ext/OGDF/src/planarity/PlanRepInc.cpp | 1046 ----- ext/OGDF/src/planarity/PlanRepUML.cpp | 1355 ------- ext/OGDF/src/planarity/PlanarPQTree.cpp | 194 - ext/OGDF/src/planarity/PlanarSubgraphModule.cpp | 75 - ext/OGDF/src/planarity/PlanarSubgraphPQTree.cpp | 246 -- ext/OGDF/src/planarity/PlanarizationGridLayout.cpp | 174 - ext/OGDF/src/planarity/PlanarizationLayout.cpp | 1354 ------- ext/OGDF/src/planarity/PlanarizationLayout_inc.cpp | 623 --- ext/OGDF/src/planarity/SimpleEmbedder.cpp | 132 - ext/OGDF/src/planarity/SubgraphPlanarizer.cpp | 241 -- ext/OGDF/src/planarity/TopologyModule.cpp | 1234 ------ .../src/planarity/VariableEmbeddingInserter.cpp | 1227 ------ .../src/planarity/VariableEmbeddingInserter2.cpp | 931 ----- .../src/planarlayout/BiconnectedShellingOrder.cpp | 1370 ------- ext/OGDF/src/planarlayout/FPPLayout.cpp | 298 -- ext/OGDF/src/planarlayout/IOPoints.cpp | 163 - ext/OGDF/src/planarlayout/IOPoints.h | 251 -- ext/OGDF/src/planarlayout/MMCBBase.cpp | 456 --- ext/OGDF/src/planarlayout/MMOrder.h | 96 - ext/OGDF/src/planarlayout/MixedModelBase.cpp | 1122 ------ ext/OGDF/src/planarlayout/MixedModelBase.h | 132 - .../MixedModelCrossingsBeautifierModule.cpp | 67 - ext/OGDF/src/planarlayout/MixedModelLayout.cpp | 128 - ext/OGDF/src/planarlayout/PlanarDrawLayout.cpp | 337 -- ext/OGDF/src/planarlayout/PlanarStraightLayout.cpp | 325 -- ext/OGDF/src/planarlayout/SchnyderLayout.cpp | 412 -- ext/OGDF/src/planarlayout/ShellingOrder.cpp | 119 - ext/OGDF/src/planarlayout/ShellingOrderModule.cpp | 73 - .../src/planarlayout/TriconnectedShellingOrder.cpp | 733 ---- ext/OGDF/src/simultaneous/SimDraw.cpp | 389 -- ext/OGDF/src/simultaneous/SimDrawCaller.cpp | 209 - ext/OGDF/src/simultaneous/SimDrawColorizer.cpp | 273 -- ext/OGDF/src/simultaneous/SimDrawCreator.cpp | 168 - ext/OGDF/src/simultaneous/SimDrawCreatorSimple.cpp | 616 --- .../src/simultaneous/SimDrawManipulatorModule.cpp | 70 - ext/OGDF/src/tree/RadialTreeLayout.cpp | 570 --- ext/OGDF/src/tree/TreeLayout.cpp | 1013 ----- ext/OGDF/src/upward/DominanceLayout.cpp | 301 -- ext/OGDF/src/upward/ExpansionGraph.cpp | 188 - ext/OGDF/src/upward/FUPSSimple.cpp | 329 -- ext/OGDF/src/upward/FaceSinkGraph.cpp | 553 --- .../src/upward/FeasibleUpwardPlanarSubgraph.cpp | 262 -- .../upward/FixedEmbeddingUpwardEdgeInserter.cpp | 832 ---- ext/OGDF/src/upward/LayerBasedUPRLayout.cpp | 1279 ------ ext/OGDF/src/upward/SubgraphUpwardPlanarizer.cpp | 695 ---- ext/OGDF/src/upward/UpwardPlanRep.cpp | 542 --- ext/OGDF/src/upward/UpwardPlanarModule.cpp | 1405 ------- ext/OGDF/src/upward/UpwardPlanarSubgraphModule.cpp | 68 - ext/OGDF/src/upward/UpwardPlanarSubgraphSimple.cpp | 308 -- ext/OGDF/src/upward/VisibilityLayout.cpp | 301 -- 669 files changed, 5 insertions(+), 241590 deletions(-) create mode 160000 ext/OGDF delete mode 100644 ext/OGDF/LICENSE.txt delete mode 100644 ext/OGDF/LICENSE_GPL_v2.txt delete mode 100644 ext/OGDF/LICENSE_GPL_v3.txt delete mode 100644 ext/OGDF/Makefile.README delete mode 100644 ext/OGDF/Makefile.header delete mode 100644 ext/OGDF/README.txt delete mode 100644 ext/OGDF/config/ogdf.dll.vcproj.vs2005.template delete mode 100644 ext/OGDF/config/ogdf.dll.vcproj.vs2008.template delete mode 100644 ext/OGDF/config/ogdf.dll.vcxproj.vs2010.template delete mode 100644 ext/OGDF/config/ogdf.dll.vcxproj.vs2012.template delete mode 100644 ext/OGDF/config/ogdf.vcproj.vs2003.template delete mode 100644 ext/OGDF/config/ogdf.vcproj.vs2005.template delete mode 100644 ext/OGDF/config/ogdf.vcproj.vs2008.template delete mode 100644 ext/OGDF/config/ogdf.vcxproj.filters.template delete mode 100644 ext/OGDF/config/ogdf.vcxproj.vs2010.template delete mode 100644 ext/OGDF/config/ogdf.vcxproj.vs2012.template delete mode 100644 ext/OGDF/doc/build-ogdf-docs.bat delete mode 100644 ext/OGDF/doc/build-ogdf-docs.sh delete mode 100644 ext/OGDF/doc/govisual-footer.html delete mode 100644 ext/OGDF/doc/govisual-header.html delete mode 100644 ext/OGDF/doc/govisual.css delete mode 100644 ext/OGDF/doc/images/ftv2doc.png delete mode 100644 ext/OGDF/doc/images/ftv2folderclosed.png delete mode 100644 ext/OGDF/doc/images/ftv2folderopen.png delete mode 100644 ext/OGDF/doc/images/insertEdgePathEmbedded.png delete mode 100644 ext/OGDF/doc/images/insertEdgePathEmbedded.svg delete mode 100644 ext/OGDF/doc/ogdf-doxygen.cfg delete mode 100644 ext/OGDF/makeMakefile.config delete mode 100644 ext/OGDF/makeMakefile.py delete mode 100644 ext/OGDF/makeMakefile.sh delete mode 100644 ext/OGDF/makeVCProj.config delete mode 100644 ext/OGDF/makeVCProj.py delete mode 100644 ext/OGDF/makeVCXProj.config delete mode 100644 ext/OGDF/makeVCXProj.py delete mode 100644 ext/OGDF/makeVCXProjPython3.py delete mode 100644 ext/OGDF/ogdf/augmentation/DfsMakeBiconnected.h delete mode 100644 ext/OGDF/ogdf/augmentation/PlanarAugmentation.h delete mode 100644 ext/OGDF/ogdf/augmentation/PlanarAugmentationFix.h delete mode 100644 ext/OGDF/ogdf/basic/AdjEntryArray.h delete mode 100644 ext/OGDF/ogdf/basic/Array.h delete mode 100644 ext/OGDF/ogdf/basic/Array2D.h delete mode 100644 ext/OGDF/ogdf/basic/ArrayBuffer.h delete mode 100644 ext/OGDF/ogdf/basic/Barrier.h delete mode 100644 ext/OGDF/ogdf/basic/BinaryHeap.h delete mode 100644 ext/OGDF/ogdf/basic/BinaryHeap2.h delete mode 100644 ext/OGDF/ogdf/basic/BoundedQueue.h delete mode 100644 ext/OGDF/ogdf/basic/BoundedStack.h delete mode 100644 ext/OGDF/ogdf/basic/CombinatorialEmbedding.h delete mode 100644 ext/OGDF/ogdf/basic/Constraints.h delete mode 100644 ext/OGDF/ogdf/basic/CriticalSection.h delete mode 100644 ext/OGDF/ogdf/basic/DisjointSets.h delete mode 100644 ext/OGDF/ogdf/basic/DualGraph.h delete mode 100644 ext/OGDF/ogdf/basic/EFreeList.h delete mode 100644 ext/OGDF/ogdf/basic/EList.h delete mode 100644 ext/OGDF/ogdf/basic/EdgeArray.h delete mode 100644 ext/OGDF/ogdf/basic/EdgeComparer.h delete mode 100644 ext/OGDF/ogdf/basic/EdgeComparerSimple.h delete mode 100644 ext/OGDF/ogdf/basic/FaceArray.h delete mode 100644 ext/OGDF/ogdf/basic/FaceSet.h delete mode 100644 ext/OGDF/ogdf/basic/Graph.h delete mode 100644 ext/OGDF/ogdf/basic/GraphAttributes.h delete mode 100644 ext/OGDF/ogdf/basic/GraphCopy.h delete mode 100644 ext/OGDF/ogdf/basic/GraphCopyAttributes.h delete mode 100644 ext/OGDF/ogdf/basic/GraphObserver.h delete mode 100644 ext/OGDF/ogdf/basic/Graph_d.h delete mode 100644 ext/OGDF/ogdf/basic/GridLayout.h delete mode 100644 ext/OGDF/ogdf/basic/GridLayoutMapped.h delete mode 100644 ext/OGDF/ogdf/basic/HashArray.h delete mode 100644 ext/OGDF/ogdf/basic/HashArray2D.h delete mode 100644 ext/OGDF/ogdf/basic/HashIterator2D.h delete mode 100644 ext/OGDF/ogdf/basic/Hashing.h delete mode 100644 ext/OGDF/ogdf/basic/HeapBase.h delete mode 100644 ext/OGDF/ogdf/basic/HyperGraph.h delete mode 100644 ext/OGDF/ogdf/basic/IncNodeInserter.h delete mode 100644 ext/OGDF/ogdf/basic/Layout.h delete mode 100644 ext/OGDF/ogdf/basic/List.h delete mode 100644 ext/OGDF/ogdf/basic/Logger.h delete mode 100644 ext/OGDF/ogdf/basic/Math.h delete mode 100644 ext/OGDF/ogdf/basic/MinHeap.h delete mode 100644 ext/OGDF/ogdf/basic/MinPriorityQueue.h delete mode 100644 ext/OGDF/ogdf/basic/Module.h delete mode 100644 ext/OGDF/ogdf/basic/ModuleOption.h delete mode 100644 ext/OGDF/ogdf/basic/NearestRectangleFinder.h delete mode 100644 ext/OGDF/ogdf/basic/NodeArray.h delete mode 100644 ext/OGDF/ogdf/basic/NodeComparer.h delete mode 100644 ext/OGDF/ogdf/basic/NodeSet.h delete mode 100644 ext/OGDF/ogdf/basic/PreprocessorLayout.h delete mode 100644 ext/OGDF/ogdf/basic/Queue.h delete mode 100644 ext/OGDF/ogdf/basic/SList.h delete mode 100644 ext/OGDF/ogdf/basic/Skiplist.h delete mode 100644 ext/OGDF/ogdf/basic/Stack.h delete mode 100644 ext/OGDF/ogdf/basic/String.h delete mode 100644 ext/OGDF/ogdf/basic/System.h delete mode 100644 ext/OGDF/ogdf/basic/Thread.h delete mode 100644 ext/OGDF/ogdf/basic/Timeouter.h delete mode 100644 ext/OGDF/ogdf/basic/TopologyModule.h delete mode 100644 ext/OGDF/ogdf/basic/UMLGraph.h delete mode 100644 ext/OGDF/ogdf/basic/basic.h delete mode 100644 ext/OGDF/ogdf/basic/comparer.h delete mode 100644 ext/OGDF/ogdf/basic/exceptions.h delete mode 100644 ext/OGDF/ogdf/basic/extended_graph_alg.h delete mode 100644 ext/OGDF/ogdf/basic/geometry.h delete mode 100644 ext/OGDF/ogdf/basic/graph_generators.h delete mode 100644 ext/OGDF/ogdf/basic/memory.h delete mode 100644 ext/OGDF/ogdf/basic/precondition.h delete mode 100644 ext/OGDF/ogdf/basic/simple_graph_alg.h delete mode 100644 ext/OGDF/ogdf/basic/tuples.h delete mode 100644 ext/OGDF/ogdf/cluster/CPlanarEdgeInserter.h delete mode 100644 ext/OGDF/ogdf/cluster/CPlanarSubClusteredGraph.h delete mode 100644 ext/OGDF/ogdf/cluster/CconnectClusterPlanar.h delete mode 100644 ext/OGDF/ogdf/cluster/CconnectClusterPlanarEmbed.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterArray.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterGraph.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterGraphAttributes.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterGraphCopyAttributes.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterGraphObserver.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterOrthoLayout.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterOrthoShaper.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterPlanRep.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterPlanarizationLayout.h delete mode 100644 ext/OGDF/ogdf/cluster/ClusterSet.h delete mode 100644 ext/OGDF/ogdf/cluster/MaximumCPlanarSubgraph.h delete mode 100644 ext/OGDF/ogdf/decomposition/BCTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/DynamicBCTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/DynamicPlanarSPQRTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/DynamicSPQRForest.h delete mode 100644 ext/OGDF/ogdf/decomposition/DynamicSPQRTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/DynamicSkeleton.h delete mode 100644 ext/OGDF/ogdf/decomposition/PertinentGraph.h delete mode 100644 ext/OGDF/ogdf/decomposition/PlanarSPQRTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/SPQRTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/Skeleton.h delete mode 100644 ext/OGDF/ogdf/decomposition/StaticPlanarSPQRTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/StaticSPQRTree.h delete mode 100644 ext/OGDF/ogdf/decomposition/StaticSkeleton.h delete mode 100644 ext/OGDF/ogdf/energybased/CoinTutteLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/DavidsonHarel.h delete mode 100644 ext/OGDF/ogdf/energybased/DavidsonHarelLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/FMMMLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/FastMultipoleEmbedder.h delete mode 100644 ext/OGDF/ogdf/energybased/GEMLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/MultilevelLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/SpringEmbedderFR.h delete mode 100644 ext/OGDF/ogdf/energybased/SpringEmbedderFRExact.h delete mode 100644 ext/OGDF/ogdf/energybased/SpringEmbedderKK.h delete mode 100644 ext/OGDF/ogdf/energybased/StressMajorizationSimple.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/BarycenterPlacer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/CirclePlacer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/EdgeCoverMerger.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/IndependentSetMerger.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/InitialPlacer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleFastLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNiceLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNoTwistLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MatchingMerger.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MedianPlacer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MixedForceLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/ModularMultilevelMixer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/MultilevelBuilder.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/RandomMerger.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/RandomPlacer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/ScalingLayout.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/SolarMerger.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/SolarPlacer.h delete mode 100644 ext/OGDF/ogdf/energybased/multilevelmixer/ZeroPlacer.h delete mode 100644 ext/OGDF/ogdf/external/abacus.h delete mode 100644 ext/OGDF/ogdf/external/coin.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoLineBuffer.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoTools.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoUmlDiagramGraph.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoUmlModelGraph.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoUmlToGraphConverter.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoXmlParser.h delete mode 100644 ext/OGDF/ogdf/fileformats/DinoXmlScanner.h delete mode 100644 ext/OGDF/ogdf/fileformats/GmlParser.h delete mode 100644 ext/OGDF/ogdf/fileformats/Ogml.h delete mode 100644 ext/OGDF/ogdf/fileformats/OgmlParser.h delete mode 100644 ext/OGDF/ogdf/fileformats/SteinLibParser.h delete mode 100644 ext/OGDF/ogdf/fileformats/XmlObject.h delete mode 100644 ext/OGDF/ogdf/fileformats/XmlParser.h delete mode 100644 ext/OGDF/ogdf/fileformats/simple_graph_load.h delete mode 100644 ext/OGDF/ogdf/graphalg/CliqueFinder.h delete mode 100644 ext/OGDF/ogdf/graphalg/Clusterer.h delete mode 100644 ext/OGDF/ogdf/graphalg/ConvexHull.h delete mode 100644 ext/OGDF/ogdf/graphalg/Dijkstra.h delete mode 100644 ext/OGDF/ogdf/graphalg/GraphReduction.h delete mode 100644 ext/OGDF/ogdf/graphalg/MinCostFlowReinelt.h delete mode 100644 ext/OGDF/ogdf/graphalg/MinimumCut.h delete mode 100644 ext/OGDF/ogdf/graphalg/PageRank.h delete mode 100644 ext/OGDF/ogdf/graphalg/ShortestPathWithBFM.h delete mode 100644 ext/OGDF/ogdf/internal/augmentation/PALabel.h delete mode 100644 ext/OGDF/ogdf/internal/basic/MallocMemoryAllocator.h delete mode 100644 ext/OGDF/ogdf/internal/basic/PoolMemoryAllocator.h delete mode 100644 ext/OGDF/ogdf/internal/basic/intrinsics.h delete mode 100644 ext/OGDF/ogdf/internal/basic/list_templates.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/CPlanarSubClusteredST.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/ClusterPQContainer.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/Cluster_ChunkConnection.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/Cluster_CutConstraint.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/Cluster_EdgeVar.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/Cluster_MaxPlanarEdges.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/KuratowskiConstraint.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Master.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/MaxCPlanar_MinimalClusterConnection.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Sub.h delete mode 100644 ext/OGDF/ogdf/internal/cluster/basics.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/AdjacencyOracle.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/Attraction.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/EdgeAttributes.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/EnergyFunction.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/FruchtermanReingold.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/IntersectionRectangle.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/MultilevelGraph.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/NMM.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/NodeAttributes.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/NodePairEnergy.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/Overlap.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/ParticleInfo.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/Planarity.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/PlanarityGrid.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/QuadTreeNM.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/QuadTreeNodeNM.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/Repulsion.h delete mode 100644 ext/OGDF/ogdf/internal/energybased/UniformGrid.h delete mode 100644 ext/OGDF/ogdf/internal/lpsolver/LPSolver_coin.h delete mode 100644 ext/OGDF/ogdf/internal/orthogonal/NodeInfo.h delete mode 100644 ext/OGDF/ogdf/internal/orthogonal/RoutingChannel.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldInit.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldPlanar.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/ConnectedSubgraph.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/EmbedIndicator.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/EmbedPQTree.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphs.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphsLayers.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/FindKuratowskis.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/IndInfo.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/MDMFLengthAttribute.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/MaxSequencePQTree.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQBasicKey.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQBasicKeyRoot.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQInternalKey.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQInternalNode.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQLeaf.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQLeafKey.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQNode.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQNodeKey.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQNodeRoot.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PQTree.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PlanarLeafKey.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PlanarPQTree.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/PlanarSubgraphPQTree.h delete mode 100644 ext/OGDF/ogdf/internal/planarity/whaInfo.h delete mode 100644 ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraph.h delete mode 100644 ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraphCopy.h delete mode 100644 ext/OGDF/ogdf/labeling/ELabelInterface.h delete mode 100644 ext/OGDF/ogdf/labeling/ELabelPosSimple.h delete mode 100644 ext/OGDF/ogdf/labeling/EdgeLabel.h delete mode 100644 ext/OGDF/ogdf/layered/BarycenterHeuristic.h delete mode 100644 ext/OGDF/ogdf/layered/CoffmanGrahamRanking.h delete mode 100644 ext/OGDF/ogdf/layered/CrossingsMatrix.h delete mode 100644 ext/OGDF/ogdf/layered/DfsAcyclicSubgraph.h delete mode 100644 ext/OGDF/ogdf/layered/ExtendedNestingGraph.h delete mode 100644 ext/OGDF/ogdf/layered/FastHierarchyLayout.h delete mode 100644 ext/OGDF/ogdf/layered/FastSimpleHierarchyLayout.h delete mode 100644 ext/OGDF/ogdf/layered/GreedyCycleRemoval.h delete mode 100644 ext/OGDF/ogdf/layered/GreedyInsertHeuristic.h delete mode 100644 ext/OGDF/ogdf/layered/GreedySwitchHeuristic.h delete mode 100644 ext/OGDF/ogdf/layered/Hierarchy.h delete mode 100644 ext/OGDF/ogdf/layered/Level.h delete mode 100644 ext/OGDF/ogdf/layered/LongestPathRanking.h delete mode 100644 ext/OGDF/ogdf/layered/MedianHeuristic.h delete mode 100644 ext/OGDF/ogdf/layered/OptimalHierarchyClusterLayout.h delete mode 100644 ext/OGDF/ogdf/layered/OptimalHierarchyLayout.h delete mode 100644 ext/OGDF/ogdf/layered/OptimalRanking.h delete mode 100644 ext/OGDF/ogdf/layered/SiftingHeuristic.h delete mode 100644 ext/OGDF/ogdf/layered/SplitHeuristic.h delete mode 100644 ext/OGDF/ogdf/layered/SugiyamaLayout.h delete mode 100644 ext/OGDF/ogdf/lpsolver/LPSolver.h delete mode 100644 ext/OGDF/ogdf/misclayout/BalloonLayout.h delete mode 100644 ext/OGDF/ogdf/misclayout/CircularLayout.h delete mode 100644 ext/OGDF/ogdf/misclayout/ProcrustesSubLayout.h delete mode 100644 ext/OGDF/ogdf/module/AcyclicSubgraphModule.h delete mode 100644 ext/OGDF/ogdf/module/AugmentationModule.h delete mode 100644 ext/OGDF/ogdf/module/CCLayoutPackModule.h delete mode 100644 ext/OGDF/ogdf/module/CPlanarSubgraphModule.h delete mode 100644 ext/OGDF/ogdf/module/ClustererModule.h delete mode 100644 ext/OGDF/ogdf/module/CrossingMinimizationModule.h delete mode 100644 ext/OGDF/ogdf/module/EdgeInsertionModule.h delete mode 100644 ext/OGDF/ogdf/module/EmbedderModule.h delete mode 100644 ext/OGDF/ogdf/module/FUPSModule.h delete mode 100644 ext/OGDF/ogdf/module/ForceLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/GridLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/HierarchyClusterLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/HierarchyLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/LayoutClusterPlanRepModule.h delete mode 100644 ext/OGDF/ogdf/module/LayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/LayoutPlanRepModule.h delete mode 100644 ext/OGDF/ogdf/module/MMCrossingMinimizationModule.h delete mode 100644 ext/OGDF/ogdf/module/MMEdgeInsertionModule.h delete mode 100644 ext/OGDF/ogdf/module/MinCostFlowModule.h delete mode 100644 ext/OGDF/ogdf/module/MixedModelCrossingsBeautifierModule.h delete mode 100644 ext/OGDF/ogdf/module/MultilevelLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/PlanarSubgraphModule.h delete mode 100644 ext/OGDF/ogdf/module/PlanarityModule.h delete mode 100644 ext/OGDF/ogdf/module/RankingModule.h delete mode 100644 ext/OGDF/ogdf/module/ShellingOrderModule.h delete mode 100644 ext/OGDF/ogdf/module/ShortestPathModule.h delete mode 100644 ext/OGDF/ogdf/module/TwoLayerCrossMin.h delete mode 100644 ext/OGDF/ogdf/module/UMLLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/UPRLayoutModule.h delete mode 100644 ext/OGDF/ogdf/module/UpwardEdgeInserterModule.h delete mode 100644 ext/OGDF/ogdf/module/UpwardPlanarSubgraphModule.h delete mode 100644 ext/OGDF/ogdf/module/UpwardPlanarizerModule.h delete mode 100644 ext/OGDF/ogdf/orthogonal/CompactionConstraintGraph.h delete mode 100644 ext/OGDF/ogdf/orthogonal/EdgeRouter.h delete mode 100644 ext/OGDF/ogdf/orthogonal/FlowCompaction.h delete mode 100644 ext/OGDF/ogdf/orthogonal/LongestPathCompaction.h delete mode 100644 ext/OGDF/ogdf/orthogonal/MinimumEdgeDistances.h delete mode 100644 ext/OGDF/ogdf/orthogonal/OrthoLayout.h delete mode 100644 ext/OGDF/ogdf/orthogonal/OrthoRep.h delete mode 100644 ext/OGDF/ogdf/orthogonal/OrthoShaper.h delete mode 100644 ext/OGDF/ogdf/packing/ComponentSplitterLayout.h delete mode 100644 ext/OGDF/ogdf/packing/TileToRowsCCPacker.h delete mode 100644 ext/OGDF/ogdf/planarity/BoothLueker.h delete mode 100644 ext/OGDF/ogdf/planarity/BoyerMyrvold.h delete mode 100644 ext/OGDF/ogdf/planarity/EdgeTypePatterns.h delete mode 100644 ext/OGDF/ogdf/planarity/EmbedderMaxFace.h delete mode 100644 ext/OGDF/ogdf/planarity/EmbedderMaxFaceLayers.h delete mode 100644 ext/OGDF/ogdf/planarity/EmbedderMinDepth.h delete mode 100644 ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFace.h delete mode 100644 ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFaceLayers.h delete mode 100644 ext/OGDF/ogdf/planarity/EmbedderMinDepthPiTa.h delete mode 100644 ext/OGDF/ogdf/planarity/ExtractKuratowskis.h delete mode 100644 ext/OGDF/ogdf/planarity/FastPlanarSubgraph.h delete mode 100644 ext/OGDF/ogdf/planarity/FixedEmbeddingInserter.h delete mode 100644 ext/OGDF/ogdf/planarity/KuratowskiSubdivision.h delete mode 100644 ext/OGDF/ogdf/planarity/MMFixedEmbeddingInserter.h delete mode 100644 ext/OGDF/ogdf/planarity/MMSubgraphPlanarizer.h delete mode 100644 ext/OGDF/ogdf/planarity/MMVariableEmbeddingInserter.h delete mode 100644 ext/OGDF/ogdf/planarity/MaximalPlanarSubgraphSimple.h delete mode 100644 ext/OGDF/ogdf/planarity/MaximumPlanarSubgraph.h delete mode 100644 ext/OGDF/ogdf/planarity/MultiEdgeApproxInserter.h delete mode 100644 ext/OGDF/ogdf/planarity/NodeTypePatterns.h delete mode 100644 ext/OGDF/ogdf/planarity/NonPlanarCore.h delete mode 100644 ext/OGDF/ogdf/planarity/PlanRep.h delete mode 100644 ext/OGDF/ogdf/planarity/PlanRepExpansion.h delete mode 100644 ext/OGDF/ogdf/planarity/PlanRepInc.h delete mode 100644 ext/OGDF/ogdf/planarity/PlanRepUML.h delete mode 100644 ext/OGDF/ogdf/planarity/PlanarizationGridLayout.h delete mode 100644 ext/OGDF/ogdf/planarity/PlanarizationLayout.h delete mode 100644 ext/OGDF/ogdf/planarity/SimpleEmbedder.h delete mode 100644 ext/OGDF/ogdf/planarity/SimpleIncNodeInserter.h delete mode 100644 ext/OGDF/ogdf/planarity/SubgraphPlanarizer.h delete mode 100644 ext/OGDF/ogdf/planarity/VariableEmbeddingInserter.h delete mode 100644 ext/OGDF/ogdf/planarity/VariableEmbeddingInserter2.h delete mode 100644 ext/OGDF/ogdf/planarlayout/BiconnectedShellingOrder.h delete mode 100644 ext/OGDF/ogdf/planarlayout/FPPLayout.h delete mode 100644 ext/OGDF/ogdf/planarlayout/MMCBBase.h delete mode 100644 ext/OGDF/ogdf/planarlayout/MMCBDoubleGrid.h delete mode 100644 ext/OGDF/ogdf/planarlayout/MMCBLocalStretch.h delete mode 100644 ext/OGDF/ogdf/planarlayout/MixedModelLayout.h delete mode 100644 ext/OGDF/ogdf/planarlayout/PlanarDrawLayout.h delete mode 100644 ext/OGDF/ogdf/planarlayout/PlanarStraightLayout.h delete mode 100644 ext/OGDF/ogdf/planarlayout/SchnyderLayout.h delete mode 100644 ext/OGDF/ogdf/planarlayout/ShellingOrder.h delete mode 100644 ext/OGDF/ogdf/planarlayout/TriconnectedShellingOrder.h delete mode 100644 ext/OGDF/ogdf/simultaneous/SimDraw.h delete mode 100644 ext/OGDF/ogdf/simultaneous/SimDrawCaller.h delete mode 100644 ext/OGDF/ogdf/simultaneous/SimDrawColorizer.h delete mode 100644 ext/OGDF/ogdf/simultaneous/SimDrawCreator.h delete mode 100644 ext/OGDF/ogdf/simultaneous/SimDrawCreatorSimple.h delete mode 100644 ext/OGDF/ogdf/simultaneous/SimDrawManipulatorModule.h delete mode 100644 ext/OGDF/ogdf/simultaneous/TwoLayerCrossMinSimDraw.h delete mode 100644 ext/OGDF/ogdf/tree/RadialTreeLayout.h delete mode 100644 ext/OGDF/ogdf/tree/TreeLayout.h delete mode 100644 ext/OGDF/ogdf/upward/DominanceLayout.h delete mode 100644 ext/OGDF/ogdf/upward/ExpansionGraph.h delete mode 100644 ext/OGDF/ogdf/upward/FUPSSimple.h delete mode 100644 ext/OGDF/ogdf/upward/FaceSinkGraph.h delete mode 100644 ext/OGDF/ogdf/upward/FeasibleUpwardPlanarSubgraph.h delete mode 100644 ext/OGDF/ogdf/upward/FixedEmbeddingUpwardEdgeInserter.h delete mode 100644 ext/OGDF/ogdf/upward/FixedUpwardEmbeddingInserter.h delete mode 100644 ext/OGDF/ogdf/upward/LayerBasedUPRLayout.h delete mode 100644 ext/OGDF/ogdf/upward/SubgraphUpwardPlanarizer.h delete mode 100644 ext/OGDF/ogdf/upward/UpwardPlanRep.h delete mode 100644 ext/OGDF/ogdf/upward/UpwardPlanarModule.h delete mode 100644 ext/OGDF/ogdf/upward/UpwardPlanarSubgraphSimple.h delete mode 100644 ext/OGDF/ogdf/upward/UpwardPlanarizationLayout.h delete mode 100644 ext/OGDF/ogdf/upward/VisibilityLayout.h delete mode 100644 ext/OGDF/src/augmentation/DfsMakeBiconnected.cpp delete mode 100644 ext/OGDF/src/augmentation/PlanarAugmentation.cpp delete mode 100644 ext/OGDF/src/augmentation/PlanarAugmentationFix.cpp delete mode 100644 ext/OGDF/src/basic/CliqueFinder.cpp delete mode 100644 ext/OGDF/src/basic/CombinatorialEmbedding.cpp delete mode 100644 ext/OGDF/src/basic/Constraint.cpp delete mode 100644 ext/OGDF/src/basic/ConstraintManager.cpp delete mode 100644 ext/OGDF/src/basic/DisjointSets.cpp delete mode 100644 ext/OGDF/src/basic/DualGraph.cpp delete mode 100644 ext/OGDF/src/basic/EdgeComparer.cpp delete mode 100644 ext/OGDF/src/basic/EdgeComparerSimple.cpp delete mode 100644 ext/OGDF/src/basic/Graph.cpp delete mode 100644 ext/OGDF/src/basic/GraphAttributes.cpp delete mode 100644 ext/OGDF/src/basic/GraphConstraints.cpp delete mode 100644 ext/OGDF/src/basic/GraphCopy.cpp delete mode 100644 ext/OGDF/src/basic/GridLayout.cpp delete mode 100644 ext/OGDF/src/basic/GridLayoutModule.cpp delete mode 100644 ext/OGDF/src/basic/Hashing.cpp delete mode 100644 ext/OGDF/src/basic/Logger.cpp delete mode 100644 ext/OGDF/src/basic/Math.cpp delete mode 100644 ext/OGDF/src/basic/NearestRectangleFinder.cpp delete mode 100644 ext/OGDF/src/basic/PoolMemoryAllocator.cpp delete mode 100644 ext/OGDF/src/basic/PreprocessorLayout.cpp delete mode 100644 ext/OGDF/src/basic/String.cpp delete mode 100644 ext/OGDF/src/basic/System.cpp delete mode 100644 ext/OGDF/src/basic/UMLGraph.cpp delete mode 100644 ext/OGDF/src/basic/basic.cpp delete mode 100644 ext/OGDF/src/basic/extended_graph_alg.cpp delete mode 100644 ext/OGDF/src/basic/geometry.cpp delete mode 100644 ext/OGDF/src/basic/graph_generators.cpp delete mode 100644 ext/OGDF/src/basic/modules.cpp delete mode 100644 ext/OGDF/src/basic/random_hierarchy.cpp delete mode 100644 ext/OGDF/src/basic/simple_graph_alg.cpp delete mode 100644 ext/OGDF/src/basic/stNumber.cpp delete mode 100644 ext/OGDF/src/cluster/CPlanarEdgeInserter.cpp delete mode 100644 ext/OGDF/src/cluster/CPlanarSubCLusteredST.cpp delete mode 100644 ext/OGDF/src/cluster/CPlanarSubClusteredGraph.cpp delete mode 100644 ext/OGDF/src/cluster/CconnectClusterPlanar.cpp delete mode 100644 ext/OGDF/src/cluster/CconnectClusterPlanarEmbed.cpp delete mode 100644 ext/OGDF/src/cluster/ClusterGraph.cpp delete mode 100644 ext/OGDF/src/cluster/ClusterGraphAttributes.cpp delete mode 100644 ext/OGDF/src/cluster/ClusterPlanarizationLayout.cpp delete mode 100644 ext/OGDF/src/cluster/Cluster_ChunkConnection.cpp delete mode 100644 ext/OGDF/src/cluster/Cluster_CutConstraint.cpp delete mode 100644 ext/OGDF/src/cluster/Cluster_EdgeVar.cpp delete mode 100644 ext/OGDF/src/cluster/Cluster_MaxPlanarEdges.cpp delete mode 100644 ext/OGDF/src/cluster/Clusterer.cpp delete mode 100644 ext/OGDF/src/cluster/KuratowskiConstraint.cpp delete mode 100644 ext/OGDF/src/cluster/MaxCPlanar_Master.cpp delete mode 100644 ext/OGDF/src/cluster/MaxCPlanar_MinimalClusterConnection.cpp delete mode 100644 ext/OGDF/src/cluster/MaxCPlanar_Sub.cpp delete mode 100644 ext/OGDF/src/cluster/MaximumCPlanarSubgraph.cpp delete mode 100644 ext/OGDF/src/decomposition/BCTree.cpp delete mode 100644 ext/OGDF/src/decomposition/DynamicBCTree.cpp delete mode 100644 ext/OGDF/src/decomposition/DynamicSPQRForest.cpp delete mode 100644 ext/OGDF/src/decomposition/DynamicSPQRTree.cpp delete mode 100644 ext/OGDF/src/decomposition/NonPlanarCore.cpp delete mode 100644 ext/OGDF/src/decomposition/PlanarSPQRTree.cpp delete mode 100644 ext/OGDF/src/decomposition/StaticSPQRTree.cpp delete mode 100644 ext/OGDF/src/decomposition/TricComp.cpp delete mode 100644 ext/OGDF/src/decomposition/TricComp.h delete mode 100644 ext/OGDF/src/energybased/AdjacencyOracle.cpp delete mode 100644 ext/OGDF/src/energybased/ArrayGraph.cpp delete mode 100644 ext/OGDF/src/energybased/ArrayGraph.h delete mode 100644 ext/OGDF/src/energybased/Attraction.cpp delete mode 100644 ext/OGDF/src/energybased/CoinTutteLayout.cpp delete mode 100644 ext/OGDF/src/energybased/ComplexDouble.h delete mode 100644 ext/OGDF/src/energybased/DavidsonHarel.cpp delete mode 100644 ext/OGDF/src/energybased/DavidsonHarelLayout.cpp delete mode 100644 ext/OGDF/src/energybased/Edge.h delete mode 100644 ext/OGDF/src/energybased/EdgeAttributes.cpp delete mode 100644 ext/OGDF/src/energybased/EnergyFunction.cpp delete mode 100644 ext/OGDF/src/energybased/FMEFunc.h delete mode 100644 ext/OGDF/src/energybased/FMEFunctional.h delete mode 100644 ext/OGDF/src/energybased/FMEKernel.cpp delete mode 100644 ext/OGDF/src/energybased/FMEKernel.h delete mode 100644 ext/OGDF/src/energybased/FMEMultipoleKernel.cpp delete mode 100644 ext/OGDF/src/energybased/FMEMultipoleKernel.h delete mode 100644 ext/OGDF/src/energybased/FMEThread.cpp delete mode 100644 ext/OGDF/src/energybased/FMEThread.h delete mode 100644 ext/OGDF/src/energybased/FMMMLayout.cpp delete mode 100644 ext/OGDF/src/energybased/FastMultipoleEmbedder.cpp delete mode 100644 ext/OGDF/src/energybased/FastUtils.h delete mode 100644 ext/OGDF/src/energybased/FruchtermanReingold.cpp delete mode 100644 ext/OGDF/src/energybased/GEMLayout.cpp delete mode 100644 ext/OGDF/src/energybased/GalaxyMultilevel.cpp delete mode 100644 ext/OGDF/src/energybased/GalaxyMultilevel.h delete mode 100644 ext/OGDF/src/energybased/IntersectionRectangle.cpp delete mode 100644 ext/OGDF/src/energybased/LinearQuadtree.cpp delete mode 100644 ext/OGDF/src/energybased/LinearQuadtree.h delete mode 100644 ext/OGDF/src/energybased/LinearQuadtreeBuilder.cpp delete mode 100644 ext/OGDF/src/energybased/LinearQuadtreeBuilder.h delete mode 100644 ext/OGDF/src/energybased/LinearQuadtreeExpansion.cpp delete mode 100644 ext/OGDF/src/energybased/LinearQuadtreeExpansion.h delete mode 100644 ext/OGDF/src/energybased/MAARPacking.cpp delete mode 100644 ext/OGDF/src/energybased/MAARPacking.h delete mode 100644 ext/OGDF/src/energybased/Multilevel.cpp delete mode 100644 ext/OGDF/src/energybased/Multilevel.h delete mode 100644 ext/OGDF/src/energybased/MultilevelGraph.cpp delete mode 100644 ext/OGDF/src/energybased/MultilevelLayout.cpp delete mode 100644 ext/OGDF/src/energybased/NMM.cpp delete mode 100644 ext/OGDF/src/energybased/Node.h delete mode 100644 ext/OGDF/src/energybased/NodeAttributes.cpp delete mode 100644 ext/OGDF/src/energybased/NodePairEnergy.cpp delete mode 100644 ext/OGDF/src/energybased/Overlap.cpp delete mode 100644 ext/OGDF/src/energybased/PQueue.h delete mode 100644 ext/OGDF/src/energybased/PackingRowInfo.h delete mode 100644 ext/OGDF/src/energybased/Planarity.cpp delete mode 100644 ext/OGDF/src/energybased/PlanarityGrid.cpp delete mode 100644 ext/OGDF/src/energybased/QuadTreeNM.cpp delete mode 100644 ext/OGDF/src/energybased/QuadTreeNodeNM.cpp delete mode 100644 ext/OGDF/src/energybased/Rectangle.h delete mode 100644 ext/OGDF/src/energybased/Repulsion.cpp delete mode 100644 ext/OGDF/src/energybased/Set.cpp delete mode 100644 ext/OGDF/src/energybased/Set.h delete mode 100644 ext/OGDF/src/energybased/SpringEmbedderFR.cpp delete mode 100644 ext/OGDF/src/energybased/SpringEmbedderFRExact.cpp delete mode 100644 ext/OGDF/src/energybased/SpringEmbedderKK.cpp delete mode 100644 ext/OGDF/src/energybased/StressMajorizationSimple.cpp delete mode 100644 ext/OGDF/src/energybased/UniformGrid.cpp delete mode 100644 ext/OGDF/src/energybased/WSPD.cpp delete mode 100644 ext/OGDF/src/energybased/WSPD.h delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/BarycenterPlacer.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/CirclePlacer.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/EdgeCoverMerger.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/IndependentSetMerger.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/LocalBiconnectedMerger.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/MMMExampleFastLayout.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/MMMExampleNiceLayout.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/MMMExampleNoTwistLayout.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/MatchingMerger.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/MedianPlacer.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/MixedForceLayout.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/ModularMultilevelMixer.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/RandomMerger.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/RandomPlacer.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/ScalingLayout.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/SolarMerger.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/SolarPlacer.cpp delete mode 100644 ext/OGDF/src/energybased/multilevelmixer/ZeroPlacer.cpp delete mode 100644 ext/OGDF/src/energybased/numexcept.cpp delete mode 100644 ext/OGDF/src/energybased/numexcept.h delete mode 100644 ext/OGDF/src/external/coin.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoLineBuffer.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoTools.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoUmlDiagramGraph.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoUmlModelGraph.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoUmlToGraphConverter.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoXmlParser.cpp delete mode 100644 ext/OGDF/src/fileformats/DinoXmlScanner.cpp delete mode 100644 ext/OGDF/src/fileformats/GmlParser.cpp delete mode 100644 ext/OGDF/src/fileformats/Ogml.cpp delete mode 100644 ext/OGDF/src/fileformats/OgmlParser.cpp delete mode 100644 ext/OGDF/src/fileformats/XmlParser.cpp delete mode 100644 ext/OGDF/src/fileformats/simple_graph_load.cpp delete mode 100644 ext/OGDF/src/graphalg/ConvexHull.cpp delete mode 100644 ext/OGDF/src/graphalg/MinCostFlowModule.cpp delete mode 100644 ext/OGDF/src/graphalg/MinCostFlowReinelt.cpp delete mode 100644 ext/OGDF/src/graphalg/MinimumCut.cpp delete mode 100644 ext/OGDF/src/graphalg/PageRank.cpp delete mode 100644 ext/OGDF/src/graphalg/ShortestPathsWithBFM.cpp delete mode 100644 ext/OGDF/src/graphalg/mcf_front_reinelt.cpp delete mode 100644 ext/OGDF/src/incremental/SimpleIncNodeInserter.cpp delete mode 100644 ext/OGDF/src/labeling/ELabelPosSimple.cpp delete mode 100644 ext/OGDF/src/layered/CoffmanGrahamRanking.cpp delete mode 100644 ext/OGDF/src/layered/CrossingsMatrix.cpp delete mode 100644 ext/OGDF/src/layered/FastHierarchyLayout.cpp delete mode 100644 ext/OGDF/src/layered/FastSimpleHierarchyLayout.cpp delete mode 100644 ext/OGDF/src/layered/HierarchyLayoutModule.cpp delete mode 100644 ext/OGDF/src/layered/OptimalHierarchyClusterLayout.cpp delete mode 100644 ext/OGDF/src/layered/OptimalHierarchyLayout.cpp delete mode 100644 ext/OGDF/src/layered/OptimalRanking.cpp delete mode 100644 ext/OGDF/src/layered/SplitHeuristic.cpp delete mode 100644 ext/OGDF/src/layered/acyclic_subgraph.cpp delete mode 100644 ext/OGDF/src/layered/heuristics.cpp delete mode 100644 ext/OGDF/src/layered/ranking.cpp delete mode 100644 ext/OGDF/src/layered/sugiyama-cluster.cpp delete mode 100644 ext/OGDF/src/layered/sugiyama.cpp delete mode 100644 ext/OGDF/src/lpsolver/LPSolver_coin.cpp delete mode 100644 ext/OGDF/src/misclayout/BalloonLayout.cpp delete mode 100644 ext/OGDF/src/misclayout/CircularLayout.cpp delete mode 100644 ext/OGDF/src/misclayout/ProcrustesSubLayout.cpp delete mode 100644 ext/OGDF/src/orthogonal/ClusterOrthoLayout.cpp delete mode 100644 ext/OGDF/src/orthogonal/ClusterOrthoShaper.cpp delete mode 100644 ext/OGDF/src/orthogonal/CompactionConstraintGraph.cpp delete mode 100644 ext/OGDF/src/orthogonal/EdgeLabel-impl.h delete mode 100644 ext/OGDF/src/orthogonal/EdgeRouter.cpp delete mode 100644 ext/OGDF/src/orthogonal/FlowCompaction.cpp delete mode 100644 ext/OGDF/src/orthogonal/LongestPathCompaction.cpp delete mode 100644 ext/OGDF/src/orthogonal/NodeInfo.cpp delete mode 100644 ext/OGDF/src/orthogonal/OrthoLayout.cpp delete mode 100644 ext/OGDF/src/orthogonal/OrthoRep.cpp delete mode 100644 ext/OGDF/src/orthogonal/OrthoShaper.cpp delete mode 100644 ext/OGDF/src/packing/CCLayoutPackModule.cpp delete mode 100644 ext/OGDF/src/packing/ComponentSplitterLayout.cpp delete mode 100644 ext/OGDF/src/packing/TileToRowsCCPacker.cpp delete mode 100644 ext/OGDF/src/planarity/BoothLueker.cpp delete mode 100644 ext/OGDF/src/planarity/BoyerMyrvold.cpp delete mode 100644 ext/OGDF/src/planarity/BoyerMyrvoldInit.cpp delete mode 100644 ext/OGDF/src/planarity/BoyerMyrvoldPlanar.cpp delete mode 100644 ext/OGDF/src/planarity/ClusterPlanRep.cpp delete mode 100644 ext/OGDF/src/planarity/EdgeInsertionModule.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedPQTree.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedderMaxFace.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedderMaxFaceLayers.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedderMinDepth.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedderMinDepthMaxFace.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedderMinDepthMaxFaceLayers.cpp delete mode 100644 ext/OGDF/src/planarity/EmbedderMinDepthPiTa.cpp delete mode 100644 ext/OGDF/src/planarity/ExtractKuratowskis.cpp delete mode 100644 ext/OGDF/src/planarity/FastPlanarSubgraph.cpp delete mode 100644 ext/OGDF/src/planarity/FindKuratowskis.cpp delete mode 100644 ext/OGDF/src/planarity/FixedEmbeddingInserter.cpp delete mode 100644 ext/OGDF/src/planarity/GraphReduction.cpp delete mode 100644 ext/OGDF/src/planarity/Layout.cpp delete mode 100644 ext/OGDF/src/planarity/LayoutPlanRepModule.cpp delete mode 100644 ext/OGDF/src/planarity/MDMFLengthAttribute.cpp delete mode 100644 ext/OGDF/src/planarity/MMCrossingMinimizationModule.cpp delete mode 100644 ext/OGDF/src/planarity/MMFixedEmbeddingInserter.cpp delete mode 100644 ext/OGDF/src/planarity/MMSubgraphPlanarizer.cpp delete mode 100644 ext/OGDF/src/planarity/MMVariableEmbeddingInserter.cpp delete mode 100644 ext/OGDF/src/planarity/MaximalPlanarSubgraphSimple.cpp delete mode 100644 ext/OGDF/src/planarity/MaximumPlanarSubgraph.cpp delete mode 100644 ext/OGDF/src/planarity/MultiEdgeApproxInserter.cpp delete mode 100644 ext/OGDF/src/planarity/PlanRep.cpp delete mode 100644 ext/OGDF/src/planarity/PlanRepExpansion.cpp delete mode 100644 ext/OGDF/src/planarity/PlanRepInc.cpp delete mode 100644 ext/OGDF/src/planarity/PlanRepUML.cpp delete mode 100644 ext/OGDF/src/planarity/PlanarPQTree.cpp delete mode 100644 ext/OGDF/src/planarity/PlanarSubgraphModule.cpp delete mode 100644 ext/OGDF/src/planarity/PlanarSubgraphPQTree.cpp delete mode 100644 ext/OGDF/src/planarity/PlanarizationGridLayout.cpp delete mode 100644 ext/OGDF/src/planarity/PlanarizationLayout.cpp delete mode 100644 ext/OGDF/src/planarity/PlanarizationLayout_inc.cpp delete mode 100644 ext/OGDF/src/planarity/SimpleEmbedder.cpp delete mode 100644 ext/OGDF/src/planarity/SubgraphPlanarizer.cpp delete mode 100644 ext/OGDF/src/planarity/TopologyModule.cpp delete mode 100644 ext/OGDF/src/planarity/VariableEmbeddingInserter.cpp delete mode 100644 ext/OGDF/src/planarity/VariableEmbeddingInserter2.cpp delete mode 100644 ext/OGDF/src/planarlayout/BiconnectedShellingOrder.cpp delete mode 100644 ext/OGDF/src/planarlayout/FPPLayout.cpp delete mode 100644 ext/OGDF/src/planarlayout/IOPoints.cpp delete mode 100644 ext/OGDF/src/planarlayout/IOPoints.h delete mode 100644 ext/OGDF/src/planarlayout/MMCBBase.cpp delete mode 100644 ext/OGDF/src/planarlayout/MMOrder.h delete mode 100644 ext/OGDF/src/planarlayout/MixedModelBase.cpp delete mode 100644 ext/OGDF/src/planarlayout/MixedModelBase.h delete mode 100644 ext/OGDF/src/planarlayout/MixedModelCrossingsBeautifierModule.cpp delete mode 100644 ext/OGDF/src/planarlayout/MixedModelLayout.cpp delete mode 100644 ext/OGDF/src/planarlayout/PlanarDrawLayout.cpp delete mode 100644 ext/OGDF/src/planarlayout/PlanarStraightLayout.cpp delete mode 100644 ext/OGDF/src/planarlayout/SchnyderLayout.cpp delete mode 100644 ext/OGDF/src/planarlayout/ShellingOrder.cpp delete mode 100644 ext/OGDF/src/planarlayout/ShellingOrderModule.cpp delete mode 100644 ext/OGDF/src/planarlayout/TriconnectedShellingOrder.cpp delete mode 100644 ext/OGDF/src/simultaneous/SimDraw.cpp delete mode 100644 ext/OGDF/src/simultaneous/SimDrawCaller.cpp delete mode 100644 ext/OGDF/src/simultaneous/SimDrawColorizer.cpp delete mode 100644 ext/OGDF/src/simultaneous/SimDrawCreator.cpp delete mode 100644 ext/OGDF/src/simultaneous/SimDrawCreatorSimple.cpp delete mode 100644 ext/OGDF/src/simultaneous/SimDrawManipulatorModule.cpp delete mode 100644 ext/OGDF/src/tree/RadialTreeLayout.cpp delete mode 100644 ext/OGDF/src/tree/TreeLayout.cpp delete mode 100644 ext/OGDF/src/upward/DominanceLayout.cpp delete mode 100644 ext/OGDF/src/upward/ExpansionGraph.cpp delete mode 100644 ext/OGDF/src/upward/FUPSSimple.cpp delete mode 100644 ext/OGDF/src/upward/FaceSinkGraph.cpp delete mode 100644 ext/OGDF/src/upward/FeasibleUpwardPlanarSubgraph.cpp delete mode 100644 ext/OGDF/src/upward/FixedEmbeddingUpwardEdgeInserter.cpp delete mode 100644 ext/OGDF/src/upward/LayerBasedUPRLayout.cpp delete mode 100644 ext/OGDF/src/upward/SubgraphUpwardPlanarizer.cpp delete mode 100644 ext/OGDF/src/upward/UpwardPlanRep.cpp delete mode 100644 ext/OGDF/src/upward/UpwardPlanarModule.cpp delete mode 100644 ext/OGDF/src/upward/UpwardPlanarSubgraphModule.cpp delete mode 100644 ext/OGDF/src/upward/UpwardPlanarSubgraphSimple.cpp delete mode 100644 ext/OGDF/src/upward/VisibilityLayout.cpp diff --git a/.gitmodules b/.gitmodules index 2ef08cd1c..1926ef4d3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "ext/googletest"] path = ext/googletest url = https://github.com/google/googletest.git +[submodule "ext/OGDF"] + path = ext/OGDF + url = https://github.com/ogdf/ogdf diff --git a/appveyor.yml b/appveyor.yml index e6b688767..c5b316f7b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,5 +26,5 @@ test_script: - reg delete HKCU\Software\TortoiseGit /v CygwinHack /f - reg delete HKCU\Software\TortoiseGit /v MSysGit /f - msbuild "src\TortoiseGit.sln" /t:"GitWCRev" /t:"GitWCRevCom" /t:"TortoiseGitSetup\CustomActions" /t:"TortoiseGitSetup\RestartExplorer" /t:"ext\Crash-Server\CrashServerSDK\CrashHandler" /t:"ext\Crash-Server\CrashServerSDK\SendRpt" /m /verbosity:minimal /p:Configuration=Release /p:Platform=x64 /maxcpucount /p:PlatformToolset=v141 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" -- git submodule update --init -- ext/apr ext/apr-util ext/editorconfig ext/pcre +- git submodule update --init -- ext/apr ext/apr-util ext/editorconfig ext/OGDF ext/pcre - msbuild "src\TortoiseGit.sln" /t:"TGitCache" /t:"TortoiseGitBlame" /t:"TortoiseGitIDiff" /t:"TortoiseGitMerge" /t:"TortoiseGitPlink" /t:"TortoiseGitProc" /t:"TortoiseGitStub" /t:"TortoiseGitUDiff" /t:"TortoiseShell" /t:"SshAskPass" /t:"tgittouch" /t:"GitWCRev" /t:"GitWCRevCom" /m /verbosity:minimal /p:Configuration=Debug /p:Platform=x64 /maxcpucount /p:PlatformToolset=v141 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" diff --git a/ext/OGDF b/ext/OGDF new file mode 160000 index 000000000..f0a0f798b --- /dev/null +++ b/ext/OGDF @@ -0,0 +1 @@ +Subproject commit f0a0f798bb13a68868765d57c6b737332fde2301 diff --git a/ext/OGDF/LICENSE.txt b/ext/OGDF/LICENSE.txt deleted file mode 100644 index 62811b7ab..000000000 --- a/ext/OGDF/LICENSE.txt +++ /dev/null @@ -1,32 +0,0 @@ -*********************************************************** -* OGDF - The Open Graph Drawing Framework * -* * -* LICENSE * -*********************************************************** - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -Version 2 or 3 as published by the Free Software Foundation -and appearing in the files LICENSE_GPL_v2.txt and -LICENSE_GPL_v3.txt included in the packaging of this file. - -In addition, as a special exception, you have permission to link -this software with - - - Tulip (http://www.tulip-software.org) - - - the libraries of the COIN-OR Osi project (see - http://www.coin-or.org/projects/Osi.xml); - - - all libraries required by Osi; - - - and all LP-solver libraries directly supported by the - COIN-OR Osi project, - -and distribute executables, as long as you follow the requirements -of the GNU General Public License in regard to all of the software -in the executable aside from these third-party libraries. - -See also: http://www.ogdf.net/license.html - -Contact: license@ogdf.net diff --git a/ext/OGDF/LICENSE_GPL_v2.txt b/ext/OGDF/LICENSE_GPL_v2.txt deleted file mode 100644 index d511905c1..000000000 --- a/ext/OGDF/LICENSE_GPL_v2.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/ext/OGDF/LICENSE_GPL_v3.txt b/ext/OGDF/LICENSE_GPL_v3.txt deleted file mode 100644 index 818433ecc..000000000 --- a/ext/OGDF/LICENSE_GPL_v3.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/ext/OGDF/Makefile.README b/ext/OGDF/Makefile.README deleted file mode 100644 index 84f904482..000000000 --- a/ext/OGDF/Makefile.README +++ /dev/null @@ -1,20 +0,0 @@ -CONTENT: - Makefile.README this file - makeMakefile.py the magical python script - makeMakefile.sh lazy? this file calls python w/ script - Makefile.header epilogue of the new makefile - -OVERVIEW - Run the python script whenever file dependencies (may) have -changed, e.g., after adding a new file to the project etc. The -script will then generate a new makefile ("Makefile") which -can be used in any traditional way. - -HINTS - Sourcefiles and subdirectories can be "hidden" in order to -prevent their inclusion into the Makefile: files and sub- -directories whose name start with a dot ('.') or an under- -score ('_') are ignored. - -------- -MCh diff --git a/ext/OGDF/Makefile.header b/ext/OGDF/Makefile.header deleted file mode 100644 index 070c85961..000000000 --- a/ext/OGDF/Makefile.header +++ /dev/null @@ -1,22 +0,0 @@ -############################################################################## -## BEGIN Makefile.header -############################################################################## - -LIBS = - -all: release - -clean: cleanrelease - -# feel free to use "debug" and "cleandebug" for Debug! - -doxy: - rm -rf doc/html - mkdir -p doc/html - doxygen ogdf-doxygen.cfg - cp -f doc/images/ftv2*.png doc/html - -############################################################################## -## END Makefile.header -############################################################################## - diff --git a/ext/OGDF/README.txt b/ext/OGDF/README.txt deleted file mode 100644 index 37bf4a4d4..000000000 --- a/ext/OGDF/README.txt +++ /dev/null @@ -1,89 +0,0 @@ -*********************************************************** -* OGDF - The Open Graph Drawing Framework * -* * -* README * -*********************************************************** - -Welcome to OGDF! - -OGDF is a portable C++ class library for graph drawing. -This archive contains the source-code of OGDF. - - -******************** LICENSE ******************** - -This software is distributed under the terms of the GNU -General Public License v2 or v3, with special exceptions -allowing to link against LP-solvers (see the LICENSE.txt -file for details!). By installing this software you agree -to these license terms. - -If you have questions, please write to license@ogdf.net . - - -******************* COPYRIGHT ******************* - -All files in the OGDF distribution are copyrighted: - -Copyright (C) 2005-2012 - - -****************** INSTALLATION ***************** - -Unpack the OGDF archive in the directory, where you want to -install OGDF. - -Build OGDF (gcc Compiler [Linux, Mac OS]): - - 1. Edit makeMakefile.config for your configuration - (if necessary): check the [GENERAL] section. If - you do not use Coin, the default parameters should - be suitable. - - 2. Execute makeMakefile.sh to generate a suitable Makefile. - - 3. Call make to build the OGDF library (you may also call - make debug_all to generate a debuggable version). - - -Build OGDF (Visual Studio [Windows]): - - 1. Create Visual Studio project file: - - Visual Studio 2008: Execute the python script makeVCProj.py - to generate a Visual Studio 2008 project file ogdf.vcproj. - - Visual Studio 2010: Execute the python script makeVCXProj.py - to generate a Visual Studio 2010 project file ogdf.vcxproj. - - 2. Open the created project file (.vcproj or .vcxproj) with - Visual Studio and call build. - -OGDF also contains some optional features which require COIN -Osi as LP solver. It is also possible to generate project -files for Visual Studio 2003 & 2005. - -Please refer to the OGDF Wiki for more detailed information: - -gcc: http://www.ogdf.net/ogdf.php/tech:installgcc -Visual C++: http://www.ogdf.net/ogdf.php/tech:installvcc - - -******************** CHANGES ******************** - -For changes refer to the version history at - -http://www.ogdf.net/doku.php?id=tech:versions - - -******************** CONTACT ******************** - -Email: info@ogdf.net - -Web: http://www.ogdf.net -Forum: http://www.ogdf.net/forum - - -Enjoy! - - The OGDF Team. diff --git a/ext/OGDF/config/ogdf.dll.vcproj.vs2005.template b/ext/OGDF/config/ogdf.dll.vcproj.vs2005.template deleted file mode 100644 index 6e1ac1dba..000000000 --- a/ext/OGDF/config/ogdf.dll.vcproj.vs2005.template +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <> - - - <> - <> - - <> - - - - diff --git a/ext/OGDF/config/ogdf.dll.vcproj.vs2008.template b/ext/OGDF/config/ogdf.dll.vcproj.vs2008.template deleted file mode 100644 index b576aebc5..000000000 --- a/ext/OGDF/config/ogdf.dll.vcproj.vs2008.template +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <> - - - <> - <> - - <> - - - - diff --git a/ext/OGDF/config/ogdf.dll.vcxproj.vs2010.template b/ext/OGDF/config/ogdf.dll.vcxproj.vs2010.template deleted file mode 100644 index 758a871f5..000000000 --- a/ext/OGDF/config/ogdf.dll.vcxproj.vs2010.template +++ /dev/null @@ -1,176 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7801D1BE-E2FE-476B-A4B4-5D27F387F479} - ogdf - Win32Proj - - - - DynamicLibrary - Unicode - true - - - DynamicLibrary - Unicode - - - DynamicLibrary - Unicode - true - - - DynamicLibrary - Unicode - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ./;<> - OGDF_DEBUG;OGDF_DLL;OGDF_INSTALL;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - X64 - - - Disabled - ./;<> - OGDF_DEBUG;OGDF_DLL;OGDF_INSTALL;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - MaxSpeed - false - ./;<> - OGDF_DLL;OGDF_INSTALL;<> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - - - X64 - - - MaxSpeed - false - ./;<> - OGDF_DLL;OGDF_INSTALL;<> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - - <> - - - <> - <> - - - - - \ No newline at end of file diff --git a/ext/OGDF/config/ogdf.dll.vcxproj.vs2012.template b/ext/OGDF/config/ogdf.dll.vcxproj.vs2012.template deleted file mode 100644 index 004a39cb4..000000000 --- a/ext/OGDF/config/ogdf.dll.vcxproj.vs2012.template +++ /dev/null @@ -1,181 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7801D1BE-E2FE-476B-A4B4-5D27F387F479} - ogdf - Win32Proj - $(VCTargetsPath11) - - - - DynamicLibrary - Unicode - true - v110 - - - DynamicLibrary - Unicode - v110 - - - DynamicLibrary - Unicode - true - v110 - - - DynamicLibrary - Unicode - v110 - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ./;<> - OGDF_DEBUG;OGDF_DLL;OGDF_INSTALL;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - X64 - - - Disabled - ./;<> - OGDF_DEBUG;OGDF_DLL;OGDF_INSTALL;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - MaxSpeed - false - ./;<> - OGDF_DLL;OGDF_INSTALL;<> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - - - X64 - - - MaxSpeed - false - ./;<> - OGDF_DLL;OGDF_INSTALL;<> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;psapi.lib;%(AdditionalDependencies) - - - - - - <> - - - <> - <> - - - - - \ No newline at end of file diff --git a/ext/OGDF/config/ogdf.vcproj.vs2003.template b/ext/OGDF/config/ogdf.vcproj.vs2003.template deleted file mode 100644 index 997f22551..000000000 --- a/ext/OGDF/config/ogdf.vcproj.vs2003.template +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <> - - - <> - <> - - <> - - - - diff --git a/ext/OGDF/config/ogdf.vcproj.vs2005.template b/ext/OGDF/config/ogdf.vcproj.vs2005.template deleted file mode 100644 index 28df65292..000000000 --- a/ext/OGDF/config/ogdf.vcproj.vs2005.template +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <> - - - <> - <> - - <> - - - - diff --git a/ext/OGDF/config/ogdf.vcproj.vs2008.template b/ext/OGDF/config/ogdf.vcproj.vs2008.template deleted file mode 100644 index d1cb59e40..000000000 --- a/ext/OGDF/config/ogdf.vcproj.vs2008.template +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <> - - - <> - <> - - <> - - - - diff --git a/ext/OGDF/config/ogdf.vcxproj.filters.template b/ext/OGDF/config/ogdf.vcxproj.filters.template deleted file mode 100644 index 7cf6aec61..000000000 --- a/ext/OGDF/config/ogdf.vcxproj.filters.template +++ /dev/null @@ -1,16 +0,0 @@ - - - - <> - - - <> - - - - - - - <> - - diff --git a/ext/OGDF/config/ogdf.vcxproj.vs2010.template b/ext/OGDF/config/ogdf.vcxproj.vs2010.template deleted file mode 100644 index 9111f7849..000000000 --- a/ext/OGDF/config/ogdf.vcxproj.vs2010.template +++ /dev/null @@ -1,160 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7801D1BE-E2FE-476B-A4B4-5D27F387F479} - ogdf - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ./;<> - OGDF_DEBUG;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - EditAndContinue - /MP %(AdditionalOptions) - - - - - X64 - - - Disabled - ./;<> - OGDF_DEBUG;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - - - MaxSpeed - false - ./;<> - <> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - - - X64 - - - MaxSpeed - false - ./;<> - <> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - - <> - - - <> - <> - - - - - \ No newline at end of file diff --git a/ext/OGDF/config/ogdf.vcxproj.vs2012.template b/ext/OGDF/config/ogdf.vcxproj.vs2012.template deleted file mode 100644 index d1c14f5cb..000000000 --- a/ext/OGDF/config/ogdf.vcxproj.vs2012.template +++ /dev/null @@ -1,165 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7801D1BE-E2FE-476B-A4B4-5D27F387F479} - ogdf - Win32Proj - $(VCTargetsPath11) - - - - StaticLibrary - Unicode - true - v110 - - - StaticLibrary - Unicode - v110 - - - StaticLibrary - Unicode - true - v110 - - - StaticLibrary - Unicode - v110 - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ./;<> - OGDF_DEBUG;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - EditAndContinue - /MP %(AdditionalOptions) - - - - - X64 - - - Disabled - ./;<> - OGDF_DEBUG;<> - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - - - MaxSpeed - false - ./;<> - <> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - - - X64 - - - MaxSpeed - false - ./;<> - <> - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - /MP %(AdditionalOptions) - - - - <> - - - <> - <> - - - - - \ No newline at end of file diff --git a/ext/OGDF/doc/build-ogdf-docs.bat b/ext/OGDF/doc/build-ogdf-docs.bat deleted file mode 100644 index c1afca741..000000000 --- a/ext/OGDF/doc/build-ogdf-docs.bat +++ /dev/null @@ -1,2 +0,0 @@ -@del /F /Q .\html -@doxygen.exe ogdf-doxygen.cfg diff --git a/ext/OGDF/doc/build-ogdf-docs.sh b/ext/OGDF/doc/build-ogdf-docs.sh deleted file mode 100644 index e043cbf9b..000000000 --- a/ext/OGDF/doc/build-ogdf-docs.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -sourcepath="$0" - -# folder wich contains the script -folder="${sourcepath%/*}" - -cd "$folder" -rm -r ./html -doxygen "ogdf-doxygen.cfg" diff --git a/ext/OGDF/doc/govisual-footer.html b/ext/OGDF/doc/govisual-footer.html deleted file mode 100644 index 1e4b886da..000000000 --- a/ext/OGDF/doc/govisual-footer.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/ext/OGDF/doc/govisual-header.html b/ext/OGDF/doc/govisual-header.html deleted file mode 100644 index 8878e2c5e..000000000 --- a/ext/OGDF/doc/govisual-header.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -$projectname: $title -$title - - - - -$treeview -$search -$mathjax - - - -
- - -
- - - - - - - - - -
- - - - - - -

Open
Graph Drawing
Framework

-  v.2012.07
  -
-
-
-
-
- - diff --git a/ext/OGDF/doc/govisual.css b/ext/OGDF/doc/govisual.css deleted file mode 100644 index fbdde725f..000000000 --- a/ext/OGDF/doc/govisual.css +++ /dev/null @@ -1,1189 +0,0 @@ -/* The standard CSS for doxygen */ - -body, table, div, p, dl { - font-family: Lucida Grande, Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 12px; - line-height: 1.2; -} - -/* @group Heading Levels */ - -h1 { - font-size: 150%; -} - -.title { - font-size: 150%; - font-weight: bold; - margin: 10px 2px; -} - -h2 { - font-size: 120%; -} - -h3 { - font-size: 100%; -} - -h1, h2, h3, h4, h5, h6 { - -webkit-transition: text-shadow 0.5s linear; - -moz-transition: text-shadow 0.5s linear; - -ms-transition: text-shadow 0.5s linear; - -o-transition: text-shadow 0.5s linear; - transition: text-shadow 0.5s linear; - margin-right: 15px; -} - -h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { - text-shadow: 0 0 15px cyan; -} - -dt { - font-weight: bold; -} - -div.multicol { - -moz-column-gap: 1em; - -webkit-column-gap: 1em; - -moz-column-count: 3; - -webkit-column-count: 3; -} - -p.startli, p.startdd, p.starttd { - margin-top: 2px; -} - -p.endli { - margin-bottom: 0px; -} - -p.enddd { - margin-bottom: 4px; -} - -p.endtd { - margin-bottom: 2px; -} - -/* @end */ - -caption { - font-weight: bold; -} - -span.legend { - font-size: 70%; - text-align: center; -} - -h3.version { - font-size: 90%; - text-align: center; -} - -div.qindex, div.navtab{ - background-color: #e8eef2; - border: 1px solid #84b0c7; - /* background-color: #EBEFF6; - border: 1px solid #A3B4D7; */ - text-align: center; - margin: 2px; - padding: 2px; -} - -div.qindex, div.navpath { - width: 100%; - line-height: 140%; -} - -div.navtab { - margin-right: 15px; -} - -/* @group Link Styling */ - -a { - color: #3D578C; - font-weight: normal; - text-decoration: none; -} - -.contents a:visited { - /* color: #4665A2; */ - color: #3D578C; -} - -a:hover { - text-decoration: underline; -} - -a.qindex { - padding: 1px 3px; - text-decoration: none; - font-weight: bold; -} - -a.qindex:hover { - font-weight: bold; - color: rgb(222,235,248); - background-color: #3D578C; -} - -a.qindexHL { - font-weight: bold; - background-color: #9CAFD4; - color: #ffffff; - border: 1px double #869DCA; -} - -.contents a.qindexHL:visited { - color: #ffffff; -} - -a.el { - font-weight: bold; -} - -a.elRef { -} - -a.code, a.code:visited { - color: #4665A2; -} - -a.codeRef, a.codeRef:visited { - color: #4665A2; -} - -/* @end */ - -dl.el { - margin-left: -1cm; -} - -pre.fragment { - border: 1px solid #C4CFE5; - background-color: #FBFCFD; - padding: 4px 6px; - margin: 4px 8px 4px 2px; - overflow: auto; - word-wrap: break-word; - font-size: 9pt; - line-height: 125%; - font-family: monospace, fixed; - font-size: 105%; -} - -div.fragment { - padding: 4px; - margin: 4px; - background-color: #FCFCFD; - border: 1px solid #CDD6E7; -} - -div.line { - font-family: monospace, fixed; - font-size: 13px; - line-height: 1.0; - text-wrap: unrestricted; - white-space: -moz-pre-wrap; /* Moz */ - white-space: -pre-wrap; /* Opera 4-6 */ - white-space: -o-pre-wrap; /* Opera 7 */ - white-space: pre-wrap; /* CSS3 */ - word-wrap: break-word; /* IE 5.5+ */ - text-indent: -53px; - padding-left: 53px; - padding-bottom: 0px; - margin: 0px; -} - -span.lineno { - padding-right: 4px; - text-align: right; - border-right: 2px solid #0F0; - background-color: #E8E8E8; - white-space: pre; -} -span.lineno a { - background-color: #D8D8D8; -} - -span.lineno a:hover { - background-color: #C8C8C8; -} - -div.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px; - padding: 0.2em; - border: solid thin #333; - border-radius: 0.5em; - -webkit-border-radius: .5em; - -moz-border-radius: .5em; - box-shadow: 2px 2px 3px #999; - -webkit-box-shadow: 2px 2px 3px #999; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); - background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); -} - -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - font-weight: bold; -} - -div.groupText { - margin-left: 16px; - font-style: italic; -} - -body { - background: white; - color: black; - margin: 0; -} - -div.contents { - margin-top: 10px; - margin-left: 12px; - margin-right: 8px; -} - -td.indexkey { - background-color: #EBEFF6; - font-weight: bold; - border: 1px solid #C4CFE5; - margin: 2px 0px 2px 0; - padding: 2px 10px; - white-space: nowrap; - vertical-align: top; -} - -td.indexvalue { - background-color: #EBEFF6; - border: 1px solid #C4CFE5; - padding: 2px 10px; - margin: 2px 0px; -} - -tr.memlist { - background-color: #EEF1F7; -} - -p.formulaDsp { - text-align: center; -} - -img.formulaDsp { - -} - -img.formulaInl { - vertical-align: middle; -} - -div.center { - text-align: center; - margin-top: 0px; - margin-bottom: 0px; - padding: 0px; -} - -div.center img { - border: 0px; -} - -address.footer { - text-align: right; - padding-right: 12px; -} - -img.footer { - border: 0px; - vertical-align: middle; -} - -/* @group Code Colorization */ - -span.keyword { - color: #008000 -} - -span.keywordtype { - color: #604020 -} - -span.keywordflow { - color: #e08000 -} - -span.comment { - color: #800000 -} - -span.preprocessor { - color: #806020 -} - -span.stringliteral { - color: #002080 -} - -span.charliteral { - color: #008080 -} - -span.vhdldigit { - color: #ff00ff -} - -span.vhdlchar { - color: #000000 -} - -span.vhdlkeyword { - color: #700070 -} - -span.vhdllogic { - color: #ff0000 -} - -blockquote { - background-color: #F8F9FB; - border-left: 2px solid #AAB9D6; - margin: 0 24px 0 4px; - padding: 0 12px 0 16px; -} - -/* @end */ - -/* -.search { - color: #003399; - font-weight: bold; -} - -form.search { - margin-bottom: 0px; - margin-top: 0px; -} - -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #e8eef2; -} -*/ - -td.tiny { - font-size: 75%; -} - -.dirtab { - padding: 4px; - border-collapse: collapse; - border: 1px solid #A3B4D7; -} - -th.dirtab { - background: #EBEFF6; - font-weight: bold; -} - -hr { - height: 0px; - border: none; - border-top: 1px solid #4A6AAA; -} - -hr.footer { - height: 1px; -} - -/* @group Member Descriptions */ - -table.memberdecls { - border-spacing: 0px; - padding: 0px; -} - -.memberdecls td { - -webkit-transition-property: background-color, box-shadow; - -webkit-transition-duration: 0.5s; - -moz-transition-property: background-color, box-shadow; - -moz-transition-duration: 0.5s; - -ms-transition-property: background-color, box-shadow; - -ms-transition-duration: 0.5s; - -o-transition-property: background-color, box-shadow; - -o-transition-duration: 0.5s; - transition-property: background-color, box-shadow; - transition-duration: 0.5s; -} - -.memberdecls td.glow { - background-color: cyan; - box-shadow: 0 0 15px cyan; -} - -.mdescLeft, .mdescRight, -.memItemLeft, .memItemRight, -.memTemplItemLeft, .memTemplItemRight, .memTemplParams { - background-color: #F9FAFC; - border: none; - margin: 4px; - padding: 1px 0 0 8px; -} - -.mdescLeft, .mdescRight { - padding: 0px 8px 4px 8px; - color: #555; -} - -.memItemLeft, .memItemRight, .memTemplParams { - border-top: 1px solid #C4CFE5; -} - -.memItemLeft, .memTemplItemLeft { - white-space: nowrap; -} - -.memItemRight { - width: 100%; -} - -.memTemplParams { - color: #4665A2; - white-space: nowrap; -} - -/* @end */ - -/* @group Member Details */ - -/* Styles for detailed member documentation */ - -.memtemplate { - font-size: 80%; - color: #4665A2; - font-weight: normal; - margin-left: 9px; -} - -.memnav { - background-color: #EBEFF6; - border: 1px solid #A3B4D7; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; -} - -.mempage { - width: 100%; -} - -.memitem { - padding: 0; - margin-bottom: 10px; - margin-right: 5px; - -webkit-transition: box-shadow 0.5s linear; - -moz-transition: box-shadow 0.5s linear; - -ms-transition: box-shadow 0.5s linear; - -o-transition: box-shadow 0.5s linear; - transition: box-shadow 0.5s linear; -} - -.memitem.glow { - box-shadow: 0 0 15px cyan; -} - -.memname { - font-weight: bold; - margin-left: 6px; -} - -.memname td { - vertical-align: bottom; -} - -.memproto, dl.reflist dt { - border-top: 1px solid #A8B8D9; - border-left: 1px solid #A8B8D9; - border-right: 1px solid #A8B8D9; - padding: 6px 0px 6px 0px; - color: #253555; - font-weight: bold; - text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); - background-image:url('nav_f.png'); - background-repeat:repeat-x; - background-color: #E7EBF3; - /* opera specific markup */ - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - border-top-right-radius: 4px; - border-top-left-radius: 4px; - /* firefox specific markup */ - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - -moz-border-radius-topright: 4px; - -moz-border-radius-topleft: 4px; - /* webkit specific markup */ - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - -webkit-border-top-right-radius: 4px; - -webkit-border-top-left-radius: 4px; - -} - -.memdoc, dl.reflist dd { - border-bottom: 1px solid #A8B8D9; - border-left: 1px solid #A8B8D9; - border-right: 1px solid #A8B8D9; - padding: 6px 10px 2px 10px; - background-color: #FBFCFD; - border-top-width: 0; - background-image:url('nav_g.png'); - background-repeat:repeat-x; - background-color: #FFFFFF; - /* opera specific markup */ - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - /* firefox specific markup */ - -moz-border-radius-bottomleft: 4px; - -moz-border-radius-bottomright: 4px; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - /* webkit specific markup */ - -webkit-border-bottom-left-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); -} - -dl.reflist dt { - padding: 5px; -} - -dl.reflist dd { - margin: 0px 0px 10px 0px; - padding: 5px; -} - -.paramkey { - text-align: right; -} - -.paramtype { - white-space: nowrap; -} - -.paramname { - color: #602020; - white-space: nowrap; -} -.paramname em { - font-style: normal; -} - -.params, .retval, .exception, .tparams { - margin-left: 0px; - padding-left: 0px; -} - -.params .paramname, .retval .paramname { - font-weight: bold; - vertical-align: top; -} - -.params .paramtype { - font-style: italic; - vertical-align: top; -} - -.params .paramdir { - font-family: "courier new",courier,monospace; - vertical-align: top; -} - -table.mlabels { - border-spacing: 0px; -} - -td.mlabels-left { - width: 100%; - padding: 0px; -} - -td.mlabels-right { - vertical-align: bottom; - padding: 0px; - white-space: nowrap; -} - -span.mlabels { - margin-left: 8px; -} - -span.mlabel { - background-color: #859AC4; - border-top:1px solid #6983B7; - border-left:1px solid #6983B7; - border-right:1px solid #CDD6E7; - border-bottom:1px solid #CDD6E7; - text-shadow: none; - color: white; - margin-right: 4px; - padding: 2px 3px; - border-radius: 3px; - font-size: 7pt; - white-space: nowrap; -} - - - -/* @end */ - -/* these are for tree view when not used as main index */ - -div.directory { - margin: 10px 0px; - border-top: 1px solid #A8B8D9; - border-bottom: 1px solid #A8B8D9; - width: 100%; -} - -.directory table { - border-collapse:collapse; -} - -.directory td { - margin: 0px; - padding: 0px; - vertical-align: top; -} - -.directory td.entry { - white-space: nowrap; - padding-right: 6px; -} - -.directory td.entry a { - outline:none; -} - -.directory td.desc { - width: 100%; - padding-left: 6px; - padding-right: 6px; - border-left: 1px solid rgba(0,0,0,0.05); -} - -.directory tr.even { - padding-left: 6px; - background-color: #F8F9FB; -} - -.directory img { - vertical-align: -30%; -} - -.directory .levels { - white-space: nowrap; - width: 100%; - text-align: right; - font-size: 9pt; -} - -.directory .levels span { - cursor: pointer; - padding-left: 2px; - padding-right: 2px; - color: #4A659B; -} - -div.dynheader { - margin-top: 8px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -address { - font-style: normal; - color: #2A3D61; -} - -table.doxtable { - border-collapse:collapse; - margin-top: 4px; - margin-bottom: 4px; -} - -table.doxtable td, table.doxtable th { - border: 1px solid #2D4068; - padding: 3px 7px 2px; -} - -table.doxtable th { - background-color: #374F7F; - color: #FFFFFF; - font-size: 110%; - padding-bottom: 4px; - padding-top: 5px; -} - -table.fieldtable { - width: 100%; - margin-bottom: 10px; - border: 1px solid #B5C2DB; - border-spacing: 0px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - border-radius: 4px; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); - box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); -} - -.fieldtable td, .fieldtable th { - padding: 3px 7px 2px; -} - -.fieldtable td.fieldtype, .fieldtable td.fieldname { - white-space: nowrap; - border-right: 1px solid #B5C2DB; - border-bottom: 1px solid #B5C2DB; - vertical-align: top; -} - -.fieldtable td.fielddoc { - border-bottom: 1px solid #B5C2DB; - width: 100%; -} - -.fieldtable tr:last-child td { - border-bottom: none; -} - -.fieldtable th { - background-image:url('nav_f.png'); - background-repeat:repeat-x; - background-color: #E7EBF3; - font-size: 90%; - color: #304165; - padding-bottom: 4px; - padding-top: 5px; - text-align:left; - -moz-border-radius-topleft: 4px; - -moz-border-radius-topright: 4px; - -webkit-border-top-left-radius: 4px; - -webkit-border-top-right-radius: 4px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom: 1px solid #B5C2DB; -} - - -.tabsearch { - top: 0px; - left: 10px; - height: 36px; - background-image: url('tab_b.png'); - z-index: 101; - overflow: hidden; - font-size: 13px; -} - -.navpath ul -{ - font-size: 11px; - background-image:url('tab_b.png'); - background-repeat:repeat-x; - height:30px; - line-height:30px; - color:#8AA0CC; - border:solid 1px #C2CDE4; - overflow:hidden; - margin:0px; - padding:0px; -} - -.navpath li -{ - list-style-type:none; - float:left; - padding-left:10px; - padding-right: 15px; - background-image:url('bc_s.png'); - background-repeat:no-repeat; - background-position:right; - color:#364D7C; -} - -.navpath li.navelem a -{ - height:32px; - display:block; - text-decoration: none; - outline: none; -} - -.navpath li.navelem a:hover -{ - color:#6884BD; -} - -.navpath li.footer -{ - list-style-type:none; - float:right; - padding-left:10px; - padding-right:15px; - background-image:none; - background-repeat:no-repeat; - background-position:right; - color:#425B8B; - font-size: 8pt; -} - - -div.summary -{ - float: right; - font-size: 8pt; - padding-right: 5px; - width: 50%; - text-align: right; -} - -div.summary a -{ - white-space: nowrap; -} - -div.ingroups -{ - margin-left: 5px; - font-size: 8pt; - padding-left: 5px; - width: 50%; - text-align: left; -} - -div.ingroups a -{ - white-space: nowrap; -} - -div.header -{ - background-image:url('nav_h.png'); - background-repeat:repeat-x; - background-color: #F9FAFC; - margin: 0px; - border-bottom: 1px solid #C4CFE5; -} - -div.headertitle -{ - padding: 5px 5px 5px 10px; -} - -dl -{ - padding: 0 0 0 10px; -} - -/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ -dl.section -{ - margin-left: 0px; - padding-left: 0px; -} - -dl.note -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #D0C000; -} - -dl.warning, dl.attention -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #FF0000; -} - -dl.pre, dl.post, dl.invariant -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #00D000; -} - -dl.deprecated -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #505050; -} - -dl.todo -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #00C0E0; -} - -dl.test -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #3030E0; -} - -dl.bug -{ - margin-left:-7px; - padding-left: 3px; - border-left:4px solid; - border-color: #C08050; -} - -dl.section dd { - margin-bottom: 6px; -} - - -#projectlogo -{ - text-align: center; - vertical-align: bottom; - border-collapse: separate; -} - -#projectlogo img -{ - border: 0px none; -} - -#projectname -{ - font: 300% Tahoma, Arial,sans-serif; - margin: 0px; - padding: 2px 0px; -} - -#projectbrief -{ - font: 120% Tahoma, Arial,sans-serif; - margin: 0px; - padding: 0px; -} - -#projectnumber -{ - font: 50% Tahoma, Arial,sans-serif; - margin: 0px; - padding: 0px; -} - -#titlearea -{ - padding: 0px 12px; /* adjusted left/right padding */ - margin: 0px; - width: 100%; - border-bottom: 1px solid #6983B7; -} - -.image -{ - text-align: center; -} - -.dotgraph -{ - text-align: center; -} - -.mscgraph -{ - text-align: center; -} - -.caption -{ - font-weight: bold; -} - -div.zoom -{ - border: 1px solid #A0B0D1; -} - -dl.citelist { - margin-bottom:50px; -} - -dl.citelist dt { - color:#3F5684; - float:left; - font-weight:bold; - margin-right:10px; - padding:5px; -} - -dl.citelist dd { - margin:2px 0; - padding:5px 0; -} - -div.toc { - padding: 14px 25px; - background-color: #F6F8FA; - border: 1px solid #DEE4EF; - border-radius: 7px 7px 7px 7px; - float: right; - height: auto; - margin: 0 20px 10px 10px; - width: 200px; -} - -div.toc li { - background: url("bdwn.png") no-repeat scroll 0 5px transparent; - font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; - margin-top: 5px; - padding-left: 10px; - padding-top: 2px; -} - -div.toc h3 { - font: bold 12px/1.2 Arial,FreeSans,sans-serif; - color: #5573AE; - border-bottom: 0 none; - margin: 0; -} - -div.toc ul { - list-style: none outside none; - border: medium none; - padding: 0px; -} - -div.toc li.level1 { - margin-left: 0px; -} - -div.toc li.level2 { - margin-left: 15px; -} - -div.toc li.level3 { - margin-left: 30px; -} - -div.toc li.level4 { - margin-left: 45px; -} - -.inherit_header { - font-weight: bold; - color: gray; - cursor: pointer; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.inherit_header td { - padding: 6px 0px 2px 5px; -} - -.inherit { - display: none; -} - -tr.heading h2 { - margin-top: 12px; - margin-bottom: 4px; -} - -@media print -{ - #top { display: none; } - #side-nav { display: none; } - #nav-path { display: none; } - body { overflow:visible; } - h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } - .summary { display: none; } - .memitem { page-break-inside: avoid; } - #doc-content - { - margin-left:0 !important; - height:auto !important; - width:auto !important; - overflow:inherit; - display:inline; - } -} - - - -/* additional GoVisual stuff for header */ - -a.menu { - display:block; - margin-bottom:0px; - padding:5px 2ex 5px 2ex; - text-decoration:none; - border-left-color: #4A7D9B; - border-left-width: 1px; - border-left-style: solid; - border-bottom-color: #4A7D9B; - border-bottom-width: 1px; - border-bottom-style: solid; -} - -a.menu:link { background-color:transparent; } -a.menu:visited { background-color:transparent; } -a.menu:hover { background-color: #4A7D9B; color:#DEEBF8; } -a.menu:active { color:#ffffff; background-color:#000000; } - -.menubox { - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-style: solid; - border-right-style: solid; -; border-bottom-style: solid; - border-bottom-style: none; - border-left-style: none; - border-top-color: #4A7D9B; - border-right-color: #4A7D9B; - border-bottom-color: #4A7D9B; - border-left-color: #4A7D9B; -} - -.menutable { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; - background-color: #DEEBF8; - font-size: 100%; -} diff --git a/ext/OGDF/doc/images/ftv2doc.png b/ext/OGDF/doc/images/ftv2doc.png deleted file mode 100644 index 6c758818f4f4cf20ce94d62ba7563676048099a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 628 zcwPZ?0*n2LP)!wQ=idhEiqMJgf0i%WxV%iLKW}Hkq9T&mBxS3dS)3ds~cj26K@4NTG8U8nvKOKfs zCvv?p0GX_%oEkxRGK=JBeqZ@3f}=?J}pf^TDw4a~+Pk_i!uNc|S11xfP+un zX!davT}p(W2BQec-!hkL;I;^-P86HK9<)gb(1b)&_4!Q_@DCucVR{Hasf3ai<2L50EEX7jUWscD^c-M6W51e<`eiHd~qP~<{8>gT*D5ja}{DY`Q7_n1*0B$ zeh1C9=S>FCbO@Ze47-mPRdL;3{8!}TbM?*|d(WGQgpUv-#Bq8qKJb7M?(hix#yW0j z$Df1#pi6tV%B^}k+JAAERM?}Ck>8yJ@)~CIF`>ApNOc=kOUECyjjaaNT8ENlvNYa^ z+({P!XxR$O@Ili%%At z&$B{~{Y>f(*&R1~(S>v~(aCn%uBj=@=iIepwy)Ufn9Hh$`c+0f% zNwnrCDP=c%hp&_CAMBC6z!Z2f{oHOw(Ic-M&&4w{lysfGu@c%zm4zGWnACKil3Yf^ecm>tDnm{r-UW|p@o5q diff --git a/ext/OGDF/doc/images/ftv2folderopen.png b/ext/OGDF/doc/images/ftv2folderopen.png deleted file mode 100644 index 3aea453a7c78d01f440c36b13d897510d465c0f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 408 zcwPaR0cZY+P)jX#KpcDkC+T=&AHng48!{H@ zP~?yx!8qKVJxzjl5f|};5IBzS`+fNbe_Hm%xKL7wA07*naRCt`kT?bedN7r89asfe9KnzF`5nF^P3i?^1Lc|gkBN0JC zs(^|FD=2ma(Zr4g6cj-L6{E2Rd#_RR*<+)ML8Yh^DVP6T2A5^)?B)7@@5940yLaZ@ z_wG(PbLQ+^No{Q{!HWkE?sw~E&7X%A62TlJhYrcidjpAAuU^9c%^NrVwr;(0s3W6S z!+)Pio{N?)g~YUw5FB1C>WQ9{;D6}MS*)L`#JsExZm%FULgca~+B(f45x*-DoyqxB z(`9ci@b3MmbV5gM1*zS}x$HZ52oldanyIR)qLZdNYMGNvA+h#eiGtK#9`338(^1;& zz#s5`^0{}hgA7zv2m?*|Wp29~vlbMf_Vw~eOim#WHEg=W|Lubf1O;(Y2m1Tz>gtx1 z6elDm^Or9wEIfVs)bXQ7ckWISrcQ|85gri%iSqJtL21P$#l7t8;16mijh%&hu!93i zXlZE)QuBa?+Qh^(H#Y|o`LFXWEZFNTiDioyqo#y)L)6vP2lwv_ja!hHm64B{khhD5 z0#Hf1b+ef{XRhF7u&5n}3?b8vDoJ%UA;E3HxcLyCb!~6;Pxe=##^+_B4hf$2@xuq6 zhrrrEYhJfx#qnAmxrCLP1dW$YP4WT`jc9W+yWA!v zZ$c-XaN8E5svVsgMiXkU4;W^qHO#E7D7yBh#xHYTH&7!3W6APJdP(P-{Ur zO30~IR8&w!9@zgs7cO6GIy*``B_Kr>_rPCG})=Uaq9A2`%TQ4eLja9!>T+0@No@9Pit|Kf&l)Uk&cd z)DFBvT~))fL##S>Wc?~)!9s0m*#XsbFi09*lI?aQJLI3IPqA(Y0BpEv)3L07#K>x~ zuv7mU9R<|T?futX-aUP+s%@^W0*MdlX}T`saW2V8jpjukDrM*pcwc;|w$zoVNHtjV zw`=e*v$CdkwtuYm6GhnsatoIIe232o4GTTGXsyq23X@)jx0wf3dZ{t`;;f z>D17uoPYXBP!Ww6N==h=dg1{&vJ@5;>gnmRt8O9=rXTR19Kb>iUxyqt zMOl=nx$j9zTCiv_d6KT0YCYiqH5Qbg%F9B{T9RvyKVkgO%tnYy{U9?RthHK-RYk?# zv;#b4S*SnP5WNrN-5W3OnC4u0Pqo%Iu3r}tI)h&gA9b7fENcU4__duJ+%PuhNQs<{C7AuBV}yj?p;|KK!~r*70!3p(Qz2Ci!IUYnVj!`)C0_1sxARy%RhqlMYAdoR#Q;PpHEF5ZE~(IvXShJH$gI6vIRf^00TyrQXV%gR)mHIw&(!MPpG zO?a9jJ2l)>_lXlz_UvKy+L;c0Ew0}~Y2bya+`z$(4vvlOncm2>CKBL}*Bckg!Z z(F1)-o2K)Rr7SmOYut8%GSHE{tl$|-1!~A&w{P|AW#{4Mnw+|iKPMLTqlXW=e%lSD zffxQOz{^fO!s!RWzF0wOE?%5jDIYbomq}jUgB=~2SY7khq(V`pTt?GiEh7^MF@#TV_R2JA!-qkM0ALmri}) zkbG^#U`KY^FhfTZO-Sc@o3S!7!R%ujsL3Yx&cA^Ut-KImP%!#T8i03iQqly^hGDaT zny1OVT@ulHX_TOFDzBWHtUx?70UTb006*V(3lb za3LHdCL}Cbz5=Iww@w`%JblieM^#l-vOQrZGBAi*8CSlKzaMD+)6e7~5AS3jZ&NdK zO-;@CU5WC?C^#w7=-ib*1A@QTq|@gwl80Evg0u@3^^V33hfdwkzUP&je=&=R?NM2% zffrRrT3zJg_4o0PShOfODDc>yrv#`8iXBo>Q2`HxJkRtFk!>PoTdc5ZDzdUNJ9X;Z zFFpT?ixC|DJ8urYidONJz7hpsw$n5bEw`kOt4VH z7eqp=_0(^Sldq90z{^e@9l3(*J2sUX$8?I_x;b#lH1bfican)u$NtdyQSPv&@&abg zW^v3lqCR~pLn@W-jF0E)3-f0LTh&q1@a*~X^=sGA0zDd0TXvA!N31S%9{jp0dgg4o zi9xfWl;DgTI(#_m`9{>JiIYbIs>z!GkK4y{ z;?AT!G!|J!1(SOFmpB)iMag+XNM4vZ%j7d$IVxYi;L6VgC$)7--u*gn{&NqLR&kld z0qr1de&kQ|DQiW>rGD`Kvs*?%s*|B*OKHoceTaZJH?Cc?@6!i9a&aDo)2vviLGKTy zS|0-~j=U->u9UTussd3&c$j}+Ak1pvQKuh1BFM{5jqU@$y`%QU{LkMT$*p()!1`6; ziJqS4&z>3Nz%nBdrltb%0#>eAfs8Jg1!J}*+$IwjpHNv@DenfbTWM3BaZV0{cJ5AY zYtm>%Z}EbN?Cg5uLX;mI6HV#Ar@k(HS#tCe~CH4LKAWr=m+3qlF~9$K+Q zvy~-_7BVLQBSwyF`ci%@HCKPSi*lKFX?73l(?r355&#U@cZn`VS)<8XGkb#l5TE`aZ za`m_V7ot&xCgT(lKrxwqHtYP~?<>dk>HyLUzf7b%w^aA*(%dRJ7p?c0?8?TRvNu&U zih>dJc*)(nF)ua3!~#n+t!)w5 z3z6kFuWQ-&Vf_dcS65eW*&H)!bc6Bu+p1NY*(Px`2#bFEwt(4-!I=%~*8VbMCV$yn z4_BV4@nl~g8uRS1FdPF`Saj>whI41lqOq@Dxe|Gxl@8mUJq7b%RS)#l>)kMQhg8ML z5MZu7VA7t-$k>})x756Nv882)>A$eVJSZX>0c?0y%klQDn|AiSgZ%wU%RVLTO~WTd z7~DJ&PtE?;cc|9gcb34>2GIi_f6YKSt6D{kM!R7@MTFfYL=nmGz$x-Ot9 z6L`_&3SUBT+v9avP1}U5xwb7=_0^-E|4NOI3T_9*?xeD^vS~qq-K?#Pi;8mVmg1=Q zz_^(j*K0zU05+LS=I8CzrEAyn^771AuegQ+T+x87F&n8WPh^!3H<{i(_l4M2+FmJfCuB9TaH zYHGkTLv=|mdR0`UtGoLsXJ@j&ABPW(c4iN1{r?1Xf9Eb=rJg~4=teGn3yb#O4;-XK#RSEyweQV7Wn=}j4{4~= zOrRGx#hRlq7QV3UYI)}oei0r(%j3E_Z^(Jx8z_kxRfqtJd1m04KsSr$x&pQbDoNgQ znDk48UIofJ| z2+?!rMNkiI_vM9t*WyuO)k3?L>B9}-%(p3d58WGHbrkDD*b=h|r*06UMAI1WxHjms z(U;yTs076`uN40NvXr#@L}B&HNF|FF93AZprSN}kKRx(EXN)#%Va-`kP+(|i$UKif z`r?Y7H75)+CkdV5BV{GUs*Jf4t73$>ZCe6@rV29Sik^=B9tjmM>}+V&nq0dmE-q@> zlD;?;wS1YDk`F#fkBHJ1gu1WElKXA zK_X_u2GMsK6}W!wYV20|V7oPLJBl$>V*N(gxNa?U&**ZqLVqc&dxZiH*R0>bRYag6 z_W4g=_@kadimR%sw#RNmV?ixJa4okKgwHmN{*8+qeg6>35*d$B5u&-EuC9(0ldlF6 zl;uqlB?tF0MaOTC^YrqTN~H=vF-1i0c=XY~Yjc!F7p|DxHZ5f@L9~ZqoE#CEK;O{s z%L|?g14}gW-__I-ZFgnA@iB{g*dQ7~LqlVdw+|!^x_0$Bk+EsRdK5fVb?5~208T@l z#*F=0OG`^xjR8wEdhTi}1Sp2Y&2h%^)p?0(MNqp%H;R@~q8?x}qSIW5j4=nH&?jt- ziE*FUB(J0*qM0D8@3O{m8meql!;c?7q6DfQP49n{99a{;D-k-D06$;U>E5`0{m&C8 z$nF*ewVN{D7!eDly}Fr~o72{$scLYbgxidsb-&(r%lg5H`C}u!2}aMG#F@eB|(8fwJ53fZBTrD)_AwO*=Z#dh6o9zA>M=j}zF0lDN3Q9m5c zKkaPPJuUBwi?M;G>g2O;k>XzaUUO}I_;nSN0hs8f))W+|85&mC$~!(J`b>`ewVuCR z+Yb6Y|I%0^yEgSMNqo7=R7{N*MJP&$H3(m*szQ9Kss*`j<6LU%A~#=tr~n z$3yavQIN~rGENklq?mv61F8ep!96?U+;Q>5Q@+eJ(ly?uJjqBHq9z%}|8SLQj_U+r&t=V^VLHLS_3EqWq6dKEf zzP>&`tFYo8wzh(K{=RqbyYAgtKH%P9pl`o^Qv(BN6$2-PQCM+E=nVeQ$m;59cDV$> zzaPRxPtQF`NfWx&o9SJa7~;6ZQBJ#D)E{fM&{<3Ydv1K^Ju zyN*)|w;o$scG#YC|{9?md6#Iapod>072Qs^Ub~=gwKyF12Z3& zB_NZ@q*5tsk*^__z*l_s^l8@ftPVniuM`cBtGLZK-w0=F3{g8e;R9FkC>jJS+|~Ru%H1`?vCwo8d52FiTUASp)+P0wrQiFVz5&?cj-bN&YV3v(BBX1HsFOM z0-ip3GBvni&y&f4fnjrID`;&-uZ$Yc*bWVC0mYBE3&V=jGBn~Z{5^4X!NSX;opDf`t=?G z#n8ecmo1}Bp^F*eBdwd!i+|XcqU%bJ^yk9nO`B+!fZ3N|DZWS%=yAX_>t$zm^Tv&~ zCMICfQ!}tS*74<%mrzkrvG3F8#}+%BPt6I~xe(uE>zMTel0dkv6?}hX(@t!|?;;3eKQ772DeNqMfm? zTdf##?BBFuhApM4?GkgEOI7bvqERdE-qGwK>?+^~$la9?@9oRJFBhj`wA%!EnDq3M zXD6Mz?<$`ZRUP`V&9^Ce>Z)>QweikI6`!Xjm>w|Ly&tiyZr8W z$s?7~&OMNLJuN^f7G^6wJswvti(=0SPO(&8ZRQ^@;Bf z=3g9Z1m7g++&jfKE8_vk<*Lvuimj|V;gDXedj$}_2`Sg|_JbyfqyyycOHFZgqj#6} zic!A^gB%R&3a@&rQhwJ+DH!D7IP;f~qM{=7f?p3?+mO&1a>X>aT7aJ~j{i#m96x$w z#K=+j`DvjV1lpIA>Cm3HV1WW*93{!ST6lQ#WLUF0ni?g5gP&YnXlFWi?yNNbF~3}* z?w4akDL$|-ttTUlz}4MdX^OLk4K_b{jwi$M40f*)7pU(aQ6b@RLx}>vTmagj8mi{1 z-`3y|4j4Fa$-)I*zK!4W1GZv-SVTyArS_uC*OP009Bfih#(fU|n&kB8Us3f_h!3RY8!|9Yw2E z6a_@A)K;&1Z&eg)-RjPz77;-~5V2YpTu_0?7B)d4VJF-#IXH%7lFUpdO8@_T=HW>u zXJ)>6IdkTm?|kR|h^|!W8Yo{tNj9WON@I}!&fC2Yf4vw!)YQwvHWF7gN5K3*3W<(> zEWu(;ojlQ?haq~)Y>S8(Y-=k+jOyL#--ufbFR!`o?lyhR+`^>%u-LoSe)MSAloekAeUvR>q0&xWec^2V{lD}VFIO`&mvLHn z#Y(Ppnk%6kAqnbzH>h*C`>$)O1I>FadhTj$!7YGbXYa6m$B$w=p?YvQ93vwm83$6g z7^`!qU-H~V5?Q~pHigZ1*PfLk3i^`B&c>O1Z)s_fZ7zd|#Y>kh$9i5EI(HWMWKrB5 zz(d#}L!LN-_1MOyuVj6L$C`$EJi^WnPCd`V!`enL#^!RlyMFu;ofnySF}F7SZq;KE z=MZouJAefNMw5#J{5OY(qpyl8T8RRk$j8eQI(yKc7CWz-r50@M4j?8(p{Aw=9mrF^ z{dPU!+5&I+p;9C)Mz9-Yhbz?%98c<{*;!3x)}LjUT-(Agi90zxJUwAMux~GJ(inv- zmZmH}*;Eq=)MDlWy38fvNM?LUs!60Im9_${D`XvHH!m}XuV0=l%=hk9QO_TFt~kf5 zO*7!#+0%-5;&4IKV$pT{OktpYs+*C+MNXQVks4D#@E4t!qM_Q|mJ%WigP0D13=p+g zbP<24zqxxtd1`T8p^vG}$wHxDlTqK&s;|L}W!L#6mRAOtc3n+wc`ZSO01_69!a$RW zC3DLbs#rk{>7&PbKHmh))zfH;7;7%!ungtA4k&=A#kh%BF`xy?y>!MW=$pb|MaJk+4 z52oC@c`Q15zL%HtM0`nRsTPY45Kzt;3X>zPb#*G5nnX%M*IqOUTW(H{sOMO|#g&zn zk^|j-{c*C<$VUC+hngct$t@;1e6qB%3J={(LOx{8svt>=XU~~KR_Kn1xzeDokDpBe z-(q`*(ULo>tE)+w3n*UbZG8ARsY5VGDy|^lTfA`bVxT!NC`feY?wvcy)?>b z-9Cd9i$?o&>sYl0b9E1~tA+X01ZW@D`)kaxIrH4bV(2J-=5tgN7{`X)%KRAQDsZM#dR&MuRKk< z9uYKBanpK4Kd=;}s+?rC04^O;w?9$KtvW}3qcIz4&Y6rNdm!L==p92!(GSF{VYVbi7~ zzx+b4h8dw+0Y)Pq%JA;$*QX1nKj0pamo2NZNwlQo648Lgi|G}Qq1d`<3Ln0|D;o9G z+jTZ3xyX{#OHH}uIA$!W(?bXKfAE+}suhLC(nG#b&-|v{VD94i^O9?dv2iGv3x8ka zu;Fh+Bt_wInn(Y2b>gXVw?{@s3sYMxNKjY(*5bXjAf{jGCGn z9UUDk9zEu0bok~FX$@j6kC$H{cr%#xGS#9<~(b`~2m$?5I9| z{t;pAoJZK`WX7yngKcd!Gz5Lv(z4P=49n1as~V+l#wizE_`N|0sL0J^@p{;RaI4@4k4fznuWFN znOphL5adWHWvaA3)DS@Wt;pz`fovdzT~dwsn_ zZ$1IVj1JB+fXA)5$IdG&D^pcfUAcNSbV#tDpbNP7-~WcU}?VWM&G2x<`x{IcU(}BgbN}pZZ#v4;pNXBpne{_UE<;nLYE8`_pK_(9QV@r@55@ z6vG%nT~)=pOWW;d&o>$Rd(rU;L{;+0q9d|A@0+h5{B=)^UxWbz2g3Hs+SK^xBMins zv=i9O_UwfQ?ba5iLx+EbmUK?F(1u}s@SUnh6^*AS8#M8OU+wgghBq}Wb9C@fXaE2p z07*naRN_m+N9da$FF=d;fb?gTO#{0LbVeL6axP8jap1}Ou&+oY6PJyS#j@wTIhl7e zaQPKQ??>69)3eYN@S0mu%|*wW5Bkc^#xzdIb<`+**igw8gLGF65`4HTbiJ&#)g5`B zlQ_fB?tF2*Faglf=iCz$yMNJ%dFCbW{~*i2Z^oT;xr@FLsxO`^+p}BU|zdKvd5MwKV{l08dXTb6&(t^*=vbU#uT52jmei3x0 z{_9#?sFb8FE#folgxM@5uB702gf+0WZE<>pON{30;B=r_J$i|xGI z-v4?cn~Oel1g<|1%fRo=q$Iieqq5PI`&!Mix3piqY&wg6MO<6j};i4* zul;*Iri)>*SlhNo$rU{!1=?7K(LsQ(511Gn5+bQg6cW6?xVRXG4@oJvX}MhKy4Bnp z3Dg#mBCegrj5ag3Fg7+0SiD%w=U2n6K@}zXSPYY7AQCRk1dn;}dGMwdJc zo&9A@{lnL5zMih$D0>I^?BXg*8wJCv70YM3iE9lh8>XgaqE!_I56x178A=)ZB`4h= z6(kD}0a>l!meLZYmaMD^9SZcb{4^`e$cRKXA;7HZQ?JCeNgOBNNE|=GS#Cn>%Dubz zwYAi({IsB-<*AdMiDVo>$bRwSPI?+fF+-4s(iz6+au?Tj4O-iM+Yahhep)D{#UL(j zZqv6fY+^g*`w;m2+|k38q%N)u(9Cjx_kzPmW9U664w%e;5XB7ISx!t$pq9Uh1o-?{ zea-*>vi$7XQ^ki#^6^ir$P9W}o-%O)@%J7z)TZ82UcLwAf#w!N+4)el9LN6SC}z;e z@{$1mUydk6VHZP=ZC@2tmgRjqRgXUnD6)KT|NeWKcU4qWT&7GJGIS`5#qwLY@OnbR znbU&l%R|vel~Ji>aNhlUcIW2ieg>Z$r?~i_L>dT5tX#eNkGMEmCZC#1IQ*)r z)}}_?8DFaz_mqDC0W>u=0mYlc!)33g_w@FD^zb1qcR`Njjlt`?%FCaKFm>9r`}gkk zv$m?`k)CN5#hy;AeyW15n?~QeZ)Uhm#gD8m_(#BKpBtuo{C?Q^xF>_sh2OaBf`SqMX_>~xWHNd zn>R5>k22cJQUnjxgAMyy*}(61m|eTnLQ_@#GYf-hEjxR%M#{zEqsOYNtAhfUYiMY! z+ps~b^{A?<+P8Z*gK#=gxuDXMv$nQDNkTVl42j$tQBz%w_Pe;c&UN<~J5F5h0K*Rt z-X|8;U7v1d0um9 zeD~gZQf=r6gK4m`C%4LqD9#t!LnRs87-E|6XDvf2Xj9T($2XEJkFN7 ztU@2bIvICsZL1T7IbJ4vAHA;?F6D6Vqy46)S?p8|&$9AoPU#30SrieG+hGG9UgqT! zOlgWhlx4cad!WaJG@}v42%`Nw1dVZ2>VEc}rU;|oSu?vv*@peke=~E|bYiqk37BA3P8e8j34`Y233Xa>BtGd-v%RvN=@Q*4N#=Q|L8U zkrt!AuCBbIoX6#fCS0Z$kr7*RUcZ*+oms%XI@XK7>qjii?em z$%PJ)1+c8h;n2N3dgPE_z@l{4`)GXhA`Na;05AhV;3%2 zqNtfN!ArWX$l=hpefzco{?cWSBw}N)5G;v^Wm)wWEaocVa17-ohCvWZ_NNS}C^nmQ z@%-<5_P1rTYN)Tz$hafJwL%TPe*PKh=|oDF2;C!s7URgVm;hg&Ns}kr*-Q0)Rg{+> z+`m6;O9ZKYA~l$ty~O8I_x(qNhq=w3gFb6?>U1?Oj&_!TgwSw7`?)kQP*S20L&lvu z3GwkjuYhG}KHyat|L31@7}W4@=FY`l8pTCLCypO)XlSUbt2=Y|-FfxVplI zKJ!~zc(uGvoir^hEFDI-trmgqVNyz(rInR3j1~pUgyMpcPl?=|9H%i3qQi)$rl$J( zI&Cd&AkB43yZoE@V?U;SQ?M&7>P*r&bd3MhxcH*I7NL!MCdnK!uAraZ-#2 zH6d`zlk*mhbDDtEe{ZE_;3ff}3l^D=ly`DP@P^GE>tIK=o>5c}PfWN*;bNq~e^-?= zVsM9QI-q(TId+`FT~nMZah^08RqE7?%wD}r!U=ZXOn~ z6{^nupXm{8r!BJ9+`@AFgo!(U+_AvdSMt}S8;NI5owBsF+#D`ndO!@!&N}At$#mG* z4lqQ_%gvqV;UTH!0e~BU+p(~uXK+9d%PW>G<#M?)d{ovpHt=iA(WBIY`_wEfDX(qE z1(;!KW+ua6x7o8{gTb(lt}dx)2wc#>a${qoY>F}X`1yg|FqFpznFR65MldgqqU8*K z*rg*gPqJKq0mvA+C6Tk2i28tR(7-ZKOsf3TtS950oXB3K+sbb{*$yf4^QtK?Q*US> zd$^bZq{{QSTy-frq69$$%Sg!-nq6q)WS1<+7d-N7zQa+iKKq(CFJ2(Hw{f`sHaqbM zc+^%vT{hUXMQ;I4yH5&W0JIo|1qCL(zW=MLp{4aF2b>%0{r5A@%B704j2Wz}tGjB=8fj(Vb{I4T zB+{vm!T9jvh7a1>+T9HdYO1T>z7@pOGMP-2{{urejdn3EHu~x<%PpBQXKYloJM&U+ zweol>bYyox2K)PX^ZA10Jl(o=gBM+SSs70l){Y#TieCkR=9Orn!j2j|j80=5`t+(F?8O`C zmeSH($FGz(;7(3WAMa>Ss(uiGQdoweR8JEe&DVs2`b`;?&dK|jkyg$201OOu%VXCA#WzcG%_ zuiKO%$VPf8w{~q>Wxh~n8dFpU#7*rHnDSObN~C^HKTB2*BeP_3YGuR$#w(J32^aLU zJl@d(nl{P(CAEBAbroK7t7|L=2pxBs<7}e2P8cCK=uDA|nfCDCi&2I(z=6l_5$QH3 z3wcd^wznzk1Ls!Ha%s0&6kt5u0=6`*%%^OFfX2HvYj1K->(ZM7cd96KyRZ#C(Fe}MG7_-1i|V_^jU6gZ9TYe z?|19PSM-u zxBPcJxb!%2$xq6*->qqw6w?l^w!*0JyLPCP5#oB~%ftNDJ&WMoIZ_`#d zPyzsAQoB_V<}ZkOz#)427?XGsmjE|KNTneVc3Y>*CJX-UE4E zZ)0m}W`;L@?1HjPeef8?F$`WsM@0n%UPhVjnQ3MQ2Ol%>_$YgwItib)8#eF^`J1!z zu_H%>N?A8HSyDxXzz6~Hp1r*LFUU;1x96!HyPPn_jF0k*^mIifB`hHkQwLCWaNONS zh(1l7ptRar)#ETBu|Zbh6XRxffRLV+hCOn8lzq+r&nO{2KH||MfFOrwh8OqS4>3fOmz%raow2-3RZVT|*s-#5a)pJ3DM?8H z7y2d_+l>P!B|cwawKys5C9$5bn4*=Hwse}o5m05NrAA{7Z-m}PN``~I9gRkVH~DxY zBTY@shWh%nw6yZFGE%#ziZ#~j@W#()dwCF*%Au%!?@rlhV#i{AT`i3P1Jn~za8zVi zq!n_9gk|0vRg=e$EiL^Fy>QmGodFlwT_LPmvsRE)dZJH^j3hiyc(!VpRm#f@6&0-G zyy(iAG^VYE#-DN3ii+~_h6aEC6H55A=ct|=d6+cWm|3(34jdStl*&BS*1k*tzHAw# z;BM3pqbG2k=P&rk#?(m@ii(QZ3a_vw0$-I#(Tr>CnpKCSS7 z{RNJ?Ejn^!-u*`Cm8kAOQO}))ni5t54!qy?DJ$nZvekU=67|<)M?D3P0`Yd zeU=E6&zh=k8rip(&!_o1a(CzRcxPhlVNW%lSX5BZ!-bbkJw&;tnXY}g;LE0tfuyoV zx_)p$jRWIPq-aM+MGiV*z0#UtO$?djo_Mo3wY(Xb`Q|9}(IRNl8jc)x;qn!DeuUl% zKO&NH3!OA2v^a2<>M*6QEhIODO0mqNLiy&)OBgoT$)gi%(%n4fQ}ow!V6YG{d-uAI|P3M(Fz z71XsREE@9xdUe3`5bS>!P1P6xAy`|ODsvxU$_tgGrObTnwrYX%Q-G2YiVhb=+#TI z2d5}WJ=~IGwV6ojT&blhBf$|dqNc`1EHSgrH)m$P88Kqy>g84k5C1V^CS!oxX@{e( zuC8PIaIln=)I9T<_ah$jcMJSUWbI`vI&|cStFyE56y6j2Q4tXk82Ju}iwX-13JMU! zpj#m~S*z^34}!sWmXwl<22iroC>B0gx@rWs8pj)(RM^8L|+e~l(~ zIfnlIfQO6wKA~p2yTqC@iN%-ev7>)vyQ;{7i;Ifjsi>%^2*XN*@FZf&!PgiofNE=NNS*&uL0A7) z?#I5R65eL6d!4&qe(3NK0@rd2Pokt;Q(djpuOCunF&nVPCR5nf+x@otm-4bQH8nMR z2M6Z9AZYepICl=vtE#CT6OP3=0wqey$Raj(7iU(J8n0fy7&~q}^UvK*PL-7v+js6% z{(dtwG<&yf+g4Ro<>TcAVUC|V)nnP_L!xhETnW7VA+M16r`M?yfx#VCbaHcY0P&7p zyOg+ifCKb!*4xt)LQ-{fdLp}gN%WLS?F-*KzO}V65raJTxkE3R8)8Io7Q#SCVJ}P& zL}EdiDW{#=PkDD3Rzd1(EVe=*%pngC2;XC-&hbk0ls^>|>uPCu`S@jJWikX(d=)0BeXWx9a9x9(+{!OpbBiqyB zZ(8z_x(dRgA=Z=uVpPOKGxIsWA2={+^5oeT7OZCmMdslbG zT($R^Tqi?C#6FMO#r!gR?YZHla=kmkZ;Pq)oz`D3xG-ZiMH+*XQa&WUlmXmeZOXIc zR1FQvy}RN6+_(Wu*}^Pav10y$g(bzs5b|Sw5gX|F;U&m~y1bOc;mHidv%)?{En?IR ztMufmnp%-y2-goa%|b#<5?ji2Ivv2pC#E3#%>gAGwY9Zzu`xM0IXXHzQ>IQ+RP6Ai zHc&$Y9tIoe4Ua3PXviSntD9&Dz^H--gZ}F9#p`A5)j1uNvd^^s(97&Y#^I_Iuf&lu zAco#xd}1=&*fC%Q*0iF+DqkcX?iYIHekD26!ZJ z6@Z4GBvjUZ(^b|+l&#d0KbTxSK!&{dUg^hmn#1}rP})T?Jfg3UDo^TMig)})&1Eyj z+I53#g=s4_O+t#3&{yf-S0hVvC!QcN$y;pdkhTZO~sT zc{$~C11-Q*1&Xt_JfnbTt<`*A+j7ZF1&&-62bt+*-$wUmJb>~>x|9TI>0mkdSI}1y z$kEbwc_u0%!G$1>N#NnmpqGq{URDn4FVNHl%2Pv2pd$yM;UOWQ`$$R*>dUx61Ti8# z#SV7VzU0?cEx*K7oi$ZK$~fptGs7BX&X*SLzC@A{7s^b;m@I5`YqUW@?&b4ocYM`x z6Xn6-^!Uhl1T^}P-Y8|M548Zg0?Ih@OX3O&HL$>FKp$e;8)88jLHsoSIYuKU9Q}nt z)eN9dq}RarG`bo*Ff5=EC$LNzC`;wq5Nza=Bo36Bh;cddY0k@)W~0pVeM>aM(jvr( z1#}Nc#FP=lPvR1AA(kMMTPw=Hiw9~EA9kCG5T}@c7A0jSV!RWh-HlL6wAUE$>Y9J| zb7X#(>0kg2@rxX^$SAk9wZY9t$Hwz9_gr9U(eyU6`_`S_5~K)AM%S*Unf{`p`6m@d z%K_qtR749}G?W3cj^@C}G4cF41d%hH1(Z<&DD{>=5F>(A7@i5WG;#_{L^1;_0?G*D zsHbs!J7kn*Sr&s)kQU>iY7P_$=$@vGAdY+zgLu{DPqNcy@L{wFKtsAB0ZlyRzph+~ zjCjQSlcK5Vaqti_g2P0N-P{;A(LR@u)p5^mK)P(8TU%TAxw#eg(x@@`N`9wq*W!JsVP$Fi{o^8xx17`S$ z5p(CwD=RJa_w%#2S^wzq6Fq$b5O;`9C-K#0fII+b$PawqvTYlywZu^d1|)`+%J{o? z?xd%s9Xfo3kem`j86G|${*R-h3MZpjY6Au!4w+7Sd7bt7cJVp7r3;4da zp}xMZu8!MwAVhF4a7V#GLE=Ig{=eYUe9j#7V2X;0WHQ-lhvV7v7X(lAy}mZ(!WG%6 z)A_j8Y3B~e33Eb=o8XQTo;^!=7C+gTs~s$iB7kzhS%37!uT0IEJNI6AxZo)wYJQ*1 zALZueW{g{6;l9rK`-=r-Ql~jsEWrq*-1LfnpV?6DVhIKrPV6>u&WDJhjIohVU|&E$ zQ>s`qEJzwGB8Kw&ckgENs+W;qgd_*5dw9S3UAD3#R!f`RbMn)eF<64}7eAW_ploAj zA9(2^mXHtb-zUo6cx~XthLj}!C_^3~Cs-&~R#sx!48S`@!K0XAY6_HNo<5y69qnCI zUtbTe9WU;lVzV+c2M-y7(Zi`AF8)rO^4#gTooAae=E)QIoIb;p?}V5lrerN#v?x3* z3`&QBf&#ZNCypHhg4_Zi4JIl@9izRLfv5fXt~M1E6(J|bj~+#_Z}R2KmnYHDi@x6; zz_*B@Y_)V*TuhATi4%*htVSCevYmw-!zuWJ(o$Z%d?_w_PQ9dM_|7eo6U2q-u3vuX z{@`D|e0e)Gv|qn|i+L@b#wfzZF;04U2l)F#=HM7Ne*7o{14&8AoSdAe(b04|U0PcD z%((!R%kj=)6s}y-n4T&~OXE_|m93i`;PFG!(@jlvbaar>qSO?IwP8W5;CC01V{(u! zI8OX|3^I!3mDFxb`1mPL#OO6QwY9Z5{qifWtz<35g%YT7Vi7#}rlzLdPP?L`qL|L( zp?q-kax935A76$nVy|8il@u4RUTcl3HBBoml^%v~;|WK><45dOTbRu}>FqsY@MOdfBpIu??;_K~&m-2gkZ4JKwxmmos zLgFCeDerf4<->t6B6v^2y9i?iEk)Jk8AeP*JY{YUgi&<(kB-I2w?qH2TDAfZzs`6y z%3w75RlNsM`O9I?OT;U<=FgcGa4~RA=WOPr$sJ>iLwK1k`afMS*VW;B^;yiF|1SG2 z(+ClKX>4eaB$K6O&^jG$&EFWqYS{YX;vj-4-???$ZbPfy+yDR|07*naRKrH>;T^lV zuaUtpUsZkD0E|F$zq9hJ?+;X*38w7s>ijgGfMIWR0b&`$pM;$Xfg+f4`>T)mRn~0M zz8NOj%}$p%OZ2P6`A{E2-b2G;B_b);)z$G1B(NIdVv6jof1pa4L@ed-uv<2Eyq(es zsFIEAdu#QOJ4~WPB;|dsE~UnX6D{f+P8(yv9K7Rt`5JvNKgOw-aQ95#_WNrs_FtuOD%2fwzjr6uV06Ug>B!uMOj(-gr^r#3E`%UAeNSv{>`~- zK2%ata@_dwaO8aYbR{s*X@}z}@6$wO5m8%1gM=a`hvygth@sfJxVtmw7~#t(0|Pj! ztEx_Wd2O(@xo|mpXSNG>%e?9r2Fq8jym|dPAt~ac92^uhZ1`}V!Di2y^ZePfciGt(Hx{6% zIg7EYUG3l>P%E`HHugfD55y>UR~H2Z1)eMO5F@y^LqY^!lZd;EMfgmbbCj@pB`xh^4so2EPhZMz zup5eXV`Zb639X`BqP_KM>+Z45+=AyNJmu!H7qTaVq4H^NzYD>In{r-mE|!8&Qc^P7 z@F$ML&F*2J+~2l*T(6DA67PEwsnB`_@_o>lvC;&MUuV2}WrD$N;G2vLLd?V9rW|tf zCbZSCgml=1wkC0K5aUJPuvJF})pDCKhKHcX@i;OP3+2Yf#y!q^1y2zl<>Mz$?f%)R zuC5N6Ybe1yPo9KN`OX@=S2yceOv#?fsdS(!_u*PzpgNW{nnVe{fh(WrI(FhDwEB7e zQ(nEoa5ICYO~q6ADEC)Ufet=&I^6c}=e8{K;e!WXYHNM{yM{OrBgjlKp+_y&n5oHo zJ-yliV$3Hn1??X_ef_{om!SK~ZIi(3jEoN-KDh1MPe_WmYYd+={?KtcxPSi|YwIC; z>}v+k`1+QYmHlVCBl;$<-D8#hG{&%OrTyh2#g_#sbnSI@+q%i&*pVa9Fr8pz#C8@+ zF(5WGH|N{35}WvGV_XWla_E4^)nLX%vWA8RyyBq#%6#*twUuF=8`{VUsN40~iZ+^r zIc$ICTtMK(i~ruc2ZxG^3ROpkMx$kAW`6tj4bJ9#`dD8#iDx7j#b-+{JvGJH#6)NC zknpgu;$nv994NdlZtf^9ByW9ch%9VurMLOdKr^Gks-iW^)V=&9RfXm5#m3$qj;P28 z=+jnIFpM&j$z*3&SABg(mlYcOHn#TYt4}eCPs*t&$su73>i||umtnkQiLR_;Oy%n} zU5`O2An(i!mDPG&M{*ldlG>V^`O6`8nawiiXlmqTX7;clI=HqWaT7n3S6D4}+_{U7 z3ybPnlzMkHCu$r}mk7}qR;bAokvaTSR8(}>ywza1enys{d*1n>oRs+dM(AyBXDgfN zMfEhqG&fWK<~7dHl%^_l%_lu7XfjssBQM3hu}mfp$#~C4_6U@V`@TyT0^qRQ;2=mm zxGAq%YPD_0PHt!an^3*qNU4uxFKPeW#x2xd?It(3J+1o7Tt)eOzFB9x?SIr=30O?) z8=t1MphSgAD~eoFxYi`HU0ZY&vbB;zmjAUxrL0AWEG3mJS67zoqHbE`N}{B$ly;G9 z(KOZce`ij2$~4P4XTCG?dwS+Mo%zmp-uE}(dC#}J-}_<#)|EnwJ_~NnO*J)ALVM+s zL4Hvw80ZCdi{!-E#7UUtw6xSeV=nUjYG3B(tFOQA9@*7UxkEjxc`tg`kk?qJLcNo8 zhz0w-m-n$AC}y%~Ny(YFARI@iesROu{>|C^>VkBg1$YG z^Cg;-ndyFcov|w0I6%L`q`MsUZO;3;uADKRAt$Q8*TWCSDssYar!Zm^A@L}JvU1lY z_KwCz{hsFJlBPC1s9!`a9;cd73E|b)(gr+nP90PqF5(XMC%M0h(K<80pF`yVb_)Vu}$TU=q-K)bWhL*d?uygRU&%VP&grMuT zY8_75B!+I?x-DG1cpfNx+Vm?vzQ)~oyWP7zv#hGBW;@?*sPRCco5l${clLBt z#^c9uJbr@ZTw7b7#eo)<84QN2OY>-5QBjdDEe)5kuau(OJBc-lCyGzeKf$(;w>OTLev*woatf8Rc6vTiF^4IMU&hOzwd z;|HMl*AXM8Or6@cuBDES1+QM6K6T2_&~Ut^r6k0clAGV5}nvvvSNhT!p084$Av|(6BEFOnYp=;g~7>FrW6$x0=MC(qGa;(*>kuqt|CSp z7852U-M=4t>=?pWc0wT2LoC-XEsk>x{+-DG4vYo!k9n zSS*$az6*v78IqZiA)a`+&^wdl1S6n(_wH7+=Xh@QA~B~!2*3uOV$d5-O-W(fWt=-z zI!S8f0_?IlW4{CY_eP$kyf2884UAhh%h*!CNFebsl>ibG5=0jg8^DILvgmy-7`HNg z4Gf-VXIsw|oz3Uo-Ma{+qaLljG|S7&u20c;oz7$CA3a0@+PnLjpea(1x)^y!nx z{2d>vt2b@gf=EbV5Ob=?KX5 z3kYB`nW#3uiA27!pBS()GKdnn!02_`=m+bTR zUngM4m>-8sEVg&^JO+$Uun6Xc{rb(ew#NGNFdmP)eLIbl7G;%(ha{7hGP0g_Cde`v zhpE%1!(Z!@Yf;Cm<^tGQxq9`Xg9m}M5hF)VoIDwu|AFRsDJCW_m)#i!RJh z?Lq4Cqen60z=h?+N%QUO^tCjQc#PpeS9>QpLj=CrRAbJ}=>;X_=gyqD8+Rw|`xHIP zTwO5JugbxFR}wRcv6{k6g;>i z;3;q~F&Tcq!omVQJ!->C%NpRy{q>^&3?#(gBlK7k^DP21BryYBb3L~6G+g=NBn*o& zqksoOmk?ta%n(=%2^i>hYc4={V1Q_Mi?GkDlD+ z*HQ$~8gwVIltIQzJTdtJ{G`Q2McO(P#@l4o)D%s%(7ByR-7N?K^u2TICb@^0nkvR6kCDj-V;%OS%TJA~z(ZJ%S&(thAJ9 zf)bpNQcz$4YQE4r;|j__1wgx-*RP5B$ch^uLjnf6)W%Bt#y#rl7mm@xhmtnOT!_mu zn5rYkL#Z>+Kh`vZUZ5RmbIb*TSTDa#pP{af67!`(U|z6 z*y=Z>nX`NBMHZ>BHE!L!asC|dg7-GR?HxLFh`n+d)dPwwZc%sPOW8t@ku5lLD z_tq`&D1t_)?uCqHX9s(rc%!FhYriQF-Fog^_zT#*8&ovx1%gXE>MPw?0W)5=azIZ_*640xDx-weY zI&t^O3iusfaN;crUw#IFM&V&-!Vx22`BX#%d}`qcB(AEex@Xr;qRqL!;FW^exUY%v zpJUj2Ta>KDbp-I=wF@K>Sq#%CDl&4>k|ko^5dq5y@%MD_P0mf4G6jpnLkPA1qyfcn zP`Qa6VNHCNF-h5kIP>#e|9Y z1uiNo67zO6R4msr7nr8=pjg@Z-%zi~OtpPHCBzRb^ zudny<^%MV&2w2wD(}T~@eiphJ(br)6-)5Ec$Jc6smq1MAm#{2d=ZPCx^xe*gYbOpKY?Snk-b z%1M|0Uz4RvNhyaEatoK(^M5scJ{u)BaFEt)1)5x*Y>fcph z-j_-r&rV~;YMeyi+~nl!Qjnj2I4H<;=+L%rl*0!PR##VpMk)e+1EN4SW;HW6H#RX@ z?e6BwNt^(jN=r+_m=Fs~>Ez-vdW^88(y$3?4*f+eh;+4g`Vfw6^=s!I|CHpU6CoiP z>FFRU2n?cfcXb2>2P=xVv$Hi&#u8UjQi5^a$B!RfU7Rs-6_u1$d3cCS)D93yF^xSr z=ZV%)5q^01%g=uqbl?D%_<_M-91RJ@vtfh~&_`?s5g()^k(imSXVE$cpBY85CeRkp z2!aj=W5+P$K~6EPon-53Xrhg}Q2vR@%Cl=;rLC-OoOZP`-A03_{nW?Os%jFK zQ7p6zmSv=9165?}SxwwCr8SLv1O#ZVxqY*X-C{|Jh6d{DW6;xBqf&h|VxqNwryTJI5RoEE- zPz;~{eqgqxm@Te4@B0ufKyoGpakVA%_FJ1=ZJ^vdsFSACYwDY1=u(ZW=5$4g<%~x* zn#mP)V>prhYB@nch1B+AeY!|MLM;E!q|26vAK+l@#frhIvU@T<`u!Ih(K(?CTCP$D zsr0waEdMX1dI%@dE!gNjQKc{ze>hizYoptbBPf0#X1T1ilyBZuU{+OLx>rPT=~C^{ z7b{j9v-f--9jB%nSz>Rbc-%s*cU0-CMa`Y%gi=N_C+O;!mgGtzDc0&Ia=whwkk?Uck@M}=O^oMReJNuZP$3zu!- zK2XVRpi=8T@=H5DkFDYiE5+X^+@S{YBkyLkixD;#c)Yu$WT_2EL8}I`q%jIQd6eV_V3m62-Xo>b_0+vNaI} zN>bp}?6Gb=!U~0eS?~%c%UasnJ=N9mQ%qyeW~>KYmboH}Yl@QP{d)uA{-$;|2Lt|r z3A3)w%ZG66zL{2YCRvParz|rV3@v=^OH91+aQkxODju%y+`dI(2bs3EHUp7Y5r&`g z?I&mS3$To*_!w9a7X-!RjJ9lG;SaPC2)~)g1w_o^07*=_#1&v&muMksC z49Hjx4Di1bFS#fS`KCsF^NNHgn##<~oMkl|JI3-q6&K^}oLJ4Vo;2RP-LVWWWlFNRV{mkB3o|9MDV<)8~_)LOxvd;Hba1*d%!3X&|_ zFJ|xZ=-9F2gozWiU_4q|`vma#F`S<@%gV}{@~2hKpdaIT78NzeT=?r+EIY5D$&eu? zCMNO<3MIwG_u}Fyu3WiNs~s6Zkdl(RaG@HHEnEc-09~Bx|1N9Fw1ZoAlK82zd;1y z^z`&Xj~^GgYeP&lzI*#M?zYkb0!j8n0%Qh?otG`+Yl}hatv)_Ge0@m}O^oGC&Q>x( z6k`Ap`x_Yr?hQb-A)hbma$i*Xc%o$)WHuTwK=|tpbocf4e){Bzv55)(nu)Ot?*u$U zkGZzCAPSf>Je#x0L8d!zHbyZ~T+H6A`MZsc$dcOH+6VRr5^6()EyheMD?G)(a0ed> z+8wZ$X#F@L+ox~uM=0NZM-Cmr8M^}*I2;s2sB*$Ack9OAd7B5ldi5$PDIr=p0Z2>J zMJ1&mgv!cFEqp!>f;O)S0aar^)_C-{R0=IgD?!W-H z!5=>eTa2)XNGyNM>a}azrk=VG9i8+1`4}^^C3f>xd90-_DGQC`_=2#u{d)rr?%%i7 z$M^EZi~r{3we2{6`t<2wU?7dd0MW|HyhETv?zVgxcFQ5dhCv62!C+)&WW0I9-mki0 z^X7j2`a3$i^wH^c{?D@yA7_%dg@iGD$l&)?RoH&pQDesV@7e{;sAtcfgH284<>jGE z`uNc!8fSJa_}Fn0^^<&4!_AmXrq|XjaC=MwfW3p`*m2{yW%7$k9hNL?|AAIP!ts`t z+&nD(`x`+sy8rjz;U~jx-ME3B?4hpi>$jbB+!ylwA-Lu4J^sSWfanj?*g^EuGqcdY z4551~UQeUy-MgWK2cD0)GJ3+P%9fa-2LIO#w`+*u@H1xGJPDe&ONS8!@T#*<#)U>kljl}YgNp5wu zprm}!0$YS;T5;+$au1;X(oeT&YXzmS*^4-`DfevxjYsdT)s$zA{I>sqP91r2Wc(n7n! z9rX0^n2V1eJ`Db)f8^=2<`$wOAyNlPu)HYl-ScXudPkY-Gk6#4K>56aB13&0Z(qMA zcXqV78M+F^OLb&|3#y%Uv3LiO3iTri4Jr;K!E)3@wZ5lI zqsO*%DooFp`Hxbu)M7`C1q#4uK#PtDKbe@!&JnBCS(@RhFMqV)ADdpoy7PZiRjhDk zH+8KAA@66JGA~=TC$B8-|{Ym^c|%v~bA) z8O!4?Rm9CwpRA=IedKk`G974uS^sD6I>4I9x^@Vi&^tkpqUfsF3nIO#tD-0t?7gh6 z|L^DOs_P1ZU02sGMT#iMDz^RBLQ|^P78OOR^p=Dsp@fj+Kgq-xA%T#D5PtGL^W?eA z+}sRj-h1ZUnS0+;OI{a`f4LB=8B{XztGb2jgQ{3}eIO}E3p%^HW)~CD$>VC zN0cI_G*OWbccojTxt(_JM?D%i1R1WkH82q3rbDg<#V4j9J0l}*#5{h?s*{tGgZ$|> zV}{q#Wynq!2fO^dTrqLP9UvSlhkhdZOrrPk5+Y@c4*iCnTTj+gVm6+ECt0Y|%StkI z>qq1^jneF9^aaLRFn12(rjhxjcJ}riWQU(6B!I193%M2!HOGt_C!Quo3Cqe~+9+9DV=q zCyyQ?CjQ;Wr}M-gFuJ{?qo0ot)VUlGG;`K$q5Lns0pVErjIH*)&&{8|kn2g5sRjxT zSjELdFh3{Nv`}c%?^mhIqlZV7u_Q$@a3o7Dy1BKlmXxnH(he%=tQ?L&jvw=0II z$>Lfl5Op9&<)x*TJgL^?GQcB~$?)kuxBFGpQ0MKx|3ZBcy!GG@qI-_vVTQSy)d>E2 zv=;r=N2Q^DPp^%hsiz!J#Ib(X$B#W~AL@@8I~FN_%F6m-#0ZYnGTyuyH(^4LS{59l zv+|ztYOt~XL`$Jkt4O#Os+lTh0@l{l^r&OYVkZCqAOJ~3K~(+P+FGP=`&N|a!tY+n zKp6?5DedhZ?z2Q6iuC0(x%W#9S)ZL@Xw);^Ji|fscK*J94@}(oC^AlwmXYCc`mAsv zzN;#S4z++!3Wd^ba#gww@Zp2_P z$o}T$<{*Fn`uh68gH3$=zDuaZ{$`~0`fq$8tgH;N$)`_Q6DCgLrCD5c_0xp-g!p)lGR_cTIypN#Iyvj=33-k4 z0LQ?kaz#aXeqQdHbp6%|=Z4OvVOUv$^{{gp+VvL4d+}tKioXE=wym|dPE+z)p z4;wiC6Mvj$4NxWE0|S@JEWl`ChO;9S?*9D`NAKwCec<%j3mm`ef8}y|S{f9zw6#~S zU5n{SFb#}{t*NOgG&s11K=^6XMk{OUO`Esy^-oA3p)%b&zJl;TT|>iiG>4VfDalEz z)~w~YJ_4LE9#4Ne;IUu<-zr$Z{;fa%{Qlj$dw1?YuPDgN1NY2dQv)0lDl?x%&*3EL z{xm*LM^~3)lzi#J1%$_oy}X7EA1>fIj2<%vf|IDoNNCgl(#1_b2`%Npz=4Fy^rYiU zm#+*D3-wyIe8k96$W9y%cVOS%3s?L(3a!-E*1lrMi;l9i6r9HhpdD!KLuO`rditUz zUK+f~Z%M#{gvxXrIer2*2s0WQ8d_SKH8r(#b#;-4bR3bB{Rt^>o4Ldvpf#W}6tc5F z^=-nd{s;+`zX8U4Y7BH+lR}}gz9QTc=+M3dyhB1|elV0VI}A{epD(Nc1CXDe&urhq zLRf7M97w3l5A^i)2M;zWE-rfg>eaaMhuRy3Nlj3 zUJh)}!hPJl0pn!n&8#fBb=8E$2 ztBl#Ia&mIN`*78o6dW4z=$8wzt`F#Q<2}teuSpC1_(fF?t)(DM<1NRqm_R~hJ^^v9 zf6&!EzwWNCtPJ$`hY_3SqD4Fkkh6nEqeb7kg{+$~FfcgMohqN;sA{IXBeYp+$?ut< z&auKaOI6r<`!s|O36%xH;Uh%vr#bP}cEYRXK@w78)2!uP)(JYnh z=4PVbk)u8O^=h1G6Wp0nwpx7tZX}(+|bZaSy}lxKfkD`h?OWnQ&V&Q z0q@q5u)8dp`k3Umq92T#U@CST1j%g zUpYowE^j$=g;`k>#q3(CrMCROiQimuUPJqWht;=c>i#lTwX&HqE~-4Qp3J_)xL-g* zPv5LGE&5h76s!4PIsaBAdfZ*ly(cmkP1U0|-n?vjV9$-G#EMN~{SBoL~b+E)xy>0dlXNvPZ-fGb_P&@(+f ztpkbK0qk^fb%TwM_OVz)Aar?I8RDV25qei@ZFO_|Jac6=IVRn}gN9}|s>w@VccZ)H zcQtL6nsV`Ft#HB+NU%6rO^=dEbeB9qBeRA~MbXA+G3S;bJSMbK-x5fpwB!z3Y4CCW zeG3Vdc>Bv-W988G#(AlNvS(eMsWveH)^tSmk2?`m^(*>kp< z%Chh!w7ns7;%Fn8Ht%6I^nn$_Rlt`oc~X7RzGF&{_Kx|an8HugO%=^_N# z^<O)AV%mF~+l}neT zBqzzp$OuScCeY|^g`t7F;P4>WFbOM>yYzYSP-WmZatH_=pIK;gv*`692OzYyjm`DQ zzXYHDu`CuJk<&OvM?T2|JO5EtF_E%ml*$D*72%!Z)M{HPFvLunZ$Ko|{#(>M#{^>` zmOMsDsN4bHkvQ!IFG+iO#Fyx(`rtrvago`pOeyXQpCH(1-fWUmNwSSDkIEySv(pCZ z%y>}AI4G5s@fp)t>11mSgtoD@yB2X%5JKN@)q(8`nI?~xikr(J>wu-E?1NeKSLiT8 zRFaiSp3i3zd(l8bWhU53oS2$E*u+G*?Mtg`kn(b&&|Y0BYtl_pR2u_%+BUNvZj^0L z`YxNorl*9Y`NsLhWhKSMPIl9TLTFXl?jv8>{;-HvLS;IM*Q{KY`1ENnkr;uz1# zKnbBy1CYuz8g1R`6$x>1K;nd?R5No?kr;)l`roaM5C4Y3&`*V^?q*rA10y3f*Ho!< z8W(mTgf9GC;Ob}(gm!dtz8V%jpa?yHsLUcUTwoEC7=ezD^(9qxxpp^ zX6o)1&`W{P1^M}|j&`Pl3g(}%Jb{33X=#;{lU2qj>+0!g>*#cmA_GXg zaqa5Zm?wQpVg#}#rh3OkC)Z*=WXR{ziu}A>Hzx-mw2O;dU}#tugeH^81Uw#BT}^Bv zwzZKJ6&19>xH>v&>YQijiyOq6$~YX(|I$TnQzbh9V&7#eR@yr_AXkf>#IaA4#A4wm zjg~iz{?0|o%G&VSP0{=&^j>yCyShye2o7bL=-Jb!5!b`p+j&YEY-VP*dFwVE?(+D3 z3vr|}g+e)g^hjQAF7l_gw)Qkz+Yuv2a`V2`RaNQFpJ%>*9~Ke}8?y6he5@Fe7=e_O z!tfET*;&o$X(Ik*gwSBp>CSXQJ2|_uRJFlMW5$l1YHiI;Bp1AO*2j;j$;seTcJHL? z*@H=c-Mg>b^#LM=*ire^@#7yqen2tir+Y11#-5vj8}#(`=X!X+27Tba4<5XG`xbUO zI=db}c}m|K5yQ&(9q(d zqF;CYGV{k-it5@?e5CqS%bN6nrZFpGNhs?}1 zD_2~&e5FVFrM(Anp>k_$E5c(%C8ht_v4f*>CXawCv}(OiHVOM{v)p-KX;yo z@Xk~q&`6}VoNP*coxo1%;hoYyDJKC$-9XvuTs0^V+A>%Ox7+Owj~?6p)_%?bkPub!Bc^+A+Wj*E>&3SbjqwW+D41=kBK48uXVf*56GVYSR3#DdBV z4Glb3O$JST!y-2F0++d{0lIvLI6 z9zSwq?fUhC+y|o~B64zapkQlj$H#zg$M&t;ckEPDRP>lVD={ryC{I+rfm22Z5diGa zNF=5vC&$LbloS^)UdsPCxT>-;I4B5t-F@cVdC7C-j!;+E2oAgE>wTc8s3_pd6%7rI zWh+)_c9~|mGvZ=mSaF5-L0>)=hIqKonlbZ72(Rnw>hAyZNXR@!p|Am=!flXutlzNF z+1bU{#~b>&ueZ1Lv}q7{^r!_0j&FpA*VWab7&_1g4*H7EggY^!GK%qb!`s)7L?U_b z|E;>Z8hLDKY;0_6Z*M+i2)Az$iNqJrpTBzfl9h;e!=}yFeBDFy^KvuZya~G=31xMS zUU`L4d+u~wZVpNst$+4%Z?xYvOwG(fu7yKy5A?qRpRhq+oius!l&Mpdxj%v^$j?to zOe`&72KRaf1_yopxaH*RD~K1B5rB=3ojiqNSn%Tcb0sAu;0bv7B7}nr7B1qL)2VCF zXtcw=K2$0#Huecz+CTrG|GMYm#Un}gZog81Yi5-aPU6?)se0{S^@5Fte0`U?W+ z)RYw1y8Ra1C%68*y$hexw-84vvjA2*efAtu4!C?NG$eT9q$zGQW;8c90o_$qRAKCl z#bN~?KEvH$zxP2hnH(Gx5EXrQiq%ws&z&pCeXE6&2-W zWdT<%H@7s~+SxleI)Qm%(9DN-5Iy?ADIz#=>}W}2J}6Y^SNHCIfqp>c`*-icC*1mFxGzT)5L7Dl z=pn!KHyIuFH#F4CvHhsLyj*>Ky&zPkl1Lb9TT)&QTBARu#OoL62UPanzYoQj$1L=g ze{^-y)Y86w^RHuv550KvR!_g9M6rXD^U42X?>fMmI=gU4NDySn2tpAA2g*`ZhRDWQ zC+bfX0db4cS{En<5v7Uu%44uHbsiT}1Hq-PYNAHhXPFgyF+=VDNJ~N^DGt`!WzTuiPf-pw>?K8xUZf z%KL)YEg63mWWXmhR2^(7feZHvMl9?^nPR@V5Mof4_M z#YbofabFcMP334#z_)nGG9LAZdJ70DD#A=q{tAI88dtroQ+{DMWHR3ASq zX=>ijaI~1HHxBhxV3*3TU#COBM<$ci2caME2^nR+UUgTaabbsszRVD{E`1i*rSks0 zoPaMdNYsk(3wl95o5wgD`Iqft*vL}vlfWpIA>fO-eGA7~*%h@e{DP=C7`$Xg#Rq~S zCTel?RbZ6LSEK)hzphJ`^!9*{SzRU8Us{Yr5>RdMZ{Px>RNnRr67coz8)GagHOG`) zHL$S72qbVsV_pG5bc2N4`Dnw8{a$K~Ud=0=NmG_72#jyjv zUVn#=>=#gX^EzqB5HYE5(VoD8IVw{ql-oDi1t)FoCyH7Zej%=*`7L=!Xuuqmk$}%- zu^Z~U_JxVc;J~WmM?lbuen%K{)Ys?afLmvM|EWoQ8qp>qV^#FT8(W`ddgySy@?|=iz@&AP^cG8=fa6!D#)`%-OT&ILyT+t%XEo zI-S0Kn{UaxcgRB>9Ua?=6Uk&=8|cAi$KSh$P#?!B!Vs`KP)dqdM^TJGZjmbtQESmD zSS;4@V@IDPw6yjasH$pbZ$EU{Fdm0AG&DR;NPt7G{QEBq;JV+A9qIzeAm<0dpmON` zeXm}!_ZrE`%R9TeDt2u{(EtU7IdkX2sI9F%8y^1Q!-uu2S7~c&W1+x$XJ9opyftL! zBFj537Gcj39*DVhEAs50I8L*i`HqfVY@a15DG79k!KngsAuBV}*W0^azkZ>I4v~c3 z9H=u0mdfzS-B+%Fzu-bFT(pSyProzB%F4QXcz{L!`15AbYSJP6e10k96w9)*v9YnW?ZFJ3DliMFRO+#?u)5mXRm+$A`fV3}i{%a> zSStUx#vOPJu9e5Sb@Kc*|uCB_%ukw+DrUC}W}6lHjJkdE*8W-hq?ACyx<; zC0^j<6n^?N$mb%@I=hJ8AN}C#_3`|0--~Yg&!>G*34+Kc%ix>Wezu-~n8yKK9=U^=@MJ1)mii+5nm_^Pm z*r|vr@9ak4Gz4mV@r?5DzNpn{3#5<;z}VOrtvMwmBn%7<;THm)M$N~MB5#E)C@Mpk zjFgg=LA$g+ObAp4L4U+BN_{=LlXn-P{ls+%?3F2q^N8APm+|AtV+fV~9cG@RGexT& z7iQ)bNOXa2rv;h+{3!6A`z)2gUaF|7mX(%PR8-LEbQE(n!9T-s;*a#KuJ(N@Z(ypN z%pWXE{Cld3F&WL9h+GFFe`?z($}j55Zp=6s(U&hrUAl1&*auZr} z_80v80V-wS)#HYYN2>bZIW0#(m7IT|jOF&Cod%XE)MePG$)NDy~wLkuV%Z)YQUbphXf7fLFH4-ThctSYcsd)WwSq^XBn6VRcp2nNz25 zoXg|tHEYq(kzWXQF>Z~A$BExbj~+a@aqU`WM#dr+mmc5qym;XPP#J`gdU~E-TiTw; zKz7k^_D*Io+-F55@M7#|GOOvfQ6=r?9HlJr*A(&y`JOvJ&BaB9b7z1+_V$x=L&w?) z2xjBW@pwYm;X|n@DFp=uD^{)QaXXwR2?@7vvA3&9Nl6_zd<2h;RZ)T8?OVQL<;yN%gqh&_t(+UnKN%**V|Y??0D_U6=Wd^;IqxI!v+GfL@`-nr~go5E0YUm_^7R- z+Xxv{3LKZNTZ0I4E^a7HCt#SEnvOOaz47OtYinvkf`Z6o@(&9acFWBL62pZNoJNr6 z{m*g6%$WjHw%ZWKjcb*G15brV6c!Zh^xvM9m9=NrE_hOX&>(O*bViJ5pUesLeUqL2 zJSi!c)A$+ywtSP9*T|msAqCRT)arl2PMIu;avqFY*vW?HiQ-DiIBZy^FM>ppICvzC zLZSHi_>`BI9}HzTL;*H~zpH0p(0;iISPNg=%NH-wQd61CmIaw+Iz2q{9ClVh5eP3c zPD4}k_diZ$Wo52fwp4wPMsZOQ4Bm&x%E>KVx@?q@5uc}q@Gg3~K)O&8$YkkhGXycS zKmo2r@c#WEl$VvA{^MjuMg}+xh|ka&z$bQccDAv#d;ToRaqb)~b=4a&cSq`qpviG( z5NeVq1iVx1Y(Thv`wln94Qw!#LTTdkDI*byQvLh$zjC+dMa_xVb-A_8U`VdaP@OTj zZNdhFg}YJE5S2?gV5Qh!yeHO$Tfcr_$N`y|bNEzPR3NLUcy9IPK4dZ&)COu(6OF-O zz_$S3QF~X=#MCUWxODnt`)QNx%*-eJb>X6LRqhnRqcZT=-r53$*KcxL=W4>wT^6OL z)?9dvk+UBpX?~%^h}^F|j{)F3|CU@MO%&@Hj{#+ye?|nE>9cySD8>K*oV2ve7b}5* zYjHj1?$alaf0*Ym_`89(V()>YC=>;GK}b~2&B^JI$AZJ^xC%Oxxy_{0Hj;N{w=E3b zbueo_GAR@gRCWg9Fqwxg1eltQ2lG5_qWu(m8*>Yb$n*b*Rv%$dIWITI&WgPZoSvQ2 z10GL`exF=HlOf_2`{BnZlPGjtRU_lt%+GvZ8WU%Esic(BEJ47NB?$p$15zqzW6Awy zeQuJ|s_4t^eyC_*RyHzzG?eumBQHbjiB-nS$!o@7F402x0P}n^_HM$Xhfa?3!93rN zi|4bNIzJFNmGkm)Z7o}P+}(xD371Nf-Z#ZLs7_FA@z|zBzrS5bbs6y~&}QLqhUebB zqcAcTsdE=7bj}uoN%k@R?0%c&rBV$U@u&0Io9#?5lmsMIPaY&?sn+exab`_Tj&5Q-+6%}nCCn9?hhT- zrTr-=LV#4x&&xx2oR;;ryY~22VMA$p#r^{4xl+0`^K$>0^#(OGygoL^!! z&|P0q!cg(k;`EBU6?6vE*O=`kv)C)6?0bH#!#lS-ADWt(8;s<7;#)A875mu5MJ2}? ze=BF$1{Ri9V4f%2*-W&tvbMEFy50*7f}(Oke!h(byHhmqm`6+d&M;h_sMHTHL;4g_ zfmw~pr4E)O22W5-siZBxTk&A7+Bjv2-*Gr2a*J^VTmH1H=~V>{$nBslwdX}mbRPB5 zJk{1SgGo-SVw+^-MmM0I&SK(lWmLwR_=*ct$?_zgVH_U+t#~~TfO!U!d_Vr4tJ4B7 z&v)-X654htfl#@iAm4g|8Lp>11`L%Gf4@{iFS2;p+2UpiGuU@i3l?k4)t1VrrVoiI)>9x}nbG#nNPCkkO%wwv zAIYJlSJJ+y7$xQ=aj-T~eUKO?Hy2_AR@OFPo+sH_LAY;gXMZX}7^NT4r*dIIfweip z<2OCyF&F7h>a8Chwdvr34s1pU&BfnS+wL=Caqe9M-qtjONw!v(bQ=DdVqIKLV}7hI zS-TPh#dRAL*8beJgTBYPS@Zw^AOJ~3K~z$Jd5(>L7$0|cv9lAH=eUOnT3XryJtN9g z1|D0Pvx6ZHk42yNm|jJ<+Qkz+Gu9w}L zquTLYV3Olv5kYn~ze$o`39N1Hz&zVqTSC+{apL3?XTk+{E;OlJSXhYgI5iU!JO+S| zQ30DOWYw`uqqv?yXR`KAP}pzLaTb`CtoW~H17Pr;O?v8dO~cW&>`ZZtRWrddz&yu2 zcoY|VXNjvbnCJLMPf*;((i*5yxu~enYCJo+J~cBN_5FN&LR}i2v^DULNkfLhKxMYC z3bytW!93eqO@JV3^3-X^Po6^k6y2sWi^Xc6-B(;xWNF6caY_d87;_~cPyzKp{JUi? zxNmKJdkQem@ed!z#>6aha{=>wKjEo{rY4W~cgQpz;6>%q($cfx;pypVyr+aOHW_F<(=GPwrt*nl-eCVX3VVFv%9OD>G<(5va_uVkaGc5>uU@_k4%(xlq7t|_7>7_9yaf;U)l@1KW?#B| z`FHB-Uzo3R4A;@|_Vo=rd>Gsh(0Eti9#ys8QTClTXnDEK6&1}7;>n`xBM9Hz)#&Ko z4jhKB>1{!=sMO#Gr6ncaTf9I}P*ikZyOy5YkP7s7z~8R zQvLe_L-;S94_pPtMw~eV>^*wqh&T`~De)=1FnsuM@VHS>nX~LNY4T)nnn8Y^lw@LN zhRU=egu?nwFhq5BxNL$wd;2Ck?Dz>}<9=`SlAk3eA_8y&trif#Sm14Tc6Q>^C*s^z z6oYs!@^u&7CBu}|ls-UZcB&|wJfa~G5ck&2>(bKF-SsRnh19fEMBu%g++6@~fyy9= zbIVZBIJMZ&LeqbZbENz8l~IHd6waK|l${BJs4_fvZubk^8zPcZqXjM#&}ABTHgRrP zmYkey%USP01uz>Tj5jw&Yfe#u$q?bmv$HapOy;!dy?gT&FyR)bx#+7`ucl0$iq^DT zrip{svTpr`(Ea;rYih1vz54wO6bh8&<>o$p{1^ndAPOjVM9AoGH;JgJB_^Wy_3*(1 z<`x$1GXg3qDypg~PaZ$MC%6|FY+wTL;Z1fna09Kt3>XW%1pzqBUcne`WHfL7|1SP> z;aO5rZEfuWCntVpPk!|Z3HSyK7~t*W%fGre#)gJ}qb?=BNN)dYW@lxA0PF=0x7;F`F>BUHUEP2k{_xt) z?c3orhNDJxcWR_iDf}34oE}6=mSVcHWw%fheyTjc4}>9!$#{8T-1phxw@p$?ad$T3h$ydz{WYdxcYi;Eh{TK7#a#Lu8FBB z*uF2;8!s;}zj5_yK|ulXaN?xNi(EdXaI{S)a&mTt@vgWyWN#20bM$aa=N~wqlCtsu zd3hp<#9%P$>gqm}mp6SLib_dI-n?-g0#*NjU-|vG7y~y)nVRrW!jP}aVi)1+wnPYL z5f#Ad-MDs@LaCoJ?RzS<;mPC2PdLF9j?=A2nM{_Eks%NWbQ-Pt>FKf_P^Y~2FJ@p*C@*Snz8>95n$9z1-I{PJa+ z60b6{vQ}1BCZ=YCG&FeJ8~Q@(JsgSTCCzvIp(|Q~X1PTrzTR6v*WjQ%5UjK>pWIu) zXr>nxHf3c>nVRE8-3_Uif<~j6j2ZQ@y4q#2+s<8qtzQCbILgR~p8~`JDINe?uHU$M z+-QU0S{l0o_d2z5XnHSLbb9_|8xUk?Ij97OidvoChscNs?=73b7{5qKSLj-w^KL;< zC0#&QFwZ_)Jwf~6y@5}jz3lDgS*)L=qPs_B*rD3!C?!vC0=bVYDF^{zjLpUwRaI6x zySfJK4ieB=1Y0u>^j^Qo(|EKYnCCsg`+iu+*NU~sq43kj{*$JXh79{w&!y`)e=gE% z(+0L@oRX#}$kJp2ujC2ZgL&TSxd}ecp54FpZu3kaNa!0PBD1az;| zs;Vl%V1d~Z+3$)ptquUL&HvZUHiVG_Obibl3z$8Jr#U{nK`$tbwd!Y0Pp|JhZi7n~ zqy7EXf-xpOdfMeWF}4sjl>u;tV4nTg`N1_G+`A`@NRmYJ+&d(qxkjh6llDpAYaQ4E zjIo_Hp`xN<_T2f0jvfS6mYd0H*JPt0hs5bfk887%@$Wr_y&yp-V%mDMQNnD z!G&0HcSoFvxqNAzua8)aF&AQ^GQvq32j+Q$pD##Z-|n61M3Q8^gDI`1W^gv@{nGgj zj~~^>T~qyrvYzn{dQ+1v#~9C=GxzYZKr!}2oK!{u*S~SoZ=(n!O-&4s1qDl1a3duf zTQ%38q*YYqO$Ug(FJi#em@9rh>@44zq{qGV_)i{(3B*rjgp&ljptx+E?`n_>nCG<2 zY;Hs^{6jAwMBH5v1L$8<>%+MK0r=R4n`I73JMGcqpq&5tgI|H_9_(gzhKK(tn%iDu@f0o z#<|G%(WjLZm$)zN{~}*fW;3#g#PHA%u&>;2z#Q~YS65L{k&%(1QK@7y`O(9NP`C&5 zH#JSVbLZ{bH`8X!3Mj!}4jwY3^HV;4{Fs!O z`1Hw>&HdTefc(rI*s@WMsi4XQ(u!rz+Wv5!vtZ0pRYg|7|ZUY~Fr7e8dQ+ zapTmxN;Cf7^XCb-Z@rkG%@ib#bxo5rNZoQ3*`ElO2pp$v!_od-DPJ~QB_l0;^wBK!|ReV zSQFHsB*e!*NJ|R~2{{oKcH~%qI&QXZLgVoqrw$7(EFwXF9Let{cd#$c z5zeS?o?uZpxBzY0j~SDil2TAm@aFYvVMkm06!lN}w$0p+xx-qf zne`4FQJW#=wanMAUx6H;Vn22)RzY?^QwR3$1m z%V6%@*4#Zkqb^?J<&@in4LucQtaQ8mo(tE(C|S`qeuc-80AF!C7`JZ5U5JW8I5I(F z`Cx+gpC!!IpcsJ*D$C0&I668dCnsU+*CyP)jaD2Sop?NjOl3~G*1X&`{|B|>4q81G zcnWH*Xim`C+#DdUKIL9r>V2rFxlUFbY0iCzN{n!Haz?3~5Fd{fl|fVQIR3YzvomNA zlQsnbE~pGx>fu2oX4co&N1Z#j%*(5fzP^ABMxHrSQBeVv4Zmz`gJ9?7X=1hs0^NEP)O*nzxY>HR78Y_TUuNH$Zt5| z%F4=cPcJXt*GJmm=8YTKSy>1tJ|LQ%2@k*vl@Sh`4<0&< zE|g>wiBLvbSOB4UUw;NAUA}awzOD}HMn*>4ckcQ+=SBTWlTKQ=l2b zaMsaP>Yj0Bl$Ym?VQ&S|-LgY{DPE$#f#>$u=`%aFZ7nP;3<(MXgF18eY~JG>)9Lh^ zadD47Z^>A**3W`K5L#!u4IEJ!1%Y6B>TKlmXU~ot`U9kf3QkW?&zwL2O=x_%ObWs+ zeE05IP7W0AwwPhVhp%0?p1(;w)ZpqU%SKJmbvEcCuw*BY>D5c#(3n>Au4*risElyJ zSnk-phrwV396gfr^eH$S2xl7>*lZ|9#>Q<72ZcfbpZF1pR905TZDGCtFWkhB_yO*y zi~=MD_5&)pZ{D0b`4@O*x8mZUbaXt(clykklU#pP5NwTYMn7ei4>oDCv^V`;vU<66 z4|RH3sjMDec0!_n`yA*96>!7;y>$~!=Ln^fQ(*Ms;km4hw}va=l*(Ly?Dp(q$H{AK zY&7d{0y@ZgoTI9$3fzS{o^yVwxJ<(T1|zuhr%j&$h5HSQ#R8knWHM`OYpq5OgZj(2 z1zkoy#slz9WiE)B8SvNE-oBH#*#d&fKTflL~0z<+s&guE96)&cb~K+YiTlzaEGh?!%?I*7YpT|+YD3kVNkZ}eWVYPIlw zLO}+}p4%t2l6o9ifK&(rU6B&cLH3U~~a#+)aL<~SN5@d%JM zP&q94_;)H}25MttY6^SN!OD7+uz$-hr5gSovTr|X>LFWAC_FZ$II?-e1Lbsto&-`E zl{QEoH9tx+9~iR>d$ZoaDz7{hiI-qp}`m1UG<+WH2K4A!EA z%92`ou%mVjjrF*SHbPs@S--93V)E+uKcsk=sjVE!bJRmQIsCiJodBc_G6%yaxkxdvCYWpfVBpkb))#(|fr3@v$xD)+?#%Vs4$2fl`bs zI|>Pq*x^bs3@8uUeqoXq#8;Nq(-Wrlp3zTv*!kjsC!Z2$==D+Nb+V6DUq`Pfm+7f3 z-J@;dJ^Vw0d<+Soa*KCiWzEa+ljF+c^6M54REuCG0Ky z!?oqPJ0*(i7>_Hd#%glM9kk0Em^K%Sa~2p>H?nh9Z?tH6&G<@QJvbPHHDxClDn{ql zZObITSY*(8jsi^b(<+*|j>7c5%B_E~j?Pk)k^0I5Z-MUa15J6ka>gbIizRVXMmUlO zDuWijQ&}Lua}9hos95thcX4W*b}wa_sMoa(3>KY-i=qzw2 z!kwCvU(lEcgUNces5x&T(DdOv_C8WLY?_HOl-7s6SkyMXVQhZ=)9NowGTaXoFJrX+ z`~wXR7~7{qHNQ18VKSNW#wNxI_j$Yu`~W0xYj2;Pnu>ED1MgHuy^H0myt{j%(wF8D z#(YS7yE8jFj6!1$JzuOOBlYi8JvhcMr5c8MDEqkp$NIUu14qePyfy(?ffHb^N-UP_*o-abI(6Ja6Wsmv!@yo*sbBK~P`HWmy}iGEW% zBd*+Qh#GhfZSI4!uWD0E8|`|tEpc!TJ43yNwtTxh2B`fs1*i-a>dP10brT5!D*t;) zNqF`#a82cG&fEn&-Ndq;y2jcDvKR|s9(8zZxcN_35gC`my4(~!3pqG_= zx)uW!=BH1XFZ;dCeRDB7%75dg-#2e^a(15dBcJb*bprhR82F_!>Rs5_+DXJ_*)E|p z+73C&j>SQH`v%)xa*rQ9nm*Yzuc$;yO3K}Hnc1L07&guYXaRJQk)B4%&a$<`W41#4 zQaK`w9olEr>TkijKsdYPgtTkfeaXV#wr)e;VjMJhFy`%Z0lEMxp9l^4PUUWZMx~;$ zQ%Bj17I$B;1Il9t9g)F6?CEK#cjDtqii;^^a>j%7veGhndAUu$Zxy`dj)3X{^a9$E z$DfaZQz~a?v)@hsX1og&<-e@^6nhye1D?M{1kQy8rV+~iJ-bW?{BZKj-&l083vhjm zY+U*nIHfW?#gK2vyFj5b-UX#Hy|h@?$VBi4nM`JA@Nv=b7{w~@)wuOB@JQtr@8X-7 zyWm1`_z3xa{S`-;Gn?pLAI$^Mk+J<)(XGI>_!u;rynMGK>j@Qjq%w(=4S#KHY_SbH zDR#*A);In)3Bv{t9oRp6?))~CVzF4ypXF3nRlR)qV%&Haa6d5oMbHT7B_ku9l$|x& z)(*p#1qU9fd?JkFUHE)c-UW($>k)JcSz1}S|KpbeHudr2M`C8i(ZHZK-`~D<6P;If zaB{wT=T6-9Yirm03;0{D0eS%{gO0vaxeLIP3lxBSV{;dup*nFACHg$GzMe&+NeT9V z{`>41k7YmW8?@cThw_+0CO=3|bD1#FdHi@me&uVRdI25b&BwqUl}YH_#W&|&pis0P zjYOY^3ZuFb{EhCO4#II;wBSy1inNRj`9t;gox9r{0N#b?(!~!+Bsn=bDverKTYLWE zWo(TC=*4=J4LlI==40TF%BXj-aH`V`*eb()w5T*Xno7}9bX?HB_(w# z@*lq2=MmmMYkKd~8ZG8ht0jixlcj9s7 zV~CT=OeV9kqN1p%=zU=!3}P58W>I0`4+G7#w6x^}UO~VqSgd>}HV@P$xatLkiMuy^ z0<<&Q*1o#BYTusShDJs*Qqt<08U_Z203BW3uLA*#2BM}i`NN0fL4Ur@&F$y_eFH=I z>*eY3`J=%a-?hE;^hDG@VFUE6s>-abZ6IcdyDQy8d0AOtz_F6zV)P?;%%G`){Cp_w z9^c>8bhXbKQKpR&5tU&$5*`+sk)Doz?5U;Y;OIDb$dHbrAj9#mUcS7SoLv0={icoV z@To(G4O_RtUtD)QhA=oAg)kV>YLXG&1)iKo4;2Xu?A-^p%U7%vLCjTAQ2EN`OV?v#5zd2Y_T0I=WX*vqHybnv-LD8RF_m6Vj`FI>n=%2cpT!-fxsf^hQgT)J=p z>=%?N)27XwCEPSw!lg18*Y#_C(R{QMU0p}n@UsvN68vS;rsvO|UA}lRCFOor7BMI! z6vIrFB1Y}a>!p6|`I)}S4`llYnmtHJ0ORVjY9*Q%bk>|X{KdEjo3(k%mduQd+qZ6k zEla(B|M0N@;hAUQQh9^lT9n5>FJCTT(kGCnzP^4?U?9lXd&Tn56A^fh6W$4Ad-p*r zjOr?UQW*>oNSH>Wfjj5p>#L#Jjc80?1MC+J2P4A6$z(F{;YdIrR{d-PAyPRtB?Wp9 zm7k_e5j=Sr0AvdO$%UvWkn*+ItF2?TOAutWnnQEY%gYpojSz2V+C}Wu7#b%mG)P-O z9-{#5|2TQ_%^Np>55NlhF+zDeP>59iC-N-9@sA0XmRPk3-m|)f#zzX}>Xj>!N@XKs zoWFe?8^eAFQA0xm!*{DJt*jDm-)?GZ0#-;EmEj?UdRlFAItdOC9k<-r% zdiBvm%$iS%mezu-{0Rw7pEJv2Vvkz`m{3_+39JBa2*WuP7L}o|&~tE;P-OeTht zXdn)RGe0YlJVw}}`4G+yilA2W35Qe$se)|Tt5+O3V+Cjsn1FByEu=w?5FLyqZti~u z9D{2}Pff*Yd-$V=59?}cp|WuCVoVwo1EibhUg+c=RGxPSXTQF8YI6DFEB_&Rs zHVw}qCA&o7Pvfa?UPA@9QyFQgDVL(pn++P$OHc1!a`OFq_a?f!T94{pdM>W@K}3=e zTNDe|XxeJHursGlf?S}$*uvbx!phoOOIy3$Q{d?aw{kX-NTpKIZ)VJ#HFY|BkQ5ej zeDVCb2q$6GU#BDSv&oQmNXg?ahy)56jke5v2^u|h^Omh>9;2%Kb?e}SksdBU}!qCr1`fXHMr z@Up(X9$~SRl$Eu5YH9Y=l<&%JfvnU1-`BqV_-B*X+lSd^--Pc2xArCNo$ zyq3)n6&1x&6cGyuJjE6)K37!wZ0laYR;sqPT2{3zB5p-RS)}atDJrdy5D1zCAtYpZ zCk)2OzC?|I|GQtlo8iu#A@k2a=bkzD+`L;*i9U32nTH}y1?-k1M}K@RJalF!;$QVC zv;%(sRX*NGn#s>MM63x8>8>UGu*l#U~@SoHYO8_K)q61`R0urkN}Wj zI^DFOsFZ51Yx8OV01E<1L_t(!)cZav0IdNtTBG8~HETlDfB{$HMnNG|4({8#bdf^x z=Y06#;Uh;iQ>0}AK73+cg_RF7{OKwmWY*dG&%=Y)u6z0C@PeQvR8|764V1dNIyVNp&R^GD;ynD-#klPUN`<3~o^Xo%=)eTCWPgk^8) zLjyy+8iGk=d_Eehqe$t3dx17aL4F?CT0mvRja^tw(>fXM04=970(h9_{ZRsyJzwqa zL8K$6k`I?R);D*Nn~>ckT|U78r;eB?xlnk|&KfF|fS^(9!qm{?^8oG!e(HDrTn5xb z)`o_DuKq)4CWZu+m4NFCrM8yMaB@UMIzIWd?UZNX)McLLw79Acdu^Rc-eRY=h)0<~ zfK+gAj8j*i2nuf%z>Nx2rc#Y=7W`pCr>nPr4ad-;G6EA5dO@*b3h_6)zjS9R!a`i; zG7d$@>R_?P1k6b%nr9{lX_>*K-{rN2WOKLXKK8dFM$e)S-hxIG^k`9E$#^`%RQ2S) zl1d~&f&Lk3sZb9L4hakYLSqA!UMRGX$}+gRGE`rTf%Rb$5DD6#WsLhxi_VZC@-0xPym@Q#sg&LUI29#&`X4HzPcxNymUcUMJm zQPJWBOtDxzibBcByQP*{XRj}`hsx|`X}}fkUB0BEL9}DqsEzM-;p$p^uCBIOn&d(Q z^;K?!2Qi4WTrU4_)UNq%uBbMVj*N~~-O<(vFAlWii{&<_stGX<4Dgr|PjgFyf&6-$ z^&x`aPD5qDtL#Xn(tig9q@F#CQY6<44*w$JHJ!1mUT6=M=_7PvXHjiV)mT$?!>4rZ zvJJ2zHnz%Cd8`DmVMD}5D6Etg3cLfhcdK>$^fsdI!?1Ba553wjY!Qg z?|qRTcuW_Tl!Hh|?TDN=*BQ1jn9Ti$Vw90F7&I!u*%*Z~{IXYy?b+k zE5H~i)ej#kM0&KDo}OOfncu9etd(unSob?w7Fu7wUvU>@Wu=SexwW*k7?R0XZ{}H8 z^qwDR$U@_&?0LREp|WY8!>CjS;?gJXFA=QG<~o=XRC)ZyPY*>B`K9^v3FP)Diz}>_ zd`=6{ODV}P{&PrXPp06nx+~mLj5JQ#gQkRgO?{!V66O{bMP;`^q<2MbXE-TlVJ%p= z@aw$?x(i=yYHG?nmywZ{CXsZzc8(4Pc$*7a%7hcK!!hC7m|{sSWar?s@0pe zZX1^2UZGi3elLLqbX@-qIq0e2N#&^Hw;RcN*b|QJ(Q^_x>b>}yDt>GBLNg_gIYMc1 zy$Gyi)zKbU#Mj;1eXHCSSy8>nilRF(4>2%l~5($UHwYIhj_#jWtwINyPKc|{2F4osPk$n87!608e1Gf;7-o9lM zBGOK-bHySt@>fes%X#kZBoe9fjxdM>)&gaf^Md$%{+Z0b~_Q`7Bm9gI+d42PgzCvggl>wXIHQcOX?}GYf zGP?-r+B0Jm6y;X}7M;a>ZbrkAipDwS1W@`10x3xK;_><$Y@a>%zn@J7sSdott>m|Y zJU?1Brh{*!_w)SEMr2?&NFF1A9#;GN$3{m(pV0Hps4oZE;ShwzQF-uq(kgfPt+x7! zgw-qs6$aaSrm0@M^K)#Iqfk^m46^ZTm5}zsU&$^s*D-xvUJV9$$WjJ&Q>PA|#|VsR zH0UiqHy3(_{*?p4Ve}DNNM(H-8u7jXUqNaA)9DSiP%58zqFM)ouKdIt8jRA#h$OPu zGC|*|eDB^pq%v-tI-}d5xBRwQ=+J)$DyJkRmX?&bG8j7}w^7KHBgcR2y!#hnpPflb zF1dY28N3R^)9H3o*lgBvAKz^|cB=7IH4s`zWhJ_^7zjFOu(q>VqDenjw@BqHCK||s z#`ep+z&@S#--Gjb08sXZRmm#=8@-lzoJvYw(6#`Ay}iT1{rkQ>c%Z}V=t~zaoc#HO znVFet5H|9nCpggmr{hP5sjRj5z*P74#{-OE_~(T7#KRTk<&)leOI@c_URH)wR1+IB zT^!TSUqtGB9uIg774H>39rj)Ay8=EB#~tmk-EH3dJOBH$u1=k4IW-eQm&$_ynM`(Y z_~7c*Y@o8b*bM#Lu29VRgPsiypE(WFvo0y?Gwl^2&ZiQS4Gaua_q}jF6T}-N*~+?$ zHG6nG-rCUhgFizJ$1s%#h?RbR_aEG^sjg0pj|UU>T|2wM^j46cpPs6Sm@_js?`{dK zV?V_49zV8s_@HB!54n7`uR^3dOEN$t5^=fQp)iOXrt-kCV^`FV$BtdTbP-s1{n|Aj zUtc1z-vLGff#7Id9FoU>_MCrtuUOGt%dML>!e?YBKV3ydIg*UMOGyU9BktHw{XMJK z5yMm-6o7e4mo1A34{vDT?)&B&7;?>=J^TIX(|gVG59GU%lk@xK%g9iVLZL?O-rYk2 z8tKy!Am;KU3MShkAU9F0@`^#O2Vh;C^GC`X#B>u@43OpYF_1?X5xjZQ$J}ou% zVpbLuRGas}#KZ)i>>$-x98S{O3Ifb#v1)5;kp#O4<}w%y7kl*jvRVg={r&pQnKP!X z^#0^zViM9G?guYVkAu;%ckkSRqkDa_{GF!(9^Cr+hz((fkNhxnUV{%)Sv>&8Eb>?a z1=Z$f$jP~W{@gis8#=T!G&FQ{cAh?c2C1J54vn$2tg5Mnicl!z^Le1Ppyj{(nh0C= wABu(ocgUlL263yHN}*DXjK1s2bk<`0A1xkoyV((&$N&HU07*qoM6N<$f>vI|5&!@I diff --git a/ext/OGDF/doc/images/insertEdgePathEmbedded.svg b/ext/OGDF/doc/images/insertEdgePathEmbedded.svg deleted file mode 100644 index 8b57a92da..000000000 --- a/ext/OGDF/doc/images/insertEdgePathEmbedded.svg +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ext/OGDF/doc/ogdf-doxygen.cfg b/ext/OGDF/doc/ogdf-doxygen.cfg deleted file mode 100644 index 7fb917dd5..000000000 --- a/ext/OGDF/doc/ogdf-doxygen.cfg +++ /dev/null @@ -1,1801 +0,0 @@ -# Doxyfile 1.8.1.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = ogdf - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = . - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class " \ - "The $name widget " \ - "The $name file " \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = .. - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = .. - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. - -MARKDOWN_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = YES - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = YES - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = YES - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = YES - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = NO - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = NO - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = NO - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= NO - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = NO - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = ../ogdf - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.inc - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = ./images - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C, C++ and Fortran comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 2 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = ./govisual-header.html - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = ./govisual-footer.html - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# style sheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = ./govisual.css - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 90 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 69 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. - -HTML_DYNAMIC_SECTIONS = YES - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = YES - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = YES - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 14 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = YES - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. - -MATHJAX_RELPATH = http://www.mathjax.org/mathjax - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = YES - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = YES - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = USE_ABACUS \ - USE_COIN \ - OGDF_SYSTEM_WINDOWS \ - OGDF_EXPORT= - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. For each -# tag file the location of the external documentation should be added. The -# format of a tag file without this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths -# or URLs. Note that each tag file must have a unique name (where the name does -# NOT include the path). If a tag file is not located in the directory in which -# doxygen is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = FreeSans.ttf - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If the UML_LOOK tag is enabled, the fields and methods are shown inside -# the class node. If there are many fields or methods and many nodes the -# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS -# threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be -# exceeded by 50% before the limit is enforced. - -UML_LIMIT_NUM_FIELDS = 10 - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 1000 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/ext/OGDF/makeMakefile.config b/ext/OGDF/makeMakefile.config deleted file mode 100644 index 74bffdf29..000000000 --- a/ext/OGDF/makeMakefile.config +++ /dev/null @@ -1,76 +0,0 @@ -[GENERAL] -#********************************************************** -#* build OGDF as a static library (false) or shared library (true) -sharedLib = false - -#* name of the static (import) library -libName = libOGDF.a -#* name of the shared library (.dll for Windows, .so for Linux) -sharedlibName = libOGDF.so - -compilerCommand = g++ -compilerParams = -I. - -#* command used to create a static library -libCommand = ar -#* command used to create a shared library -sharedlibCommand = g++ - -#* blank means don't call ranlib -ranlibCommand = ranlib - -#* gccMessageLength: if not defined -> no param -#* set to 0 for use in IDEs (0 = no line breaks) -gccMessageLength = 0 - -rmCommand = rm -rf -mkdirCommand = mkdir -p - -#* the option below does not work in public releases, -#* as the solver is non-GPL. Please use COIN instead! -useOwnLpSolver = false -includeLegacyCode = false - - -[VERSIONS] -#********************************************************** -#* for each entry , makeMakefile will generate a -#* and clean Make-target -debug = -g3 -O0 -DOGDF_DEBUG -release = -O2 - - -[COIN] -#********************************************************** -#* set to "true" to use COIN -useCoin = false -coinIncl = /somewhere/COIN/include - -#* Select your solver for COIN -#* CPLEX: -# solver_name = COIN_OSI_CPX -# solver_incl = /somewhere/ILOG/cplex90/include/ilcplex -#* Coin's CLP: -# solver_name = COIN_OSI_CLP -# solver_incl = -#* Coin's Symphony -# solver_name = COIN_OSI_SYM -# solver_incl = /home/plug/COIN/SYMPHONY/include - -#* For compilation of a executable program, you have to link against the corresponding libraries. -#* Use parameters like: -#* for COIN itself: "-L/somewhere/COIN/lib -lCoinUtils -lOsi" -#* for CPLEX: "-L/somewhere/CPLEX/bin/i86_linux2_glibc2.3_gcc3.2 -lcplex90 -lOsiCpx" -#* for CLP: "-L/home/plug/COIN/lib -lOsiClp -lClp" -#* for Symphony: "-L/comewhere/COIN/SYMPHONY/lib -lsym -lOsiSym" -#* -#* ATTENTION: When compiling your executable, you have to set the compiler-flags just as -#* you did for OGDF - - -[ABACUS] -#********************************************************** -useAbacus = false -# abacusDef = -DABACUS_COMPILER_GCC -# abacusIncl = /somewhere/abacus/include -# abacusLib = -L/somewhere/abacus/lib/linux-gcc33 -labacus-cplex80 diff --git a/ext/OGDF/makeMakefile.py b/ext/OGDF/makeMakefile.py deleted file mode 100644 index 3e764e447..000000000 --- a/ext/OGDF/makeMakefile.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env python -# Make Makefile -# -# Jul 28, 2005 -# Markus Chimani, markus.chimani@cs.uni-dortmund.de -######################################################### - -import os, sys, fnmatch, ConfigParser, posixpath - -class versionclass: - def call(self): - return '$(' + self.var + ')' - def library(self): - return self.call() + '/' + libName - def sharedlibrary(self): - return self.call() + '/' + sharedlibName - def objects(self): - return '$(' +self.var + '_OBJS)' - def path(self): - return '_' + self.var - -def bailout(msg): - print msg - print 'Please use the original makeMakefile.config as a template' - sys.exit() - -def loadConfig(sect, key, noError = False ): - if config.has_option(sect, key): - v = config.get(sect, key) - print ' [', sect, ']', key, '=', v - return v - else: - if noError: - return None - else: - bailout('Option "' + key + '" in section "' + sect + '" is missing') - -######################################################### -# LOAD CONFIGURATION - -config = ConfigParser.ConfigParser() -print 'Loading makeMakefile.config...' - -try: - config.readfp( open('makeMakefile.config') ) -except IOError: - bailout('makeMakefile.config not found') - -if not config.has_section('GENERAL'): - bailout('Section "GENERAL" is missing') -if not config.has_section('VERSIONS'): - bailout('Section "VERSIONS" is missing') -if not config.has_section('COIN'): - bailout('Section "COIN" is missing') -if not config.has_section('ABACUS'): - bailout('Section "ABACUS" is missing') - -sharedLib = loadConfig('GENERAL', 'sharedLib').startswith('t') -libName = loadConfig('GENERAL', 'libName') -sharedlibName = loadConfig('GENERAL', 'sharedlibName') -compilerCommand = loadConfig('GENERAL', 'compilerCommand') -compilerParams = loadConfig('GENERAL', 'compilerParams') -libCommand = loadConfig('GENERAL', 'libCommand') -sharedlibCommand = loadConfig('GENERAL', 'sharedlibCommand') -rmCommand = loadConfig('GENERAL', 'rmCommand') -mkdirCommand = loadConfig('GENERAL', 'mkdirCommand') -includeLegacyCode = loadConfig('GENERAL', 'includeLegacyCode').startswith('t') -useOwnLpSolver = loadConfig('GENERAL', 'useOwnLpSolver').startswith('t') - -ranlibCommand = loadConfig('GENERAL', 'ranlibCommand', True) -if ranlibCommand == None: - ranlibCommand = '' - -gccMessageLength = loadConfig('GENERAL', 'gccMessageLength', True) -if gccMessageLength == None: - gccMessageLength = '' -else: - gccMessageLength = '-fmessage-length=' + gccMessageLength - -compiler = ' '.join( [ compilerCommand, gccMessageLength, compilerParams ] ) - -libs = '' - -if sharedLib: - compiler = ' '.join( [compiler, '-DOGDF_DLL -DOGDF_INSTALL' ] ) - if sys.platform == 'win32' or sys.platform == 'cygwin': - libs = ' '.join( [libs, '-lpsapi'] ) - else: - compiler = ' '.join( [compiler, '-fPIC'] ) - -if useOwnLpSolver: - compiler = ' '.join( [compiler, '-DOGDF_OWN_LPSOLVER' ] ) - -useCoin = loadConfig('COIN', 'useCoin').startswith('t') -if useCoin: - coinIncl = loadConfig('COIN', 'coinIncl') - # coinLib = loadConfig('COIN', 'coinLib') - solver_name = loadConfig('COIN', 'solver_name') - solver_incl = loadConfig('COIN', 'solver_incl') - # solver_lib = loadConfig('COIN', 'solver_lib') - si2 = ' ' - if solver_incl.strip() != '': - si2 = '-I'+solver_incl - compiler = ' '.join( [ compiler, '-I'+coinIncl, si2, '-D'+solver_name, '-DUSE_COIN', ' ' ] ) - -useAbacus = loadConfig('ABACUS', 'useAbacus').startswith('t') -if useAbacus: - abacusDef = loadConfig('ABACUS', 'abacusDef') - abacusIncl = loadConfig('ABACUS', 'abacusIncl') - # abacusLib = loadConfig('ABACUS', 'abacusLib') - compiler = ' '.join( [ compiler, abacusDef, '-I'+abacusIncl, '-DUSE_ABACUS', ' ' ] ) - -versions = [] -V = config.items('VERSIONS') -if len(V) == 0: - bailout('Versions missing') -else: - for ve in V: - v = versionclass() - v.var, v.params = ve - print ' [ VERSIONS ] Name:', v.var, ', Cmd:',v.params - versions.append(v) - -print 'Resulting compiler call:', compiler - -print 'Finished loading makeMakefile.config' - -######################################################### -# ANALYZE & GENERATE - -print 'Analyzing sources & generating Makefile...' - -makefile = open('Makefile','w') - -# add header -header = open('Makefile.header') -headercontent = header.read() -header.close() -makefile.write(headercontent) - -# define release & debug - -for v in versions: - makefile.write(v.var + ' = ' + v.path() + '\n') -makefile.write('\n'); - -# just the def. nothing happens yet -def Walk( curdir ): - - objs = [] - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - fullname = posixpath.normpath(posixpath.join(curdir, name)) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - objs = objs + Walk( fullname ) - else: - for pat in [ '*.c', '*.cpp' ]: - if fnmatch.fnmatch(name, pat): - objfullname = fullname[:-len(pat)+2] + 'o' - objs.append(objfullname) - - callForDeps = callForDepsBase + fullname + ' > targetAndDepend' - os.system( callForDeps ) - t = open('targetAndDepend') - targetAndDepend = t.read() - t.close() - - for v in versions: - # print target&depend: add full path spec, incl. version & ignore extra line - path = v.call() + '/' +fullname[:-len(name)] - makefile.write(path + targetAndDepend[:-1] + '\n') - - # ensure folder - makefile.write('\t' + mkdirCommand + ' ' + v.call() + '/' + fullname[:-len(name)-1] + '\n') - # what to do: call the compiler - makefile.write('\t' + compiler + ' ' + v.params + ' -o ' + v.call() + '/' + objfullname + ' -c ' + fullname + '\n\n') - - # pattern found: don't try other suffix - break - return objs - -callForDepsBase = compiler + ' -MM '; -if useCoin: - callForDepsBase += '-DUSE_COIN -D' + solver_name + ' ' -if useAbacus: - callForDepsBase += '-DUSE_ABACUS -DABACUS_COMPILER_GCC ' - -# Call recursive function -objs = Walk( '.' ) -# Clean up -os.system(rmCommand + ' targetAndDepend') - -# List all Objs for use in lib-generation and clear -for v in versions: - makefile.write(v.objects()[2:-1] + ' = \\\n') - for o in objs: - makefile.write(v.call() + '/' + o + ' \\\n') - makefile.write('\n') - -# generate alls and cleans etc... - -for v in versions: - - if sharedLib: - makefile.write(v.var + ': ' + v.sharedlibrary() + '\n\n') - makefile.write(v.sharedlibrary() + ': ' + v.objects() + '\n') - makefile.write('\t' + sharedlibCommand + ' -shared -o ' + v.sharedlibrary() + ' ' + v.objects() + ' ' + libs + ' $(LIBS)\n') - - else: - makefile.write(v.var + ': ' + v.library() + '\n\n') - makefile.write(v.library() + ': ' + v.objects() + '\n') - makefile.write('\t' + libCommand + ' -r ' + v.library() + ' ' + v.objects() + ' $(LIBS)\n') - if ranlibCommand != '': - makefile.write('\t' + ranlibCommand + ' ' + v.library() + '\n') - - makefile.write('\n') - makefile.write('clean' + v.var + ':\n') -# makefile.write('\t' + rmCommand + ' ' + v.objects() + ' ' + v.library() + '\n\n') - makefile.write('\t' + rmCommand + ' ' + v.path() + '\n\n') - -makefile.close() - -print 'Makefile generated' - - diff --git a/ext/OGDF/makeMakefile.sh b/ext/OGDF/makeMakefile.sh deleted file mode 100644 index bf0cf9c61..000000000 --- a/ext/OGDF/makeMakefile.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -python makeMakefile.py diff --git a/ext/OGDF/makeVCProj.config b/ext/OGDF/makeVCProj.config deleted file mode 100644 index 3919e6066..000000000 --- a/ext/OGDF/makeVCProj.config +++ /dev/null @@ -1,25 +0,0 @@ -[GENERAL] -#* File name of project template file -templateFile = config/ogdf.vcproj.vs2008.template -#* File name of created project file -projectFile = ogdf.vcproj -#* the option below does not work in public releases, -#* as the solver is non-GPL. Please use COIN instead! -useOwnLpSolver = false - -[COIN] -#* set to "true" to use COIN -useCoin = false -coinIncl = C:/somewhere/COIN/include -coinLib = C:/somewhere/COIN/lib - -#* Select your solver for COIN -#* CPLEX: -# solver_name = COIN_OSI_CPX -# solver_incl = C:/somewhere/ILOG/cplex90/include/ilcplex -#* Coin's CLP: -# solver_name = COIN_OSI_CLP -# solver_incl = -#* Coin's Symphony -# solver_name = COIN_OSI_SYM -# solver_incl = C:/home/plug/COIN/SYMPHONY/include diff --git a/ext/OGDF/makeVCProj.py b/ext/OGDF/makeVCProj.py deleted file mode 100644 index b85fa00c7..000000000 --- a/ext/OGDF/makeVCProj.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python -# Make VCProj -# -# March 2006 -# Markus Chimani, markus.chimani@cs.uni-dortmund.de -######################################################### - -######################################################### -# edit July 2009: -# -# argument config= sets template file -# Sebastian Stein, sebastian.stein@tu-dortmund.de -######################################################### - -import os, sys, fnmatch, ConfigParser - -class stuff: - def __init__(self, ttag, tpath, tpats): - self.tag, self.path, self.pats = ttag, tpath, tpats - -def bailout(msg): - print msg - print 'Please use the original makeVCProj.config as a template' - sys.exit() - -def loadConfig(sect, key, noError = False ): - if config.has_option(sect, key): - v = config.get(sect, key) - print ' [', sect, ']', key, '=', v - return v - else: - if noError: - return None - else: - bailout('Option "' + key + '" in section "' + sect + '" is missing') - -######################################################### -# LOAD CONFIGURATION - -config = ConfigParser.ConfigParser() - -makecfg = 'makeVCProj.config' -for x in sys.argv[1:]: - if x[:7] == "config=": - makecfg = x[7:] - -print 'Loading ' + makecfg + '...' - -try: - config.readfp( open(makecfg)) -except IOError: - bailout(makecfg + ' not found') - -if not config.has_section('GENERAL'): - bailout('Section "GENERAL" is missing') -if not config.has_section('COIN'): - bailout('Section "COIN" is missing') - -######################################################### -# CONFIGS - -# Filenames -filename_vcproj = loadConfig('GENERAL', 'projectFile') -filename_template = loadConfig('GENERAL', 'templateFile') -addIncludes = '' -addDefines = '' -addLibs = '' -addLibPathsDebugWin32 = '' -addLibPathsReleaseWin32 = '' -addLibPathsDebugX64 = '' -addLibPathsReleaseX64 = '' - -useOwnLpSolver = loadConfig('GENERAL', 'useOwnLpSolver', 'false').startswith('t') -if useOwnLpSolver: - addDefines += 'OGDF_OWN_LPSOLVER;' - -useCoin = loadConfig('COIN', 'useCoin').startswith('t') -if useCoin: - coinIncl = loadConfig('COIN', 'coinIncl') - coinLib = loadConfig('COIN', 'coinLib') - solver_name = loadConfig('COIN', 'solver_name') - solver_incl = loadConfig('COIN', 'solver_incl') - - addDefines += 'USE_COIN;'+solver_name+';' - addIncludes += coinIncl+';' - if solver_incl.strip() != '': - addIncludes += solver_incl+';' - addLibs += 'libCoinUtils.lib libOsi.lib ' - addLibs += 'libClp.lib libOsiClp.lib ' - addLibPathsDebugWin32 += coinLib+'/win32/Debug;' - addLibPathsReleaseWin32 += coinLib+'/win32/Release;' - addLibPathsDebugX64 += coinLib+'/x64/Debug;' - addLibPathsReleaseX64 += coinLib+'/x64/Release;' - -addDefines = addDefines[:-1] -addIncludes = addIncludes[:-1] -addLibs = addLibs[:-1] -addLibPathsDebugWin32 = addLibPathsDebugWin32[:-1] -addLibPathsReleaseWin32 = addLibPathsReleaseWin32[:-1] -addLibPathsDebugX64 = addLibPathsDebugX64[:-1] -addLibPathsReleaseX64 = addLibPathsReleaseX64[:-1] -defineTag = '<>' -includeTag = '<>' -libTag = '<>' -libPathsTagDebugWin32 = '<>' -libPathsTagReleaseWin32 = '<>' -libPathsTagDebugX64 = '<>' -libPathsTagReleaseX64 = '<>' - -# Params are: -# - Tag in template-File -# - Directory to start search & subfilters from -# - File Patterns -cppStuff = stuff( '<>', '.\\src', [ '*.c', '*.cpp' ] ) -hStuff = stuff( '<>', '.\\ogdf', [ '*.h' ] ) -hLegacyStuff = stuff( '<>', '.\\ogdf_legacy', [ '*.h' ] ) -otherStuff = stuff( '<>', '.', [ ] ) - -includeStuff = stuff - -stuff = [ cppStuff, hStuff, hLegacyStuff, otherStuff ] - - -######################################################### -######################################################### -## only code below... - -# just the def. nothing happens yet -def Walk( curdir, pats, intro ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - if Walk( outpath, pats, intro + '\n'): - intro = '' - vcproj.write('\n') - else: - for pat in pats: - if fnmatch.fnmatch(name, pat): - if len(intro)>0: - vcproj.write(intro) - intro = '' - vcproj.write(' \n') - return len(intro) == 0 - -########################################## -## Main below... - -print 'Generating VCProj...' - -includeLegacyCode = 0; -if len(sys.argv)>1 and sys.argv[1]=='legacy': - includeLegacyCode = 1 - print '(including legacy code)' - -vcproj = open(filename_vcproj,'w') -template = open(filename_template) - -check = 0 -for line in template: - if check < len(stuff) and line.find(stuff[check].tag) > -1: - if (stuff[check].tag!='<>' or includeLegacyCode): - Walk(stuff[check].path, stuff[check].pats, '') - check = check + 1 - elif line.find(defineTag) > -1: - vcproj.write(line.replace(defineTag,addDefines,1)) - elif line.find(includeTag) > -1: - vcproj.write(line.replace(includeTag,addIncludes,1)) - elif line.find(libTag) > -1: - vcproj.write(line.replace(libTag,addLibs,1)) - elif line.find(libPathsTagDebugWin32) > -1: - vcproj.write(line.replace(libPathsTagDebugWin32,addLibPathsDebugWin32,1)) - elif line.find(libPathsTagReleaseWin32) > -1: - vcproj.write(line.replace(libPathsTagReleaseWin32,addLibPathsReleaseWin32,1)) - elif line.find(libPathsTagDebugX64) > -1: - vcproj.write(line.replace(libPathsTagDebugX64,addLibPathsDebugX64,1)) - elif line.find(libPathsTagReleaseX64) > -1: - vcproj.write(line.replace(libPathsTagReleaseX64,addLibPathsReleaseX64,1)) - else: - vcproj.write(line) - -template.close() -vcproj.close() - -print 'VCProj generated' diff --git a/ext/OGDF/makeVCXProj.config b/ext/OGDF/makeVCXProj.config deleted file mode 100644 index c7c51dbee..000000000 --- a/ext/OGDF/makeVCXProj.config +++ /dev/null @@ -1,29 +0,0 @@ -[GENERAL] -#* File name of project template file -templateFile = config/ogdf.vcxproj.vs2010.template -#* File name of project filters template file -templateFiltersFile = config/ogdf.vcxproj.filters.template -#* File name of created project file -projectFile = ogdf.vcxproj -#* File name of created project filters file -projectFiltersFile = ogdf.vcxproj.filters -#* the option below does not work in public releases, -#* as the solver is non-GPL. Please use COIN instead! -useOwnLpSolver = false - -[COIN] -#* set to "true" to use COIN -useCoin = false -coinIncl = C:/somewhere/COIN/include -coinLib = C:/somewhere/COIN/lib - -#* Select your solver for COIN -#* CPLEX: -# solver_name = COIN_OSI_CPX -# solver_incl = C:/somewhere/ILOG/cplex90/include/ilcplex -#* Coin's CLP: -# solver_name = COIN_OSI_CLP -# solver_incl = -#* Coin's Symphony -# solver_name = COIN_OSI_SYM -# solver_incl = C:/home/plug/COIN/SYMPHONY/include diff --git a/ext/OGDF/makeVCXProj.py b/ext/OGDF/makeVCXProj.py deleted file mode 100644 index 5e0a00db1..000000000 --- a/ext/OGDF/makeVCXProj.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env python -# Make VCXProj -# -# May 2010 -# Markus Chimani, markus.chimani@cs.tu-dortmund.de -# Carsten Gutwenger, carsten.gutwenger@cs.tu-dortmund.de -######################################################### - - -import os, sys, fnmatch, ConfigParser - -class stuff: - def __init__(self, ttag, tpath, tpats, tcommand, tfilter): - self.tag, self.path, self.pats, self.command, self.filter = ttag, tpath, tpats, tcommand, tfilter - -def bailout(msg): - print msg - print 'Please use the original makeVCXProj.config as a template' - sys.exit() - -def loadConfig(sect, key, noError = False ): - if config.has_option(sect, key): - v = config.get(sect, key) - print ' [', sect, ']', key, '=', v - return v - else: - if noError: - return None - else: - bailout('Option "' + key + '" in section "' + sect + '" is missing') - -######################################################### -# LOAD CONFIGURATION - -config = ConfigParser.ConfigParser() - -makecfg = 'makeVCXProj.config' -for x in sys.argv[1:]: - if x[:7] == "config=": - makecfg = x[7:] - -print 'Loading ' + makecfg + '...' - -try: - config.readfp( open(makecfg)) -except IOError: - bailout(makecfg + ' not found') - -if not config.has_section('GENERAL'): - bailout('Section "GENERAL" is missing') -if not config.has_section('COIN'): - bailout('Section "COIN" is missing') - -######################################################### -# CONFIGS - -# Filenames -filename_vcxproj = loadConfig('GENERAL', 'projectFile') -filename_template = loadConfig('GENERAL', 'templateFile') -filename_vcxfilters = loadConfig('GENERAL', 'projectFiltersFile') -filename_template_filters = loadConfig('GENERAL', 'templateFiltersFile') -addIncludes = '' -addDefines = '' -addLibs = '' -addLibPathsDebugWin32 = '' -addLibPathsReleaseWin32 = '' -addLibPathsDebugX64 = '' -addLibPathsReleaseX64 = '' - -useOwnLpSolver = loadConfig('GENERAL', 'useOwnLpSolver', 'false').startswith('t') -if useOwnLpSolver: - addDefines += 'OGDF_OWN_LPSOLVER;' - -useCoin = loadConfig('COIN', 'useCoin').startswith('t') -if useCoin: - coinIncl = loadConfig('COIN', 'coinIncl') - coinLib = loadConfig('COIN', 'coinLib') - solver_name = loadConfig('COIN', 'solver_name') - solver_incl = loadConfig('COIN', 'solver_incl') - - addDefines += 'USE_COIN;'+solver_name+';' - addIncludes += coinIncl+';' - if solver_incl.strip() != '': - addIncludes += solver_incl+';' - addLibs += 'libCoinUtils.lib libOsi.lib ' - addLibs += 'libClp.lib libOsiClp.lib ' - addLibPathsDebugWin32 += coinLib+'/win32/Debug;' - addLibPathsReleaseWin32 += coinLib+'/win32/Release;' - addLibPathsDebugX64 += coinLib+'/x64/Debug;' - addLibPathsReleaseX64 += coinLib+'/x64/Release;' - -addDefines = addDefines[:-1] -addIncludes = addIncludes[:-1] -addLibs = addLibs[:-1] -addLibPathsDebugWin32 = addLibPathsDebugWin32[:-1] -addLibPathsReleaseWin32 = addLibPathsReleaseWin32[:-1] -addLibPathsDebugX64 = addLibPathsDebugX64[:-1] -addLibPathsReleaseX64 = addLibPathsReleaseX64[:-1] -defineTag = '<>' -includeTag = '<>' -libTag = '<>' -libPathsTagDebugWin32 = '<>' -libPathsTagReleaseWin32 = '<>' -libPathsTagDebugX64 = '<>' -libPathsTagReleaseX64 = '<>' -filtersTag = '<>' - -# Params are: -# - Tag in template-File -# - Directory to start search & subfilters from -# - File Patterns -cppStuff = stuff( '<>', 'src', [ '*.c', '*.cpp' ], 'ClCompile', 'Source Files' ) -hStuff = stuff( '<>', 'ogdf', [ '*.h' ], 'ClInclude', 'Header Files' ) -hLegacyStuff = stuff( '<>', 'ogdf_legacy', [ '*.h' ], 'ClInclude', 'Header Files Legacy' ) - -includeStuff = stuff - -stuff = [ cppStuff, hStuff, hLegacyStuff ] - - -######################################################### -######################################################### -## only code below... - -# just the def. nothing happens yet -def Walk( curdir, pats, command ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - Walk( outpath, pats, command) - else: - for pat in pats: - if fnmatch.fnmatch(name, pat): - vcxproj.write(' <' + command + ' Include="' + outpath + '" />\n') - -def WalkFilterFiles( curdir, pats, command, filter ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - WalkFilterFiles( outpath, pats, command, filter + '\\' + name ) - else: - for pat in pats: - if fnmatch.fnmatch(name, pat): - vcxfilters.write(' <' + command + ' Include="' + outpath + '">\n') - vcxfilters.write(' ' + filter + '\n') - vcxfilters.write(' \n') - -def WalkFilters( curdir, filter ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - filtername = filter + '\\' + name - vcxfilters.write(' \n') - vcxfilters.write(' \n') - WalkFilters( outpath, filtername ) - - -########################################## -## Main below... - -print 'Generating VCXProj...' - -includeLegacyCode = 0; -if len(sys.argv)>1 and sys.argv[1]=='legacy': - includeLegacyCode = 1 - print '(including legacy code)' - -vcxproj = open(filename_vcxproj,'w') -template = open(filename_template) - -check = 0 -for line in template: - if check < len(stuff) and line.find(stuff[check].tag) > -1: - if (stuff[check].tag!='<>' or includeLegacyCode): - Walk(stuff[check].path, stuff[check].pats, stuff[check].command) - check = check + 1 - elif line.find(defineTag) > -1: - vcxproj.write(line.replace(defineTag,addDefines,1)) - elif line.find(includeTag) > -1: - vcxproj.write(line.replace(includeTag,addIncludes,1)) - elif line.find(libTag) > -1: - vcxproj.write(line.replace(libTag,addLibs,1)) - elif line.find(libPathsTagDebugWin32) > -1: - vcxproj.write(line.replace(libPathsTagDebugWin32,addLibPathsDebugWin32,1)) - elif line.find(libPathsTagReleaseWin32) > -1: - vcxproj.write(line.replace(libPathsTagReleaseWin32,addLibPathsReleaseWin32,1)) - elif line.find(libPathsTagDebugX64) > -1: - vcxproj.write(line.replace(libPathsTagDebugX64,addLibPathsDebugX64,1)) - elif line.find(libPathsTagReleaseX64) > -1: - vcxproj.write(line.replace(libPathsTagReleaseX64,addLibPathsReleaseX64,1)) - else: - vcxproj.write(line) - -template.close() -vcxproj.close() - -# Creation of filters file... - -vcxfilters = open(filename_vcxfilters,'w') -template_filters = open(filename_template_filters) - -check = 0 -for line in template_filters: - if check < len(stuff) and line.find(stuff[check].tag) > -1: - if (stuff[check].tag!='<>' or includeLegacyCode): - WalkFilterFiles(stuff[check].path, stuff[check].pats, stuff[check].command, stuff[check].filter) - check = check + 1 - elif line.find(filtersTag) > -1: - for s in stuff: - if (s.tag!='<>' or includeLegacyCode): - WalkFilters(s.path, s.filter) - else: - vcxfilters.write(line) - - -template_filters.close() -vcxfilters.close() - - -print 'VCXProj generated' diff --git a/ext/OGDF/makeVCXProjPython3.py b/ext/OGDF/makeVCXProjPython3.py deleted file mode 100644 index 272ef2e2a..000000000 --- a/ext/OGDF/makeVCXProjPython3.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env python -# Make VCXProj -# -# May 2010 -# Markus Chimani, markus.chimani@cs.tu-dortmund.de -# Carsten Gutwenger, carsten.gutwenger@cs.tu-dortmund.de -######################################################### - - -import os, sys, fnmatch, configparser - -class stuff: - def __init__(self, ttag, tpath, tpats, tcommand, tfilter): - self.tag, self.path, self.pats, self.command, self.filter = ttag, tpath, tpats, tcommand, tfilter - -def bailout(msg): - print(msg) - print('Please use the original makeVCXProj.config as a template') - sys.exit() - -def loadConfig(sect, key, noError = False ): - if config.has_option(sect, key): - v = config.get(sect, key) - print((' [', sect, ']', key, '=', v)) - return v - else: - if noError: - return None - else: - bailout('Option "' + key + '" in section "' + sect + '" is missing') - -######################################################### -# LOAD CONFIGURATION - -config = configparser.ConfigParser() - -makecfg = 'makeVCXProj.config' -for x in sys.argv[1:]: - if x[:7] == "config=": - makecfg = x[7:] - -print(('Loading ' + makecfg + '...')) - -try: - config.readfp( open(makecfg)) -except IOError: - bailout(makecfg + ' not found') - -if not config.has_section('GENERAL'): - bailout('Section "GENERAL" is missing') -if not config.has_section('COIN'): - bailout('Section "COIN" is missing') - -######################################################### -# CONFIGS - -# Filenames -filename_vcxproj = loadConfig('GENERAL', 'projectFile') -filename_template = loadConfig('GENERAL', 'templateFile') -filename_vcxfilters = loadConfig('GENERAL', 'projectFiltersFile') -filename_template_filters = loadConfig('GENERAL', 'templateFiltersFile') -addIncludes = '' -addDefines = '' -addLibs = '' -addLibPathsDebugWin32 = '' -addLibPathsReleaseWin32 = '' -addLibPathsDebugX64 = '' -addLibPathsReleaseX64 = '' - -useOwnLpSolver = loadConfig('GENERAL', 'useOwnLpSolver', 'false').startswith('t') -if useOwnLpSolver: - addDefines += 'OGDF_OWN_LPSOLVER;' - -useCoin = loadConfig('COIN', 'useCoin').startswith('t') -if useCoin: - coinIncl = loadConfig('COIN', 'coinIncl') - coinLib = loadConfig('COIN', 'coinLib') - solver_name = loadConfig('COIN', 'solver_name') - solver_incl = loadConfig('COIN', 'solver_incl') - - addDefines += 'USE_COIN;'+solver_name+';' - addIncludes += coinIncl+';' - if solver_incl.strip() != '': - addIncludes += solver_incl+';' - addLibs += 'libCoinUtils.lib libOsi.lib ' - addLibs += 'libClp.lib libOsiClp.lib ' - addLibPathsDebugWin32 += coinLib+'/win32/Debug;' - addLibPathsReleaseWin32 += coinLib+'/win32/Release;' - addLibPathsDebugX64 += coinLib+'/x64/Debug;' - addLibPathsReleaseX64 += coinLib+'/x64/Release;' - -addDefines = addDefines[:-1] -addIncludes = addIncludes[:-1] -addLibs = addLibs[:-1] -addLibPathsDebugWin32 = addLibPathsDebugWin32[:-1] -addLibPathsReleaseWin32 = addLibPathsReleaseWin32[:-1] -addLibPathsDebugX64 = addLibPathsDebugX64[:-1] -addLibPathsReleaseX64 = addLibPathsReleaseX64[:-1] -defineTag = '<>' -includeTag = '<>' -libTag = '<>' -libPathsTagDebugWin32 = '<>' -libPathsTagReleaseWin32 = '<>' -libPathsTagDebugX64 = '<>' -libPathsTagReleaseX64 = '<>' -filtersTag = '<>' - -# Params are: -# - Tag in template-File -# - Directory to start search & subfilters from -# - File Patterns -cppStuff = stuff( '<>', 'src', [ '*.c', '*.cpp' ], 'ClCompile', 'Source Files' ) -hStuff = stuff( '<>', 'ogdf', [ '*.h' ], 'ClInclude', 'Header Files' ) -hLegacyStuff = stuff( '<>', 'ogdf_legacy', [ '*.h' ], 'ClInclude', 'Header Files Legacy' ) - -includeStuff = stuff - -stuff = [ cppStuff, hStuff, hLegacyStuff ] - - -######################################################### -######################################################### -## only code below... - -# just the def. nothing happens yet -def Walk( curdir, pats, command ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - Walk( outpath, pats, command) - else: - for pat in pats: - if fnmatch.fnmatch(name, pat): - vcxproj.write(' <' + command + ' Include="' + outpath + '" />\n') - -def WalkFilterFiles( curdir, pats, command, filter ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - WalkFilterFiles( outpath, pats, command, filter + '\\' + name ) - else: - for pat in pats: - if fnmatch.fnmatch(name, pat): - vcxfilters.write(' <' + command + ' Include="' + outpath + '">\n') - vcxfilters.write(' ' + filter + '\n') - vcxfilters.write(' \n') - -def WalkFilters( curdir, filter ): - names = os.listdir( curdir) - names.sort() - - for name in names: - if name.startswith('.') or name.startswith('_') or (name=='legacy' and not includeLegacyCode): - continue - - outpath = curdir + '\\' + name - fullname = os.path.normpath(outpath) - - if os.path.isdir(fullname) and not os.path.islink(fullname): - filtername = filter + '\\' + name - vcxfilters.write(' \n') - vcxfilters.write(' \n') - WalkFilters( outpath, filtername ) - - -########################################## -## Main below... - -print('Generating VCXProj...') - -includeLegacyCode = 0; -if len(sys.argv)>1 and sys.argv[1]=='legacy': - includeLegacyCode = 1 - print('(including legacy code)') - -vcxproj = open(filename_vcxproj,'w') -template = open(filename_template) - -check = 0 -for line in template: - if check < len(stuff) and line.find(stuff[check].tag) > -1: - if (stuff[check].tag!='<>' or includeLegacyCode): - Walk(stuff[check].path, stuff[check].pats, stuff[check].command) - check = check + 1 - elif line.find(defineTag) > -1: - vcxproj.write(line.replace(defineTag,addDefines,1)) - elif line.find(includeTag) > -1: - vcxproj.write(line.replace(includeTag,addIncludes,1)) - elif line.find(libTag) > -1: - vcxproj.write(line.replace(libTag,addLibs,1)) - elif line.find(libPathsTagDebugWin32) > -1: - vcxproj.write(line.replace(libPathsTagDebugWin32,addLibPathsDebugWin32,1)) - elif line.find(libPathsTagReleaseWin32) > -1: - vcxproj.write(line.replace(libPathsTagReleaseWin32,addLibPathsReleaseWin32,1)) - elif line.find(libPathsTagDebugX64) > -1: - vcxproj.write(line.replace(libPathsTagDebugX64,addLibPathsDebugX64,1)) - elif line.find(libPathsTagReleaseX64) > -1: - vcxproj.write(line.replace(libPathsTagReleaseX64,addLibPathsReleaseX64,1)) - else: - vcxproj.write(line) - -template.close() -vcxproj.close() - -# Creation of filters file... - -vcxfilters = open(filename_vcxfilters,'w') -template_filters = open(filename_template_filters) - -check = 0 -for line in template_filters: - if check < len(stuff) and line.find(stuff[check].tag) > -1: - if (stuff[check].tag!='<>' or includeLegacyCode): - WalkFilterFiles(stuff[check].path, stuff[check].pats, stuff[check].command, stuff[check].filter) - check = check + 1 - elif line.find(filtersTag) > -1: - for s in stuff: - if (s.tag!='<>' or includeLegacyCode): - WalkFilters(s.path, s.filter) - else: - vcxfilters.write(line) - - -template_filters.close() -vcxfilters.close() - - -print('VCXProj generated') diff --git a/ext/OGDF/ogdf/augmentation/DfsMakeBiconnected.h b/ext/OGDF/ogdf/augmentation/DfsMakeBiconnected.h deleted file mode 100644 index 48ab333b8..000000000 --- a/ext/OGDF/ogdf/augmentation/DfsMakeBiconnected.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Provides a simple, dfs-based algorithm for biconnectivity augmentation. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DFS_MAKE_BICONNECTED_H -#define OGDF_DFS_MAKE_BICONNECTED_H - - - -#include - -namespace ogdf { - -/** - * \brief Implementation of a DFS-based algorithm for biconnectivity augmentation. - * - * The class \a DfsMakeBiconnected implements an augmentation algorithms - * that augments a graph to a biconnected graph. In addition, if the graph was - * planar before augmentation, the resulting graph will be biconnected and - * planar. - * The algorithm simply uses DFS and, whenever a cut vertex is discovered, - * a new edge is added. - */ - -class OGDF_EXPORT DfsMakeBiconnected : public AugmentationModule { -public: - //! Creates an instance of DFS-based biconnectivity augmentation. - DfsMakeBiconnected() { } - - // destruction - ~DfsMakeBiconnected() { } - -protected: - //! Implements the algorithm call. - void doCall(Graph& G, List &L); -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/augmentation/PlanarAugmentation.h b/ext/OGDF/ogdf/augmentation/PlanarAugmentation.h deleted file mode 100644 index 8a0088223..000000000 --- a/ext/OGDF/ogdf/augmentation/PlanarAugmentation.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief planar biconnected augmentation approximation algorithm - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANAR_AUGMENTATION_H -#define OGDF_PLANAR_AUGMENTATION_H - -#include -#include -#include - - -namespace ogdf { - - class DynamicBCTree; - - -/** - * \brief The algorithm for planar biconnectivity augmentation (Mutzel, Fialko). - * - * The class \a PlanarAugmentation implements an augmentation algorithm - * that augments a graph to a biconnected graph. In addition, if the graph was - * planar before augmentation, the resulting graph will be biconnected and - * planar. - * The algorithm uses (dynamic) BC-trees and achieves biconnectivity by - * inserting edges between nodes of pendants (that are leaves in the bc-tree). - * The guaranteed approximation-quality is 5/3. - * - * The implementation is based on the following publication: - * - * Sergej Fialko, Petra Mutzel: A New Approximation Algorithm for the Planar - * Augmentation Problem. Proc. SODA 1998, pp. 260-269. - */ -class OGDF_EXPORT PlanarAugmentation : public AugmentationModule { - -public: - //! Creates an instance of the planar augmentation algorithm. - PlanarAugmentation() { } - - ~PlanarAugmentation() { } - -protected: - /** - * \brief The implementation of the algorithm call. - * - * \param G is the working graph. - * \param L is the list of all new edges. - */ - void doCall(Graph& G, List& L); - - -private: - /** - * \brief Counts the number of planarity tests. - */ - int m_nPlanarityTests; - - /** - * \brief The working graph. - */ - Graph* m_pGraph; - /** - * \brief The corresponding BC-Tree. - */ - DynamicBCTree* m_pBCTree; - - /** - * \brief The inserted edges by the algorithm. - */ - List* m_pResult; - - /** - * \brief The list of all labels, sorted by size (decreasing). - */ - List m_labels; - /** - * \brief The list of all pendants (leaves in the BC-Tree). - */ - List m_pendants; - - /** - * \brief The list of pendants that has to be deleted after each reduceChain. - */ - List m_pendantsToDel; - - /** - * \brief The label a BC-Node belongs to. - */ - NodeArray m_belongsTo; - /** - * \brief The list iterator in m_labels if the node in the BC-Tree is a label. - */ - NodeArray< ListIterator > m_isLabel; - - /** - * \brief Stores for each node of the bc-tree the children that have an adjacent bc-node - * that doesn't belong to the same parent-node. - * - * This is necessary because the bc-tree uses an union-find-data-structure to store - * dependencies between bc-nodes. The adjacencies in the bc-tree won't be updated. - */ - NodeArray< SList > m_adjNonChildren; - - -private: - - /** - * \brief The main function for planar augmentation. - */ - void augment(); - - /** - * \brief Makes the graph connected by new edges between pendants of - * the connected components - */ - void makeConnectedByPendants(); - - /** - * \brief Is called for every pendant-node. It traverses to the - * root and creates a label or updates one. - * - * \param p is a pendant in the BC-Tree. - * \param labelOld is the old label of \a p. - */ - void reduceChain(node p, pa_label labelOld = 0); - - /** - * \brief Is called in reduceChain. It traverses to the root and checks - * several stop conditions. - * - * \param v is a node of the BC-Tree. - * \param last is the last found C-vertex in the BC-Tree, is modified by - * the method. - * \return the stop-cause. - */ - paStopCause followPath(node v, node& last); - - /** - * \brief Checks planarity for a new edge (v1,v2) in the original graph. - * - * \param v1 is a node in the original graph. - * \param v2 is a node in the original graph. - * \return true iff the graph (including the new edge) is planar. - */ - bool planarityCheck(node v1, node v2); - - /** - * \brief Returns a node that belongs to bc-node v and is adjacent to the cutvertex. - * - * \param v is a node in the BC-Tree. - * \param cutvertex is the last cutvertex found. - * \return a node of the original graph. - */ - node adjToCutvertex(node v, node cutvertex = 0); - - /** - * \brief Traverses from pendant to ancestor and returns the - * last node before ancestor on the path. - */ - node findLastBefore(node pendant, node ancestor); - - /** - * \brief Deletes the pendant p, removes it from the corresponding label - * and updates the label-order. - */ - void deletePendant(node p, bool removeFromLabel = true); - /** - * \brief Adds a pendant p to the label l and updates the label-order. - */ - void addPendant(node p, pa_label& l); - - /** - * \brief Connects two pendants. - * - * \return the new edge in the original graph. - */ - edge connectPendants(node pendant1, node pendant2); - /** - * \brief Removes all pendants of a label. - */ - void removeAllPendants(pa_label& l); - - /** - * \brief Connects all pendants of label \a l with new edges. - */ - void joinPendants(pa_label& l); - - /** - * \brief Connects the only pendant of l with a computed ancestor. - */ - void connectInsideLabel(pa_label& l); - - /** - * \brief Inserts label l into m_labels by decreasing order. - * - * \return the corresponding list iterator. - */ - ListIterator insertLabel(pa_label l); - - /** - * \brief deletes label \a l. - */ - void deleteLabel(pa_label& l, bool removePendants = true); - - /** - * \brief Inserts edges between pendants of label first and second. - * first.size() is gerater than second.size() or equal. - */ - void connectLabels(pa_label first, pa_label second); - - /** - * \brief Creates a new label and inserts it into m_labels. - */ - pa_label newLabel(node cutvertex, node p, paStopCause whyStop); - - /** - * \brief Finds two matching labels, so all pendants can be connected - * without losing planarity. - * - * \param first is the label with maximum size, modified by the function. - * \param second is the matching label, modified by the function: - * 0 if no matching is found. - * \return true iff a matching label is found. - */ - bool findMatching(pa_label& first, pa_label& second); - - /** - * \brief Checks if the pendants of label a and label b can be connected - * without creating a new pendant. - */ - bool connectCondition(pa_label a, pa_label b); - - /** - * \brief Updates the adjNonChildren-data. - * - * \param newBlock is a new created block of the BC-Tree. - * \param path is the path in the BC-Tree between the two connected nodes. - */ - void updateAdjNonChildren(node newBlock, SList& path); - - /** - * \brief Modifies the root of the BC-Tree that newRoot replaces oldRoot. - */ - void modifyBCRoot(node oldRoot, node newRoot); - - /** - * \brief Major updates caused by the new edges. - * - * \param newEdges is a list of all new edges. - */ - void updateNewEdges(const SList &newEdges); - - /** - * \brief Cleanup. - */ - void terminate(); - -}; // class PlanarAugmentation - - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/augmentation/PlanarAugmentationFix.h b/ext/OGDF/ogdf/augmentation/PlanarAugmentationFix.h deleted file mode 100644 index 6da51f3c7..000000000 --- a/ext/OGDF/ogdf/augmentation/PlanarAugmentationFix.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief planar biconnected augmentation algorithm with fixed - * combinatorial embedding. - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANAR_AUGMENTATION_FIX_H -#define OGDF_PLANAR_AUGMENTATION_FIX_H - -#include -#include -#include - - -namespace ogdf { - - class DynamicBCTree; - - -/** - * \brief The algorithm for biconnectivity augmentation with fixed combinatorial embedding. - * - */ -class OGDF_EXPORT PlanarAugmentationFix : public AugmentationModule { - -public: - //! Creates an instance of planar augmentation with fixed embedding. - PlanarAugmentationFix() { } - - ~PlanarAugmentationFix() { } - - -protected: - /** - * \brief The implementation of the algorithm call. - * - * \param g is the working graph. - * \param L is the list of all new edges. - */ - void doCall(Graph& g, List& L); - -private: - /** - * \brief The embedding of g. - */ - CombinatorialEmbedding* m_pEmbedding; - - /** - * \brief The embedding of the actual partial graph. - */ - CombinatorialEmbedding* m_pActEmbedding; - - /** - * \brief The working graph. - */ - Graph* m_pGraph; - - /** - * \brief The inserted edges by the algorithm. - */ - List* m_pResult; - - /** - * \brief The actual dynamic bc-tree. - */ - DynamicBCTree* m_pBCTree; - - /** - * \brief The actual partial graph. - */ - GraphCopy m_graphCopy; - - /** - * \brief Edge-array required for construction of the graph copy. - */ - EdgeArray m_eCopy; - - /** - * \brief The list of all labels. - */ - List m_labels; - - /** - * \brief Array that contains iterators to the list of labels - * if a node is a parent of a label. - */ - NodeArray< ListIterator > m_isLabel; - - /** - * \brief Array that contains the label a node belongs to. - */ - NodeArray m_belongsTo; - - /** - * \brief Array that contains the iterator of the label a node belongs to. - */ - NodeArray< ListIterator > m_belongsToIt; - - /** - * \brief The actual root of the bc-tree. - */ - node m_actBCRoot; - - /** - * \brief The main function for planar augmentation. - */ - void augment(adjEntry adjOuterFace); - - /** - * \brief Modifies the root of the bc-tree. - */ - void modifyBCRoot(node oldRoot, node newRoot); - - /** - * \brief Exchanges oldRoot by newRoot and updates data structurs in the bc-tree. - */ - void changeBCRoot(node oldRoot, node newRoot); - - /** - * \brief Adds the pendant to a label or creates one (uses followPath()). - */ - void reduceChain(node pendant); - - /** - * \brief Traverses upwards in the bc-tree, starting at the pendant node. - */ - paStopCause followPath(node v, node& last); - - /** - * \brief Finds the next matching pendants. - */ - bool findMatching(node& pendant1, node& pendant2, adjEntry& v1, adjEntry& v2); - - /** - * \brief Called by findMatching, if a dominating tree was detected. - */ - void findMatchingRev(node& pendant1, node& pendant2, adjEntry& v1, adjEntry& v2); - - /** - * \brief Creates a new label. - */ - pa_label newLabel(node cutvertex, node parent, node pendant, paStopCause whyStop); - - /** - * \brief Adds pendant \a p to label \a l. - */ - void addPendant(node p, pa_label& l); - - /** - * \brief Inserts the label into the list of labels maintaining decreasing order. - */ - ListIterator insertLabel(pa_label l); - - /** - * \brief Connect the two pendants. - */ - void connectPendants(node pendant1, node pendant2, adjEntry adjV1, adjEntry adjV2); - - /** - * \brief Connects the remaining label. - */ - void connectSingleLabel(); - - /** - * \brief Deletes the pendant. - */ - void deletePendant(node pendant); - - /** - * \brief Deletes the label. - */ - void deleteLabel(pa_label& l, bool removePendants = true); - - /** - * \brief Removes the label from the list of labels. - */ - void removeLabel(pa_label& l); - -}; // class PlanarAugmentationFix - - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/AdjEntryArray.h b/ext/OGDF/ogdf/basic/AdjEntryArray.h deleted file mode 100644 index 33d0eba25..000000000 --- a/ext/OGDF/ogdf/basic/AdjEntryArray.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of AdjEntryArray class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ADJ_ENTRY_ARRAY_H -#define OGDF_ADJ_ENTRY_ARRAY_H - - -#include - - -namespace ogdf { - - -//! Abstract base class for adjacency entry arrays. -/** - * Defines the interface for event handling used by the Graph class. - * Use the parameterized class AdjEntryArray for creating adjacency arrays. - */ -class AdjEntryArrayBase { - /** - * Pointer to list element in the list of all registered adjacency - * entry arrays which references this array. - */ - ListIterator m_it; - -public: - const Graph *m_pGraph; //!< The associated graph. - - //! Initializes an adjacency entry array not associated with a graph. - AdjEntryArrayBase() : m_pGraph(0) { } - //! Initializes an adjacency entry array associated with \a pG. - AdjEntryArrayBase(const Graph *pG) : m_pGraph(pG) { - if(pG) m_it = pG->registerArray(this); - } - - // destructor, unregisters the array - virtual ~AdjEntryArrayBase() { - if (m_pGraph) m_pGraph->unregisterArray(m_it); - } - - // event interface used by Graph - //! Virtual function called when table size has to be enlarged. - virtual void enlargeTable(int newTableSize) = 0; - //! Virtual function called when table has to be reinitialized. - virtual void reinit(int initTableSize) = 0; - //! Virtual function called when array is disconnected from the graph. - virtual void disconnect() = 0; - //! Virtual function called when the index of an adjacency entry is changed. - virtual void resetIndex(int newIndex, int oldIndex) = 0; - - //! Associates the array with a new graph. - void reregister(const Graph *pG) { - if (m_pGraph) m_pGraph->unregisterArray(m_it); - if ((m_pGraph = pG) != 0) m_it = pG->registerArray(this); - } -}; // class AdjEntryArrayBase - - -//! Dynamic arrays indexed with adjacency entries. -/** - * Adjacency entry arrays represent a mapping from adjacency entries to data of type \a T. - * They adjust their table size automatically when the graph grows. - * - * @tparam T is the element type. - */ -template class AdjEntryArray : private Array, protected AdjEntryArrayBase { - T m_x; //!< The default value for array elements. - -public: - //! Constructs an empty adjacency entry array associated with no graph. - AdjEntryArray() : Array(), AdjEntryArrayBase() { } - //! Constructs an adjacency entry array associated with \a G. - AdjEntryArray(const Graph &G) : Array(G.adjEntryArrayTableSize()), AdjEntryArrayBase(&G) { } - //! Constructs an adjacency entry array associated with \a G. - /** - * @param G is the associated graph. - * @param x is the default value for all array elements. - */ - AdjEntryArray(const Graph &G, const T &x) : - Array(0,G.adjEntryArrayTableSize()-1,x), AdjEntryArrayBase(&G), m_x(x) { } - //! Constructs an adjacency entry array that is a copy of \a A. - /** - * Associates the array with the same graph as \a A and copies all elements. - */ - AdjEntryArray(const AdjEntryArray &A) : Array(A), AdjEntryArrayBase(A.m_pGraph), m_x(A.m_x) { } - - //! Returns true iff the array is associated with a graph. - bool valid() const { return (Array::low() <= Array::high()); } - - //! Returns a reference to the element with index \a adj. - const T &operator[](adjEntry adj) const { - OGDF_ASSERT(adj != 0 && adj->graphOf() == m_pGraph) - return Array::operator [](adj->index()); - } - - //! Returns a reference to the element with index \a adj. - T &operator[](adjEntry adj) { - OGDF_ASSERT(adj != 0 && adj->graphOf() == m_pGraph) - return Array::operator [](adj->index()); - } - - //! Returns a reference the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for an adjacency - * entry in the associated graph! - */ - const T &operator[](int index) const { - return Array::operator [](index); - } - - //! Returns a reference the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for an adjacency - * entry in the associated graph! - */ - T &operator[](int index) { - return Array::operator [](index); - } - - //! Assignment operator. - AdjEntryArray &operator=(const AdjEntryArray &A) { - Array::operator =(A); - m_x = A.m_x; - reregister(A.m_pGraph); - return *this; - } - - //! Reinitializes the array. Associates the array with no graph. - void init() { - Array::init(); reregister(0); - } - - //! Reinitializes the array. Associates the array with \a G. - void init(const Graph &G) { - Array::init(G.adjEntryArrayTableSize()); reregister(&G); - } - - //! Reinitializes the array. Associates the array with \a G. - /** - * @param G is the associated graph. - * @param x is the default value. - */ - void init(const Graph &G, const T &x) { - Array::init(0,G.adjEntryArrayTableSize()-1, m_x = x); reregister(&G); - } - - //! Sets all array elements to \a x. - void fill(const T &x) { - int high = m_pGraph->maxAdjEntryIndex(); - if(high >= 0) - Array::fill(0,high,x); - } - -private: - virtual void enlargeTable(int newTableSize) { - Array::grow(newTableSize-Array::size(),m_x); - } - - virtual void reinit(int initTableSize) { - Array::init(0,initTableSize-1,m_x); - } - - virtual void resetIndex(int newIndex, int oldIndex) { - Array::operator [](newIndex) = Array::operator [](oldIndex); - } - - virtual void disconnect() { - Array::init(); - m_pGraph = 0; - } - - OGDF_NEW_DELETE - -}; // class AdjEntryArray - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Array.h b/ext/OGDF/ogdf/basic/Array.h deleted file mode 100644 index 41793ad7b..000000000 --- a/ext/OGDF/ogdf/basic/Array.h +++ /dev/null @@ -1,587 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of Array class and - * Array algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ARRAY_H -#define OGDF_ARRAY_H - - -#include - - -namespace ogdf { - -//! Iteration over all indices \a i of an array \a A. -/** - * Note that the index variable \a i has to be defined prior to this macro - * (just as for \c #forall_edges, etc.). - *

Example

- * - * \code - * Array A; - * ... - * int i; - * forall_arrayindices(i, A) { - * cout << A[i] << endl; - * } - * \endcode - * - * Note that this code is equivalent to the following tedious long version - * - * \code - * Array A; - * ... - * int i; - * for(i = A.low(); i <= A.high(); ++i) { - * cout << A[i] << endl; - * } - * \endcode - */ -#define forall_arrayindices(i, A) \ - for(i = (A).low(); i<=(A).high(); ++i) - -//! Iteration over all indices \a i of an array \a A, in reverse order. -/** - * Note that the index variable \a i has to be defined prior to this macro - * (just as for \c #forall_edges, etc.). - * See \c #forall_arrayindices for an example - */ -#define forall_rev_arrayindices(i, A) \ - for(i = (A).high(); i>=(A).low(); --i) - - - -//! The parameterized class \a Array implements dynamic arrays of type \a E. -/** - * @tparam E denotes the element type. - * @tparam INDEX denotes the index type. The index type must be chosen such that it can - * express the whole index range of the array instance, as well as its size. - * The default index type is \c int, other possible types are \c short and - * long long (on 64-bit systems). - */ -template class Array { -public: - //! Threshold used by \a quicksort() such that insertion sort is - //! called for instances smaller than \a maxSizeInsertionSort. - enum { maxSizeInsertionSort = 40 }; - - - //! Creates an array with empty index set. - Array() { construct(0,-1); } - - //! Creates an array with index set [0..\a s-1]. - explicit Array(INDEX s) { - construct(0,s-1); initialize(); - } - - //! Creates an array with index set [\a a..\a b]. - Array(INDEX a, INDEX b) { - construct(a,b); initialize(); - } - - //! Creates an array with index set [\a a..\a b] and initializes each element with \a x. - Array(INDEX a, INDEX b, const E &x) { - construct(a,b); initialize(x); - } - - //! Creates an array that is a copy of \a A. - Array(const Array &A) { - copy(A); - } - - // destruction - ~Array() { - deconstruct(); - } - - //! Returns the minimal array index. - INDEX low() const { return m_low; } - - //! Returns the maximal array index. - INDEX high() const { return m_high; } - - //! Returns the size (number of elements) of the array. - INDEX size() const { return m_high - m_low + 1; } - - //! Returns a pointer to the first element. - E *begin() { return m_pStart; } - - //! Returns a pointer to the first element. - const E *begin() const { return m_pStart; } - - //! Returns a pointer to one past the last element. - E *end() { return m_pStop; } - - //! Returns a pointer to one past the last element. - const E *end() const { return m_pStop; } - - //! Returns a pointer to the last element. - E *rbegin() { return m_pStop-1; } - - //! Returns a pointer to the last element. - const E *rbegin() const { return m_pStop-1; } - - //! Returns a pointer to one before the first element. - E *rend() { return m_pStart-1; } - - //! Returns a pointer to one before the first element. - const E *rend() const { return m_pStart-1; } - - //! Returns a reference to the element at position \a i. - const E &operator[](INDEX i) const { - OGDF_ASSERT(m_low <= i && i <= m_high) - return m_vpStart[i]; - } - - //! Returns a reference to the element at position \a i. - E &operator[](INDEX i) { - OGDF_ASSERT(m_low <= i && i <= m_high) - return m_vpStart[i]; - } - - //! Swaps the elements at position \a i and \a j. - void swap(INDEX i, INDEX j) { - OGDF_ASSERT(m_low <= i && i <= m_high) - OGDF_ASSERT(m_low <= j && j <= m_high) - - std::swap(m_vpStart[i], m_vpStart[j]); - } - - //! Reinitializes the array to an array with empty index set. - void init() { - //init(0,-1); - deconstruct(); - construct(0,-1); - } - - //! Reinitializes the array to an array with index set [0..\a s-1]. - /** - * Notice that the elements contained in the array get discarded! - */ - void init(INDEX s) { init(0,s-1); } - - //! Reinitializes the array to an array with index set [\a a..\a b]. - /** - * Notice that the elements contained in the array get discarded! - */ - void init(INDEX a, INDEX b) { - deconstruct(); - construct(a,b); - initialize(); - } - - //! Reinitializes the array to an array with index set [\a a..\a b] and sets all entries to \a x. - void init(INDEX a, INDEX b, const E &x) { - deconstruct(); - construct(a,b); - initialize(x); - } - - //! Assignment operator. - Array &operator=(const Array &array2) { - deconstruct(); - copy(array2); - return *this; - } - - //! Sets all elements to \a x. - void fill(const E &x) { - E *pDest = m_pStop; - while(pDest > m_pStart) - *--pDest = x; - } - - //! Sets elements in the intervall [\a i..\a j] to \a x. - void fill(INDEX i, INDEX j, const E &x) { - OGDF_ASSERT(m_low <= i && i <= m_high) - OGDF_ASSERT(m_low <= j && j <= m_high) - - E *pI = m_vpStart + i, *pJ = m_vpStart + j+1; - while(pJ > pI) - *--pJ = x; - } - - //! Enlarges the array by \a add elements and sets new elements to \a x. - /** - * Note: address of array entries in memory may change! - * @param add is the number of additional elements; \a add can be negative in order to shrink the array. - * @param x is the inital value of all new elements. - */ - void grow(INDEX add, const E &x); - - //! Enlarges the array by \a add elements. - /** - * Note: address of array entries in memory may change! - * @param add is the number of additional elements; \a add can be negative in order to shrink the array. - */ - void grow(INDEX add); - - //! Randomly permutes the subarray with index set [\a l..\a r]. - void permute (INDEX l, INDEX r); - - //! Randomly permutes the array. - void permute() { - permute(low(), high()); - } - - //! Performs a binary search for element \a x. - /** - * \pre The array must be sorted! - * \return the index of the found element, and low()-1 if not found. - */ - inline int binarySearch (const E& x) const { - return binarySearch(x, StdComparer()); - } - - //! Performs a binary search for element \a x with comparer \a comp. - /** - * \pre The array must be sorted according to \a comp! - * \return the index of the found element, and low()-1 if not found. - */ - template - int binarySearch(const E& e, const COMPARER &comp) const { - if(size() < 2) { - if(size() == 1 && comp.equal(e, m_vpStart[low()])) - return low(); - return low()-1; - } - int l = low(); - int r = high(); - do { - int m = (r + l)/2; - if(comp.greater(e, m_vpStart[m])) - l = m+1; - else - r = m; - } while(r>l); - return comp.equal(e, m_vpStart[l]) ? l : low()-1; - } - - //! Performs a linear search for element \a x. - /** - * Warning: This method has linear running time! - * Note that the linear search runs from back to front. - * \return the index of the found element, and low()-1 if not found. - */ - inline int linearSearch (const E& e) const { - int i; - for(i = size(); i-->0;) - if(e == m_pStart[i]) break; - return i+low(); } - - //! Performs a linear search for element \a x with comparer \a comp. - /** - * Warning: This method has linear running time! - * Note that the linear search runs from back to front. - * \return the index of the found element, and low()-1 if not found. - */ - template - int linearSearch(const E& e, const COMPARER &comp) const { - int i; - for(i = size(); i-->0;) - if(comp.equal(e, m_pStart[i])) break; - return i+low(); - } - - //! Sorts array using Quicksort. - inline void quicksort() { - quicksort(StdComparer()); - } - - //! Sorts subarray with index set [\a l..\a r] using Quicksort. - inline void quicksort(INDEX l, INDEX r) { - quicksort(l, r, StdComparer()); - } - - //! Sorts array using Quicksort and a user-defined comparer \a comp. - /** - * @param comp is a user-defined comparer; \a C must be a class providing a \a less(x,y) method. - */ - template - inline void quicksort(const COMPARER &comp) { - if(low() < high()) - quicksortInt(m_pStart,m_pStop-1,comp); - } - - //! Sorts the subarray with index set [\a l..\a r] using Quicksort and a user-defined comparer \a comp. - /** - * @param l is the left-most position in the range to be sorted. - * @param r is the right-most position in the range to be sorted. - * @param comp is a user-defined comparer; \a C must be a class providing a \a less(x,y) method. - */ - template - void quicksort(INDEX l, INDEX r, const COMPARER &comp) { - OGDF_ASSERT(low() <= l && l <= high()) - OGDF_ASSERT(low() <= r && r <= high()) - if(l < r) - quicksortInt(m_vpStart+l,m_vpStart+r,comp); - } - - template friend class ArrayBuffer; // for efficient ArrayBuffer::compact-method - -private: - E *m_vpStart; //!< The virtual start of the array (address of A[0]). - E *m_pStart; //!< The real start of the array (address of A[m_low]). - E *m_pStop; //!< Successor of last element (address of A[m_high+1]). - INDEX m_low; //!< The lowest index. - INDEX m_high; //!< The highest index. - - //! Allocates new array with index set [\a a..\a b]. - void construct(INDEX a, INDEX b); - - //! Initializes elements with default constructor. - void initialize(); - - //! Initializes elements with \a x. - void initialize(const E &x); - - //! Deallocates array. - void deconstruct(); - - //! Constructs a new array which is a copy of \a A. - void copy(const Array &A); - - //! Internal Quicksort implementation with comparer template. - template - static void quicksortInt(E *pL, E *pR, const COMPARER &comp) { - size_t s = pR-pL; - - // use insertion sort for small instances - if (s < maxSizeInsertionSort) { - for (E *pI = pL+1; pI <= pR; pI++) { - E v = *pI; - E *pJ = pI; - while (--pJ >= pL && comp.less(v,*pJ)) { - *(pJ+1) = *pJ; - } - *(pJ+1) = v; - } - return; - } - - E *pI = pL, *pJ = pR; - E x = *(pL+(s>>1)); - - do { - while (comp.less(*pI,x)) pI++; - while (comp.less(x,*pJ)) pJ--; - if (pI <= pJ) std::swap(*pI++,*pJ--); - } while (pI <= pJ); - - if (pL < pJ) quicksortInt(pL,pJ,comp); - if (pI < pR) quicksortInt(pI,pR,comp); - } - - OGDF_NEW_DELETE -}; // class Array - - - - -// enlarges array by add elements and sets new elements to x -template -void Array::grow(INDEX add, const E &x) -{ - INDEX sOld = size(), sNew = sOld + add; - - // expand allocated memory block - if(m_pStart != 0) { - E *p = (E *)realloc(m_pStart, sNew*sizeof(E)); - if(p == 0) OGDF_THROW(InsufficientMemoryException); - m_pStart = p; - } else { - m_pStart = (E *)malloc(sNew*sizeof(E)); - if (m_pStart == 0) OGDF_THROW(InsufficientMemoryException); - } - - m_vpStart = m_pStart-m_low; - m_pStop = m_pStart+sNew; - m_high += add; - - // initialize new array entries - for (E *pDest = m_pStart+sOld; pDest < m_pStop; pDest++) - new (pDest) E(x); -} - -// enlarges array by add elements (initialized with default constructor) -template -void Array::grow(INDEX add) -{ - INDEX sOld = size(), sNew = sOld + add; - - // expand allocated memory block - if(m_pStart != 0) { - E *p = (E *)realloc(m_pStart, sNew*sizeof(E)); - if(p == 0) OGDF_THROW(InsufficientMemoryException); - m_pStart = p; - } else { - m_pStart = (E *)malloc(sNew*sizeof(E)); - if (m_pStart == 0) OGDF_THROW(InsufficientMemoryException); - } - - m_vpStart = m_pStart-m_low; - m_pStop = m_pStart+sNew; - m_high += add; - - // initialize new array entries - for (E *pDest = m_pStart+sOld; pDest < m_pStop; pDest++) - new (pDest) E; -} - -template -void Array::construct(INDEX a, INDEX b) -{ - m_low = a; m_high = b; - INDEX s = b-a+1; - - if (s < 1) { - m_pStart = m_vpStart = m_pStop = 0; - - } else { - m_pStart = (E *)malloc(s*sizeof(E)); - if (m_pStart == 0) OGDF_THROW(InsufficientMemoryException); - - m_vpStart = m_pStart - a; - m_pStop = m_pStart + s; - } -} - - -template -void Array::initialize() -{ - E *pDest = m_pStart; - try { - for (; pDest < m_pStop; pDest++) - new(pDest) E; - } catch (...) { - while(--pDest >= m_pStart) - pDest->~E(); - free(m_pStart); - throw; - } -} - - -template -void Array::initialize(const E &x) -{ - E *pDest = m_pStart; - try { - for (; pDest < m_pStop; pDest++) - new(pDest) E(x); - } catch (...) { - while(--pDest >= m_pStart) - pDest->~E(); - free(m_pStart); - throw; - } -} - - -template -void Array::deconstruct() -{ - if (doDestruction((E*)0)) { - for (E *pDest = m_pStart; pDest < m_pStop; pDest++) - pDest->~E(); - } - free(m_pStart); -} - - -template -void Array::copy(const Array &array2) -{ - construct(array2.m_low, array2.m_high); - - if (m_pStart != 0) { - E *pSrc = array2.m_pStop; - E *pDest = m_pStop; - while(pDest > m_pStart) - //*--pDest = *--pSrc; - new (--pDest) E(*--pSrc); - } -} - - -// permutes array a from a[l] to a[r] randomly -template -void Array::permute (INDEX l, INDEX r) -{ - OGDF_ASSERT(low() <= l && l <= high()) - OGDF_ASSERT(low() <= r && r <= high()) - - E *pI = m_vpStart+l, *pStart = m_vpStart+l, *pStop = m_vpStart+r; - while(pI <= pStop) - std::swap(*pI++,*(pStart+randomNumber(0,r-l))); -} - - -// prints array a to output stream os using delimiter delim -template -void print(ostream &os, const Array &a, char delim = ' ') -{ - for (int i = a.low(); i <= a.high(); i++) { - if (i > a.low()) os << delim; - os << a[i]; - } -} - - -// output operator -template -ostream &operator<<(ostream &os, const ogdf::Array &a) -{ - print(os,a); - return os; -} - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Array2D.h b/ext/OGDF/ogdf/basic/Array2D.h deleted file mode 100644 index e751f40a9..000000000 --- a/ext/OGDF/ogdf/basic/Array2D.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of class Array2D which - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ARRAY2D_H -#define OGDF_ARRAY2D_H - - -#include -#include - - -namespace ogdf { - - -//! The parameterized class \a Array2D implements dynamic two-dimensional arrays. -/** - * @tparam E denotes the element type. - */ -template class Array2D -{ -public: - // constructors - - //! Creates a two-dimensional array with empty index set. - Array2D() { construct(0,-1,0,-1); } - - //! Creates a two-dimensional array with index set [\a a..\a b]*[\a c..\a d]. - Array2D(int a, int b, int c, int d) { - construct(a,b,c,d); initialize(); - } - - //! Creates a two-dimensional array with index set [\a a..\a b]*[\a c..\a d] and initailizes all elements with \a x. - Array2D(int a, int b, int c, int d, const E &x) { - construct(a,b,c,d); initialize(x); - } - - //! Creates a two-dimensional array that is a copy of \a A. - Array2D(const Array2D &array2) { - copy(array2); - } - - // destructor - ~Array2D() { - deconstruct(); - } - - //! Returns the minimal array index in dimension 1. - int low1() const { return m_a; } - - //! Returns the maximal array index in dimension 1. - int high1() const { return m_b; } - - //! Returns the minimal array index in dimension 2. - int low2() const { return m_c; } - - //! Returns the maximal array index in dimension 2. - int high2() const { return m_d; } - - //! Returns the size (number of elements) of the array. - int size() const { return size1() * size2(); } - - //! Returns the length of the index interval (number of entries) in dimension 1. - int size1() const { return m_b - m_a + 1; } - - //! Returns the length of the index interval (number of entries) in dimension 2. - int size2() const { return m_lenDim2; } - - //! Returns the determinant of the matrix - /*! \note use only for square matrices and floating point values */ - float det() const; - - //! Returns a reference to the element with index (\a i,\a j). - const E &operator()(int i, int j) const { - OGDF_ASSERT(m_a <= i && i <= m_b && m_c <= j && j <= m_d); - return m_vpStart[(i-m_a)*m_lenDim2+j]; - } - - //! Returns a reference to the element with index (\a i,\a j). - E &operator()(int i, int j) { - OGDF_ASSERT(m_a <= i && i <= m_b && m_c <= j && j <= m_d); - return m_vpStart[(i-m_a)*m_lenDim2+j]; - } - - //! Reinitializes the array to an array with empty index set. - void init() { init(0,-1,0,-1); } - - //! Reinitializes the array to an array with index set [\a a..\a b]*[\a c,\a d]. - void init(int a, int b, int c, int d) { - deconstruct(); - construct(a,b,c,d); - initialize(); - } - - //! Reinitializes the array to an array with index set [\a a..\a b]*[\a c,\a d] and initializes all entries with \a x. - void init(int a, int b, int c, int d, const E &x) { - deconstruct(); - construct(a,b,c,d); - initialize(x); - } - - //! Assignment operator. - Array2D &operator=(const Array2D &array2) { - deconstruct(); - copy(array2); - return *this; - } - - //! Sets all elements to \a x. - void fill(const E &x) { - E *pDest = m_pStop; - while(pDest > m_pStart) - *--pDest = x; - } - -private: - E *m_vpStart; //!< The virtual start of the array (address of A[0,0]). - int m_a; //!< The lowest index in dimension 1. - int m_lenDim2; //!< The number of elements in dimension 2. - E *m_pStart; //!< The real start of the array (address of A[low1,low2]). - E *m_pStop; //!< Successor of last element (address of A[high1,high2+1]). - int m_b; //!< The highest index in dimension 1. - int m_c; //!< The lowest index in dimension 2. - int m_d; //!< The highest index in dimension 2. - - void construct(int a, int b, int c, int d); - - void initialize(); - void initialize(const E &x); - - void deconstruct(); - - void copy(const Array2D &array2); - -}; - - - -template -void Array2D::construct(int a, int b, int c, int d) -{ - m_a = a; - m_b = b; - m_c = c; - m_d = d; - - int lenDim1 = b-a+1; - m_lenDim2 = d-c+1; - - if (lenDim1 < 1 || m_lenDim2 < 1) { - m_pStart = m_vpStart = m_pStop = 0; - - } else { - int len = lenDim1*m_lenDim2; - m_pStart = (E *)malloc(len*sizeof(E)); - if (m_pStart == 0) - OGDF_THROW(InsufficientMemoryException); - - m_vpStart = m_pStart - c; - m_pStop = m_pStart + len; - } -} - - -template -void Array2D::initialize() -{ - E *pDest = m_pStart; - try { - for (; pDest < m_pStop; pDest++) - new(pDest) E; - } catch (...) { - while(--pDest >= m_pStart) - pDest->~E(); - free(m_pStart); - throw; - } -} - - -template -void Array2D::initialize(const E &x) -{ - E *pDest = m_pStart; - try { - for (; pDest < m_pStop; pDest++) - new(pDest) E(x); - } catch (...) { - while(--pDest >= m_pStart) - pDest->~E(); - free(m_pStart); - throw; - } -} - - -template -void Array2D::deconstruct() -{ - if (doDestruction((E*)0)) { - for (E *pDest = m_pStart; pDest < m_pStop; pDest++) - pDest->~E(); - } - free(m_pStart); -} - - -template -void Array2D::copy(const Array2D &array2) -{ - construct(array2.m_a, array2.m_b, array2.m_c, array2.m_d); - - if (m_pStart != 0) { - E *pSrc = array2.m_pStop; - E *pDest = m_pStop; - while(pDest > m_pStart) - new (--pDest) E(*--pSrc); - } -} - - - -template -float Array2D::det() const -{ - int a = m_a; - int b = m_b; - int c = m_c; - int d = m_d; - int m = m_b - m_a + 1; - int n = m_lenDim2; - - int i, j; - int rem_i, rem_j, column; - - float determinant = 0.0; - - OGDF_ASSERT(m == n); - - switch(n) { - case 0: - break; - case 1: - determinant = (float)((*this)(a, c)); - break; - case 2: - determinant = (float)((*this)(a, c) * (*this)(b, d) - (*this)(a, d) * (*this)(b, c)); - break; - - // Expanding along the first row (Laplace's Formula) - default: - Array2D remMatrix(0, n-2, 0, n-2); // the remaining matrix - for(column = c; column <= d; column++) { - rem_i = 0; - rem_j = 0; - for(i = a; i <= b; i++) { - for(j = c; j <= d; j++) { - if(i != a && j != column) { - remMatrix(rem_i, rem_j) = (*this)(i, j); - if(rem_j < n-2) { - rem_j++; - } - else { - rem_i++; - rem_j = 0; - } - } - } - } - determinant += pow(-1.0,(a+column)) * (*this)(a,column) * remMatrix.det(); - } - } - - return determinant; -} - - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/ArrayBuffer.h b/ext/OGDF/ogdf/basic/ArrayBuffer.h deleted file mode 100644 index 730ecd923..000000000 --- a/ext/OGDF/ogdf/basic/ArrayBuffer.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of ArrayBuffer class. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ARRAY_BUFFER_H -#define OGDF_ARRAY_BUFFER_H - -#include - -namespace ogdf { - -//! An array that keeps track of the number of inserted elements; also usable as an efficient stack. -/** - * This is a growable array (with some initial size \a s) which starts out being empty. Using - * stack functions you can put elements into and out of it. The initial array size is automatically - * expanded if neccessary, but never automatically shrunken. You may also access the elements it - * contains using the []-operator. Tha valid indices are 0..(\a s - 1). - * - * @tparam E denotes the element type. - * @tparam INDEX denotes the index type. The index type must be chosen such that it can - * express the whole index range of the array instance, as well as its size. - * The default index type is \c int, other possible types are \c short and - * long long (on 64-bit systems). - */ -template -class ArrayBuffer : private Array { - INDEX num; //!< The number of elements in te buffer -public: - //! Constructs an empty ArrayBuffer, without initial memory allocation. - ArrayBuffer() : Array(), num(0) {} - //! Constructs an empty ArrayBuffer, allocating memory for up to \a size elements. - explicit ArrayBuffer(INDEX size) : Array(size), num(0) {} - - //! Reinitializes the array, clearing it, and without initial memory allocation. - void init() { Array::init(); } - //! Reinitializes the array, clearing it, and allocating memory for up to \a size elements. - void init(INDEX size) { Array::init(size); } - - //! Clears the buffer - void clear() { num = 0; } - - //! Returns the newest element of the buffer. - const E &top() const { OGDF_ASSERT(num>0); return Array::operator[](num-1); } - //! Returns the newest element of the buffer. - E &top() { OGDF_ASSERT(num>0); return Array::operator[](num-1); } - - //! Puts a new element in the buffer. - void push(E e) { - if(num == Array::size()) - Array::grow(max(num,1)); // double the size - Array::operator[](num++) = e; - } - - //! Removes the newest element from the buffer. - void pop() { OGDF_ASSERT(num>0); --num; } - //! Removes the newest element from the buffer and returns it. - E popRet() { OGDF_ASSERT(num>0); return Array::operator[](--num); } - - //! Returns true if the buffer is empty, false otherwise. - bool empty() const { return !num; } - - //! Returns number of elements in the buffer. - INDEX size() const { return num; } - - //! Returns a pointer to the first element. - E *begin() { return Array::begin(); } - - //! Returns a pointer to the first element. - const E *begin() const { return Array::begin(); } - - //! Returns a pointer to one past the last element. - E *end() { return Array::begin()+num; } - - //! Returns a pointer to one past the last element. - const E *end() const { return Array::begin()+num; } - - //! Returns a pointer to the last element. - E *rbegin() { return Array::begin()+(num-1); } - - //! Returns a pointer to the last element. - const E *rbegin() const { return Array::begin()+(num-1); } - - //! Returns a pointer to one before the first element. - E *rend() { return Array::rend(); } - - //! Returns a pointer to one before the first element. - const E *rend() const { return Array::rend(); } - - //! Returns a reference to the element at position \a i. - const E &operator[](INDEX i) const { - OGDF_ASSERT(0 <= i && i < num) - return Array::operator[](i); - } - //! Returns a reference to the element at position \a i. - E &operator[](INDEX i) { - OGDF_ASSERT(0 <= i && i < num) - return Array::operator[](i); - } - - //! Generates a compact copy holding the current elements. - /** - * Creates a copy of the ArrayBuffer and stores it into - * the given Array \a A. - * \a A has exactly the neccessary size to hold all - * elements in the buffer. - * - * This method uses an elementwise operator=. - * If you need a bitcopy of the buffer, use compactMemcpy() - * instead; if you need a traditional array copy (using the Array's - * copy-constructor) use compactCpyCon() instead. - */ - void compactCopy(Array& A2) const { - OGDF_ASSERT(this != &A2); - if(num) { - A2.init(num); - for(INDEX i = num; i-->0;) - A2[i] = (*this)[i]; - } else - A2.init(0); - } - - //! Generates a compact copy holding the current elements. - /** - * Creates a copy of the ArrayBuffer and stores it into - * the given Array \a A. - * \a A has exactly the neccessary size to hold all - * elements in the buffer - * - * This method uses the Array's copy constructur. If you - * need a bitcopy of the buffer, use compactMemcpy() - * instead; if you neeed a elementwise operator=-copy, use - * compactCopy() instead. - */ - void compactCpycon(Array& A2) const { - OGDF_ASSERT(this != &A2); - if(num) { - INDEX tmp = Array::m_high; // thank god i'm a friend of Array - Array::m_high = num-1; // fake smaller size - A2.copy(*this); // copy - Array::m_high = tmp; - } else - A2.init(0); - } - - //! Generates a compact copy holding the current elements. - /** - * Creates a copy of the ArrayBuffer and stores it into - * the given Array \a A. - * \a A has exactly the neccessary size to hold all - * elements in the buffer. - * - * This method uses memcpy. If you need a traditional - * arraycopy using a copy constructur, use compactCopy() - * instead; if you neeed a elementwise operator=-copy, use - * compactCopy() instead. - */ - void compactMemcpy(Array& A2) const { - OGDF_ASSERT(this != &A2); - if(num) { - A2.init(num); - memcpy(A2.m_pStart,this->m_pStart,sizeof(E)*num); - } else - A2.init(0); - } - - //! Performs a linear search for element \a x. - /** - * Warning: linear running time! - * Note that the linear search runs from back to front. - * \return the index of the found element, and low()-1 if not found. - */ - INDEX linearSearch (const E& x) const { - INDEX i; - for(i = num; i-->0;) - if(x == Array::m_vpStart[i]) break; - return i; - } - - //! Performs a linear search for element \a x with comparer \a comp. - /** - * Warning: linear running time! - * Note that the linear search runs from back to front. - * \return the index of the found element, and low()-1 if not found. - */ - template - INDEX linearSearch (const E& x, const COMPARER &comp) const { - INDEX i; - for(i = num; i-->0;) - if(comp.equal(x, Array::m_vpStart[i])) break; - return i; - } - - OGDF_NEW_DELETE -}; - -} //namespace - -#endif // OGDF_ARRAY_BUFFER_H diff --git a/ext/OGDF/ogdf/basic/Barrier.h b/ext/OGDF/ogdf/basic/Barrier.h deleted file mode 100644 index 0b66f5b06..000000000 --- a/ext/OGDF/ogdf/basic/Barrier.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of a thread barrier. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_THREAD_BARRIER_H -#define OGDF_THREAD_BARRIER_H - -#include - -#ifdef OGDF_SYSTEM_WINDOWS -#include -#else -#include -#endif - -namespace ogdf { - -#ifdef OGDF_SYSTEM_WINDOWS - -// if Windows >= Vista, Server 2008 -#if (_WIN32_WINNT >= 0x0600) - -//--------------------------------------------------------- -// Windows Vista (and above) Barrier implementation -//--------------------------------------------------------- - -class Barrier -{ -public: - inline Barrier(__uint32 numThreads) : m_threadCount(numThreads) - { - InitializeConditionVariable( &m_allThreadsReachedSync); - InitializeCriticalSection( &m_numThreadsReachedSyncLock); - m_numThreadsReachedSync = 0; - m_syncNumber = 0; - } - - ~Barrier() { } - - inline void threadSync() - { - EnterCriticalSection( &m_numThreadsReachedSyncLock); - __uint32 syncNr = m_syncNumber; - m_numThreadsReachedSync++; - if (m_numThreadsReachedSync == m_threadCount) - { - m_syncNumber++; - WakeAllConditionVariable( &m_allThreadsReachedSync); - m_numThreadsReachedSync = 0; - } - else - { - while (syncNr == m_syncNumber) - { - // Sleeping while waiting for the Condition Variable to signal, releases (leaves) the CriticalSection temporarily - SleepConditionVariableCS( &m_allThreadsReachedSync, &m_numThreadsReachedSyncLock, INFINITE); - } - // when awake, whe thread is again in the Critical Section - } - LeaveCriticalSection( &m_numThreadsReachedSyncLock); - } -private: - __uint32 m_threadCount; - CRITICAL_SECTION m_numThreadsReachedSyncLock; - CONDITION_VARIABLE m_allThreadsReachedSync; - __uint32 m_numThreadsReachedSync; - __uint32 m_syncNumber; -}; - -#else //(_WIN32_WINNT >= 0x0600) - -//--------------------------------------------------------- -// Windows XP (and below) Barrier implementation -//--------------------------------------------------------- - -//! Representation of a barrier. -/** - * A barrier is used for synchronizing threads. A barrier for a group of threads means - * that all threads in the group must have reached the barrier before any of the threads - * may proceed executing code after the barrier. - */ -class Barrier -{ -public: - inline Barrier(__uint32 numThreads) : m_threadCount(numThreads) - { - m_allThreadsReachedSync = CreateEvent( NULL, TRUE, FALSE, NULL ); - InitializeCriticalSection( &m_numThreadsReachedSyncLock); - m_numThreadsReachedSync = 0; - m_syncNumber = 0; - } - - ~Barrier() { } - - inline void threadSync() - { - EnterCriticalSection( &m_numThreadsReachedSyncLock); - __uint32 syncNr = m_syncNumber; - m_numThreadsReachedSync++; - if (m_numThreadsReachedSync == m_threadCount) - { - SetEvent(m_allThreadsReachedSync); - m_syncNumber++; - m_numThreadsReachedSync = 0; - LeaveCriticalSection( &m_numThreadsReachedSyncLock); - } - else - { - if ( (m_syncNumber == syncNr) && (m_numThreadsReachedSync == 1) ) - { - ResetEvent(m_allThreadsReachedSync); - } - while (m_syncNumber == syncNr) - { - LeaveCriticalSection( &m_numThreadsReachedSyncLock); - WaitForSingleObject(m_allThreadsReachedSync, 100); - EnterCriticalSection( &m_numThreadsReachedSyncLock); - } - LeaveCriticalSection( &m_numThreadsReachedSyncLock); - } - } -private: - __uint32 m_threadCount; - CRITICAL_SECTION m_numThreadsReachedSyncLock; - HANDLE m_allThreadsReachedSync; - __uint32 m_numThreadsReachedSync; - __uint32 m_syncNumber; -}; - -#endif //(_WIN32_WINNT >= 0x0600) -#else //OGDF_SYSTEM_WINDOWS - - -#ifndef OGDF_PTHREAD_BARRRIER - -//--------------------------------------------------------- -// pthread implementation without using pthread's barrier -//--------------------------------------------------------- - -class Barrier -{ -public: - inline Barrier(__uint32 numThreads) : m_threadCount(numThreads) - { - pthread_cond_init( &m_allThreadsReachedSync, NULL); - pthread_mutex_init( &m_numThreadsReachedSyncLock, NULL); - m_numThreadsReachedSync = 0; - m_syncNumber = 0; - } - - ~Barrier() - { - pthread_cond_destroy( &m_allThreadsReachedSync); - pthread_mutex_destroy( &m_numThreadsReachedSyncLock); - } - - inline void threadSync() - { - pthread_mutex_lock( &m_numThreadsReachedSyncLock); - __uint32 syncNr = m_syncNumber; - m_numThreadsReachedSync++; - if (m_numThreadsReachedSync == m_threadCount) - { - m_syncNumber++; - pthread_cond_signal( &m_allThreadsReachedSync); - m_numThreadsReachedSync = 0; - } - else - { - while (syncNr == m_syncNumber) - pthread_cond_wait( &m_allThreadsReachedSync, &m_numThreadsReachedSyncLock); - } - pthread_mutex_unlock( &m_numThreadsReachedSyncLock); - } -private: - __uint32 m_threadCount; - pthread_mutex_t m_numThreadsReachedSyncLock; - pthread_cond_t m_allThreadsReachedSync; - __uint32 m_numThreadsReachedSync; - __uint32 m_syncNumber; -}; -#else - -//--------------------------------------------------------- -// pthread barrier implementation -//--------------------------------------------------------- - -class Barrier -{ -public: - inline Barrier(__uint32 numThreads) : m_threadCount(numThreads) - { - pthread_barrier_init(&m_barrier, NULL, m_threadCount); - } - - ~Barrier() - { - pthread_barrier_destroy(&m_barrier); - } - - inline void threadSync() - { - pthread_barrier_wait(&m_barrier); - } -private: - pthread_barrier_t m_barrier; - __uint32 m_threadCount; -}; -#endif - -#endif //OGDF_SYSTEM_UNIX - -} // end of namespace ogdf - -#endif //OGDF_THREAD_BARRIER_H diff --git a/ext/OGDF/ogdf/basic/BinaryHeap.h b/ext/OGDF/ogdf/basic/BinaryHeap.h deleted file mode 100644 index 61a907d6b..000000000 --- a/ext/OGDF/ogdf/basic/BinaryHeap.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of binary heap class that allows the - * decreaseKey operation. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BINARY_HEAP_H -#define OGDF_BINARY_HEAP_H - -#include - -namespace ogdf { - - - -// using min heaps -template -class OGDF_EXPORT BinaryHeap { - -public: - - class Element { - - friend class BinaryHeap; - - private: - Priority priority; - X elem; - INDEX backIdx ; // the position in element array - - // empty constructor - Element() { } - - // construct element with object and priority - Element(X x, Priority prior) : priority(prior), elem(x) { } - - //copy constructor - Element(const Element &origElem): priority(origElem.priority), elem(origElem.elem), backIdx(origElem.backIdx) { } - - public: - - //return the priority - Priority getPriority() const { return priority; } - - // return reference to elem - const X &getElement() const { return elem; } - - // return the position of this element in the heap array - INDEX getPos() const { return backIdx; } - }; - - - //! construct a binary heap with capacity c - BinaryHeap(INDEX c) : data(1, c, 0), s(0) { } - - //! destructor - ~BinaryHeap() { - for (INDEX i = 1; i <= s; ++i) { - delete data[i]; - data[i] = 0; - } - } - - //! return true if heap is empty - bool empty() const { return s == 0; } - - //! return the number of elements in the heap - INDEX size() const { return s; } - - - - //! decrease the priority of elem - void decPriority(const Element &elem, // handle to the element - Priority prior // new priority, must be smaller then the old value - ) { - INDEX i = elem.backIdx; - - OGDF_ASSERT(i <= s); - - if (data[i]->getPriority() < prior) - throw "New key is greater than current key."; - - data[i]->priority = prior; - while (i > 1 && (data[getParent(i)]->getPriority() > data[i]->getPriority()) ) { - swap(i, getParent(i)); - i = getParent(i); - } - } - - //! insert elem and return a handle - const Element & insert(X obj, Priority prior) { - Element *h_elem = new Element (obj, prior); - ++s; - if (s == capacity()) - data.grow(capacity(), 0); // double the size - h_elem->backIdx = s; // store the position - data[s] = h_elem; - INDEX i = s; - while ( (i > 1) && ( data[getParent(i)]->getPriority() > data[i]->getPriority()) ) { - swap(i, getParent(i)); - i = getParent(i); - } - return *h_elem; - } - - //! ! insert elem and return a handle [same as insert] - const Element & push(X obj, Priority prior) { - return insert(obj, prior); - } - - //! return the Object with the min. score - const X & getMin() const { - return data[1]->getElement(); - } - - //! return the Object with the min. score [same as getMin] - const X & top() const { - return getMin(); - } - - //! return the smallest element and remove it from heap - X extractMin() { - if (empty()) - throw "Heap underflow error!"; - - Element copy = *data[1]; - Element *p = data[1]; - swap(1, s); - --s; - delete p; - minHeapify(1); - data[s+1] = 0; - return copy.getElement(); - } - - //! return the smallest element and remove it from heap [same as extractMin] - X pop() { - return extractMin(); - } - - //! empty the heap - void clear() { - for (INDEX i = 1; i <= s; ++i) { - delete data[i]; - data[i] = 0; - } - s = 0; - } - - //! obtain const references to the element at index \a idx (the smallest heap array index is 0.). - const X & operator[](INDEX idx) const { - return data[idx+1]->getElement(); - } - - - private : - - Array data; // heap array starts at index 1 - INDEX s; // current number of elements - - //! return current capacity of the heap - INDEX capacity() const { return data.size(); } - - void swap(INDEX pos1, INDEX pos2) { - Element *tmp = data[pos1]; - data[pos1] = data[pos2]; - data[pos2] = tmp; - // update the position - data[pos2]->backIdx = pos2; - data[pos1]->backIdx = pos1; - } - - - - void minHeapify(INDEX pos) { - INDEX l = getLeft(pos); - INDEX r = getRight(pos); - INDEX smallest; - if (l <= size() && data[l]->getPriority() < data[pos]->getPriority() ) - smallest = l; - else - smallest = pos; - if (r <= size() && data[r]->getPriority() < data[smallest]->getPriority()) - smallest = r; - if (smallest != pos) { - swap(pos, smallest); - minHeapify(smallest); - } - } - - - INDEX getParent(INDEX pos) const {return pos/2;} - - INDEX getLeft(INDEX pos) const {return pos*2;} - - INDEX getRight(INDEX pos) const {return pos*2+1;} - -}; - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/BinaryHeap2.h b/ext/OGDF/ogdf/basic/BinaryHeap2.h deleted file mode 100644 index ec0202398..000000000 --- a/ext/OGDF/ogdf/basic/BinaryHeap2.h +++ /dev/null @@ -1,526 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of binary heap class that allows the - * decreaseKey operation. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BINARY_HEAP2_H -#define OGDF_BINARY_HEAP2_H - -#include - -namespace ogdf { - -/** - * \brief Min-heap priority queue realized by a data array. - * - * Heaps store objects that are weighted with costs; - * the minimal cost object is accessible over - * member function minRet() and extracted by extractMin(). - * - * The class uses two template parameters: - * - \a key is the key type. - * - \a HeapElement is the type of the elements that are stored. - * - * HeapObjects can be all types with copy constructor, - * as copies of inserted elements are created; - * \a key should be of a type with compare operators. - * We only allow integer as index/size type; the array index starts with 1. - * - * To allow direct access to the underlying array structure - * in order to minimize decreaseKey() runningtime, - * a pointer to an integer storage can be provided as input() - * parameter that will be kept updated with the index position - * during heap operations. - * - *

Running Time

- * The worst case running times of the methods is given by the following - * table, where \a n is the current number of elements. - * - * - * - * - * - * - * - * - * - *
methodworst-caseamortized - *
extractMin()O(n)O(lg(\a n)) - *
siftDown()O(lg(\a n)) - *
siftUp()O(lg(\a n)) - *
minRet()O(1) - *
insert()O(\a n)O(lg(\a n)) - *
- */ - - -//to allow directobject adress, a pointer to an integer storage -//can be provided, where the array index is updated by the -//heap class - - -template -class BinaryHeap2 : public HeapBase -{ -public: - //! Creates a binary heap. - BinaryHeap2(int startSize = 128); - - //copy Constructor, todo - //BinaryHeap2(const BinaryHeap2& source); - - // Destructor, deletes the heap array. - virtual ~BinaryHeap2() { - if (m_heapArray) delete[] m_heapArray; - }//destructor - - - //! Assignment operator. - const BinaryHeap2& operator=(const BinaryHeap2& rhs); - - //------------------------------------------------------------ - //modification: - - //! Inserts a new element \a obj with priority \a p and pointer for index update. - void insert(HeapObject& obj, key& p, int* keyUpdate = 0); - - //! Obtains heap property, only needed if the elements are not inserted by insert method. - virtual void makeHeap(); - //delete - //it is not clear how a delete without explicit - //given heapentry pointer should behave, e.g. if equal values - //for objects are allowed - - //! Returns minimum priority element and removes it from the heap. - // arraySize is decreased if size < 1/3arraySize (amortized runtime O(1)) - HeapObject extractMin(); - - //! Decreases priority of an object that is addressed by \a index. - // use updated m_foreign position index to address entry for decreasekey - virtual void decreaseKey(int index, key priority); - //TODO: version mit Aenderungswert statt absolutem Wert - - //-------------------------------------------------------------- - //const access functions - - //! Returns minimum priority element. - HeapObject minRet() const {return m_heapArray[1].m_object;} - - key getPriority(int index) const - { - OGDF_ASSERT( (index > 0) && (index <= HeapBase::m_size) ); - return m_heapArray[index].m_priority; - }//getPriority - - //! Returns the current size. - int capacity() const { return m_arraySize; } - - //! Returns the number of stored elements. - int size() const { return HeapBase::m_size; } - - //! Returns true iff the heap is empty. - int empty() const { return HeapBase::empty(); } - - //! Reinitializes the data structure. - /** - * Deletes the array and reallocates it with size that was passed at - * construction time. - */ - void clear(); - -protected: - //! Establishes heap property by moving element up in heap if necessary. - void siftUp(int pos); - - //! Establishes heap property by moving element down in heap if necessary. - void siftDown(int pos); - - //---------------------------------------------------------- - //modelling the binary tree structure on the data array - //array position 0 is left empty, positions are from 1..m_size - //! Array index of parent node. - int parentIndex(int num) - { - OGDF_ASSERT(num>0); - return num/2; - }//parent - - //! Array index of left child. - int leftChildIndex(int num) - { - OGDF_ASSERT(num>0); - return 2*num; - }//leftChild - - //! Array index of right child. - int rightChildIndex(int num) - { - OGDF_ASSERT(num>0); - return 2*num+1; - }//rightChild - - //! Returns true if left child exists. - bool hasLeft(int num) - { - OGDF_ASSERT(num>0); - return (leftChildIndex(num) <= HeapBase::m_size); - } - - //! Returns true if right child exists. - bool hasRight(int num) - { - OGDF_ASSERT(num>0); - return (rightChildIndex(num) <= HeapBase::m_size); - } - - //---------------------------------------------------------- - //helper functions for internal maintainance - int arrayBound(int arraySize) {return arraySize+1;} - int higherArrayBound(int arraySize) {return 2*arraySize+1;} - int higherArraySize(int arraySize) {return 2*arraySize;} - int lowerArrayBound(int arraySize) {return arraySize/2+1;} - int lowerArraySize(int arraySize) {return arraySize/2;} - - void init(int initSize); - -private: - //holding object and priority key - struct HeapEntry - { - key m_priority; - HeapObject m_object; - - //we maintain positions during operations - int m_pos; - int* m_foreignPos; //storage structure given by user - - //! Initializes HeapEntry object. - HeapEntry() {m_priority = 0; - m_pos = 0; - m_foreignPos = 0; - } - - //! Initializes HeapEntry object with priority. - /** - * @param k ist the priority. - * @param ob is the corresponding HeapObject. - */ - HeapEntry(key k, const HeapObject& ob) {m_priority = k; m_object = ob; - m_foreignPos = 0; - //m_pos = ob.m_pos; - } - - //! Initializes HaepEntry object with priority. - /** - * @param k ist the priority. - * @param ob is the corresponding HeapObject. - * @param pos is the position of the object within the array. - * @param fp is a pointer to the index. - */ - HeapEntry(key k, const HeapObject& ob, int pos, int* fp) - { - m_priority = k; - m_object = ob; - if (fp == 0) m_foreignPos = 0; - else m_foreignPos = fp; - m_pos = pos; - } - }; - - HeapEntry* m_heapArray; //dynamically maintained array of heapentries - - //in addition to m_size, the inherited number of objects from class HeapBase, - //we store the actual size of the array, valid array object positions - //are from 1 to m_size - int m_arraySize; //current size of the heap - - int m_startSize; //(decide: optionally??) used to check reallocation bound - -};//BinaryHeap2 - - - -//************************************************************** -//implementation -//************************************************************** - - -//************************************************************** -//constructor and initialization -template -BinaryHeap2::BinaryHeap2(int startSize) -: HeapBase() -{ - init(startSize); -}//constructor - - -template -void BinaryHeap2::init(int initSize) -{ - //create an array of HeapEntry Elements - m_arraySize = initSize; - m_heapArray = new HeapEntry[arrayBound(m_arraySize)]; //start at 1 - - m_startSize = initSize; - - HeapBase::m_size = 0; -} - - -template -void BinaryHeap2::clear() -{ - if (m_heapArray) delete[] m_heapArray; - init(m_startSize); -} - - -//************************************************************** -//element shifting operations -//restore heap property by finding correct position for object -//at position pos on higher levels, pos is given as array index (1..m_size) -//updates array index values -template -void BinaryHeap2::siftUp(int pos) -{ - OGDF_ASSERT( (pos > 0) && (pos <= HeapBase::m_size) ) - - if (pos == 1) - { - m_heapArray[1].m_pos = 1; - if (m_heapArray[1].m_foreignPos != 0) //address is defined - *(m_heapArray[1].m_foreignPos) = 1; - return;//nothing to do - } - - HeapEntry tempEntry = m_heapArray[pos]; - int run = pos; - while ( (parentIndex(run) >= 1) && - (m_heapArray[parentIndex(run)].m_priority > tempEntry.m_priority) ) - { - m_heapArray[run] = m_heapArray[parentIndex(run)]; - if (m_heapArray[run].m_foreignPos != 0) *(m_heapArray[run].m_foreignPos) = run; - run = parentIndex(run); - }//while - - m_heapArray[run] = tempEntry; - m_heapArray[run].m_pos = run; - if (m_heapArray[run].m_foreignPos != 0) *(m_heapArray[run].m_foreignPos) = run; - - -}//siftup - - -//restore heap property by finding correct position for object -//at position pos on lower levels, updates array index values -template -void BinaryHeap2::siftDown(int pos) -{ - OGDF_ASSERT( (pos > 0) && (pos <= HeapBase::m_size) ); - - if (pos >= int(HeapBase::m_size/2)+1) - { - m_heapArray[pos].m_pos = pos; - if (m_heapArray[pos].m_foreignPos != 0) *(m_heapArray[pos].m_foreignPos) = pos; - return; //leafs cant move down - }//if leaf - - key sPrio = getPriority(pos); - int sIndex = pos; - - if (hasLeft(pos) && (getPriority(leftChildIndex(pos)) < sPrio) ) - { - sIndex = leftChildIndex(pos); - sPrio = getPriority(leftChildIndex(pos)); - }//if left child smaller - if (hasRight(pos) && (getPriority(rightChildIndex(pos)) < sPrio) ) - { - sIndex = rightChildIndex(pos); - sPrio = getPriority(rightChildIndex(pos)); - }//if right child smaller - - if (sIndex != pos) - { - HeapEntry tempEntry = m_heapArray[pos]; - m_heapArray[pos] = m_heapArray[sIndex]; - m_heapArray[sIndex] = tempEntry; - - //update both index entries - m_heapArray[pos].m_pos = pos; - if (m_heapArray[pos].m_foreignPos != 0) *(m_heapArray[pos].m_foreignPos) = pos; - m_heapArray[sIndex].m_pos = sIndex; - if (m_heapArray[sIndex].m_foreignPos != 0) *(m_heapArray[sIndex].m_foreignPos) = sIndex; - - siftDown(sIndex); //TODO: dont use recursion - }//if sift necessary - else //update in case of new elements (non-insert) - { - m_heapArray[pos].m_pos = pos; - if (m_heapArray[pos].m_foreignPos != 0) *(m_heapArray[pos].m_foreignPos) = pos; - }//else -}//siftdown - - -template -void BinaryHeap2::makeHeap() -{ - //only needed if insertion is not done over insert - //(if we allow array parameter in constructor) - for (int i=HeapBase::m_size/2; i > 0; i--) - siftDown(i); -}//makeheap - - -template -void BinaryHeap2::decreaseKey(int index, key priority) -{ - HeapEntry& he = m_heapArray[index]; - - //check if error value - if (he.m_priority < priority) OGDF_THROW_PARAM(AlgorithmFailureException, afcIllegalParameter); - - he.m_priority = priority; - siftUp(index); - -}//decreaseKey - - -//extract the minimum priority object and reallocate array if size < 1/3 arraysize -template -HeapObject BinaryHeap2::extractMin() -{ - OGDF_ASSERT((!HeapBase::empty())); - - HeapEntry tempEntry = m_heapArray[1]; //save minimum object - - HeapBase::m_size--; - - if (HeapBase::m_size > 0) - { - m_heapArray[1] = m_heapArray[HeapBase::m_size+1]; //old last leaf - - //check if reallocation is possible - if ((HeapBase::m_size < (m_arraySize/3)) && (m_arraySize > 2*m_startSize-1)) - { - HeapEntry* tempHeap = new HeapEntry[lowerArrayBound(m_arraySize)]; - for (int i = 1; i <= HeapBase::m_size ; i++) - tempHeap[i] = m_heapArray[i]; - delete[] m_heapArray; - m_heapArray = tempHeap; - m_arraySize = lowerArraySize(m_arraySize); - - }//if small enough - - //restore tree by sifting down old leaf - siftDown(1); - }//if not empty - - return tempEntry.m_object; - -}//extractMin - - -//place a copy of the given input element in the queue, doubles -//array size if necessary -template -void BinaryHeap2::insert(HeapObject& ho, key& priority, int* keyUpdate) -{ - OGDF_ASSERT((HeapBase::m_size) < m_arraySize); - HeapBase::m_size++; - //check if the array size has to be adjusted - if (HeapBase::m_size == m_arraySize) - { - HeapEntry* tempHeap = new HeapEntry[higherArrayBound(m_arraySize)]; - for (int i = 1; i <= m_arraySize ; i++) //last one is not occupied yet - tempHeap[i] = m_heapArray[i]; - delete[] m_heapArray; - m_heapArray = tempHeap; - m_arraySize = higherArraySize(m_arraySize); - - }//if array full - - //now insert object and reestablish heap property - m_heapArray[HeapBase::m_size] = HeapEntry(priority, ho, HeapBase::m_size, keyUpdate); - - siftUp(HeapBase::m_size); - -}//insert - - - -template -const BinaryHeap2& BinaryHeap2::operator=(const BinaryHeap2& rhs) -{ - if (this != &rhs) - { - if (m_heapArray && !(m_arraySize == rhs.m_arraySize)) - { - delete[] m_heapArray; - m_heapArray = 0; - }//if - - if (!m_heapArray) - m_heapArray = new HeapEntry[arrayBound(rhs.m_arraySize)]; //start at 1 - - OGDF_ASSERT(m_heapArray); - - HeapBase::m_size = rhs.m_size; - - m_startSize = rhs.m_startSize; - m_arraySize = rhs.m_arraySize; - - for (int i = 1; i <= HeapBase::m_size ; i++) - m_heapArray[i] = rhs.m_heapArray[i]; - - }//if not self - return *this; -} - - - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/BoundedQueue.h b/ext/OGDF/ogdf/basic/BoundedQueue.h deleted file mode 100644 index 4d4a5f25f..000000000 --- a/ext/OGDF/ogdf/basic/BoundedQueue.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of bounded queue class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_B_QUEUE_H -#define OGDF_B_QUEUE_H - - -#include - - -namespace ogdf { - -template class BoundedQueue; - -// output -template -void print(ostream &os, const BoundedQueue &S, char delim = ' '); - - -//! The parameterized class \a BoundedQueue implements queues with bounded size. -/** - * @tparam E is the element type. - * @tparam INDEX is the index type. The default index type is \c int, other possible types - * are \c short and long long (on 64-bit systems). - */ -template class BoundedQueue { - - E *m_pStart; //! Pointer to first element of current sequence. - E *m_pEnd; //! Pointer to one past last element of current sequence. - E *m_pStop; //! Pointer to one past last element of total array. - E *m_pFirst; //! Pointer to first element of total array. - -public: - //! Constructs an empty bounded queue for at most \a n elements. - explicit BoundedQueue(INDEX n) { - OGDF_ASSERT(n >= 1) - m_pStart = m_pEnd = m_pFirst = new E[n+1]; - if (m_pFirst == 0) OGDF_THROW(InsufficientMemoryException); - - m_pStop = m_pFirst+n+1; - } - - //! Constructs a bounded queue that is a copy of \a Q. - BoundedQueue(const BoundedQueue &Q) { - copy(Q); - } - - // destruction - ~BoundedQueue() { delete [] m_pFirst; } - - //! Returns front element. - const E &top() const { - OGDF_ASSERT(m_pStart != m_pEnd) - return *m_pStart; - } - - //! Returns front element. - E &top() { - OGDF_ASSERT(m_pStart != m_pEnd) - return *m_pStart; - } - - //! Returns back element. - const E &bottom() const { - OGDF_ASSERT(m_pStart != m_pEnd) - if (m_pEnd == m_pFirst) return *(m_pStop-1); - else return *(m_pEnd-1); - } - - //! Returns back element. - E &bottom() { - OGDF_ASSERT(m_pStart != m_pEnd) - if (m_pEnd == m_pFirst) return *(m_pStop-1); - else return *(m_pEnd-1); - } - - //! Returns current size of the queue. - INDEX size() const { - return (m_pEnd >= m_pStart) ? - (m_pEnd - m_pStart) : - (m_pEnd-m_pFirst)+(m_pStop-m_pStart); - } - - //! Returns the capacity of the bounded queue. - INDEX capacity() const { return (m_pStop - m_pFirst)-1; } - - //! Returns true iff the queue is empty. - bool empty() { return m_pStart == m_pEnd; } - - //! Returns true iff the queue is full. - bool full() { - INDEX h = m_pEnd-m_pStart - return ( h>=0 ) ? - (h == m_pStop-m_pFirst-1) : - (h == -1); - } - - //! Assignment operator. - BoundedQueue &operator=(const BoundedQueue &Q) { - delete [] m_pFirst; - copy(Q); - return *this; - } - - //! Adds \a x at the end of queue. - void append(const E &x) { - *m_pEnd++ = x; - if (m_pEnd == m_pStop) m_pEnd = m_pFirst; - OGDF_ASSERT(m_pStart != m_pEnd) - } - - //! Removes front element and returns it. - E pop() { - OGDF_ASSERT(m_pStart != m_pEnd) - E x = *m_pStart++; - if (m_pStart == m_pStop) m_pStart = m_pFirst; - return x; - } - - //! Makes the queue empty. - void clear() { m_pStart = m_pEnd = m_pFirst; } - - //! Prints the queue to output stream \a os. - void print(ostream &os, char delim = ' ') const - { - for (const E *pX = m_pStart; pX != m_pEnd; ) { - if (pX != m_pStart) os << delim; - os << *pX; - if (++pX == m_pStop) pX = m_pFirst; - } - } - -private: - void copy(const BoundedQueue &Q) { - int n = Q.size()+1; - m_pEnd = m_pStart = m_pFirst = new E[n]; - if (m_pFirst == 0) OGDF_THROW(InsufficientMemoryException); - - m_pStop = m_pStart + n; - for (E *pX = Q.m_pStart; pX != Q.m_pEnd; ) { - *m_pEnd++ = *pX++; - if (pX == Q.m_pStop) pX = Q.m_pFirst; - } - } -}; // class BoundedQueue - - - -// output operator -template -ostream &operator<<(ostream &os, const BoundedQueue &Q) -{ - Q.print(os); - return os; -} - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/BoundedStack.h b/ext/OGDF/ogdf/basic/BoundedStack.h deleted file mode 100644 index a10b0088f..000000000 --- a/ext/OGDF/ogdf/basic/BoundedStack.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of bounded stack class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_B_STACK_H -#define OGDF_B_STACK_H - - -#include - - -namespace ogdf { - -template class BoundedStack; - -// output -template -void print(ostream &os, const BoundedStack &S, char delim = ' '); - - -//! The parameterized class \a BoundedStack implements stacks with bounded size. -/** - * @tparam E is the element type. - * @tparam INDEX is the index type. The default index type is \c int, other possible types - * are \c short and long long (on 64-bit systems). - */ -template class BoundedStack { - - E *m_pTop; //!< Pointer to top element. - E *m_pStart; //!< Pointer to first element. - E *m_pStop; //!< Pointer to one past last element. - -public: - //! Constructs an empty bounded stack for no elements at all. - /** - * The default constructor does not allocate any space for elements; before - * using the stack, it is required to initialize the stack with init(). - */ - BoundedStack() { - m_pTop = m_pStart = m_pStop = 0; - } - - //! Constructs an empty bounded stack for at most \a n elements. - explicit BoundedStack(INDEX n) { - OGDF_ASSERT(n >= 1) - m_pStart = new E[n]; - if (m_pStart == 0) OGDF_THROW(InsufficientMemoryException); - m_pTop = m_pStart - 1; - m_pStop = m_pStart+n; - } - - //! Constructs a bounded stack that is a copy of \a S. - BoundedStack(const BoundedStack &S) { - copy(S); - } - - // destruction - ~BoundedStack() { - delete [] m_pStart; - } - - //! Returns top element. - const E &top() const { - OGDF_ASSERT(m_pTop != m_pStart-1) - return *m_pTop; - } - - //! Returns top element. - E &top() { - OGDF_ASSERT(m_pTop != m_pStart-1) - return *m_pTop; - } - - //! Returns current size of the stack. - INDEX size() const { return m_pTop - (m_pStart-1); } - - //! Returns true iff the stack is empty. - bool empty() { return m_pTop == (m_pStart-1); } - - //! Returns true iff the stack is full. - bool full() { return m_pTop == (m_pStop-1); } - - //! Returns true iff the stack was initialized. - bool valid() const { return m_pStart != 0; } - - //! Returns the capacity of the bounded stack. - INDEX capacity() const { return m_pStop - m_pStart; } - - //! Reinitializes the stack for no elements at all (actually frees memory). - void init() { - delete [] m_pStart; - m_pTop = m_pStart = m_pStart = 0; - } - - //! Reinitializes the stack for \a n elements. - void init(INDEX n) { - OGDF_ASSERT(n >= 1) - - delete [] m_pStart; - - m_pStart = new E[n]; - if (m_pStart == 0) OGDF_THROW(InsufficientMemoryException); - m_pTop = m_pStart - 1; - m_pStop = m_pStart+n; - } - - //! Assignment operator. - BoundedStack &operator=(const BoundedStack &S) { - delete [] m_pStart; - copy(S); - return *this; - } - - //! Adds element \a x as top-most element to the stack. - void push(const E &x) { - OGDF_ASSERT(m_pTop != m_pStop-1) - *++m_pTop = x; - } - - //! Removes the top-most element from the stack and returns it. - E pop() { - OGDF_ASSERT(m_pTop != (m_pStart-1)) - return *m_pTop--; - } - - //! Makes the stack empty. - void clear() { m_pTop = m_pStart-1; } - - //! Prints the stack to output stream \a os. - void print(ostream &os, char delim = ' ') const - { - for (const E *pX = m_pStart; pX != m_pTop; ) - os << *++pX << delim; - } - -private: - void copy(const BoundedStack &S) - { - if(!S.valid()) { - m_pTop = m_pStart = m_pStop = 0; - } else { - INDEX sz = S.m_pStop - S.m_pStart; - m_pStart = new E[sz+1]; - if (m_pStart == 0) OGDF_THROW(InsufficientMemoryException); - m_pStop = m_pStart + sz; - m_pTop = m_pStart-1; - for (E *pX = S.m_pStart-1; pX != S.m_pTop; ) - *++m_pTop = *++pX; - } - } -}; // class BoundedStack - - - -// output operator -template -ostream &operator<<(ostream &os, const BoundedStack &S) -{ - S.print(os); - return os; -} - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/CombinatorialEmbedding.h b/ext/OGDF/ogdf/basic/CombinatorialEmbedding.h deleted file mode 100644 index 671691b36..000000000 --- a/ext/OGDF/ogdf/basic/CombinatorialEmbedding.h +++ /dev/null @@ -1,484 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of CombinatorialEmbedding and face. - * - * Enriches graph by the notion of faces - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_COMBINATORIAL_EMBEDDING_H -#define OGDF_COMBINATORIAL_EMBEDDING_H - - -#include - - -namespace ogdf { - -class OGDF_EXPORT ConstCombinatorialEmbedding; - -typedef FaceElement *face; - -/** - * \brief Faces in a combinatorial embedding. - */ -class OGDF_EXPORT FaceElement : private GraphElement -{ - friend class ConstCombinatorialEmbedding; - friend class CombinatorialEmbedding; - friend class GraphList; - - adjEntry m_adjFirst; //!< The first adjacency element in the face. - int m_id; //!< The index of the face. - int m_size; //!< The size of the face. - -#ifdef OGDF_DEBUG - const ConstCombinatorialEmbedding *m_pEmbedding; -#endif - - // constructor -#ifdef OGDF_DEBUG - FaceElement(const ConstCombinatorialEmbedding *pEmbedding, - adjEntry adjFirst, - int id) : - m_adjFirst(adjFirst), m_id(id), m_size(0), m_pEmbedding(pEmbedding) { } -#else - //! Creates a face with given first adjacency element \a adjFirst and face index \a id. - FaceElement(adjEntry adjFirst, int id) : - m_adjFirst(adjFirst), m_id(id), m_size(0) { } -#endif - -public: - //! Returns the index of the face. - int index() const { return m_id; } - - //! Returns the first adjacency element in the face. - adjEntry firstAdj() const { return m_adjFirst; } - - //! Returns the size of the face, i.e., the number of edges in the face. - int size() const { return m_size; } - - //! Returns the successor in the list of all faces. - face succ() const { return (face)m_next; } - - //! Returns the predecessor in the list of all faces. - face pred() const { return (face)m_prev; } - - //! Returns the successor of \a adj in the list of all adjacency elements in the face. - adjEntry nextFaceEdge(adjEntry adj) const { - adj = adj->faceCycleSucc(); - return (adj != m_adjFirst) ? adj : 0; - } - -#ifdef OGDF_DEBUG - const ConstCombinatorialEmbedding *embeddingOf() const { return m_pEmbedding; } -#endif - - OGDF_NEW_DELETE -}; // class FaceElement - - -class FaceArrayBase; -templateclass FaceArray; - - -/** - * \brief Combinatorial embeddings of planar graphs. - * - * Maintains a combinatorial embedding of an embedded graph, i.e., the set of - * faces. A combinatorial embedding is defined by the (cyclic) order of the - * adjacency entries around a vertex; more precisely, the adjacency list - * gives the cyclic order of the adjacency entries in clockwise order. - * Each adjacency entry \a adj is contained in exactly one face, the face - * to the right of \a adj. The list of adjacency entries defining a face is given - * in clockwise order for internal faces, and in counter-clockwise order for the - * external face. - * - * \see CombinatorialEmbedding provides additional functionality for modifying - * the embedding. - */ -class OGDF_EXPORT ConstCombinatorialEmbedding -{ -protected: - const Graph *m_cpGraph; //!< The associated graph. - - GraphList m_faces; //!< The list of all faces. - int m_nFaces; //!< The number of faces. - int m_faceIdCount; //!< The index assigned to the next created face. - int m_faceArrayTableSize; //!< The current table size of face arrays. - - AdjEntryArray m_rightFace; //!< The face to which an adjacency entry belongs. - face m_externalFace; //! The external face. - - mutable ListPure m_regFaceArrays; //!< The registered face arrays. - -public: - /** @{ - * \brief Creates a combinatorial embedding associated with no graph. - */ - ConstCombinatorialEmbedding(); - - /** - * \brief Creates a combinatorial embedding of graph \a G. - * - * \pre Graph \a G must be embedded, i.e., the adjacency lists of its nodes - * must define an embedding. - */ - explicit ConstCombinatorialEmbedding(const Graph &G); - - - //! Copy constructor. - ConstCombinatorialEmbedding(const ConstCombinatorialEmbedding &C); - - //! Assignment operator. - ConstCombinatorialEmbedding &operator=(const ConstCombinatorialEmbedding &C); - - /** @} @{ - * \brief Returns the associated graph of the combinatorial embedding. - */ - const Graph &getGraph() const { return *m_cpGraph; } - - //! Returns associated graph - operator const Graph &() const { return *m_cpGraph; } - - /** @} @{ - * \brief Returns the first face in the list of all faces. - */ - face firstFace() const { return m_faces.begin(); } - - //! Returns the last face in the list of all faces. - face lastFace() const { return m_faces.rbegin(); } - - //! Returns the number of faces. - int numberOfFaces() const { return m_nFaces; } - - /** @} @{ - * \brief Returns the face to the right of \a adj, i.e., the face containing \a adj. - * @param adj is an adjecency element in the associated graph. - */ - face rightFace(adjEntry adj) const { return m_rightFace[adj]; } - - /** - * \brief Returns the face to the left of \a adj, i.e., the face containing the twin of \a adj. - * @param adj is an adjacency element in the associated graph. - */ - face leftFace(adjEntry adj) const { return m_rightFace[adj->twin()]; } - - /** @} @{ - * \brief Returns the largest used face index. - */ - int maxFaceIndex() const { return m_faceIdCount-1; } - - //! Returns the table size of face arrays associated with this embedding. - int faceArrayTableSize() const { return m_faceArrayTableSize; } - - /** @} @{ - * \brief Returns a random face. - */ - face chooseFace() const; - - //! Returns a face of maximal size. - face maximalFace() const; - - /** @} @{ - * \brief Returns the external face. - */ - face externalFace() const { - return m_externalFace; - } - - /** - * \brief Sets the external face to \a f. - * @param f is a face in this embedding. - */ - void setExternalFace(face f) { - OGDF_ASSERT(f->embeddingOf() == this); - m_externalFace = f; - } - - bool isBridge(edge e) const { - return m_rightFace[e->adjSource()] == m_rightFace[e->adjTarget()]; - } - - /** @} @{ - * \brief Initializes the embedding for graph \a G. - * - * \pre Graph \a G must be embedded, i.e., the adjacency lists of its nodes - * must define an embedding. - */ - void init(const Graph &G); - - void init(); - - //! Computes the list of faces. - void computeFaces(); - - - /** @} @{ - * \brief Checks the consistency of the data structure. - */ - bool consistencyCheck(); - - - /** @} @{ - * \brief Registers the face array \a pFaceArray. - * - * This method is only used by face arrays. - */ - ListIterator registerArray(FaceArrayBase *pFaceArray) const; - - /** - * \brief Unregisters the face array identified by \a it. - * - * This method is only used by face arrays. - */ - void unregisterArray(ListIterator it) const; - - /** @} */ - -protected: - //! Create a new face. - face createFaceElement(adjEntry adjFirst); - - //! Reinitialize associated face arrays. - void reinitArrays(); - -}; // class ConstCombinatorialEmbedding - - - -/** - * \brief Combinatorial embeddings of planar graphs with modification functionality. - * - * Maintains a combinatorial embedding of an embedded graph, i.e., the set of - * faces, and provides method for modifying the embedding, e.g., by inserting edges. - */ -class OGDF_EXPORT CombinatorialEmbedding : public ConstCombinatorialEmbedding -{ - Graph *m_pGraph; //!< The associated graph. - - // the following methods are private in order to make them unusable - // It is not clear which meaning copying of a comb. embedding should - // have since we only store a pointer to the topology (Graph) - CombinatorialEmbedding(const CombinatorialEmbedding &) : ConstCombinatorialEmbedding() { } - CombinatorialEmbedding &operator=(const CombinatorialEmbedding &) { - return *this; - } - -public: - /** @{ - * \brief Creates a combinatorial embedding associated with no graph. - */ - CombinatorialEmbedding() : ConstCombinatorialEmbedding() { - m_pGraph = 0; - } - - /** - * \brief Creates a combinatorial embedding of graph \a G. - * - * \pre Graph \a G must be embedded, i.e., the adjacency lists of its nodes - * must define an embedding. - */ - explicit CombinatorialEmbedding(Graph &G) : ConstCombinatorialEmbedding(G) { - m_pGraph = &G; - } - - //@} - /** - * @name Access to the associated graph - */ - //@{ - - /** - * \brief Returns the associated graph. - */ - const Graph &getGraph() const { return *m_cpGraph; } - - Graph &getGraph() { return *m_pGraph; } - - operator const Graph &() const { return *m_cpGraph; } - - operator Graph &() { return *m_pGraph; } - - - //@} - /** - * @name Initialization - */ - //@{ - - /** - * \brief Initializes the embedding for graph \a G. - * - * \pre Graph \a G must be embedded, i.e., the adjacency lists of its nodes - * must define an embedding. - */ - void init(Graph &G) { - ConstCombinatorialEmbedding::init(G); - m_pGraph = &G; - } - - /** - * \brief Removes all nodes, edges, and faces from the graph and the embedding. - */ - void clear(); - - - //@} - /** - * @name Update of embedding - */ - //@{ - - /** - * \brief Splits edge \a e=(\a v,\a w) into \a e=(\a v,\a u) and \a e'=(\a u,\a w) creating a new node \a u. - * @param e is the edge to be split; \a e is modified by the split. - * \return the edge \a e'. - */ - edge split(edge e); - - /** - * \brief Undoes a split operation. - * @param eIn is the edge (\a v,\a u). - * @param eOut is the edge (\a u,\a w). - */ - void unsplit(edge eIn, edge eOut); - - /** - * \brief Splits a node while preserving the order of adjacency entries. - * - * This method splits a node \a v into two nodes \a vl and \a vr. Node - * \a vl receives all adjacent edges of \a v from \a adjStartLeft until - * the edge preceding \a adjStartRight, and \a vr the remaining nodes - * (thus \a adjStartRight is the first edge that goes to \a vr). The - * order of adjacency entries is preserved. Additionally, a new edge - * (\a vl,\a vr) is created, such that this edge is inserted before - * \a adjStartLeft and \a adjStartRight in the the adjacency lists of - * \a vl and \a vr. - * - * Node \a v is modified to become node \a vl, and node \a vr is returned. - * - * @param adjStartLeft is the first entry that goes to the left node. - * @param adjStartRight is the first entry that goes to the right node. - * \return the newly created node. - */ - node splitNode(adjEntry adjStartLeft, adjEntry adjStartRight); - - /** - * \brief Contracts edge \a e. - * @param e is an edge is the associated graph. - * @return the node resulting from the contraction. - */ - node contract(edge e); - - /** - * \brief Splits a face by inserting a new edge. - * - * This operation introduces a new edge \a e from the node to which \a adjSrc - * belongs to the node to which \a adjTgt belongs. - * \pre \a adjSrc and \a adjTgt belong to the same face. - * \return the new edge \a e. - */ - edge splitFace(adjEntry adjSrc, adjEntry adjTgt); - - // incremental stuff - - //special version of the above function doing a pushback of the new edge - //on the adjacency list of v making it possible to insert new degree 0 - //nodes into a face - edge splitFace(node v, adjEntry adjTgt); - edge splitFace(adjEntry adjSrc, node v); - - /** - * \brief Removes edge e and joins the two faces adjacent to \a e. - * @param e is an edge in the associated graph. - * \return the resulting (joined) face. - */ - face joinFaces(edge e); - - //! Reverses edges \a e and updates embedding. - void reverseEdge(edge e); - - void moveBridge(adjEntry adjBridge, adjEntry adjBefore); - - void removeDeg1(node v); - - //! Update face information after inserting a merger in a copy graph. - void updateMerger(edge e, face fRight, face fLeft); - - - /** @} */ - -}; // class CombinatorialEmbedding - - -//--------------------------------------------------------- -// iteration macros -//--------------------------------------------------------- - -//! Iteration over all faces \a f of the combinatorial embedding \a E. -#define forall_faces(f,E) for((f)=(E).firstFace(); (f); (f)=(f)->succ()) - - -//! Iteration over all faces \a f of the combinatorial embedding \a E (in reverse order). -#define forall_rev_faces(f,E) for((f)=(E).lastFace(); (f); (f)=(f)->pred()) - -/** - * \brief Iteration over all adjacency entries \a adj of the face \a f. - * - * A faster version for this iteration demonstrates the following code snippet: - * \code - * adjEntry adj1 = f->firstAdj(), adj = adj1; - * do { - * ... - * adj = adj->faceCycleSucc(); - * } while (adj != adj1); - * \endcode - */ -#define forall_face_adj(adj,f) for((adj)=(f)->firstAdj(); (adj); (adj)=(f)->nextFaceEdge(adj)) - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Constraints.h b/ext/OGDF/ogdf/basic/Constraints.h deleted file mode 100644 index fe3f06d58..000000000 --- a/ext/OGDF/ogdf/basic/Constraints.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of base class for drawing constraints. - * - * \author PG478 - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CONSTRAINTS_H -#define OGDF_CONSTRAINTS_H - -#include -#include - - -namespace ogdf { - - -class GraphConstraints; -struct XmlTagObject; - - -/* -------------------------- Constraint ----------------------------------------- */ -class Constraint -{ - friend class GraphConstraints; - -private: - ListIterator listIt; - -protected: - String m_Name; - /* */ - bool m_UserDisabled; - - int m_Status; // OK, Suspended, notOk - /* The Graph this Constraint belongs to. No Constraint without a Graph! */ - const Graph *m_pGraph; - - /* Will be called by the GraphConstraints when a Node in mGraph is removed. */ - virtual void nodeDeleted(node v) { } - -public: - Constraint(const Graph &g) : m_pGraph(&g) { m_Status = 0; m_UserDisabled = false; } - - virtual ~Constraint() {} - - const Graph& constGraph() const { return *m_pGraph; } - - virtual bool isValid() { return (!m_UserDisabled && (m_Status==0)); } - - virtual int getInternalStatus() { return m_Status; } - - virtual void setInternalStatus(int s) { m_Status = s; } - - //virtual bool load(int stuff) = 0; - //virtual bool save(int stuff) = 0; - //virtual bool checkConstraints(List csts) {return true; } - - void userEnable() { m_UserDisabled = false; } - - void userDisable() { m_UserDisabled = true; } - - bool isUserDisabled() { return m_UserDisabled; } - - virtual int getType() { return 0; } - - static int getStaticType() { return 0; } - - void setName(String text) { m_Name = text; } - - String getName() { return m_Name; } - - //DEBUG - virtual bool buildFromOgml(XmlTagObject * constraintTag, Hashing * nodes); - virtual bool storeToOgml(int id, ostream & os, int indentStep); - //static void generateIndent(char ** indent, const int & indentSize); - - OGDF_NEW_DELETE -}; - - -/* -------------------------- GraphConstraints ----------------------------------------- */ -/* For each Graph a Set of Constraints*/ -class GraphConstraints //: public GraphStructure -{ - friend class ConstraintManager; - -protected: - /* The Graph this Constraint belongs to. No Constraint without a Graph! */ - const Graph *m_pGraph; - - /* All Constraints for mGraph */ - List m_List; - -public: - /* Constructor, GraphStructure */ - GraphConstraints(const Graph &g) : m_pGraph(&g), m_List() { } - - /* Returns the Graph */ - const Graph *constGraph() { return m_pGraph; } - - /* adds a Constraint to this Set */ - void addConstraint(Constraint *c) { c->listIt = m_List.pushBack(c); } - - /* removes a Constraint from this set */ - void removeConstraint(Constraint *c) { m_List.del(c->listIt); } - - /* returns all Constraints */ - List *getConstraints() { return &m_List; } - - /* Return Constraint Count */ - int numberOfConstraints() { return m_List.size(); } - - /* returns all Constraints of Type type */ - List getConstraintsOfType(int type); - - template void getConstraintsOfType(List *res) { - //List res; - ListConstIterator it; - for(it = m_List.begin(); it.valid(); ++it) - { - Constraint *c = *it; - - if (TYP::getStaticType()==c->getType()) - { - if (c->isValid()) res->pushBack(static_cast(c)); - } - } - //return res; - } - - void clear() { - m_List.clear(); - } - - virtual ~GraphConstraints() { - ListConstIterator it; - for(it = m_List.begin(); it.valid(); ++it) - { - Constraint *c = *it; - delete c; - } - } - - virtual void nodeDeleted(node v); - virtual void nodeAdded(node v) { } - virtual void edgeDeleted(edge e) { } - virtual void edgeAdded(edge e) { } - virtual void reInit() { } - virtual void cleared() { } - - OGDF_NEW_DELETE -}; - - -/* -------------------------- ConstraintManager ----------------------------------------- */ -class ConstraintManager -{ -public: - - static Constraint *createConstraintByName(const Graph &G, String *name); - - static String getClassnameOfConstraint(Constraint *c); - - OGDF_NEW_DELETE -}; - -} // end namespace - -#endif diff --git a/ext/OGDF/ogdf/basic/CriticalSection.h b/ext/OGDF/ogdf/basic/CriticalSection.h deleted file mode 100644 index 4c617b139..000000000 --- a/ext/OGDF/ogdf/basic/CriticalSection.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of criticial sections. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CRITICAL_SECTION_H -#define OGDF_CRITICAL_SECTION_H - -#if !defined(OGDF_SYSTEM_WINDOWS) -#include -#include -#endif - -#include - - -namespace ogdf { - -#if defined(OGDF_SYSTEM_WINDOWS) - -//! Representation of a critical section. -/** - * Critical sections are used to synchronize access to resources shared by - * several threads. It can be used to protect an object or a piece of code - * allowing always one thread at a time access. - */ -class OGDF_EXPORT CriticalSection -{ -public: - //! Creates a critical section object. - CriticalSection() { - InitializeCriticalSection(&m_cs); - } - - //! Creates a critical section object with spin count. - /** - * The spin count determines how many times the calling thread spins - * when the critical section is unavailable, before it performs a wait. - * \remark The spin count is only used on multiprocessor systems; - * otherwise it makes no sense. - */ - explicit CriticalSection(int spinCount) { - InitializeCriticalSectionAndSpinCount(&m_cs, spinCount); - } - - ~CriticalSection() { - DeleteCriticalSection(&m_cs); - } - - //! Enters the critical section. - void enter() { - EnterCriticalSection(&m_cs); - } - - //! Tries to enter the critical section; returns true on success. - bool tryEnter() { - return (TryEnterCriticalSection(&m_cs) != 0); - } - - //! Leaves the critical section. - void leave() { - LeaveCriticalSection(&m_cs); - } - -private: - CRITICAL_SECTION m_cs; //!< The Windows critical section object. -}; - - -#else - -class OGDF_EXPORT CriticalSection -{ -public: - CriticalSection() : m_spinCount(0) { - pthread_mutex_init(&m_mutex, NULL); - } - - explicit CriticalSection(int spinCount) { - m_spinCount = (System::numberOfProcessors() >= 2) ? spinCount : 0; - int ret = pthread_mutex_init(&m_mutex, NULL); - if(ret != 0) - cout << "initialization of mutex failed: " << ret << endl; - } - - ~CriticalSection() { - pthread_mutex_destroy(&m_mutex); - } - - void enter() { - if(m_spinCount > 0) { - for(int i = m_spinCount; i > 0; --i) - if(pthread_mutex_trylock(&m_mutex) != EBUSY) - return; - } - pthread_mutex_lock(&m_mutex); - } - - bool tryEnter() { - return (pthread_mutex_trylock(&m_mutex) != EBUSY); - } - - void leave() { - pthread_mutex_unlock(&m_mutex); - } - -private: - pthread_mutex_t m_mutex; - int m_spinCount; -}; - -#endif - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/DisjointSets.h b/ext/OGDF/ogdf/basic/DisjointSets.h deleted file mode 100644 index 0591542fa..000000000 --- a/ext/OGDF/ogdf/basic/DisjointSets.h +++ /dev/null @@ -1,579 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of disjoint sets data structures (union-find functionality). - * - * \author Andrej Dudenhefner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
- * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef DISJOINTSETS_H -#define DISJOINTSETS_H - -namespace ogdf { - -#define INTERMEDIATE_PARENT_CHECK -struct AnyOption {}; - -/** - * Defines options for linking two sets. - * NL = Naive Link, LI = Link by Index (default), LS = Link by Size, LR = Link by Rank - */ -enum LinkOptions { NL=0, LI=1, LS=2, LR=3 }; -template struct LinkOption : AnyOption {}; -extern const char *linkOptionNames[]; - -/** - * Defines options for compression search paths. - * PC = Path Compression, PS = Path Splitting (default), PH = Path Halving, R1 = Reversal of type 1, CO = Collapsing, NF = No Compression - */ -enum CompressionOptions { PC=0, PS=1, PH=2, R1=4, CO=5, NF=6 }; -template struct CompressionOption : AnyOption {}; -extern const char *compressionOptionNames[]; - -/* - * Defines options for interleaving find/link operations in quickUnion. - * NI = No Interleaving - * Rem = Rem's Algorithm (only compatible with linkOption = LI) (default) - * TvL = Tarjan's and van Leeuwen's Algorithm (only compatible with linkOption = LR) - * IR0 = Interleaved Reversal of Type 0 (only compatible with linkOption = NF) - * IPSPC = Interleaved Path Splitting Path Compression (only compatible with linkOption = LI) - */ -enum InterleavingOptions { NI=0, Rem=1, TvL=2, IR0=3, IPSPC=4 }; -template struct InterleavingOption : AnyOption {}; -extern const char *interleavingOptionNames[]; - - -//! A Union/Find data structure for maintaining disjoint sets. -template -class DisjointSets -{ -private: - int numberOfSets; //!< Current number of disjoint sets. - int numberOfElements; //!< Current number of elements. - int maxNumberOfElements; //!< Maximum number of elements (array size) adjusted dynamically. - - // Arrays parents, elements, parameters, siblings map a set id to its properties. - - int *parents; //!< Maps set id to parent set id. - Element *elements; //!< Maps set id to element. - int *parameters; //!< Maps set id to rank/size. - int *siblings; //!< Maps set id to sibling set id. - - //find - int find(CompressionOption,int set); - int find(CompressionOption,int set); - int find(CompressionOption,int set); - int find(CompressionOption,int set); - int find(CompressionOption,int set); - int find(CompressionOption,int set); - - //link - int link(LinkOption,int set1,int set2); - int link(LinkOption
  • ,int set1,int set2); - int link(LinkOption,int set1,int set2); - int link(LinkOption,int set1,int set2); - - //quickUnion - bool quickUnion(LinkOption
  • ,InterleavingOption,int set1,int set2); - bool quickUnion(LinkOption
  • ,InterleavingOption,int set1,int set2); - bool quickUnion(LinkOption,InterleavingOption,int set1,int set2); - bool quickUnion(AnyOption,InterleavingOption,int set1,int set2); - bool quickUnion(LinkOption,InterleavingOption,int set1,int set2); - -public: - //! Cretes an empty DisjointSets structure. - /** - * \param maxNumberOfElements Expected number of Elements. - */ - DisjointSets(int maxNumberOfElements = (1<<15) ) - { - this->numberOfSets=0; - this->numberOfElements=0; - this->maxNumberOfElements = maxNumberOfElements; - this->parents = new int[this->maxNumberOfElements]; - this->elements = new Element[this->maxNumberOfElements]; - this->parameters = (linkOption==LR || linkOption==LS) ? new int[this->maxNumberOfElements] : 0; - this->siblings = (compressionOption==CO) ? new int[this->maxNumberOfElements] : 0; - } - - ~DisjointSets() - { - delete [] this->parents; - delete [] this->elements; - if (this->parameters != 0) delete [] this->parameters; - if (this->siblings != 0) delete [] this->siblings; - } - - //! Returns the id of the largest superset of \a set and compresses the path according to \a compressionOption. - /** - * \param set Set. - * \return Superset id - * \pre \a set is a non negative properly initialized id. - */ - int find(int set) - { - return find(CompressionOption(), set); - } - - //! Returns the id of the largest superset of \a set. - /** - * \param set Set. - * \return Superset id - * \pre \a set is a non negative properly initialized id. - */ - int getRepresentative(int set) - { - while (set!=parents[set]) set=parents[set]; - return set; - } - - //! Initializes a singleton set containing \a element. - /** - * \param element Element. - * \return Set id of the initialized singleton set. - */ - int makeSet(Element element) - { - if (this->numberOfElements==this->maxNumberOfElements) - { - int *parents = this->parents; - this->parents = new int[this->maxNumberOfElements * 2]; - memcpy(this->parents,parents,sizeof(int)*this->maxNumberOfElements); - delete [] parents; - - Element *elements=this->elements; - this->elements = new Element[this->maxNumberOfElements*2]; - memcpy(this->elements,elements,sizeof(Element)*this->maxNumberOfElements); - delete [] elements; - - if (this->parameters != 0) - { - int *parameters = this->parameters; - this->parameters = new int[this->maxNumberOfElements*2]; - memcpy(this->parameters,parameters,sizeof(int)*this->maxNumberOfElements); - delete [] parameters; - } - - if (this->siblings != 0) - { - int *siblings = this->siblings; - this->siblings = new int[this->maxNumberOfElements*2]; - memcpy(this->siblings,siblings,sizeof(int)*this->maxNumberOfElements); - delete [] siblings; - } - this->maxNumberOfElements*=2; - } - this->numberOfSets++; - int id = this->numberOfElements++; - this->parents[id]=id; - this->elements[id]=element; - //Initialize size/ rank/ sibling. - if (linkOption == LS) this->parameters[id]=1; - else if (linkOption == LR) this->parameters[id]=0; - if (compressionOption == CO) this->siblings[id] = -1; - return id; - } - - //! Unions \a set1 and \a set2. - /** - * \pre \a set1 and \a set2 are maximal disjoint sets. - * \return Set id of the union. - */ - int link(int set1, int set2) - { - if (set1==set2) return -1; - this->numberOfSets--; - int superset = link(LinkOption(), set1, set2); - //Collapse subset tree. - if (compressionOption == CO) - { - int subset = set1 == superset ? set2 : set1; - int id = subset; - while (this->siblings[id] != -1) - { - id = this->siblings[id]; - this->parents[id]=superset; - } - this->siblings[id] = this->siblings[superset]; - this->siblings[superset] = subset; - } - return superset; - } - - //! Unions the maximal disjoint sets containing \a set1 and \a set2. - /** - * \return True, if the maximal sets containing \a set1 and \a set2 were disjoint und joined correctly. False otherwise. - */ - bool quickUnion(int set1, int set2) - { - if (set1==set2) return false; - this->numberOfSets--; - return quickUnion(LinkOption(),InterleavingOption(), set1, set2); - } - - //! Returns the current number of disjoint sets. - int getNumberOfSets() { return numberOfSets; } - - //! Returns the current number of elements. - int getNumberOfElements() {return numberOfElements; } -}; - - -//find -template -int DisjointSets::find(CompressionOption,int set) -{ - int parent = parents[set]; - if (set==parent) - { - return set; - } - else - { - parent = find(CompressionOption(),parent); - parents[set]=parent; - return parent; - } -} - -template -int DisjointSets::find(CompressionOption,int set) -{ - while (set!=parents[set]) - { - int parent = parents[set]; - int grandParent = parents[parent]; - parents[set]=grandParent; - set = grandParent; - } - return set; -} - -template -int DisjointSets::find(CompressionOption,int set) -{ - int parent = parents[set]; - int grandParent = parents[parent]; - while (parent!=grandParent) - { - parents[set]=grandParent; - set = parent; - parent = grandParent; - grandParent = parents[grandParent]; - } - return parent; -} - -template -int DisjointSets::find(CompressionOption,int set) -{ - int root = set; - set = parents[root]; - - while (set!=parents[set]) - { - int parent = parents[set]; - parents[set] = root; - set = parent; - } - parents[root] = set; - return set; -} - -template -int DisjointSets::find(CompressionOption,int set) -{ - while (set!=parents[set]) set=parents[set]; - return set; -} - -template -int DisjointSets::find(CompressionOption,int set) -{ - return parents[set]; -} - - -//quickUnion -template -bool DisjointSets::quickUnion(AnyOption,InterleavingOption,int set1,int set2) -{ -#ifdef INTERMEDIATE_PARENT_CHECK - if (parents[set1]==parents[set2]) return false; -#endif - set1 = find(set1); - set2 = find(set2); - if (set1 != set2) - { - link(set1,set2); - return true; - } - return false; -} - -template -bool DisjointSets::quickUnion(LinkOption,InterleavingOption,int set1,int set2) -{ -#ifdef INTERMEDIATE_PARENT_CHECK - if (parents[set1]==parents[set2]) return false; -#endif - int root = set2; - int set = set2; - int parent = parents[set]; - parents[set]=root; - while (set != parent) - { - if (parent == set1) - { - parents[root]=set1; - return false; - } - set = parent; - parent = parents[set]; - parents[set]=root; - } - - set = set1; - parent = parents[set]; - while (true) - { - if (parent == root) return false; - parents[set] = root; - if (parent == set) return true; - set = parent; - parent = parents[set]; - } -} - -template -bool DisjointSets::quickUnion(LinkOption
  • ,InterleavingOption,int set1,int set2) -{ - int r_x = set1; int r_y = set2; - int p_r_x =parents[r_x]; - int p_r_y =parents[r_y]; - while (p_r_x != p_r_y) - { - if (p_r_x < p_r_y) - { - if (r_x == p_r_x) - { - parents[r_x]=p_r_y; - return true; - } - parents[r_x]=p_r_y; - r_x = p_r_x; - p_r_x = parents[r_x]; - } - else - { - if (r_y == p_r_y) - { - parents[r_y]=p_r_x; - return true; - } - parents[r_y]=p_r_x; - r_y = p_r_y; - p_r_y = parents[r_y]; - } - } - return false; -} - -template -bool DisjointSets::quickUnion(LinkOption
  • ,InterleavingOption,int set1,int set2) -{ -#ifdef INTERMEDIATE_PARENT_CHECK - if (parents[set1]==parents[set2]) return false; -#endif - int set = set1; - - if (set1 < set2) - { - set = set2; - set2 = set1; - set1 = set; - } - - //!Use path splitting to compress the path of set1 and get the root - set = parents[set]; - int parent = parents[set]; - int grandParent = parents[parent]; - while (parent!=grandParent) - { - parents[set]=grandParent; - set = parent; - parent = grandParent; - grandParent = parents[grandParent]; - } - parents[set1]=parent; - int root = parent; - - //!Redirect all nodes with smaller indices on the path of set2 to the root - set = set2; - parent = parents[set]; - while (true) - { - if (parent < root) - { - parents[set]=root; - if (set == parent) return true; - set=parent; - parent = parents[set]; - } - else if (parent > root) - { - parents[root]=parent; - parents[set1]=parent; - parents[set2]=parent; - return true; - } - else return false; - } -} - -template -bool DisjointSets::quickUnion(LinkOption,InterleavingOption,int set1,int set2) -{ - int r_x = set1; int r_y = set2; - int p_r_x =parents[r_x]; - int p_r_y =parents[r_y]; - while (p_r_x != p_r_y) - { - if (parameters[p_r_x]<=parameters[p_r_y]) - { - if (r_x==p_r_x) - { - if (parameters[p_r_x]==parameters[p_r_y]) - { - if (p_r_y==parents[p_r_y]) - { - parameters[p_r_y]++; - } - } - parents[r_x]=parents[p_r_y]; - return true; - } - parents[r_x]=p_r_y; - r_x = p_r_x; - p_r_x = parents[r_x]; - } - else - { - if (r_y==p_r_y) - { - parents[r_y]=parents[p_r_x]; - return true; - } - parents[r_y]=p_r_x; - r_y = p_r_y; - p_r_y = parents[r_y]; - } - } - return false; -} - - -//link -template -int DisjointSets::link(LinkOption
  • ,int set1,int set2) -{ - if (set1 -int DisjointSets::link(LinkOption,int set1,int set2) -{ - int parameter1 = parameters[set1]; - int parameter2 = parameters[set2]; - - if (parameter1parameter2) - { - parents[set2]=set1; - return set1; - } - else - { - parents[set1]=set2; - parameters[set2]++; - return set2; - } -} - -template -int DisjointSets::link(LinkOption,int set1,int set2) -{ - int parameter1 = parameters[set1]; - int parameter2 = parameters[set2]; - - if (parameter1 -int DisjointSets::link(LinkOption,int set1,int set2) -{ - parents[set1]=set2; - return set2; -} - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/DualGraph.h b/ext/OGDF/ogdf/basic/DualGraph.h deleted file mode 100644 index bda2f952e..000000000 --- a/ext/OGDF/ogdf/basic/DualGraph.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Includes declaration of dual graph class. - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DUAL_GRAPH_H -#define OGDF_DUAL_GRAPH_H - - -#include -#include -#include -#include - -namespace ogdf { - -//! A dual graph including its combinatorial embedding of an embedded graph -class OGDF_EXPORT DualGraph : public CombinatorialEmbedding -{ -public: - //! Constructor; creates dual graph and its combinatorial embedding - DualGraph(CombinatorialEmbedding &CE); - //! Destructor - ~DualGraph(); - //! Returns a reference to the combinatorial embedding of the primal graph - const CombinatorialEmbedding &getPrimalEmbedding() const { return *m_primalEmbedding; } - //! Returns a reference to the primal graph - const Graph &getPrimalGraph() const { return m_primalEmbedding->getGraph(); } - - //! Returns the node in the primal graph corresponding to \a f. - /** - * @param f is a face in the embedding of the dual graph - * \return the corresponding node in the primal graph - */ - const node &primalNode(face f) const { return m_primalNode[f]; } - //! Returns the edge in the primal graph corresponding to \a e. - /** - * @param e is an edge in the dual graph - * \return the corresponding edge in the primal graph - */ - const edge &primalEdge(edge e) const { return m_primalEdge[e]; } - //! Returns the face in the embedding of the primal graph corresponding to \a v. - /** - * @param v is a node in the dual graph - * \return the corresponding face in the embedding of the primal graph - */ - const face &primalFace(node v) const { return m_primalFace[v]; } - //! Returns the node in the dual graph corresponding to \a f. - /** - * @param f is a face in the embedding of the primal graph - * \return the corresponding node in the dual graph - */ - const node &dualNode(face f) const { return m_dualNode[f]; } - //! Returns the edge in the dual graph corresponding to \a e. - /** - * @param e is an edge in the primal graph - * \return the corresponding edge in the dual graph - */ - const edge &dualEdge(edge e) const { return m_dualEdge[e]; } - //! Returns the face in the embedding of the dual graph corresponding to \a v. - /** - * @param v is a node in the primal graph - * \return the corresponding face in the embedding of the dual graph - */ - const face &dualFace(node v) const { return m_dualFace[v]; } - -protected: - CombinatorialEmbedding *m_primalEmbedding; //!< The embedding of the primal graph. - FaceArray m_primalNode; //!< The corresponding node in the primal graph. - NodeArray m_primalFace; //!< The corresponding facee in the embedding of the primal graph. - EdgeArray m_primalEdge; //!< The corresponding edge in the primal graph. - FaceArray m_dualNode; //!< The corresponding node in the dual graph. - NodeArray m_dualFace; //!< The corresponding face in embedding of the dual graph. - EdgeArray m_dualEdge; //!< The corresponding edge in the dual graph. -}; // class DualGraph - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/EFreeList.h b/ext/OGDF/ogdf/basic/EFreeList.h deleted file mode 100644 index c5a5b0be0..000000000 --- a/ext/OGDF/ogdf/basic/EFreeList.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * $Revision: 2579 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-11 15:28:17 +0200 (Mi, 11. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of a simple freelist and an - * index pool which generates unique indices for elements. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EFREE_LIST_H -#define OGDF_EFREE_LIST_H - -#include - -namespace ogdf { - -template class EFreeList; -template class EFreeListIndexPool; - -template class EFreeListTypes; - - -//! Simple implementation of a FreeList which buffers the memory allocation of an embedded list item. -template -class EFreeList -{ - friend class EFreeListTypes; -public: - //! Constructs a new freelist - inline EFreeList() { EFreeListTypes::FreeStack::init(this); } - - //! Destructor. Releases the mem used by the remaining elements on the stack. - ~EFreeList() { this->freeFreeList(); } - - //! Returns a new instance of E by either using an instance from the stack or creating a new one. - inline E* alloc() - { - if (!EFreeListTypes::FreeStack::empty(this)) - return EFreeListTypes::FreeStack::popRet(this); - else - return new E(); - } - - //! Returns true if the stack is empty. - inline bool empty() const { return EFreeListTypes::FreeStack::empty(this); } - - //! Frees an item buy putting it onto the stack of free instances - inline void free(E* ptr) { EFreeListTypes::FreeStack::push(this, ptr); } - -protected: - //! deletes all instances in the list - inline void freeFreeList() - { - while (!EFreeListTypes::FreeStack::empty(this)) { delete EFreeListTypes::FreeStack::popRet(this); } - } - - //! Top of the stack - E* m_pTop; - - //! Typedef for the embedded stack - //typedef EStack, E, &EFreeList::m_pTop, next> FreeStack; -}; - -//! Type declarations for EFreeList. -template -class EFreeListTypes -{ -public: - typedef EStack, E, &EFreeList::m_pTop, next> FreeStack; -}; - - -//! More complex implementation of a FreeList, which is able to generate indeices for the elements. -template -class EFreeListIndexPool -{ -public: - //! Creates a new IndexPool and a FreeList. - EFreeListIndexPool() : m_nextFreeIndex(0) { } - - //! Frees an element using the FreeList - inline void free(E* ptr) { m_freeList.free(ptr); } - - //! The value indicates that all indices in 0..numUsedIndices-1 might be in use. - inline int numUsedIndices() const { return m_nextFreeIndex; } - - //! Allocates a new Element by either using the free list or allocating a new one with a brand new index. - inline E* alloc() - { - if (m_freeList.empty()) - { - E* res = new E(); - res->*index = m_nextFreeIndex++; - return res; - } else - { - return m_freeList.alloc(); - } - } - -protected: - //! The next brand new index. - int m_nextFreeIndex; - - //! The free list for allocating the memory. - EFreeList m_freeList; -}; - -} // end of namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/EList.h b/ext/OGDF/ogdf/basic/EList.h deleted file mode 100644 index 3d13e1162..000000000 --- a/ext/OGDF/ogdf/basic/EList.h +++ /dev/null @@ -1,507 +0,0 @@ -/* - * $Revision: 2579 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-11 15:28:17 +0200 (Mi, 11. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of embedded stack and list - * functionality which is useful for embedded chains of elements - * (classes with internal next and previous pointer). - * \par The templates declared in this file can be used whenever - * a so called embedded list has to be implemented. Example: - * - * \author Martin Gronemann - * - * \code - * class MyNode - * { - * public: - * ... - * private: - * MyNode* prev; - * MyNode* next; - * }; - * - * class MyDataStructure - * { - * private: - * MyNode* m_head; - * MyNode* m_tail; - * int m_numNodes; - * MyNode* m_stackTop; - * public: - * typedef EList< MyDataStructure, - * MyNode, - * &MyDataStructure::m_numNodes, - * &MyDataStructure::m_head, - * &MyDataStructure::m_tail, - * &MyNode::prev, - * &MyNode::next> NodeChain; - * - * typedef EStack< MyDataStructure, - * MyNode, - * &MyDataStructure::m_stackTop, - * &MyNode::next> NodeStack; - * }; - * ... - * MyDataStructure ds; - * MyDataStructure::NodeChain.init(&ds); - * MyDataStructure::NodeStack.init(&ds); - * ... - * MyNode* ptr = new MyNode(); - * MyDataStructure::NodeChain.pushBack(&ds, ptr); - * ... - * ptr = MyDataStructure::NodeChain.front(&ds); - * MyDataStructure::NodeStack.push(&ds,ptr); - * ... - * for (MyDataStructure::NodeChain::iterator it = MyDataStructure::NodeChain.begin(&ds); - * it.valid(); it++) - * { - * ptr = *it; - * } - * \endcode - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ELIST_H -#define OGDF_ELIST_H - -namespace ogdf { - -// EStack forward declaration -template class EStack; -// EListIterator forward declaration -template class EListIterator; -// EList forward declaration -template class EList; - -//! The embedded stack class template -template -class EStack -{ -public: - //! Initializes \a pStack as empty stack - static inline void init(S* pStack) - { - pStack->*first = 0; - } - - //! Removes the top element from \a pStack without returning it - static inline void pop(S* pStack) - { - pStack->*first = pStack->*first->*next; - } - - //! Removes the top element and returns it. - static inline E* popRet(S* pStack) - { - E* res = pStack->*first; - pStack->*first = pStack->*first->*next; - return res; - } - - //! Pushes the new element \a pElem onto \a pStack. - static inline void push(S* pStack, E* pElem) - { - pElem->*next = pStack->*first; - pStack->*first = pElem; - } - - //! Returns a pointer to the top element of \a pStack. - static inline E* top(const S* pStack) - { - return pStack->*first; - } - - //! Returns true if \a pStack is empty - static inline bool empty(const S* pStack) - { - return (pStack->*first == 0); - } -}; - - -//! Implementation of an embedded list iterator used by \a EList -template -class EListIterator -{ -public: - //! Constructs an iterator pointing at NULL - inline EListIterator( ) : m_ptr(0) {} - - //! Constructs an iterator pointing at ptr - inline EListIterator(E* ptr) : m_ptr(ptr) {} - - //! constructs an iterator pointing at the same element as \a other - inline EListIterator(const EListIterator& other) : m_ptr(other.m_ptr) {} - - //! returns false if the iterator points at NULL - inline bool valid() const { return (m_ptr != 0); } - - //! Equality operator. - inline bool operator==(const EListIterator& other) const { return m_ptr == other.m_ptr; } - - //! Inequality operator. - inline bool operator!=(const EListIterator& other) const { return m_ptr != other.m_ptr; } - - //! Returns successor iterator. - inline EListIterator succ() const { return m_ptr->*next; } - - //! Returns predecessor iterator. - inline EListIterator pred() const { return m_ptr->*prev; } - - //! Returns a reference to the element. - //E& operator*() const { return *m_ptr; } - - //! Returns a pointer to the element. - E* operator*() const { return m_ptr; } - - //! Assignment operator. - inline EListIterator &operator=(const EListIterator& other) - { - m_ptr = other.m_ptr; - return *this; - } - - //! Increment operator (prefix). - inline EListIterator& operator++() - { - m_ptr = m_ptr->*next; - return *this; - } - - //! Increment operator (postfix). - inline EListIterator operator++(int) - { - EListIterator it = *this; - m_ptr = m_ptr->*next; - return it; - } - - //! Decrement operator (prefix). - inline EListIterator& operator--() - { - m_ptr = m_ptr->*prev; - return *this; - } - - //! Decrement operator (postfix). - inline EListIterator operator--(int) - { - EListIterator it = *this; - m_ptr = m_ptr->*prev; - return it; - } - -private: - //! The pointer to the element the iterator is pointing at. - E* m_ptr; -}; - - -//! The embedded list template. -template< - typename L, - typename E, - int L::*numElem, - E* L::*first, - E* L::*last, - E* E::*next, - E* E::*prev -> -class EList -{ -public: - //! The iterator typdef for elements of type E and prev, next pointer - typedef EListIterator iterator; - - //! Initializes \a pList as an empty embedded list. - static inline void init(L* pList) - { - pList->*first = 0; - pList->*last = 0; - pList->*numElem = 0; - } - - //! Returns the number of elements in this embedded list by reading the numElem var. - static inline int size(const L* pList) { return (pList->*numElem); } - - //! Returns true if /a pList is empty. - static inline bool empty(const L* pList) { return (pList->*first == 0); } - - //! Returns a pointer to the first element. - static inline E* front(const L* pList) { return pList->*first; } - - //! Returns a pointer to the last element. - static inline E* back(const L* pList) { return pList->*last; } - - //! Appends the element \a elem to the end of \a pList. - static inline iterator pushBack(L* pList, E* elem) - { - elem->*next = 0; - elem->*prev = pList->*last; - if (pList->*last) - pList->*last = pList->*last->*next = elem; - else - pList->*last = pList->*first = elem; - - (pList->*numElem)++; - return iterator(elem); - } - - //! Adds element \a x at the begin of the list. - static inline iterator pushFront(L* pList, E* elem) - { - elem->*next = pList->*first; - elem->*prev = 0; - - if (pList->*first) - pList->*first = pList->*first->*prev = elem; - else - pList->*first = pList->*last = elem; - - (pList->*numElem)++; - - return iterator(elem); - } - - //! Inserts \a elem into \a pList before \a pNext - static inline iterator insertBefore(L* pList, E* elem, E* pNext) - { - E* pPrev; - - if (pNext) - pPrev = pNext->*prev; - else - pPrev = 0; - - elem->*next = pNext; - elem->*prev = pPrev; - - if (pNext) - pNext->*prev = elem; - else - pList->*last = elem; - if (pPrev) - pPrev->*next = elem; - else - pList->*first = elem; - - (pList->*numElem)++; - return iterator(elem); - } - - //! Inserts \a elem into \a pList before position \a itNext - static inline iterator insertBefore(L* pList, E* elem, const iterator& itNext) - { - return insertBefore(pList, elem, (E*)(*itNext)); - } - - //! Inserts \a elem into \a pList before \a pPrev - static inline iterator insertAfter(L* pList, E* elem, E* pPrev) - { - E* pNext; - - if (pPrev) - pNext = pPrev->*next; - else - pNext = 0; - - elem->*next = pNext; - elem->*prev = pPrev; - - if (pNext) - pNext->*prev = elem; - else - pList->*last = elem; - if (pPrev) - pPrev->*next = elem; - else - pList->*first = elem; - - (pList->*numElem)++; - return iterator(elem); - } - - //! Inserts \a elem into \a pList after position \a itPrev - static inline iterator insertAfter(L* pList, E* elem, const iterator& itPrev) - { - return insertAfter(pList, elem, (E*)(*itPrev)); - } - - //! Removes the first element of \a pList. - inline static void popFront(L* pList) - { - if (front(pList)) - remove(pList, front(pList)); - } - - //! Removes the last element of \a pList. - inline static void popBack(L* pList) - { - if (back(pList)) - remove(pList, back(pList)); - } - - //! Removes \a elem from \a pList. - static inline iterator remove(L* pList, E* elem) - { - E* pPrev = elem->*prev; - E* pNext = elem->*next; - if (pPrev) - pPrev->*next = pNext; - else - pList->*first = pNext; - if (pNext) - pNext->*prev = pPrev; - else - pList->*last = pPrev; - - (pList->*numElem)--; - return iterator(pNext); - } - - //! Removes the element \a it is pointing at from \a pList. - static inline iterator remove(L* pList, const iterator& it) - { - return remove(pList, (E*)(*it)); - } - - template< - typename L_other, - E* L_other::*other_first, - E* L_other::*other_last, - int L_other::*other_numElem - > - inline static void appendFrom( L* pList, L_other* pListOther ) - { - if (!pListOther->*other_first) - return; - - if (empty(pList)) - { - pList->*first = pListOther->*other_first; - pList->*last = pListOther->*other_last; - } else - { - // link the pList->last element to other->first - pList->*last->*next = pListOther->*other_first; - pListOther->*other_first->*prev = pList->*last; - - // link the pList->last element to other->first - pList->*last = pListOther->*other_first; - } - - // add the size of the other pList - pList->*numElem += pListOther->*other_numElem; - // clear other pList - pListOther->*other_numElem = 0; - pListOther->*other_first = 0; - pListOther->*other_last = 0; - } - - //! Returns an iterator pointing at the first element of \a pList. - static inline iterator begin(const L* pList) { return iterator(pList->*first); } - - //! Returns an iterator pointing at NULL. - static inline iterator end(const L* pList) { return iterator(); } - - //! Returns a reverse iterator pointing at the last element of \a pList. - static inline iterator rbegin(const L* pList) { return iterator(pList->*last); } - - //! Returns a reverse iterator pointing at NULL. - static inline iterator rend(const L* pList) { return iterator(); } - - template - static inline void forall(const L* pList, const Func& func) - { - for(iterator it = begin(pList);it.valid();it++) - { - func(*it); - } - } - - template - static inline void forall_call(const L* pList, void (E::*func)( A1 ), const A1& a1) - { - for(iterator it = begin(pList);it.valid();it++) - { - ((*it)->*func)(a1); - } - } - - //! Constructor. - inline EList(L* pList) : m_pList(pList) { } - - inline void init() { init(m_pList); } - - inline int size() const { return size(m_pList); } - inline bool empty() const { return empty(m_pList); } - - inline E* front() const { return front(m_pList); } - inline E* back() const { return back(m_pList); } - - inline iterator pushBack(E* elem) { return pushBack(m_pList, elem); } - inline iterator pushFront(E* elem) { return pushFront(m_pList, elem); } - - inline iterator insertBefore(E* elem, E* pNext) { return insertBefore(m_pList, elem, pNext); } - inline iterator insertBefore(E* elem, const iterator& it) { return insertBefore(m_pList, elem, it); } - - inline iterator insertAfter(E* elem, E* pPrev) { return insertAfter(m_pList, elem, pPrev); } ; - inline iterator insertAfter(E* elem, const iterator& it) { return insertAfter(m_pList, elem, it); } ; - - inline void popFront() { popFront(m_pList); } - inline void popBack() { popBack(m_pList); } - - void operator<<(E* elem) { pushBack(elem); } - - inline iterator remove(E* elem) { return remove(m_pList, elem); } - inline iterator remove(const iterator& it) { return remove(m_pList, (E*)(*it)); } - - inline iterator begin() const { return begin(m_pList); } - inline iterator end() const { return end(m_pList); } - inline iterator rbegin() const { return rbegin(m_pList); } - inline iterator rend() const { return rend(m_pList); } - -private: - L* m_pList; -}; - - -} // end of namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/EdgeArray.h b/ext/OGDF/ogdf/basic/EdgeArray.h deleted file mode 100644 index 5303ac28e..000000000 --- a/ext/OGDF/ogdf/basic/EdgeArray.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of EdgeArray class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_ARRAY_H -#define OGDF_EDGE_ARRAY_H - - -#include - - -namespace ogdf { - - -//! Abstract base class for edge arrays. -/** - * Defines the interface for event handling used by the Graph class. - * Use the parameterized class EdgeArray for creating edge arrays. - */ -class EdgeArrayBase { - /** - * Pointer to list element in the list of all registered edge - * arrays which references this array. - */ - ListIterator m_it; - -public: - const Graph *m_pGraph; //!< The associated graph. - - //! Initializes an edge array not associated with a graph. - EdgeArrayBase() : m_pGraph(0) { } - //! Initializes an edge array associated with \a pG. - EdgeArrayBase(const Graph *pG) : m_pGraph(pG) { - if(pG) m_it = pG->registerArray(this); - } - - // destructor, unregisters the array - virtual ~EdgeArrayBase() { - if (m_pGraph) m_pGraph->unregisterArray(m_it); - } - - // event interface used by Graph - //! Virtual function called when table size has to be enlarged. - virtual void enlargeTable(int newTableSize) = 0; - //! Virtual function called when table has to be reinitialized. - virtual void reinit(int initTableSize) = 0; - //! Virtual function called when array is disconnected from the graph. - virtual void disconnect() = 0; - - //! Associates the array with a new graph. - void reregister(const Graph *pG) { - if (m_pGraph) m_pGraph->unregisterArray(m_it); - if ((m_pGraph = pG) != 0) m_it = pG->registerArray(this); - } -}; // class EdgeArrayBase - - -//! Dynamic arrays indexed with edges. -/** - * Edge arrays represent a mapping from edges to data of type \a T. - * They adjust their table size automatically when the graph grows. - * - * @tparam T is the element type. - */ -template class EdgeArray : private Array, protected EdgeArrayBase { - T m_x; //!< The default value for array elements. - -public: - //! Constructs an empty edge array associated with no graph. - EdgeArray() : Array(), EdgeArrayBase() { } - //! Constructs an edge array associated with \a G. - EdgeArray(const Graph &G) : Array(G.edgeArrayTableSize()), EdgeArrayBase(&G) { } - //! Constructs an edge array associated with \a G. - /** - * @param G is the associated graph. - * @param x is the default value for all array elements. - */ - EdgeArray(const Graph &G, const T &x) : - Array(0,G.edgeArrayTableSize()-1,x), EdgeArrayBase(&G), m_x(x) { } - //! Constructs an edge array that is a copy of \a A. - /** - * Associates the array with the same graph as \a A and copies all elements. - */ - EdgeArray(const EdgeArray &A) : Array(A), EdgeArrayBase(A.m_pGraph), m_x(A.m_x) { } - - //! Returns true iff the array is associated with a graph. - bool valid() const { return (Array::low() <= Array::high()); } - - //! Returns a pointer to the associated graph. - const Graph *graphOf() const { - return m_pGraph; - } - - //! Returns a reference to the element with index \a e. - const T &operator[](edge e) const { - OGDF_ASSERT(e != 0 && e->graphOf() == m_pGraph) - return Array::operator [](e->index()); - } - - //! Returns a reference to the element with index \a e. - T &operator[](edge e) { - OGDF_ASSERT(e != 0 && e->graphOf() == m_pGraph) - return Array::operator [](e->index()); - } - - //! Returns a reference to the element with index edge of \a adj. - const T &operator[](adjEntry adj) const { - OGDF_ASSERT(adj != 0) - return Array::operator [](adj->index() >> 1); - } - - //! Returns a reference to the element with index edge of \a adj. - T &operator[](adjEntry adj) { - OGDF_ASSERT(adj != 0) - return Array::operator [](adj->index() >> 1); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for an edge - * in the associated graph! - */ - const T &operator[](int index) const { - return Array::operator [](index); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for an edge - * in the associated graph! - */ - T &operator[](int index) { - return Array::operator [](index); - } - - //! Assignment operator. - EdgeArray &operator=(const EdgeArray &a) { - Array::operator =(a); - m_x = a.m_x; - reregister(a.m_pGraph); - return *this; - } - - //! Reinitializes the array. Associates the array with no graph. - void init() { - Array::init(); reregister(0); - } - - //! Reinitializes the array. Associates the array with \a G. - void init(const Graph &G) { - Array::init(G.edgeArrayTableSize()); reregister(&G); - } - - //! Reinitializes the array. Associates the array with \a G. - /** - * @param G is the associated graph. - * @param x is the default value. - */ - void init(const Graph &G, const T &x) { - Array::init(0,G.edgeArrayTableSize()-1, m_x = x); reregister(&G); - } - - //! Sets all array elements to \a x. - void fill(const T &x) { - int high = m_pGraph->maxEdgeIndex(); - if(high >= 0) - Array::fill(0,high,x); - } - -private: - virtual void enlargeTable(int newTableSize) { - Array::grow(newTableSize-Array::size(),m_x); - } - - virtual void reinit(int initTableSize) { - Array::init(0,initTableSize-1,m_x); - } - - virtual void disconnect() { - Array::init(); - m_pGraph = 0; - } - - OGDF_NEW_DELETE - -}; // class EdgeArray - - -//! Bucket function for edges. -/** - * The bucket of an edge is stored in an edge array which is passed - * by the user at construction; only a pointer is stored to that array. - */ -class OGDF_EXPORT BucketEdgeArray : public BucketFunc -{ - const EdgeArray *m_pEdgeArray; //!< Pointer to edge array. - -public: - //! Constructs a bucket function. - /** - * @param edgeArray contains the buckets for the edges. May not be deleted - * as long as the bucket function is used. - */ - BucketEdgeArray(const EdgeArray &edgeArray) : m_pEdgeArray(&edgeArray) { } - - //! Returns bucket of edge \a e. - int getBucket(const edge &e) { return (*m_pEdgeArray)[e]; } -}; - - -} // end namespace ogdf -#include - -#endif diff --git a/ext/OGDF/ogdf/basic/EdgeComparer.h b/ext/OGDF/ogdf/basic/EdgeComparer.h deleted file mode 100644 index 6da73dd1d..000000000 --- a/ext/OGDF/ogdf/basic/EdgeComparer.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares EdgeComparer class. - * - * The EdgeComparer compares adjacency entries on base of - * the position of the nodes given by an Attributed Graph's - * layout information. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_EDGECOMPARER_H -#define OGDF_EDGECOMPARER_H - - - -#include -#include - -namespace ogdf { - -//! The EdgeComparer compares adjacency entries on base of the position of the nodes given by an Attributed Graph's layout information -/** - * helper function for ordering / sorting - * assumes that PG is a planrep on original AG and that PG is - * not normalized, i.e., if there are bends in AG, they do not - * have a counterpart in PG (all nodes in PG have an original) - * temporary: we assume that we have two adjentries - * at a common point, so we leave the check for now - * if they meet and at which point - * - * \todo check if sorting order fits adjacency list - */ -class OGDF_EXPORT EdgeComparer : public VComparer -{ -public: - //order: clockwise - - EdgeComparer(const GraphAttributes& AG, const PlanRep& PR) : m_AG(&AG), m_PR(&PR) { } - - //! compare the edges directly in AG - EdgeComparer(const GraphAttributes &AG) : m_AG(&AG), m_PR(0) {} - - int compare(const adjEntry &e1, const adjEntry &e2) const; - - //! check if vector u->v lies within 180degree halfcircle before vector u->w in clockwise order (i.e. twelve o'clock lies before 1) - bool before(const DPoint u, const DPoint v, const DPoint w) const; - -private: - - //! returns a value > 0, if vector uv lies "before" vector uw - int orientation( - const DPoint u, - const DPoint v, - const DPoint w) const; - - //! compares by angle relative to x-axis - int compareVectors( - const double& x1, - const double& y1, - const double& x2, - const double& y2) const; - //! computes angle between vectors p->q, p->r - double angle(DPoint p, DPoint q, DPoint r) const; - - inline int signOf(const double& x) const - { - if ( x == 0 ) return 0; - else if (x > 0 ) return 1; - else return -1; - } - - - const GraphAttributes *m_AG; - const PlanRep *m_PR; -};//EdgeComparer - - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/EdgeComparerSimple.h b/ext/OGDF/ogdf/basic/EdgeComparerSimple.h deleted file mode 100644 index 20faf1665..000000000 --- a/ext/OGDF/ogdf/basic/EdgeComparerSimple.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares EdgeComparerSimple class. - * - * The EdgeComparerSimple compares incident edges of a node - * based on the position of the last bend point or the position - * of the adjacent node given by the layout information of the - * graph. - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_EDGECOMPARER_SIMPLE_H -#define OGDF_EDGECOMPARER_SIMPLE_H - - - -#include -#include - -namespace ogdf { - - - -class OGDF_EXPORT EdgeComparerSimple : public VComparer -{ -public: - - EdgeComparerSimple(const GraphAttributes& AG, const node v) : basis(v), m_AG(&AG) { } - - int compare(const adjEntry &e1, const adjEntry &e2) const; - -private: - node basis; - const GraphAttributes *m_AG; - -};//EdgeComparerSimple - - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/FaceArray.h b/ext/OGDF/ogdf/basic/FaceArray.h deleted file mode 100644 index 11b681330..000000000 --- a/ext/OGDF/ogdf/basic/FaceArray.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration and implementation of FaceArray class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FACE_ARRAY_H -#define OGDF_FACE_ARRAY_H - - -#include -#include - - -namespace ogdf { - - -//! Abstract base class for face arrays. -/** - * Defines the interface for event handling used by the - * CombinatorialEmbedding class. - * Use the parameterized class FaceArray for creating face arrays. - */ -class FaceArrayBase { - /** - * Pointer to list element in the list of all registered face - * arrays which references this array. - */ - ListIterator m_it; - -public: - const ConstCombinatorialEmbedding *m_pEmbedding; //!< The associated combinatorial embedding. - - //! Initializes a face array not associated with a combinatorial embedding. - FaceArrayBase() : m_pEmbedding(0) { } - //! Initializes a face array associated with \a pE. - FaceArrayBase(const ConstCombinatorialEmbedding *pE) : m_pEmbedding(pE) { - if(pE) m_it = pE->registerArray(this); - } - - // destructor, unregisters the array - virtual ~FaceArrayBase() { - if (m_pEmbedding) m_pEmbedding->unregisterArray(m_it); - } - - // event interface used by CombinatorialEmbedding - //! Virtual function called when table size has to be enlarged. - virtual void enlargeTable(int newTableSize) = 0; - //! Virtual function called when table has to be reinitialized. - virtual void reinit(int initTableSize) = 0; - - //! Associates the array with a new combinatorial embedding. - void reregister(const ConstCombinatorialEmbedding *pE) { - if (m_pEmbedding) m_pEmbedding->unregisterArray(m_it); - if ((m_pEmbedding = pE) != 0) m_it = pE->registerArray(this); - } -}; // class FaceArrayBase - - -//! Dynamic arrays indexed with faces of a combinatorial embedding. -/** - * Face arrays represent a mapping from faces to data of type \a T. - * They adjust their table size automatically when the number of faces in the - * corresponding combinatorial embedding increases. - * - * @tparam T is the element type. - */ -template class FaceArray : private Array, protected FaceArrayBase { - T m_x; //!< The default value for array elements. - -public: - //! Constructs an empty face array associated with no combinatorial embedding. - FaceArray() : Array(), FaceArrayBase() { } - //! Constructs a face array associated with \a E. - FaceArray(const ConstCombinatorialEmbedding &E) : - Array(E.faceArrayTableSize()), FaceArrayBase(&E) { } - //! Constructs a face array associated with \a E. - /** - * @param E is the associated combinatorial embedding. - * @param x is the default value for all array elements. - */ - FaceArray(const ConstCombinatorialEmbedding &E, const T &x) : - Array(0,E.faceArrayTableSize()-1,x), FaceArrayBase(&E), m_x(x) { } - //! Constructs an face array that is a copy of \a A. - /** - * Associates the array with the same combinatorial embedding as - * \a A and copies all elements. - */ - FaceArray(const FaceArray &A) : Array(A), FaceArrayBase(A.m_pEmbedding), m_x(A.m_x) { } - - //! Returns true iff the array is associated with a combinatorial embedding. - bool valid() const { return (Array::low() <= Array::high()); } - - //! Returns a pointer to the associated combinatorial embedding. - const ConstCombinatorialEmbedding *embeddingOf() const { - return m_pEmbedding; - } - - //! Returns a reference to the element with index \a f. - const T &operator[](face f) const { - OGDF_ASSERT(f != 0 && f->embeddingOf() == m_pEmbedding) - return Array::operator [](f->index()); - } - - //! Returns a reference to the element with index \a f. - T &operator[](face f) { - OGDF_ASSERT(f != 0 && f->embeddingOf() == m_pEmbedding) - return Array::operator [](f->index()); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for a face - * in the associated combinatorial embedding! - */ - const T &operator[](int index) const { - return Array::operator [](index); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for a face - * in the associated combinatorial embedding! - */ - T &operator[](int index) { - return Array::operator [](index); - } - - //! Assignment operator. - FaceArray &operator=(const FaceArray &a) { - Array::operator =(a); - m_x = a.m_x; - reregister(a.m_pEmbedding); - return *this; - } - - //! Reinitializes the array. Associates the array with no combinatorial embedding. - void init() { - Array::init(); reregister(0); - } - - //! Reinitializes the array. Associates the array with \a E. - void init(const ConstCombinatorialEmbedding &E) { - Array::init(E.faceArrayTableSize()); reregister(&E); - } - - //! Reinitializes the array. Associates the array with \a E. - /** - * @param E is the associated combinatorial embedding. - * @param x is the default value. - */ - void init(const ConstCombinatorialEmbedding &E, const T &x) { - Array::init(0,E.faceArrayTableSize()-1, m_x = x); reregister(&E); - } - - //! Sets all array elements to \a x. - void fill(const T &x) { - int high = m_pEmbedding->maxFaceIndex(); - if(high >= 0) - Array::fill(0,high,x); - } - -private: - virtual void enlargeTable(int newTableSize) { - Array::grow(newTableSize-Array::size(),m_x); - } - - virtual void reinit(int initTableSize) { - Array::init(0,initTableSize-1,m_x); - } - - OGDF_NEW_DELETE - -}; // class FaceArray - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/FaceSet.h b/ext/OGDF/ogdf/basic/FaceSet.h deleted file mode 100644 index 5105274ab..000000000 --- a/ext/OGDF/ogdf/basic/FaceSet.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration and implementation of class FaceSetSimple, - * FaceSetPure and FaceSet - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FACE_SET_H -#define OGDF_FACE_SET_H - - -#include -#include - - - -namespace ogdf { - - -//! Maintains a subset S of the faces contained in an associated combinatorial embedding E -/** (only insertion of elements and clear operation) - */ -class OGDF_EXPORT FaceSetSimple { -public: - //! creates a new empty face set associated with combinatorial embedding E - FaceSetSimple(const CombinatorialEmbedding &E) : m_isContained(E,false) { } - - //! destructor - ~FaceSetSimple() { } - - //! inserts face f into set S - /** running time: O(1) - * Precond.: f is a face in the associated combinatorial embedding - */ - void insert(face f) { - OGDF_ASSERT(f->embeddingOf() == m_isContained.embeddingOf()); - bool &isContained = m_isContained[f]; - if (isContained == false) { - isContained = true; - m_faces.pushFront(f); - } - } - - - //! removes all faces from set S - /** running time: O(|S|) - */ - void clear() { - SListIterator it; - for(it = m_faces.begin(); it.valid(); ++it) { - m_isContained[*it] = false; - } - m_faces.clear(); - } - - - //! returns true iff face f is contained in S - /** running time: O(1) - * Precond.: f is a face in the asociated embedding - */ - bool isMember(face f) const { - OGDF_ASSERT(f->embeddingOf() == m_isContained.embeddingOf()); - return m_isContained[f]; - } - - //! returns the list of faces contained in S - const SListPure &faces() const { - return m_faces; - } - -private: - //! m_isContained[f] is true <=> f is contained in S - FaceArray m_isContained; - //! list of faces contained in S - SListPure m_faces; -}; - - - -//! maintains a subset S of the faces contained in an associated combinatorial embedding E -/** (no efficient access to size of S) - */ -class OGDF_EXPORT FaceSetPure { -public: - //! creates a new empty face set associated with combinatorial embedding E - FaceSetPure(const CombinatorialEmbedding &E) : m_it(E,ListIterator()) { } - - //! destructor - ~FaceSetPure() { } - - //! inserts face f into set S - /** running time: O(1) - * Precond.: f is a face in the associated combinatorial embedding - */ - void insert(face f) { - OGDF_ASSERT(f->embeddingOf() == m_it.embeddingOf()); - ListIterator &itF = m_it[f]; - if (!itF.valid()) - itF = m_faces.pushBack(f); - } - - //! removes face f from set S - /** running time: O(1) - * Precond.: f is a face in the asociated embedding - */ - void remove(face f) { - OGDF_ASSERT(f->embeddingOf() == m_it.embeddingOf()); - ListIterator &itF = m_it[f]; - if (itF.valid()) { - m_faces.del(itF); - itF = ListIterator(); - } - } - - - //! removes all faces from set S - /** running time: O(|S|) - */ - void clear() { - ListIterator it; - for(it = m_faces.begin(); it.valid(); ++it) { - m_it[*it] = ListIterator(); - } - m_faces.clear(); - } - - - //! returns true iff face f is contained in S - /** running time: O(1) - * Precond.: f is a face in the asociated embedding - */ - bool isMember(face f) const { - OGDF_ASSERT(f->embeddingOf() == m_it.embeddingOf()); - return m_it[f].valid(); - } - - //! returns the list of faces contained in S - const ListPure &faces() const { - return m_faces; - } - -private: - //! m_it[f] contains list iterator pointing to f if f is contained in S, an invalid list iterator otherwise - FaceArray > m_it; - //! list of faces contained in S - ListPure m_faces; -}; - - - -//! maintains a subset S of the faces contained in an associated combinatorial embedding E -class OGDF_EXPORT FaceSet { -public: - //! creates a new empty face set associated with combinatorial embedding E - FaceSet(const CombinatorialEmbedding &E) : m_it(E,ListIterator()) { } - - //! destructor - ~FaceSet() { } - - //! inserts face f into set S - /** running time: O(1) - * Precond.: f is a face in the associated combinatorial embedding - */ - void insert(face f) { - OGDF_ASSERT(f->embeddingOf() == m_it.embeddingOf()); - ListIterator &itF = m_it[f]; - if (!itF.valid()) - itF = m_faces.pushBack(f); - } - - //! removes face f from set S - /* running time: O(1) - * Precond.: f is a face in the asociated embedding - */ - void remove(face f) { - OGDF_ASSERT(f->embeddingOf() == m_it.embeddingOf()); - ListIterator &itF = m_it[f]; - if (itF.valid()) { - m_faces.del(itF); - itF = ListIterator(); - } - } - - - //! removes all faces from set S - /** running time: O(|S|) - */ - void clear() { - ListIterator it; - for(it = m_faces.begin(); it.valid(); ++it) { - m_it[*it] = ListIterator(); - } - m_faces.clear(); - } - - - //! returns true iff face f is contained in S - /** running time: O(1) - * Precond.: f is a face in the asociated embedding - */ - bool isMember(face f) const { - OGDF_ASSERT(f->embeddingOf() == m_it.embeddingOf()); - return m_it[f].valid(); - } - - //! returns the size of set S - /** running time: O(1) - */ - int size() const { - return m_faces.size(); - } - - //! returns the list of faces contained in S - const List &faces() const { - return m_faces; - } - -private: - //! m_it[f] contains list iterator pointing to f if f is contained in S,an invalid list iterator otherwise - FaceArray > m_it; - //! list of faces contained in S - List m_faces; -}; - - -} // end namespace ogdf - - -#endif - diff --git a/ext/OGDF/ogdf/basic/Graph.h b/ext/OGDF/ogdf/basic/Graph.h deleted file mode 100644 index ffc6859ed..000000000 --- a/ext/OGDF/ogdf/basic/Graph.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Includes declaration of graph class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRAPH_H -#define OGDF_GRAPH_H - - -#include -#include -#include - - - -namespace ogdf { - - //! Output operator for nodes; prints node index (or "nil"). - OGDF_EXPORT ostream &operator<<(ostream &os, ogdf::node v); - - //! Output operator for edges; prints source and target indices (or "nil"). - OGDF_EXPORT ostream &operator<<(ostream &os, ogdf::edge e); - - //! Output operator for adjacency entries; prints node and twin indices (or "nil"). - OGDF_EXPORT ostream &operator<<(ostream &os, ogdf::adjEntry adj); - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/GraphAttributes.h b/ext/OGDF/ogdf/basic/GraphAttributes.h deleted file mode 100644 index 9077ead26..000000000 --- a/ext/OGDF/ogdf/basic/GraphAttributes.h +++ /dev/null @@ -1,860 +0,0 @@ -/* - * $Revision: 2585 $ - * - * last checkin: - * $Author: klein $ - * $Date: 2012-07-12 03:46:50 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GraphAttributes which extends a Graph - * by additional attributes. - * - * \author Carsten Gutwenger - * Karsten Klein - * Joachim Kupke - * Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ATTRIBUTED_GRAPH_H -#define OGDF_ATTRIBUTED_GRAPH_H - -#include -#include -#include -#include - -namespace ogdf { - -//--------------------------------------------------------- -// GraphAttributes -// graph topology + graphical attributes -//--------------------------------------------------------- -//! Stores additional attributes of a graph (like layout information). -/** - * It is frequently necessary to associate additional attributes with a graph. - * The class GraphAttributes provides various such attributes and is the - * central place were such attributes are stored. - * - * Attributes are simply stored in node or edge arrays; for memory consumption - * reasons, only a subset of these arrays is in fact initialized for the graph; - * non-initialized arrays require only a few bytes of extra memory. - * - * Which arrays are initialized is specified by a bit vector; each bit in this - * bit vector corresponds to one or more attributes. E.g., \a #nodeGraphics - * corresponds to the attributes \a #m_x, \a #m_y, \a #m_width, and \a #m_height; - * whereas \a #edgeDoubleWeight only corresponds to the attribute \a #m_doubleWeight. - * - * Attributes can be initialized by the constructor GraphAttributes(const Graph &,long) - * or the function initAttributes(); attributes can also be deinitialized by - * calling destroyAttributes(). - */ - -class OGDF_EXPORT GraphAttributes { -public: - //! Types for edge arrows. - enum EdgeArrow { - none, //!< no edge arrows - last, //!< edge arrow at target node of the edge - first, //!< edge arrow at source node of the edge - both, //!< edge arrow at target and source node of the edge - undefined - }; - - //! Types for line styles. - /** - * The line styles are preliminary the same as in QT. - */ - enum EdgeStyle { - esNoPen = 0, //!< no line - esSolid = 1, //!< solid line - esDash = 2, //!< dashed line - esDot = 3, //!< dotted line - esDashdot = 4, //!< line style "dash dot dash dot ..." - esDashdotdot = 5 - //!< line style "dash dot dot dash dot dot ..." - }; - - //! Converts integer \a i to edge style. - static EdgeStyle intToStyle(int i) { - switch (i) { - case 0: - return esNoPen; - case 1: - return esSolid; - case 2: - return esDash; - case 3: - return esDot; - case 4: - return esDashdot; - case 5: - return esDashdotdot; - default: - return esNoPen; - - } - } - - //! Types for object brush patterns. - /** - * The brush patterns are currently the same as the GDE project. - */ - enum BrushPattern { - bpNone = 0, - bpSolid = 1, - bpDense1 = 2, - bpDense2 = 3, - bpDense3 = 4, - bpDense4 = 5, - bpDense5 = 6, - bpDense6 = 7, - bpDense7 = 8, - bpHorizontal = 9, - bpVertical = 10, - bpCross = 11, - BackwardDiagonal = 12, - ForwardDiagonal = 13, - DiagonalCross = 14 - }; - - //! Converts integer \a i to brush pattern. - static BrushPattern intToPattern(int i) { - switch (i) { - case 0: - return bpNone; - break; - case 1: - return bpSolid; - break; - case 2: - return bpDense1; - break; - case 3: - return bpDense2; - break; - case 4: - return bpDense3; - break; - case 5: - return bpDense4; - break; - case 6: - return bpDense5; - break; - case 7: - return bpDense6; - break; - case 8: - return bpDense7; - break; - case 9: - return bpHorizontal; - break; - case 10: - return bpVertical; - break; - case 11: - return bpCross; - break; - case 12: - return BackwardDiagonal; - break; - case 13: - return ForwardDiagonal; - break; - case 14: - return DiagonalCross; - break; - default: - return bpNone; - break; - } - } - - //! Specifies scaling of images. - enum ImageStyle { - FreeScale = 0, FixScale = 1 - }; - //! Specifies image alignment. - enum ImageAlignment { - TopLeft = 0, TopCenter, TopRight, CenterLeft, Center, CenterRight, BottomLeft, BottomCenter, BottomRight - }; - - //! Helper function mapping int values to image styles - static ImageStyle intToImageStyle(int i) { - switch (i) { - case 0: - return FreeScale; - break; - case 1: - return FixScale; - break; - default: - return FreeScale; - }//switch - }//intToStyle - - //! Helper function mapping int values to image alignment - static ImageAlignment intToImageAlignment(int i) { - switch (i) { - case 0: - return TopLeft; - break; - case 1: - return TopCenter; - break; - case 2: - return TopRight; - break; - case 3: - return CenterLeft; - break; - case 4: - return Center; - break; - case 5: - return CenterRight; - break; - case 6: - return BottomLeft; - break; - case 7: - return BottomCenter; - break; - case 8: - return BottomRight; - break; - default: - return TopLeft; - }//switch - }//intToAlignment - -protected: - /** - * Writes string \a str into a GML file such that line length limits - * are respected and characters '\', '"' are correctly escaped. - */ - void writeLongString(ostream &os, const String &str) const; - - /* Methods for OGML serialization */ - - //! Static helper method for mapping edge styles to ogml. - static const char * edgeStyleToOGML(const GraphAttributes::EdgeStyle & edgeStyle); - - //! Static helper method for mapping image alignments to ogml. - static const char * imageAlignmentToOGML(const GraphAttributes::ImageAlignment &imgAlign); - - //! Static helper method for mapping image style to ogml. - static const char * imageStyleToOGML(const GraphAttributes::ImageStyle &imgStyle); - - //! Static helper method for mapping brush patterns styles to ogml. - static const char * brushPatternToOGML(const GraphAttributes::BrushPattern & brushPattern); - - //static void generateIndent(char ** indent, const int & indentSize); - - //! Static helper method for exchanging X(HT)ML-tag specific chars. - String formatLabel(const String & labelText); - - /* End methods for OGML serialization */ - - const Graph *m_pGraph; //!< associated graph - - bool m_directed; //!< whether or not the graph is directed - - // graphical representation of nodes - NodeArray m_x; //!< x-coordinate of a node - NodeArray m_y; //!< y-coordinate pf a node - NodeArray m_width; //!< width of a node's bounding box - NodeArray m_height; //!< height of a nodes's bounding box - NodeArray m_nodeLabel; //!< label of a node - NodeArray m_nodeColor; //!< color of a node - NodeArray m_nodeLine; //!< line color of a node - NodeArray m_nodeShape; //!< shape of a node - NodeArray m_nodeLineWidth; //!< line width of a node - NodeArray m_nodePattern; //!< brush pattern of a node - NodeArray m_nodeStyle; //!< line style of a node - NodeArray m_nodeTemplate; //!< name of template of a node - - // images - NodeArray m_imageUri; - NodeArray m_imageStyle; - NodeArray m_imageAlign; - NodeArray m_imageDrawLine; - NodeArray m_imageWidth; - NodeArray m_imageHeight; - - // other node attributes - NodeArray m_nodeId; //!< user ID of a node - NodeArray m_level; //!< level of a node - NodeArray m_nodeIntWeight; //!< (integer) weight of a node - NodeArray m_vType; // type (vertex, dummy, generalizationMerger) - - // graphical representation of edges - EdgeArray m_bends; //!< list of bend points of an edge - EdgeArray m_edgeLabel; //!< label of an edge - EdgeArray m_edgeArrow; //!< arrow type of an edge - EdgeArray m_edgeStyle; //!< line style of an edge - EdgeArray m_edgeColor; //!< line color of an edge - EdgeArray m_edgeWidth; //!< line width of an edge - EdgeArray m_eType; //!< type of an edge (association or generalization) - - // other edge attributes - EdgeArray m_intWeight; //!< (integer) weight of an edge - EdgeArray m_doubleWeight; //!< (real number) weight of an edge - EdgeArray m_subGraph; //!< is element of subgraphs given by bitvector - - long m_attributes; //!< bit vector of currently used attributes - -public: - //! Bits for specifying attributes. - enum { - nodeGraphics = 0x00001, //!< node attributes m_x, m_y, m_width, m_height, m_nodeShape - edgeGraphics = 0x00002, //!< edge attribute m_bends - nodeLevel = 0x00004, //!< node attribute m_level - edgeIntWeight = 0x00008, //!< edge attribute m_intWeight - edgeDoubleWeight = 0x00010, //!< edge attribute m_doubleWeight - edgeLabel = 0x00020, //!< edge attribute m_edgeLabel - nodeLabel = 0x00040, //!< node attribute m_nodeLabel - edgeType = 0x00080, //!< edge attribute m_eType - nodeType = 0x00100, //!< node attribute m_vType - nodeColor = 0x00200, //!< node attribute m_nodeColor, m_nodeLine - nodeId = 0x00400, //!< node attribute m_nodeId - edgeArrow = 0x00800, //!< edge attribute m_edgeArrow - edgeColor = 0x01000, //!< edge attribute m_edgeColor - edgeStyle = 0x02000, //!< edge attribute m_edgeStyle, m_edgeWidth - nodeStyle = 0x04000, //!< node attributes m_nodePattern, m_nodeStyle, m_nodeLineWidth; - //!< experimental: m_imageUri, m_imageStyle, m_imageAlign, - //!< m_imageDrawLine, m_imageWidth, m_imageHeight - nodeTemplate = 0x08000, //!< node attribute m_nodeTemplate - edgeSubGraph = 0x10000, //!< edge attribute m_subGraph - nodeWeight = 0x20000 - //!< node attribute m_nodeIntWeight - }; - - //! Bits for specifying node shapes. - enum { - oval = 0x8001, rectangle = 0x8002 - }; - - //! Constructs graph attributes for no associated graph (default constructor). - /** - * The associated graph can be set later with the init() function. - */ - GraphAttributes(); - - //! Constructs graph attributes associated with the graph \a G. - /** - * @param G is the associated graph. - * @param initAttributes specifies the set of attributes that can be accessed. - */ - GraphAttributes(const Graph &G, long initAttributes = nodeGraphics | edgeGraphics); - - virtual ~GraphAttributes() { - } - - //! Initializes the graph attributes for graph \a G. - /** - * @param G is the new associated graph. - * @param initAttr specifies the set of attributes that can be accessed. - * - * \warning All attributes that were allocated before are destroyed by this function! - * If you wish to extend the set of allocated attributes, use initAttributes(). - */ - virtual void init(const Graph &G, long initAttr); - - //! Returns currently accessible attributes. - long attributes() const { - return m_attributes; - } - - //! Initializes attributes in \a attr for usage. - void initAttributes(long attr); - - //! Destroys attributes in attr. - void destroyAttributes(long attr); - - //! Returns a reference to the associated graph - const Graph& constGraph() const { - return *m_pGraph; - } - - //! Returns if the graph is directed. - bool directed() { - return m_directed; - } - - //! Sets if the graph is directed to \a directed. - void directed(bool directed) { - m_directed = directed; - } - - //! Returns the template name of node \a v. - const String &templateNode(node v) const { - return m_nodeTemplate[v]; - } - //! Returns the template name of node \a v. - String &templateNode(node v) { - return m_nodeTemplate[v]; - } - - //! Returns the x-coordinate of node \a v. - const double &x(node v) const { - return m_x[v]; - } - //! Returns the x-coordinate of node \a v. - double &x(node v) { - return m_x[v]; - } - - //! Returns the y-coordinate of node \a v. - const double &y(node v) const { - return m_y[v]; - } - //! Returns the y-coordinate of node \a v. - double &y(node v) { - return m_y[v]; - } - - //! Returns a reference to the NodeArray \a m_width. - const NodeArray &width() const { - return m_width; - } - //! Returns a refeence to the NodeArray \a m_width. - NodeArray &width() { - return m_width; - } - - //! Returns the width of the bounding box of node \a v. - const double &width(node v) const { - return m_width[v]; - } - //! Returns the width of the bounding box of node \a v. - double &width(node v) { - return m_width[v]; - } - - //! Returns a reference to the NodeArray \a m_height. - const NodeArray &height() const { - return m_height; - } - //! Returns a refeence to the NodeArray \a m_height. - NodeArray &height() { - return m_height; - } - - //! Returns the height of the bounding box of node \a v. - const double &height(node v) const { - return m_height[v]; - } - //! Returns the height of the bounding box of node \a v. - double &height(node v) { - return m_height[v]; - } - - //! Returns the level of node \a v. - const int &level(node v) const { - return m_level[v]; - } - //! Returns the level of node \a v. - int &level(node v) { - return m_level[v]; - } - - //! Returns the weight of node \a v. - const int &weight(node v) const { - return m_nodeIntWeight[v]; - } - //! Returns the weight of node \a v. - int &weight(node v) { - return m_nodeIntWeight[v]; - } - - //! Returns the brush pattern of node \a v. - const BrushPattern &nodePattern(node v) const { - return m_nodePattern[v]; - } - //! Returns the brush pattern of node \a v. - BrushPattern &nodePattern(node v) { - return m_nodePattern[v]; - } - - //! Returns the line style of node \ v. - const EdgeStyle &styleNode(node v) const { - return m_nodeStyle[v]; - } - //! Returns the line style of node \ v. - EdgeStyle &styleNode(node v) { - return m_nodeStyle[v]; - } - - //! Returns the line width of node \a v. - const double &lineWidthNode(node v) const { - return m_nodeLineWidth[v]; - } - //! Returns the line width of node \a v. - double &lineWidthNode(node v) { - return m_nodeLineWidth[v]; - } - - //! Returns the line color of node \a v. - const String &nodeLine(node v) const { - return m_nodeLine[v]; - } - //! Returns the line color of node \a v. - String &nodeLine(node v) { - return m_nodeLine[v]; - } - - //! Returns the list of bend points of edge \a e. - const DPolyline &bends(edge e) const { - return m_bends[e]; - } - //! Returns the list of bend points of edge \a e. - DPolyline &bends(edge e) { - return m_bends[e]; - } - - //! Returns the (integer) weight of edge \a e. - const int &intWeight(edge e) const { - return m_intWeight[e]; - } - //! Returns the (integer) weight of edge \a e. - int &intWeight(edge e) { - return m_intWeight[e]; - } - - //! Returns the (real number) weight of edge \a e. - const double &doubleWeight(edge e) const { - return m_doubleWeight[e]; - } - //! Returns the (real number) weight of edge \a e. - double &doubleWeight(edge e) { - return m_doubleWeight[e]; - } - - //! Returns the line width of edge \a e. - const double &edgeWidth(edge e) const { - return m_edgeWidth[e]; - } - //! Returns the line width of edge \a e. - double &edgeWidth(edge e) { - return m_edgeWidth[e]; - } - - //! Returns the color of node \a v. - const String &colorNode(node v) const { - return m_nodeColor[v]; - } - //! Returns the color of node \a v. - String &colorNode(node v) { - return m_nodeColor[v]; - } - - //! Returns the shape type of node \a v. - int shapeNode(node v) const { - return m_nodeShape[v]; - } - //! Returns the shape type of node \a v. - int &shapeNode(node v) { - return m_nodeShape[v]; - } - - //! Returns the label of node \ v. - const String &labelNode(node v) const { - return m_nodeLabel[v]; - } - //! Returns the label of node \ v. - String &labelNode(node v) { - return m_nodeLabel[v]; - } - - //! Returns the label of edge \a e. - const String &labelEdge(edge e) const { - return m_edgeLabel[e]; - } - //! Returns the label of edge \a e. - String &labelEdge(edge e) { - return m_edgeLabel[e]; - } - - //! Returns the type of edge \a e. - Graph::EdgeType type(edge e) const { - return m_eType.valid() ? m_eType[e] : Graph::association; - } - //! Returns the type of edge \a e. - Graph::EdgeType &type(edge e) { - return m_eType[e]; - } - - //! Returns the type of node \a v. - Graph::NodeType type(node v) const { - return m_vType.valid() ? m_vType[v] : Graph::vertex; - } - //! Returns the type of node \a v. - Graph::NodeType &type(node v) { - return m_vType[v]; - } - - //! Returns the user ID of node \a v. - const int &idNode(node v) const { - return m_nodeId[v]; - } - //! Returns the user ID of node \a v. - int &idNode(node v) { - return m_nodeId[v]; - } - - //! Returns the arrow type of edge \a e. - const EdgeArrow &arrowEdge(edge e) const { - return m_edgeArrow[e]; - } - //! Returns the arrow type of edge \a e. - EdgeArrow &arrowEdge(edge e) { - return m_edgeArrow[e]; - } - - //! Returns the line style of an edge \a e. - const EdgeStyle &styleEdge(edge e) const { - return m_edgeStyle[e]; - } - //! Returns the line style of an edge \a e. - EdgeStyle &styleEdge(edge e) { - return m_edgeStyle[e]; - } - - //! Returns the color of node \a v. - const String &colorEdge(edge e) const { - return m_edgeColor[e]; - } - //! Returns the color of node \a v. - String &colorEdge(edge e) { - return m_edgeColor[e]; - } - - // Images: - //! Returns image uri of node v. - const String &imageUriNode(node v) const { - return m_imageUri[v]; - } - //! Returns image uri of node v. - String &imageUriNode(node v) { - return m_imageUri[v]; - } - //! Returns image style of node v. - const ImageStyle &imageStyleNode(node v) const { - return m_imageStyle[v]; - } - //! Returns image style of node v. - ImageStyle &imageStyleNode(node v) { - return m_imageStyle[v]; - } - // Returns image alignment of node v. - const ImageAlignment &imageAlignmentNode(node v) const { - return m_imageAlign[v]; - } - // Returns image alignment of node v. - ImageAlignment &imageAlignmentNode(node v) { - return m_imageAlign[v]; - } - //! Returns bool value drawLine of node v. - const bool &imageDrawLineNode(node v) const { - return m_imageDrawLine[v]; - } - //! Returns bool value drawLine of node v. - bool &imageDrawLineNode(node v) { - return m_imageDrawLine[v]; - } - //! Returns image width of node v. - const double &imageWidthNode(node v) const { - return m_imageWidth[v]; - } - //! Returns image width of node v. - double &imageWidthNode(node v) { - return m_imageWidth[v]; - } - // Returns image height of node v. - const double &imageHeightNode(node v) const { - return m_imageHeight[v]; - } - // Returns image height of node v. - double &imageHeightNode(node v) { - return m_imageHeight[v]; - } - - //! Returns the edgesubgraph value of an edge \a e. - const unsigned int &subGraphBits(edge e) const { - return m_subGraph[e]; - } - //! Returns the edgesubgraph value of an edge \a e. - unsigned int &subGraphBits(edge e) { - return m_subGraph[e]; - } - - //! Checks whether edge \a e belongs to basic graph \a n. - bool inSubGraph(edge e, int n) const { - OGDF_ASSERT( n>=0 && n<32 ); - return (m_subGraph[e] & (1 << n)) != 0; - } - //! Addes edge \a e to basic graph \a n. - void addSubGraph(edge e, int n) { - OGDF_ASSERT( n>=0 && n<32 ); - m_subGraph[e] |= (1 << n); - } - //! Removes edge \a e from basic graph \a n. - void removeSubGraph(edge e, int n) { - OGDF_ASSERT( n>=0 && n<32 ); - m_subGraph[e] &= ~(1 << n); - } - - //! Returns the bounding box of the graph. - const DRect boundingBox() const; - - /** - * We hide the internal representation of semantic node types from - * the user to be able to change this later (semantic node type member array). - * We are not allowed to set association classes manually, only by calling - * createAssociationClass(). - */ - bool isAssociationClass(node v) const { - return (type(v) == Graph::associationClass); - } - - /** - * According to the \a mode switch add either the node center points to - * the bends or the anchor point on the node boundary - * - \a mode = 0: only add node center - * - \a mode = 1: compute intersection with the line segment to the center - * and the boundary of the rectangular node - * - \a mode = 2: compute intersection with the first/last line segment - * and the boundary of the rectangular node - */ - void addNodeCenter2Bends(int mode = 1); - - void clearAllBends(); - - //! Returns a list of all inheritance hierarchies in the graph. - /** - * Inheritance hierarchies are identified by edges with type Graph::generalization. - * - * @param list is a list of all hierarchies; each hierarchie is itself a list - * of all nodes in this hierarchy. - * - * \return Returns the number of generalization hierarchies. - */ - int hierarchyList(List*> &list) const; - - //! Returns a list of all inheritance hierarchies in the graph. - /** - * Inheritance hierarchies are identified by edges with type Graph::generalization. - * - * @param list is a list of all hierarchies; each hierarchie is itself a list - * of all edges in this hierarchy. - * - * \return Returns the number of generalization hierarchies. - */ - int hierarchyList(List*> &list) const; - - //! Sets the width of all nodes to \a w. - void setAllWidth(double w); - //! Sets the height of all nodes to \a h. - void setAllHeight(double h); - - //! Reads the graph from a GML file \a fileName. - bool readGML(Graph &G, const String &fileName); - - //! Reads the graph from a GML input stream \a is. - bool readGML(Graph &G, istream &is); - - //! Writes the graph with its attributes in GML format to file \a fileName. - void writeGML(const String &fileName) const; - - //! Writes the graph with its attributes in GML format to output stream \a os. - void writeGML(ostream &os) const; - - //! Writes the graph with its attributes in SVG format to file \a fileName. - /** - * @param fileName filename of the SVG - * @param fontSize size of node label (default = 3) - * @param fontColor color of node label (default = #000000) - */ - void writeSVG(const String &fileName, int fontSize = 3, const String &fontColor = "#000000") const; - - //! Writes the graph with its attributes in SVG format to output stream \a os. - /** - * @param os output stream for SVG - * @param fontSize size of node label - * @param fontColor color of node label - */ - void writeSVG(ostream &os, int fontSize, const String &fontColor) const; - - //! Reads the graph and attributes from the XML file \a fileName. - bool readXML(Graph &G, const String &fileName); - - //! Reads the graph and attributes from the XML input stream \a is. - bool readXML(Graph &G, istream &is); - - //! Writes the graph to the XML file \a fileName. - void writeXML(const String &fileName, const char* delimiter = "", const char* offset = "") const; - - //! Writes the graph to XML output stream \a os. - virtual void writeXML(ostream &os, const char* delimiter = "", const char* offset = "") const; - - //! Reads a graph in Rudy format from file \a fileName. - bool readRudy(Graph &G, const String &fileName); - - //! Reads a graph in Rudy format from input stream \a is. - bool readRudy(Graph &G, istream &is); - - //! Writes the graph in Rudy format to file \a fileName. - void writeRudy(const String &fileName) const; - - //! Writes the graph in Rudy format to output stream \a os. - void writeRudy(ostream &os) const; - - //! Removes unnecessary bend points in orthogonal segements. - /** - * Processes all edges and removes unnecessary bend points in the bend point list - * of the edge, i.e., bend points such that the preceding and succeeding bend point - * form a horizontal or vertical segement containing this bend point. This function - * is useful to remove redundant bend points in an orthogonal layout. - */ - void removeUnnecessaryBendsHV(); -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/GraphCopy.h b/ext/OGDF/ogdf/basic/GraphCopy.h deleted file mode 100644 index c5c0a42ee..000000000 --- a/ext/OGDF/ogdf/basic/GraphCopy.h +++ /dev/null @@ -1,642 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of graph copy classes. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRAPH_COPY_H -#define OGDF_GRAPH_COPY_H - - -#include -#include -#include -#include - - -namespace ogdf { - -class FaceSetPure; - - -//--------------------------------------------------------- -// GraphCopySimple -// simple graph copies (no support for edge splitting) -//--------------------------------------------------------- -/** - * \brief Copies of graphs with mapping between nodes and edges - * - * The class GraphCopySimple represents a copy of a graph and - * maintains a mapping between the nodes and edges of the original - * graph to the copy and vice versa. - * - * New nodes and edges can be added to the copy; the counterpart - * of those nodes and edges is 0 indicating that there is no counterpart. - * This class does not support splitting of edges in such a way - * that both edges resulting from the split are mapped to the same - * original edge; this feature is provided by GraphCopy. - */ -class OGDF_EXPORT GraphCopySimple : public Graph -{ - const Graph *m_pGraph; //!< The original graph. - NodeArray m_vOrig; //!< The corresponding node in the original graph. - NodeArray m_vCopy; //!< The corresponding node in the graph copy. - EdgeArray m_eOrig; //!< The corresponding edge in the original graph. - EdgeArray m_eCopy; //!< The corresponding edge in the graph copy. - -public: - // construction - - //! Constructs a copy of graph \a G. - GraphCopySimple(const Graph &G); - - //! Copy constructor. - GraphCopySimple(const GraphCopySimple &GC); - - virtual ~GraphCopySimple() { } - - //! Returns a reference to the original graph. - const Graph &original() const { return *m_pGraph; } - - /** - * \brief Returns the node in the original graph corresponding to \a v. - * @param v is a node in the graph copy. - * \return the corresponding node in the original graph, or 0 if no - * such node exists. - */ - node original(node v) const { return m_vOrig[v]; } - - /** - * \brief Returns the edge in the original graph corresponding to \a e. - * @param e is an edge in the graph copy. - * \return the corresponding edge in the original graph, or 0 if no - * such edge exists. - */ - edge original(edge e) const { return m_eOrig[e]; } - - /** - * \brief Returns the node in the graph copy corresponding to \a v. - * @param v is a node in the original graph. - * \return the corresponding node in the graph copy. - */ - node copy(node v) const { return m_vCopy[v]; } - - /** - * \brief Returns the edge in the graph copy corresponding to \a e. - * @param e is an edge in the original graph. - * \return the corresponding edge in the graph copy. - */ - edge copy(edge e) const { return m_eCopy[e]; } - - /** - * \brief Returns true iff \a v has no corresponding node in the original graph. - * @param v is a node in the graph copy. - */ - bool isDummy(node v) const { return (m_vOrig[v] == 0); } - - /** - * \brief Returns true iff \a e has no corresponding edge in the original graph. - * @param e is an edge in the graph copy. - */ - bool isDummy(edge e) const { return (m_eOrig[e] == 0); } - - //! Assignment operator. - GraphCopySimple &operator=(const GraphCopySimple &GC); - - - //! Creates a new node in the graph copy. - node newNode() { - return Graph::newNode(); - } - - /** - * \brief Creates a new node in the graph copy with original node \a vOrig. - * \warning You have to make sure that the original node makes sense, in - * particular that \a vOrig is not the original node of another node in the copy. - */ - node newNode(node vOrig) { - OGDF_ASSERT(vOrig != 0 && vOrig->graphOf() == m_pGraph); - node v = Graph::newNode(); - m_vCopy[m_vOrig[v] = vOrig] = v; - return v; - } - - //! Creates a new edge from \a v to \a w in the graph copy. - edge newEdge(node v, node w) { - return Graph::newEdge(v,w); - } - - /** - * \brief Creates a new edge in the graph copy with original edge \a eOrig. - * \warning You have to make sure that the original edge makes sense, in - * particular that \a eOrig is not the original edge of another edge in the copy. - */ - edge newEdge(edge eOrig) { - OGDF_ASSERT(eOrig != 0 && eOrig->graphOf() == m_pGraph); - edge e = Graph::newEdge(m_vCopy[eOrig->source()], m_vCopy[eOrig->target()]); - m_eCopy[m_eOrig[e] = eOrig] = e; - return e; - } - -private: - void initGC(const GraphCopySimple &GC, NodeArray &vCopy, - EdgeArray &eCopy); -}; // class GraphCopySimple - - -//--------------------------------------------------------- -// GraphCopy -// graph copies (support for edge splitting) -//--------------------------------------------------------- -/** - * \brief Copies of graphs supporting edge splitting - * - * The class GraphCopy represents a copy of a graph and - * maintains a mapping between the nodes and edges of the original - * graph to the copy and vice versa. - * - * New nodes and edges can be added to the copy; the counterpart - * of those nodes and edges is 0 indicating that there is no counterpart. - * GraphCopy also support splitting of edges in such a way - * that both edges resulting from the split are mapped to the same - * original edge, and each edge of the original graph is mapped to a list - * of edges. Furthermore, it is allowed to reverse edges in the graph copy. - * - *

    Do's and Dont's

    - * Here is a short summary, what can be done with GraphCopy, and what should not - * be done. The following operations are safely supported: - * - Splitting of edges such that an original edge is represented by a path - * in the copy (split(), unsplit()). - * - Reversing edges in the copy (Graph::reverseEdge(), Graph::reverseAllEdges()). - * - Reinsertion of original edges such that they are represented by a path - * in the copy (insertEdgePath(), insertEdgePathEmbedded(), removeEdgePath(), - * removeEdgePathEmbedded()). - * - Inserting and removing dummy edges in the copy which are not associated - * with edges in the original graph. - * - * The following operations are not supported and are thus dangerous: - * - Any modifications on the original graph, since the copy will not be - * notified. - * - Moving the source or target node of an edge in the copy to a different node. - * - Removing edges in the graph copy that belong to a path representing an - * original edge. - * - ... (better think first!) - */ -class OGDF_EXPORT GraphCopy : public Graph { -protected: - - const Graph *m_pGraph; //!< The original graph. - NodeArray m_vOrig; //!< The corresponding node in the original graph. - EdgeArray m_eOrig; //!< The corresponding edge in the original graph. - EdgeArray > m_eIterator; //!< The position of copy edge in the list. - - NodeArray m_vCopy; //!< The corresponding node in the graph copy. - EdgeArray > m_eCopy; //!< The corresponding list of edges in the graph copy. - -public: - //! Creates a graph copy of \a G. - /** - * The constructor assures that the adjacency lists of nodes in the - * constructed copy are in the same order as the adjacency lists in \a G. - * This is in particular important when dealing with embedded graphs. - */ - GraphCopy(const Graph &G); - - //! Default constructor (does nothing!). - GraphCopy() : Graph() { } - - //! Copy constructor. - /** - * Creates a graph copy that is a copy of \a GC and represents a graph - * copy of the original graph of \a GC. - */ - GraphCopy(const GraphCopy &GC); - - virtual ~GraphCopy() { } - - - /** - * @name Mapping between original graph and copy - */ - //@{ - - //! Returns a reference to the original graph. - const Graph &original() const { return *m_pGraph; } - - /** - * \brief Returns the node in the original graph corresponding to \a v. - * @param v is a node in the graph copy. - * \return the corresponding node in the original graph, or 0 if no - * such node exists. - */ - node original(node v) const { return m_vOrig[v]; } - - /** - * \brief Returns the edge in the original graph corresponding to \a e. - * @param e is an edge in the graph copy. - * \return the corresponding edge in the original graph, or 0 if no - * such edge exists. - */ - edge original(edge e) const { return m_eOrig[e]; } - - /** - * \brief Returns the node in the graph copy corresponding to \a v. - * @param v is a node in the original graph. - * \return the corresponding node in the graph copy. - */ - node copy(node v) const { return m_vCopy[v]; } - - /** - * \brief Returns the list of edges coresponding to edge \a e. - * \param e is an edge in the original graph. - * \return the corresponding list of edges in the graph copy. - */ - const List &chain(edge e) const { return m_eCopy[e]; } - - // returns first edge in chain(e) - /** - * \brief Returns the first edge in the list of edges coresponding to edge \a e. - * @param e is an edge in the original graph. - * \return the first edge in the corresponding list of edges in - * the graph copy. - */ - edge copy(edge e) const { return m_eCopy[e].front(); } - - /** - * \brief Returns true iff \a v has no corresponding node in the original graph. - * @param v is a node in the graph copy. - */ - bool isDummy(node v) const { return (m_vOrig[v] == 0); } - - /** - * \brief Returns true iff \a e has no corresponding edge in the original graph. - * @param e is an edge in the graph copy. - */ - bool isDummy(edge e) const { return (m_eOrig[e] == 0); } - - /** - * \brief Returns true iff edge \a e has been reversed. - * @param e is an edge in the original graph. - */ - bool isReversed (edge e) const { - return e->source() != original(copy(e)->source()); - } - - - /** - * @name Creation and deletion of nodes and edges - */ - //@{ - - //! Creates a new node in the graph copy. - node newNode() { - return Graph::newNode(); - } - - /** - * \brief Creates a new node in the graph copy with original node \a vOrig. - * \warning You have to make sure that the original node makes sense, in - * particular that \a vOrig is not the original node of another node in the copy. - */ - node newNode(node vOrig) { - OGDF_ASSERT(vOrig != 0 && vOrig->graphOf() == m_pGraph); - node v = Graph::newNode(); - m_vCopy[m_vOrig[v] = vOrig] = v; - return v; - } - - /** - * \brief Removes node \a v and all its adjacent edges cleaning-up their corresponding lists of original edges. - * - * \pre The corresponding lists oforiginal edges contain each only one edge. - * \param v is a node in the graph copy. - */ - void delCopy(node v); - - /** - * \brief Removes edge e and clears the list of edges corresponding to \a e's original edge. - * - * \pre The list of edges corresponding to \a e's original edge contains only \a e. - * \param e is an edge in the graph copy. - */ - void delCopy(edge e); - - - /** - * \brief Splits edge \a e. - * @param e is an edge in the graph copy. - */ - virtual edge split(edge e); - - - /** - * \brief Undoes a previous split operation. - * The two edges \a eIn and \a eOut are merged to a single edge \a eIn. - * \pre The vertex \a u that was created by the previous split operation has - * exactly one incoming edge \a eIn and one outgoing edge \a eOut. - * @param eIn is an edge (*,\a u) in the graph copy. - * @param eOut is an edge (\a u,*) in the graph copy. - */ - void unsplit(edge eIn, edge eOut); - - //! Creates a new edge (\a v,\a w) with original edge \a eOrig. - edge newEdge(edge eOrig); - - //! Creates a new edge with original edge \a eOrig at predefined positions in the adjacency lists. - /** - * Let \a v be the node whose adjacency list contains \a adjSrc. Then, - * the created edge is (\a v,\a w). - * @param eOrig is the original edge. - * @param adjSrc is the adjacency entry after which the new edge is inserted - * in the adjacency list of \a v. - * @param w is the source node of the new edge; the edge is added at the end - * of the adjacency list of \a w. - * @return the created edge. - */ - edge newEdge(edge eOrig, adjEntry adjSrc, node w); - - //! Creates a new edge with original edge \a eOrig at predefined positions in the adjacency lists. - /** - * Let \a w be the node whose adjacency list contains \a adjTgt. Then, - * the created edge is (\a v,\a w). - * @param eOrig is the original edge. - * @param v is the source node of the new edge; the edge is added at the end - * of the adjacency list of \a v. - * @param adjTgt is the adjacency entry after which the new edge is inserted - * in the adjacency list of \a w. - * @return the created edge. - */ - edge newEdge(edge eOrig, node v, adjEntry adjTgt); - - edge newEdge(node v, node w) { return Graph::newEdge(v, w); } - edge newEdge(adjEntry adjSrc, adjEntry adjTgt) { return Graph::newEdge(adjSrc, adjTgt); } - edge newEdge(node v, adjEntry adjTgt) { return Graph::newEdge(v, adjTgt); } - edge newEdge(adjEntry adjSrc, node w) { return Graph::newEdge(adjSrc, w); } - - //! sets eOrig to be the corresponding original edge of eCopy and vice versa - /** - * @param eOrig is the original edge - * @param eCopy is the edge copy - */ - void setEdge(edge eOrig, edge eCopy); - - //! Re-inserts edge \a eOrig by "crossing" the edges in \a crossedEdges. - /** - * Let \a v and \a w be the copies of the source and target nodes of \a eOrig. - * Each edge in \a crossedEdges is split creating a sequence - * \f$u_1,\ldots,u_k\f$ of new nodes, and additional edges are inserted creating - * a path \f$v,u_1,\ldots,u_k,w\f$. - * @param eOrig is an edge in the original graph and becomes the original edge of - * all edges in the path \f$v,u_1,\ldots,u_k,w\f$. - * @param crossedEdges are edges in the graph copy. - */ - void insertEdgePath(edge eOrig, const SList &crossedEdges); - - //for FixedEmbeddingUpwardEdgeInserter only - void insertEdgePath(node srcOrig, node tgtOrig, const SList &crossedEdges); - - - //! Removes the complete edge path for edge \a eOrig. - /** - * \@param eOrig is an edge in the original graph. - */ - void removeEdgePath(edge eOrig); - - //! Inserts crossings between two copy edges. - /** - * This method is used in TopologyModule. - * - * Let \a crossingEdge = (\a a, \a b) and \a crossedEdge = (\a v, \a w). - * Then \a crossedEdge is split creating two edges \a crossedEdge = (\a v, \a u) - * and (\a u, \a w), \a crossingEdge is removed and replaced by two new edges - * \a e1 = (\a a, \a u) and \a e1 = (\a u, \a b). - * Finally it sets \a crossingEdge to \a e2 and returns (\a u, \a w). - * - * @param crossingEdge is the edge that gets split. - * @param crossedEdge is the edge that is replaced by two new edges. - * @param topDown is used as follows: If set to true, \a crossingEdge will cross - * \a crossedEdge from right to left, otherwise from left to right. - */ - edge insertCrossing( - edge& crossingEdge, - edge crossedEdge, - bool topDown); - - - /** - * @name Combinatorial Embeddings - */ - //@{ - - //! Creates a new edge with original edge \a eOrig in an embedding \a E. - /** - * Let \a w be the node whose adjacency list contains \a adjTgt. The original - * edge \a eOrig must connect the original nodes of \a v and \a w. If \a eOrig = - * (original(\a v),original(\a w)), then the created edge is (\a v,\a w), otherwise - * it is (\a w,\a v). The new edge \a e must split a face in \a E, such that \a e - * comes after \a adj in the adjacency list of \a v and at the end of the adjacency - * list of \a v. - * - * @param v is a node in the graph copy. - * @param adj is an adjacency entry in the graph copy. - * @param eOrig is an edge in the original graph. - * @param E is an embedding of the graph copy. - * @return the created edge. - */ - edge newEdge(node v, adjEntry adj, edge eOrig, CombinatorialEmbedding &E); - - /** - * \brief Sets the embedding of the graph copy to the embedding of the original graph. - * \pre The graph copy has not been changed after construction, i.e., no new nodes - * or edges have been added and no edges have been split. - */ - void setOriginalEmbedding(); - - //! Re-inserts edge \a eOrig by "crossing" the edges in \a crossedEdges in embedding \a E. - /** - * Let \a v and \a w be the copies of the source and target nodes of \a eOrig, - * and let \f$e_0,e_1,\ldots,e_k,e_{k+1}\f$ be the sequence of edges corresponding - * to the adjacency entries in \a crossedEdges. The first edge needs to be incident - * to \a v and the last to \a w; the edges \f$e_1,\ldots,e_k\f$ are each split - * creating a sequence \f$u_1,\ldots,u_k\f$ of new nodes, and additional edges - * are inserted creating a path \f$v,u_1,\ldots,u_k,w\f$. - * - * The following figure illustrates, which adjacency entries need to be in the list - * \a crossedEdges. It inserts an edge connecting \a v and \a w by passing through - * the faces \f$f_0,f_1,f_2\f$; in this case, the list \a crossedEdges must contain - * the adjacency entries \f$adj_0,\ldots,adj_3\f$ (in this order). - * \image html insertEdgePathEmbedded.png - * - * @param eOrig is an edge in the original graph and becomes the original edge of - * all edges in the path \f$v,u_1,\ldots,u_k,w\f$. - * @param E is an embedding of the graph copy. - * @param crossedEdges are a list of adjacency entries in the graph copy. - */ - void insertEdgePathEmbedded( - edge eOrig, - CombinatorialEmbedding &E, - const SList &crossedEdges); - - /** - * Removes the complete edge path for edge \a eOrig while preserving the embedding. - * @param E is an embedding of the graph copy. - * @param eOrig is an edge in the original graph. - * @param newFaces is assigned the set of new faces resulting from joining faces - * when removing edges. - */ - void removeEdgePathEmbedded( - CombinatorialEmbedding &E, - edge eOrig, - FaceSetPure &newFaces); - - - //@} - /** - * @name Miscellaneous - */ - //@{ - - //! Checks the consistency of the data structure (for debugging only). - bool consistencyCheck() const; - - //! Associates the graph copy with \a G, but does not create any nodes or edges. - /** - * This method is used for a special creation of the graph copy. - * The graph copy needs to be constructed with the default constructor, - * gets associated with \a G using this method, and then is initialized - * using either initByNodes() or initByActiveNodes(). - * - * The following code snippet shows a typical application of this functionality: - * \code - * GraphCopy GC; - * GC.createEmpty(G); - * - * // compute connected components of G - * NodeArray component(G); - * int numCC = connectedComponents(G,component); - * - * // intialize the array of lists of nodes contained in a CC - * Array > nodesInCC(numCC); - * - * node v; - * forall_nodes(v,G) - * nodesInCC[component[v]].pushBack(v); - * - * EdgeArray auxCopy(G); - * Array boundingBox(numCC); - * - * for(int i = 0; i < numCC; ++i) { - * GC.initByNodes(nodesInCC[i],auxCopy); - * ... - * } - * \endcode - * @param G is the graph of which this graph copy shall be a copy. - */ - void createEmpty(const Graph &G); - - //! Initializes the graph copy for the nodes in a component. - /** - * Creates copies of all nodes in \a nodes and their incident edges. - * Any nodes and edges allocated before are removed. - * - * The order of entries in the adjacency lists is preserved, i.e., if - * the original graph is embedded, its embedding induces the embedding - * of the created copy. - * - * It is important that \a nodes is the complete list of nodes in - * a connected component. If you wish to initialize the graph copy for an - * arbitrary set of nodes, use the method initByActiveNodes(). - * \see createEmpty() for an example. - * @param nodes is the list of nodes in the original graph for which - * copies are created in the graph copy. - * @param eCopy is assigned the copy of each original edge. - */ - void initByNodes(const List &nodes, EdgeArray &eCopy); - - //! Initializes the graph copy for the nodes in \a nodes. - /** - * Creates copies of all nodes in \a nodes and edges between two nodes - * which are both contained in \a nodes. - * Any nodes and edges allocated before are destroyed. - * - * \see createEmpty() - * @param nodes is the list of nodes in the original graph for which - * copies are created in the graph copy. - * @param activeNodes must be true for every node in \a nodes, false - * otherwise. - * @param eCopy is assigned the copy of each original edge. - */ - void initByActiveNodes(const List &nodes, - const NodeArray &activeNodes, EdgeArray &eCopy); - - //@} - /** - * @name Operators - */ - //@{ - - //! Assignment operator. - /** - * Creates a graph copy that is a copy of \a GC and represents a graph - * copy of the original graph of \a GC. - * - * The constructor assures that the adjacency lists of nodes in the - * constructed graph are in the same order as the adjacency lists in \a G. - * This is in particular important when dealing with embedded graphs. - */ - GraphCopy &operator=(const GraphCopy &GC); - - - //@} - -private: - void initGC(const GraphCopy &GC, - NodeArray &vCopy, EdgeArray &eCopy); - -}; // class GraphCopy - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/GraphCopyAttributes.h b/ext/OGDF/ogdf/basic/GraphCopyAttributes.h deleted file mode 100644 index debe0cdbc..000000000 --- a/ext/OGDF/ogdf/basic/GraphCopyAttributes.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GraphCopy Attributes which manages - * access on a copy of an attributed graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_A_GRAPH_COPY_H -#define OGDF_A_GRAPH_COPY_H - - - -#include -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// GraphCopyAttributes -// manages access on copy of an attributed graph -//--------------------------------------------------------- -class OGDF_EXPORT GraphCopyAttributes { - - const GraphCopy *m_pGC; - GraphAttributes *m_pAG; - NodeArray m_x, m_y; - -public: - // construction - GraphCopyAttributes(const GraphCopy &GC, GraphAttributes &AG) : - m_pGC(&GC), m_pAG(&AG), m_x(GC,0), m_y(GC,0) { } - - // destruction - ~GraphCopyAttributes() { } - - // returns width of node v - double getWidth(node v) const { - return (m_pGC->isDummy(v) ? 0.0 : m_pAG->width(m_pGC->original(v))); - } - - // returns height of node v - double getHeight(node v) const { - return (m_pGC->isDummy(v) ? 0.0 : m_pAG->height(m_pGC->original(v))); - } - - // returns reference to x-coord. of node v - const double &x(node v) const { - return m_x[v]; - } - - // returns reference to x-coord. of node v - double &x(node v) { - return m_x[v]; - } - - // returns reference to y-coord. of node v - const double &y(node v) const { - return m_y[v]; - } - - // returns reference to y-coord. of node v - double &y(node v) { - return m_y[v]; - } - - // sets attributes for the original graph in AG - void transform(); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/GraphObserver.h b/ext/OGDF/ogdf/basic/GraphObserver.h deleted file mode 100644 index 0d39ef5de..000000000 --- a/ext/OGDF/ogdf/basic/GraphObserver.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Abstract base class for structures on graphs, that need - * to be informed about graph changes (e.g. cluster graphs). - * - * Follows the observer pattern: graphs are observable - * objects that can inform observers on changes made to their - * structure. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRAPH_STRUCTURE_H -#define OGDF_GRAPH_STRUCTURE_H - - -#include -#include - -namespace ogdf { - -// -// in embedded graphs, adjacency lists are given in clockwise order. -// - - -//---------------------------------------------------------- -// GraphObserver -//---------------------------------------------------------- -/** - * \brief Abstract Base class for classes that need to keep track - * of changes in the graph like addition/deletion of nodes - * or edges. - * derived classes have to overload nodeDeleted, nodeAdded - * edgeDeleted, edgeAdded - * these functions should be called by Graph before (delete) - * - */ - -class OGDF_EXPORT GraphObserver { - friend class Graph; - -public: - //! Constructs instance of GraphObserver class - GraphObserver() : m_pGraph(0) { } - - /** - *\brief Constructs instance of GraphObserver class - * \param G is the graph to be watched - */ - GraphObserver(const Graph* G) : m_pGraph(G) - { - m_itGList = G->registerStructure(this); - }//constructor - - //! Destroys the instance, unregisters it from watched graph - virtual ~GraphObserver() - { - if (m_pGraph) m_pGraph->unregisterStructure(m_itGList); - }//destructor - - //! Associates observer instance with graph \a G - void reregister(const Graph *pG) { - //small speedup: check if == m_pGraph - if (m_pGraph) m_pGraph->unregisterStructure(m_itGList); - if ((m_pGraph = pG) != 0) m_itGList = pG->registerStructure(this); - } - - //! Called by watched graph when a node is deleted - //! Has to be implemented by derived classes - virtual void nodeDeleted(node v) = 0; - - //! Called by watched graph when a node is added - //! Has to be implemented by derived classes - virtual void nodeAdded(node v) = 0; - - //! Called by watched graph when an edge is deleted - //! Has to be implemented by derived classes - virtual void edgeDeleted(edge e) = 0; - - //! Called by watched graph when an edge is added - //! Has to be implemented by derived classes - virtual void edgeAdded(edge e) = 0; - - //! Called by watched graph when it is reinitialized - //! Has to be implemented by derived classes - virtual void reInit() = 0; - - //! Called by watched graph when its clear function is called - //! Has to be implemented by derived classes - virtual void cleared() = 0; - - const Graph* getGraph() const { return m_pGraph; } - -protected: - const Graph* m_pGraph; //! watched graph - ListIterator m_itGList; //! List entry in graphs list of all registered graphobservers - - -}; - -} //end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/Graph_d.h b/ext/OGDF/ogdf/basic/Graph_d.h deleted file mode 100644 index 222a55b9d..000000000 --- a/ext/OGDF/ogdf/basic/Graph_d.h +++ /dev/null @@ -1,1557 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Pure declaration header, find template implementation in - * Graph.h - * - * Declaration of NodeElement, EdgeElement, and Graph classes. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRAPH_D_H -#define OGDF_GRAPH_D_H - - -#include - - -namespace ogdf { - -// -// in embedded graphs, adjacency lists are given in clockwise order. -// - - -class OGDF_EXPORT Graph; -class OGDF_EXPORT NodeElement; -class OGDF_EXPORT EdgeElement; -class OGDF_EXPORT AdjElement; -class OGDF_EXPORT FaceElement; -class OGDF_EXPORT GraphListBase; -class OGDF_EXPORT ClusterElement; - - -//! The base class for objects used by graphs like nodes, edges, etc. -/** - * Such graph objects are maintained in list (see GraphList), - * and \a GraphElement basically provides a next and previous pointer - * for these objects. - */ -class OGDF_EXPORT GraphElement { - friend class Graph; - friend class GraphListBase; - -protected: - GraphElement *m_next; //!< The successor in the list. - GraphElement *m_prev; //!< The predecessor in the list. - - OGDF_NEW_DELETE -}; // class GraphElement - - -//! Base class for GraphElement lists. -class OGDF_EXPORT GraphListBase { -protected: - GraphElement *m_head; //!< Pointer to the first element in the list. - GraphElement *m_tail; //!< Pointer to the last element in the list. - -public: - //! Constructs an empty list. - GraphListBase() { m_head = m_tail = 0; } - // destruction - ~GraphListBase() { } - - //! Adds element \a pX at the end of the list. - void pushBack(GraphElement *pX) { - pX->m_next = 0; - pX->m_prev = m_tail; - if (m_head) - m_tail = m_tail->m_next = pX; - else - m_tail = m_head = pX; - } - - //! Inserts element \a pX after element \a pY. - void insertAfter(GraphElement *pX, GraphElement *pY) { - pX->m_prev = pY; - GraphElement *pYnext = pX->m_next = pY->m_next; - pY->m_next = pX; - if (pYnext) pYnext->m_prev = pX; - else m_tail = pX; - } - - //! Inserts element \a pX before element \a pY. - void insertBefore(GraphElement *pX, GraphElement *pY) { - pX->m_next = pY; - GraphElement *pYprev = pX->m_prev = pY->m_prev; - pY->m_prev = pX; - if (pYprev) pYprev->m_next = pX; - else m_head = pX; - } - - //! Removes element \a pX from the list. - void del(GraphElement *pX) { - GraphElement *pxPrev = pX->m_prev, *pxNext = pX->m_next; - - if (pxPrev) - pxPrev->m_next = pxNext; - else - m_head = pxNext; - if (pxNext) - pxNext->m_prev = pxPrev; - else - m_tail = pxPrev; - } - - //! Sorts the list according to \a newOrder. - template - void sort(const LIST &newOrder) { - GraphElement *pPred = 0; - typename LIST::const_iterator it = newOrder.begin(); - if (!it.valid()) return; - - m_head = *it; - for(; it.valid(); ++it) { - GraphElement *p = *it; - if ((p->m_prev = pPred) != 0) pPred->m_next = p; - pPred = p; - } - - (m_tail = pPred)->m_next = 0; - } - - //! Reverses the order of the list elements. - void reverse() { - GraphElement *pX = m_head; - m_head = m_tail; - m_tail = pX; - while(pX) { - GraphElement *pY = pX->m_next; - pX->m_next = pX->m_prev; - pX = pX->m_prev = pY; - } - } - - //! Exchanges the positions of \a pX and \a pY in the list. - void swap(GraphElement *pX, GraphElement *pY) { - if (pX->m_next == pY) { - pX->m_next = pY->m_next; - pY->m_prev = pX->m_prev; - pY->m_next = pX; - pX->m_prev = pY; - - } else if(pY->m_next == pX) { - pY->m_next = pX->m_next; - pX->m_prev = pY->m_prev; - pX->m_next = pY; - pY->m_prev = pX; - - } else { - ::swap(pX->m_next,pY->m_next); - ::swap(pX->m_prev,pY->m_prev); - } - - if(pX->m_prev) - pX->m_prev->m_next = pX; - else - m_head = pX; - if(pX->m_next) - pX->m_next->m_prev = pX; - else - m_tail = pX; - - if(pY->m_prev) - pY->m_prev->m_next = pY; - else - m_head = pY; - if(pY->m_next) - pY->m_next->m_prev = pY; - else - m_tail = pY; - - OGDF_ASSERT(consistencyCheck()); - } - - - //! Checks consistency of graph list. - bool consistencyCheck() { - if (m_head == 0) { - return (m_tail == 0); - - } else if (m_tail == 0) { - return false; - - } else { - if (m_head->m_prev != 0) - return false; - if (m_tail->m_next != 0) - return false; - - GraphElement *pX = m_head; - for(; pX; pX = pX->m_next) { - if (pX->m_prev) { - if (pX->m_prev->m_next != pX) - return false; - } else if(pX != m_head) - return false; - - if (pX->m_next) { - if (pX->m_next->m_prev != pX) - return false; - } else if (pX != m_tail) - return false; - } - } - - return true; - } - - OGDF_NEW_DELETE -}; // class GraphListBase - - -//! Lists of graph objects (like nodes, edges, etc.). -/** - * The template type \a T must be a class derived from GraphElement. - */ -template class GraphList : protected GraphListBase { -public: - //! Constructs an empty list. - GraphList() { } - // destruction (deletes all elements) - ~GraphList() { - if (m_head) - OGDF_ALLOCATOR::deallocateList(sizeof(T), m_head,m_tail); - } - - //! Returns the first element in the list. - T *begin () const { return (T *)m_head; } - //! Returns the last element in the list. - T *rbegin() const { return (T *)m_tail; } - - //! Returns true iff the list is empty. - bool empty() { return m_head; } - - //! Adds element \a pX at the end of the list. - void pushBack(T *pX) { - GraphListBase::pushBack(pX); - } - - //! Inserts element \a pX after element \a pY. - void insertAfter(T *pX, T *pY) { - GraphListBase::insertAfter(pX,pY); - } - - //! Inserts element \a pX before element \a pY. - void insertBefore(T *pX, T *pY) { - GraphListBase::insertBefore(pX,pY); - } - - //! Moves element \a pX to list \a L and inserts it before or after \a pY. - void move(T *pX, GraphList &L, T *pY, Direction dir) { - GraphListBase::del(pX); - if (dir == after) - L.insertAfter(pX,pY); - else - L.insertBefore(pX,pY); - } - - //! Moves element \a pX to list \a L and inserts it at the end. - void move(T *pX, GraphList &L) { - GraphListBase::del(pX); - L.pushBack(pX); - } - - //! Moves element \a pX from its current position to a position after \a pY. - void moveAfter(T *pX, T *pY){ - GraphListBase::del(pX); - insertAfter(pX,pY); - } - - //! Moves element \a pX from its current position to a position before \a pY. - void moveBefore(T *pX, T *pY){ - GraphListBase::del(pX); - insertBefore(pX,pY); - } - - //! Removes element \a pX from the list and deletes it. - void del(T *pX) { - GraphListBase::del(pX); - delete pX; - } - - //! Only removes element \a pX from the list; does not delete it. - void delPure(T *pX) { - GraphListBase::del(pX); - } - - //! Removes all elements from the list and deletes them. - void clear() { - if (m_head) { - OGDF_ALLOCATOR::deallocateList(sizeof(T),m_head,m_tail); - m_head = m_tail = 0; - } - } - - //! Sorts all elements according to \a newOrder. - template - void sort(const T_LIST &newOrder) { - GraphListBase::sort(newOrder); - } - - - //! Reverses the order of the list elements. - void reverse() { - GraphListBase::reverse(); - } - - //! Exchanges the positions of \a pX and \a pY in the list. - void swap(T *pX, T *pY) { - GraphListBase::swap(pX,pY); - } - - - //! Checks consistency of graph list; returns true if ok. - bool consistencyCheck() { - return GraphListBase::consistencyCheck(); - } - - - OGDF_NEW_DELETE -}; // class GraphList - - -typedef NodeElement *node; //!< The type of nodes. -typedef EdgeElement *edge; //!< The type of edges. -typedef AdjElement *adjEntry; //!< The type of adjacency entries. - - - -//! Class for adjacency list elements. -/** - * Adjacency list elements represent the occurrence of an edges in - * the adjacency list of a node. - */ -class OGDF_EXPORT AdjElement : private GraphElement { - friend class Graph; - friend class GraphListBase; - friend class GraphList; - - AdjElement *m_twin; //!< The corresponding adjacency entry (same edge) - edge m_edge; //!< The associated edge. - node m_node; //!< The node whose adjacency list contains this entry. - int m_id; //!< The (unique) index of the adjacency entry. - - //! Constructs an adjacency element for a given node. - AdjElement(node v) : m_node(v) { } - //! Constructs an adjacency entry for a given edge and index. - AdjElement(edge e, int id) : m_edge(e), m_id(id) { } - -public: - //! Returns the edge associated with this adjacency entry. - edge theEdge() const { return m_edge; } - //! Conversion to edge. - operator edge() const { return m_edge; } - //! Returns the node whose adjacency list contains this element. - node theNode() const { return m_node; } - - //! Returns the corresponding adjacency element associated with the same edge. - adjEntry twin() const { return m_twin; } - - //! Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()). - node twinNode() const { return m_twin->m_node; } - - //! Returns the index of this adjacency element. - int index() const { return m_id; } - - // traversing faces in clockwise (resp. counter-clockwise) order - // (if face is an interior face) - - //! Returns the clockwise successor in face. Use faceCycleSucc instead! - adjEntry clockwiseFaceSucc() const { return m_twin->cyclicPred(); } - //! Returns the clockwise predecessor in face. Use faceCycleSucc instead! - adjEntry clockwiseFacePred() const { return cyclicSucc()->m_twin; } - //! Returns the counter-clockwise successor in face. - adjEntry counterClockwiseFaceSucc() const { return m_twin->cyclicSucc(); } - //! Returns the counter-clockwise predecessor in face. - adjEntry counterClockwiseFacePred() const { return cyclicPred()->m_twin; } - - // default is traversing faces in clockwise order - //! Returns the cyclic successor in face. - adjEntry faceCycleSucc() const { return clockwiseFaceSucc(); } - //! Returns the cyclic predecessor in face. - adjEntry faceCyclePred() const { return clockwiseFacePred(); } - - - //! Returns the successor in the adjacency list. - adjEntry succ() const { return (adjEntry)m_next; } - //! Returns the predecessor in the adjacency list. - adjEntry pred() const { return (adjEntry)m_prev; } - - //! Returns the cyclic successor in the adjacency list. - adjEntry cyclicSucc() const; - //! Returns the cyclic predecessor in the adjacency list. - adjEntry cyclicPred() const; - -#ifdef OGDF_DEBUG - const Graph *graphOf() const; -#endif - - OGDF_NEW_DELETE -}; // class AdjElement - - -//! Class for the representation of nodes. -class OGDF_EXPORT NodeElement : private GraphElement { - friend class Graph; - friend class GraphList; - - GraphList m_adjEdges; //!< The adjacency list of the node. - int m_indeg; //!< The indegree of the node. - int m_outdeg; //!< The outdegree of the node. - int m_id; //!< The (unique) index of the node. - -#ifdef OGDF_DEBUG - // we store the graph containing this node for debugging purposes - const Graph *m_pGraph; //!< The graph containg this node (debug only). -#endif - - - // construction -#ifdef OGDF_DEBUG - //! Constructs a node element with index \a id. - /** - * \remarks The parameter \a pGraph is only passed in a debug build. - * It is used, e.g., by NodeArray for checking if a node belongs to - * the correct graph. - */ - NodeElement(const Graph *pGraph, int id) : - m_indeg(0), m_outdeg(0), m_id(id), m_pGraph(pGraph) { } -#else - NodeElement(int id) : m_indeg(0), m_outdeg(0), m_id(id) { } -#endif - - -public: - //! Returns the (unique) node index. - int index() const { return m_id; } - - //! Returns the indegree of the node. - int indeg() const { return m_indeg; } - //! Returns the outdegree of the node. - int outdeg() const { return m_outdeg; } - //! Returns the degree of the node (indegree + outdegree). - int degree() const { return m_indeg + m_outdeg; } - - //! Returns the first entry in the adjaceny list. - adjEntry firstAdj() const { return m_adjEdges.begin(); } - //! Returns the last entry in the adjacency list. - adjEntry lastAdj () const { return m_adjEdges.rbegin(); } - - //! Returns the successor in the list of all nodes. - node succ() const { return (node)m_next; } - //! Returns the predecessor in the list of all nodes. - node pred() const { return (node)m_prev; } - -#ifdef OGDF_DEBUG - //! Returns the graph containing this node (debug only). - const Graph *graphOf() const { return m_pGraph; } -#endif - - OGDF_NEW_DELETE -}; // class NodeElement - - -inline adjEntry AdjElement::cyclicSucc() const -{ - return (m_next) ? (adjEntry)m_next : m_node->firstAdj(); -} - -inline adjEntry AdjElement::cyclicPred() const -{ - return (m_prev) ? (adjEntry)m_prev : m_node->lastAdj(); -} - -inline bool test_forall_adj_edges(adjEntry &adj, edge &e) -{ - if (adj) { e = adj->theEdge(); return true; } - else return false; -} - - - -//! Class for the representation of edges. -class OGDF_EXPORT EdgeElement : private GraphElement { - friend class Graph; - friend class GraphList; - - node m_src; //!< The source node of the edge. - node m_tgt; //!< The target node of the edge. - AdjElement *m_adjSrc; //!< Corresponding adjacancy entry at source node. - AdjElement *m_adjTgt; //!< Corresponding adjacancy entry at target node. - int m_id; // The (unique) index of the node. - - //! Constructs an edge element (\a src,\a tgt). - /** - * @param src is the source node of the edge. - * @param tgt is the target node of the edge. - * @param adjSrc is the corresponding adjacency entry at source node. - * @param adjTgt is the corresponding adjacency entry at target node. - * @param id is the index of the edge. - */ - EdgeElement(node src, node tgt, AdjElement *adjSrc, AdjElement *adjTgt, int id) : - m_src(src), m_tgt(tgt), m_adjSrc(adjSrc), m_adjTgt(adjTgt), m_id(id) { } - - //! Constructs an edge element (\a src,\a tgt). - /** - * @param src is the source node of the edge. - * @param tgt is the target node of the edge. - * @param id is the index of the edge. - */ - EdgeElement(node src, node tgt, int id) : - m_src(src), m_tgt(tgt), m_id(id) { } - -public: - //! Returns the index of the edge. - int index() const { return m_id; } - //! Returns the source node of the edge. - node source() const { return m_src; } - //! Returns the target node of the edge. - node target() const { return m_tgt; } - - //! Returns the corresponding adjacancy entry at source node. - adjEntry adjSource() const { return m_adjSrc; } - //! Returns the corresponding adjacancy entry at target node. - adjEntry adjTarget() const { return m_adjTgt; } - - //! Returns the adjacent node different from \a v. - node opposite(node v) const { return (v == m_src) ? m_tgt : m_src; } - // Returns true iff the edge is a self-loop (source node = target node). - bool isSelfLoop() const { return m_src == m_tgt; } - - //! Returns the successor in the list of all edges. - edge succ() const { return (edge)m_next; } - //! Returns the predecessor in the list of all edges. - edge pred() const { return (edge)m_prev; } - -#ifdef OGDF_DEBUG - //! Returns the graph containing this node (debug only). - const Graph *graphOf() const { return m_src->graphOf(); } -#endif - - //! Returns true iff \a v is incident to the edge. - bool isIncident(node v) const { return v == m_src || v == m_tgt; } - - //! Returns the common node of the edge and \a e. Returns NULL if the two edges are not adjacent. - node commonNode(edge e) const { return (m_src==e->m_src || m_src==e->m_tgt) ? m_src : ((m_tgt==e->m_src || m_tgt==e->m_tgt) ? m_tgt: 0); } - - OGDF_NEW_DELETE -}; // class EdgeElement - - -#ifdef OGDF_DEBUG -inline const Graph *AdjElement::graphOf() const { - return m_node->graphOf(); -} -#endif - - -template<>inline bool doDestruction(const node *) { return false; } -template<>inline bool doDestruction(const edge *) { return false; } -template<>inline bool doDestruction(const adjEntry *) { return false; } - -class NodeArrayBase; -class EdgeArrayBase; -class AdjEntryArrayBase; -template class NodeArray; -template class EdgeArray; -template class AdjEntryArray; -class OGDF_EXPORT GraphObserver; - - -//--------------------------------------------------------- -// iteration macros -//--------------------------------------------------------- - -//! Iteration over all nodes \a v of graph \a G. -#define forall_nodes(v,G) for((v)=(G).firstNode(); (v); (v)=(v)->succ()) -//! Iteration over all nodes \a v of graph \a G in reverse order. -#define forall_rev_nodes(v,G) for((v)=(G).lastNode(); (v); (v)=(v)->pred()) - -//! Iteration over all edges \a e of graph \a G. -#define forall_edges(e,G) for((e)=(G).firstEdge(); (e); (e)=(e)->succ()) -//! Iteration over all edges \a e of graph \a G in reverse order. -#define forall_rev_edges(e,G) for((e)=(G).lastEdge(); (e); (e)=(e)->pred()) - -//! Iteration over all adjacency list entries \a adj of node \a v. -#define forall_adj(adj,v) for((adj)=(v)->firstAdj(); (adj); (adj)=(adj)->succ()) -//! Iteration over all adjacency list entries \a adj of node \a v in reverse order. -#define forall_rev_adj(adj,v) for((adj)=(v)->lastAdj(); (adj); (adj)=(adj)->pred()) - -//! Iteration over all adjacent edges \a e of node \a v. -#define forall_adj_edges(e,v)\ -for(ogdf::adjEntry ogdf_loop_var=(v)->firstAdj();\ - ogdf::test_forall_adj_edges(ogdf_loop_var,(e));\ - ogdf_loop_var=ogdf_loop_var->succ()) - - -//! Data type for general directed graphs (adjacency list representation). -/** - *

    Iteration

    - * Besides the usage of iteration macros defined in Graph_d.h, the following - * code is recommended for further iteration tasks. - *
      - *
    • Iteration over all outgoing edges \a e of node \a v: - * \code - * forall_adj_edges(e,v) - * if(e->source() != v) continue; - * \endcode - * - *
    • Iteration over all ingoing edges \a e of node \a v: - * \code - * forall_adj_edges(e,v) - * if(e->target() != v) continue; - * \endcode - * - *
    • Iteration over all nodes \a x reachable by an outgoing edge \a e - * of node \a v (without self-loops): - * \code - * forall_adj_edges(e,v) - * if ((x = e->target()) == v) continue; - * \endcode - * - *
    • Iteration over all nodes \a x reachable by an outgoing edge \a e - * of node \a v (with self-loops): - * \code - * forall_adj_edges(e,v) { - * if (e->source() != v) continue; - * x = e->target(); - * } - * \endcode - * - *
    • Iteration over all nodes \a x reachable by an ingoing edge \a e - * of node \a v (without self-loops): - * \code - * forall_adj_edges(e,v) - * if ((x = e->source()) == v) continue; - * \endcode - * - *
    • Iteration over all nodes \a x reachable by an ingoing edge \a e - * of node \a v (with self-loops): - * \code - * forall_adj_edges(e,v) { - * if (e->target() != v) continue; - * x = e->source(); - * } - * \endcode - *
    - */ - -class OGDF_EXPORT Graph -{ - GraphList m_nodes; //!< The list of all nodes. - GraphList m_edges; //!< The list of all edges. - int m_nNodes; //!< The number of nodes in the graph. - int m_nEdges; //!< The number of edges in the graph. - - int m_nodeIdCount; //!< The Index that will be assigned to the next created node. - int m_edgeIdCount; //!< The Index that will be assigned to the next created edge. - - int m_nodeArrayTableSize; //!< The current table size of node arrays associated with this graph. - int m_edgeArrayTableSize; //!< The current table size of edge arrays associated with this graph. - - mutable ListPure m_regNodeArrays; //!< The registered node arrays. - mutable ListPure m_regEdgeArrays; //!< The registered edge arrays. - mutable ListPure m_regAdjArrays; //!< The registered adjEntry arrays. - mutable ListPure m_regStructures; //!< The registered graph structures. - - GraphList m_hiddenEdges; //!< The list of hidden edges. - -public: - // - // enumerations - // - - //! The type of edges (only used in derived classes). - enum EdgeType { - association = 0, - generalization = 1, - dependency = 2 - }; // should be more flexible, standard, dissect, expand - - //! The type of nodes. - enum NodeType { - vertex, - dummy, - generalizationMerger, - generalizationExpander, - highDegreeExpander, - lowDegreeExpander, - associationClass - }; - - - //! Constructs an empty graph. - Graph(); - - //! Constructs a graph that is a copy of \a G. - /** - * The constructor assures that the adjacency lists of nodes in the - * constructed graph are in the same order as the adjacency lists in \a G. - * This is in particular important when dealing with embedded graphs. - * - * @param G is the graph that will be copied. - */ - Graph(const Graph &G); - - //! Destructor. - virtual ~Graph(); - - - /** - * @name Access methods - */ - //@{ - - //! Returns true iff the graph is empty, i.e., contains no nodes. - bool empty() const { return m_nNodes == 0; } - - //! Returns the number of nodes in the graph. - int numberOfNodes() const { return m_nNodes; } - - //! Returns the number of edges in the graph. - int numberOfEdges() const { return m_nEdges; } - - //! Returns the largest used node index. - int maxNodeIndex() const { return m_nodeIdCount-1; } - //! Returns the largest used edge index. - int maxEdgeIndex() const { return m_edgeIdCount-1; } - //! Returns the largest used adjEntry index. - int maxAdjEntryIndex() const { return (m_edgeIdCount<<1)-1; } - - //! Returns the table size of node arrays associated with this graph. - int nodeArrayTableSize() const { return m_nodeArrayTableSize; } - //! Returns the table size of edge arrays associated with this graph. - int edgeArrayTableSize() const { return m_edgeArrayTableSize; } - //! Returns the table size of adjEntry arrays associated with this graph. - int adjEntryArrayTableSize() const { return m_edgeArrayTableSize << 1; } - - //! Returns the first node in the list of all nodes. - node firstNode() const { return m_nodes.begin (); } - //! Returns the last node in the list of all nodes. - node lastNode () const { return m_nodes.rbegin(); } - - //! Returns the first edge in the list of all edges. - edge firstEdge() const { return m_edges.begin (); } - //! Returns the last edge in the list of all edges. - edge lastEdge () const { return m_edges.rbegin(); } - - //! Returns a randomly chosen node. - node chooseNode() const; - //! Returns a randomly chosen edge. - edge chooseEdge() const; - - //! Returns a list with all nodes of the graph. - /** - * @tparam NODELIST is the type of node list, which is returned. - * @param nodes is assigned the list of all nodes. - */ - template - void allNodes(NODELIST &nodes) const { - nodes.clear(); - for (node v = m_nodes.begin(); v; v = v->succ()) - nodes.pushBack(v); - } - - //! Returns a list with all edges of the graph. - /** - * @tparam EDGELIST is the type of edge list, which is returned. - * @param edges is assigned the list of all edges. - */ - template - void allEdges(EDGELIST &edges) const { - edges.clear(); - for (edge e = m_edges.begin(); e; e = e->succ()) - edges.pushBack(e); - } - - //! Returns a list with all edges adjacent to node \a v. - /** - * @tparam EDGELIST is the type of edge list, which is returned. - * @param v is the node whose incident edges are queried. - * @param edges is assigned the list of all edges incident to \a v - * (including incoming and outcoming edges). - */ - template - void adjEdges(node v, EDGELIST &edges) const { - edges.clear(); - edge e; - forall_adj_edges(e,v) - edges.pushBack(e); - } - - //! Returns a list with all entries in the adjacency list of node \a v. - /** - * @tparam ADJLIST is the type of adjacency entry list, which is returned. - * @param v is the node whose adjacency entries are queried. - * @param entries is assigned the list of all adjacency entries in the adjacency list of \a v. - */ - template - void adjEntries(node v, ADJLIST &entries) const { - entries.clear(); - adjEntry adj; - forall_adj(adj,v) - entries.pushBack(adj); - } - - //! Returns a list with all incoming edges of node \a v. - /** - * @tparam EDGELIST is the type of edge list, which is returned. - * @param v is the node whose incident edges are queried. - * @param edges is assigned the list of all incoming edges incident to \a v. - */ - template - void inEdges(node v, EDGELIST &edges) const { - edges.clear(); - edge e; - forall_adj_edges(e,v) - if (e->target() == v) edges.pushBack(e); - } - - //! Returns a list with all outgoing edges of node \a v. - /** - * @tparam EDGELIST is the type of edge list, which is returned. - * @param v is the node whose incident edges are queried. - * @param edges is assigned the list of all outgoing edges incident to \a v. - */ - template - void outEdges(node v, EDGELIST &edges) const { - edges.clear(); - edge e; - forall_adj_edges(e,v) - if (e->source() == v) edges.pushBack(e); - } - - - //@} - /** - * @name Creation of new nodes and edges - */ - //@{ - - //! Creates a new node and returns it. - node newNode(); - - //! Creates a new node with predefined index and returns it. - /** - * \pre \a index is currently not the index of any other node in the graph. - * - * \attention Passing a node index that is already in use results in an inconsistent - * data structure. Only use this method if you know what you're doing! - * - * @param index is the index that will be assigned to the newly created node. - * @return the newly created node. - */ - node newNode(int index); - - //! Creates a new edge (\a v,\a w) and returns it. - /** - * @param v is the source node of the newly created edge. - * @param w is the target node of the newly created edge. - * @return the newly created edge. - */ - edge newEdge(node v, node w); - - //! Creates a new edge (\a v,\a w) with predefined index and returns it. - /** - * \pre \a index is currently not the index of any other edge in the graph. - * - * \attention Passing an edge index that is already in use results in an inconsistent - * data structure. Only use this method if you know what you're doing! - * - * @param v is the source node of the newly created edge. - * @param w is the target node of the newly created edge. - * @param index is the index that will be assigned to the newly created edge. - * @return the newly created edge. - */ - edge newEdge(node v, node w, int index); - - //! Creates a new edge at predefined positions in the adjacency lists. - /** - * Let \a v be the node whose adjacency list contains \a adjSrc, - * and \a w the node whose adjacency list contains \a adjTgt. Then, - * the created edge is (\a v,\a w). - * - * @param adjSrc is the adjacency entry after which the new edge is inserted - * in the adjacency list of \a v. - * @param adjTgt is the adjacency entry after which the new edge is inserted - * in the adjacency list of \a w. - * @param dir specifies if the edge is inserted before or after the given - * adjacency entries. - * @return the newly created edge. - */ - edge newEdge(adjEntry adjSrc, adjEntry adjTgt, Direction dir = ogdf::after); - - //! Creates a new edge at predefined positions in the adjacency lists. - /** - * Let \a w be the node whose adjacency list contains \a adjTgt. Then, - * the created edge is (\a v,\a w). - * - * @param v is the source node of the new edge; the edge is added at the end - * of the adjacency list of \a v. - * @param adjTgt is the adjacency entry after which the new edge is inserted - * in the adjacency list of \a w. - * @return the newly created edge. - */ - edge newEdge(node v, adjEntry adjTgt); - - //! Creates a new edge at predefined positions in the adjacency lists. - /** - * Let \a v be the node whose adjacency list contains \a adjSrc. Then, - * the created edge is (\a v,\a w). - * - * @param adjSrc is the adjacency entry after which the new edge is inserted - * in the adjacency list of \a v. - * @param w is the source node of the new edge; the edge is added at the end - * of the adjacency list of \a w. - * @return the newly created edge. - */ - edge newEdge(adjEntry adjSrc, node w); - - - //@} - /** - * @name Removing nodes and edges - */ - //@{ - - //! Removes node \a v and all incident edges from the graph. - /** - * @param v is the node that will be deleted. - */ - void delNode(node v); - - //! Removes edge \a e from the graph. - /** - * @param e is the egde that will be deleted. - */ - void delEdge(edge e); - - //! Removes all nodes and all edges from the graph. - void clear(); - - - //@} - /** - * @name Hiding edges - * These methods are used for temporarily hiding edges. Edges are removed from the - * list of all edges and their corresponding adfjacency entries from the repsective - * adjacency lists, but the edge objects themselves are not destroyed; hiddenedges - * can later be reactivated with restoreEdge(). - */ - //@{ - - //! Hides the edge \a e. - /** - * The edge \a e is removed from the list of all edges and adjacency lists of nodes, but - * not deleted; \a e can be restored by calling restoreEdge(e). - * - * \attention If an edge is hidden, its source and target node may not be deleted! - * - * @param e is the edge that will be hidden. - */ - void hideEdge(edge e); - - //! Restores a hidden edge \a e. - /** - * \pre \a e is currently hidden and its source and target have not been removed! - * - * @param e is the hidden edge that will be restored. - */ - void restoreEdge(edge e); - - //! Restores all hidden edges. - void restoreAllEdges(); - - - /** - * @name Advanced modification methods - */ - //@{ - - //! Splits edge \a e into two edges introducing a new node. - /** - * Let \a e=(\a v,\a w). Then, the resulting two edges are \a e=(\a v,\a u) - * and \a e'=(\a u,\a w), where \a u is a new node. - * - * \note The edge \a e is modified by this operation. - * - * @param e is the edge to be split. - * @return The edge \a e'. - */ - virtual edge split(edge e); - - //! Undoes a split operation. - /** - * Removes node \a u by joining the two edges adjacent to \a u. The - * outgoing edge of \a u is removed and the incoming edge \a e is reused - * - * \pre \a u has exactly one incoming and one outgoing edge, and - * none of them is a self-loop. - * - * @param u is the node to be unsplit. - * @return The edge \a e. - */ - void unsplit(node u); - - //! Undoes a split operation. - /** - * For two edges \a eIn = (\a x,\a u) and \a eOut = (\a u,\a y), removes - * node \a u by joining \a eIn and \a eOut. Edge \a eOut is removed and - * \a eIn is reused. - * - * \pre \a eIn and \a eOut are the only edges incident with \a u and - * none of them is a self-loop. - * - * @param eIn is the (only) incoming edge of \a u. - * @param eOut is the (only) outgoing edge of \a u. - */ - virtual void unsplit(edge eIn, edge eOut); - - //! Splits a node while preserving the order of adjacency entries. - /** - * This method splits a node \a v into two nodes \a vl and \a vr. Node - * \a vl receives all adjacent edges of \a v from \a adjStartLeft until - * the edge preceding \a adjStartRight, and \a vr the remaining nodes - * (thus \a adjStartRight is the first edge that goes to \a vr). The - * order of adjacency entries is preserved. Additionally, a new edge - * (\a vl,\a vr) is created, such that this edge is inserted before - * \a adjStartLeft and \a adjStartRight in the the adjacency lists of - * \a vl and \a vr. - * - * Node \a v is modified to become node \a vl, and node \a vr is returned. - * This method is useful when modifying combinatorial embeddings. - * - * @param adjStartLeft is the first entry that goes to the left node. - * @param adjStartRight is the first entry that goes to the right node. - * @return the newly created node. - */ - node splitNode(adjEntry adjStartLeft, adjEntry adjStartRight); - - //! Contracts edge \a e while preserving the order of adjacency entries. - /** - * @param e is the edge to be contracted. - * @return the endpoint of \a e to which all edges have been moved. - */ - node contract(edge e); - - //! Moves edge \a e to a different adjacency list. - /** - * The source adjacency entry of \a e is moved to the adjacency list containing - * \a adjSrc and is inserted before or after \a adjSrc, and its target adjacency entry - * to the adjacency list containing \a adjTgt and is inserted before or after - * \a adjTgt; e is afterwards an edge from owner(\a adjSrc) to owner(\a adjTgt). - * - * @param e is the edge to be moved. - * @param adjSrc is the adjaceny entry before or after which the source adjacency entry - * of \a e will be inserted. - * @param dirSrc specifies if the source adjacency entry of \a e will be inserted before or after \a adjSrc. - * @param adjTgt is the adjaceny entry before or after which the target adjacency entry - * of \a e will be inserted. - * @param dirTgt specifies if the target adjacency entry of \a e will be inserted before or after \a adjTgt. - */ - void move(edge e, adjEntry adjSrc, Direction dirSrc, - adjEntry adjTgt, Direction dirTgt); - - //! Moves the target node of edge \a e to node \a w. - /** - * If \a e=(\a v,\a u) before, then \a e=(\a v,\a w) afterwards. - * - * @param e is the edge whose target node is moved. - * @param w is the new target node of \a e. - */ - void moveTarget(edge e, node w); - - //! Moves the target node of edge \a e to a specific position in an adjacency list. - /** - * Let \a w be the node containing \a adjTgt. If \a e=(\a v,\a u) before, then \a e=(\a v,\a w) afterwards. - * Inserts the adjacency entry before or after \a adjTgt according to \a dir. - * - * @param e is the edge whose target node is moved. - * @param adjTgt is the adjacency entry before or after which the target adjacency entry of \a e is inserted. - * @param dir specifies if the target adjacency entry of \a e is inserted before or after \a adjTgt. - */ - void moveTarget(edge e, adjEntry adjTgt, Direction dir); - - //! Moves the source node of edge \a e to node \a w. - /** - * If \a e=(\a v,\a u) before, then \a e=(\a w,\a u) afterwards. - * - * @param e is the edge whose source node is moved. - * @param w is the new source node of \a e. - */ - void moveSource(edge e, node w); - - //! Moves the source node of edge \a e to a specific position in an adjacency list. - /** - * Let \a w be the node containing \a adjSrc. If \a e=(\a v,\a u) before, then \a e=(\a w,\a u) afterwards. - * Inserts the adjacency entry before or after \a adjSrc according to \a dir. - * - * @param e is the edge whose source node is moved. - * @param adjSrc is the adjacency entry before or after which the source adjacency entry of \a e is inserted. - * @param dir specifies if the source adjacency entry of \a e is inserted before or after \a adjSrc. - */ - void moveSource(edge e, adjEntry adjSrc, Direction dir); - - //! Searches and returns an edge connecting nodes \a v and \a w. - /** - * @param v is the source node of the edge to be searched. - * @param w is the target node of the edge to be searched. - * @return an edge (\ v,\a w) if such an edge exists, 0 otherwise. - */ - edge searchEdge (node v, node w) const; - - //! Reverses the edge \a e, i.e., exchanges source and target node. - /** - * @param e is the edge to be reveresed. - */ - void reverseEdge(edge e); - - //! Reverses all edges in the graph. - void reverseAllEdges(); - - //! Collapses all nodes in the list \a nodes to the first node in the list. - /** - * Parallel edges are removed. - * - * @tparam NODELIST is the type of input node list. - * @param nodes is the list of nodes that will be collapsed. This list will be empty after the call. - */ - template - void collaps(NODELIST &nodes){ - node v = nodes.popFrontRet(); - while (!nodes.empty()) - { - node w = nodes.popFrontRet(); - adjEntry adj = w->firstAdj(); - while (adj !=0) - { - adjEntry succ = adj->succ(); - edge e = adj->theEdge(); - if (e->source() == v || e->target() == v) - delEdge(e); - else if (e->source() == w) - moveSource(e,v); - else - moveTarget(e,v); - adj = succ; - } - delNode(w); - } - } - - //! Sorts the adjacency list of node \a v according to \a newOrder. - /** - * \pre \a newOrder contains exactly the adjacency entries of \a v! - * - * @tparam ADJ_ENTRY_LIST is the type of the input adjacency entry list. - * @param v is the node whose adjacency list will be sorted. - * @param newOrder is the list of adjacency entries of \a v in the new order. - */ - template - void sort(node v, const ADJ_ENTRY_LIST &newOrder) { -#ifdef OGDF_DEBUG - typename ADJ_ENTRY_LIST::const_iterator it; - for(it = newOrder.begin(); it.valid() ; ++it) { - OGDF_ASSERT((*it)->theNode() == v); - } -#endif - v->m_adjEdges.sort(newOrder); - } - - //! Reverses the adjacency list of \a v. - /** - * @param v is the node whose adjacency list will be reveresed. - */ - void reverseAdjEdges(node v) { - v->m_adjEdges.reverse(); - } - - //! Moves adjacency entry \a adjMove before or after \a adjPos. - /** - * \pre \a adjMove and adjAfter are distinct entries in the same adjacency list. - * - * @param adjMove is an entry in the adjacency list of a node in this graph. - * @param adjPos is an entry in the same adjacency list as \a adjMove. - * @param dir specifies if \a adjMove is moved before or after \a adjPos. - */ - void moveAdj(adjEntry adjMove, Direction dir, adjEntry adjPos) { - OGDF_ASSERT(adjMove->graphOf() == this && adjPos->graphOf() == this); - OGDF_ASSERT(adjMove != 0 && adjPos != 0); - GraphList &adjList = adjMove->m_node->m_adjEdges; - adjList.move(adjMove, adjList, adjPos, dir); - } - - //! Moves adjacency entry \a adjMove after \a adjAfter. - /** - * \pre \a adjMove and \a adjAfter are distinct entries in the same adjacency list. - * - * @param adjMove is an entry in the adjacency list of a node in this graph. - * @param adjAfter is an entry in the same adjacency list as \a adjMove. - */ - void moveAdjAfter(adjEntry adjMove, adjEntry adjAfter) { - OGDF_ASSERT(adjMove->graphOf() == this && adjAfter->graphOf() == this); - OGDF_ASSERT(adjMove != 0 && adjAfter != 0); - adjMove->m_node->m_adjEdges.moveAfter(adjMove,adjAfter); - } - - //! Moves adjacency entry \a adjMove before \a adjBefore. - /** - * \pre \a adjMove and \a adjBefore are distinct entries in the same adjacency list. - * - * @param adjMove is an entry in the adjacency list of a node in this graph. - * @param adjBefore is an entry in the same adjacency list as \a adjMove. - */ - void moveAdjBefore(adjEntry adjMove, adjEntry adjBefore) { - OGDF_ASSERT(adjMove->graphOf() == this && adjBefore->graphOf() == this); - OGDF_ASSERT(adjMove != 0 && adjBefore != 0); - adjMove->m_node->m_adjEdges.moveBefore(adjMove,adjBefore); - } - - //! Reverses all adjacency lists. - void reverseAdjEdges(); - - //! Exchanges two entries in an adjacency list. - /** - * \pre \a adj1 and \a adj2 must be belong to the same adjacency list. - * - * @param adj1 the first adjacency entry to be swapped. - * @param adj2 the secomd adjacency entry to be swapped. - */ - void swapAdjEdges(adjEntry adj1, adjEntry adj2) { - OGDF_ASSERT(adj1->theNode() == adj2->theNode()); - OGDF_ASSERT(adj1->graphOf() == this); - - adj1->theNode()->m_adjEdges.swap(adj1,adj2); - } - - - //@} - /** - * @name Input and output - */ - //@{ - - //! Reads a graph in GML format from file \a fileName. - /** - * @param fileName is the name of the input file. - * @return true if successful, false otherwise. - */ - bool readGML(const char *fileName); - - //! Reads a graph in GML format from input stream \a is. - /** - * @param is is the input file stream. - * @return true if successful, false otherwise. - */ - bool readGML(istream &is); - - //! Writes the graph in GML format to file \a fileName. - /** - * @param fileName is the name of the output file. - */ - void writeGML(const char *fileName) const; - - //! Writes the graph in GML format to output stream \a os. - /** - * @param os is the output file stream. - * @return true if successful, false otherwise. - */ - void writeGML(ostream &os) const; - - //! Reads a graph in LEDA format from file \a fileName. - /** - * @param fileName is the name of the input file. - * @return true if successful, false otherwise. - */ - bool readLEDAGraph(const char *fileName); - - //! Read a graph in LEDA format from input stream \a is. - /** - * @param is is the input file stream. - * @return true if successful, false otherwise. - */ - bool readLEDAGraph(istream &is); - - - //@} - /** - * @name Miscellaneous - */ - //@{ - - //! Returns the genus of the graph's embedding. - /** - * The genus of a graph is defined as follows. Let \f$G\f$ be a graph - * with \f$m\f$ edges, \f$n\f$ nodes, \f$c\f$ connected components, \f$nz\f$ - * isolated vertices, and \f$fc\f$ face cycles. Then, - * \f[ - * genus(G) = (m/2 + 2c - n -nz -fc)/2 - * \f] - * - * @return the genus of the graph's current embedding; if this is 0, then the graph is planarly embedded. - */ - int genus() const; - - //! Returns true iff the graph represents a combinatorial embedding. - /** - * @return true if the current embedding (given by the adjacency lists) represents a combinatorial embedding, false otherwise. - */ - bool representsCombEmbedding() const { - return (genus() == 0); - } - - //! Checks the consistency of the data structure. - /** - * \remark This method is meant for debugging purposes only. - * - * @return true if everything is ok, false if the data structure is inconsistent. - */ - bool consistencyCheck() const; - - - //@} - /** - * @name Registering arrays and observers - * These methods are used by various graph array types like NodeArray or EdgeArray. - * There should be no need to use them directly in user code. - */ - //@{ - - //! Registers a node array. - /** - * \remark This method is automatically called by node arrays; it should not be called manually. - * - * @param pNodeArray is a pointer to the node array's base; this node array must be associated with this graph. - * @return an iterator pointing to the entry for the registered node array in the list of registered node arrays. - * This iterator is required for unregistering the node array again. - */ - ListIterator registerArray(NodeArrayBase *pNodeArray) const; - - //! Registers an edge array. - /** - * \remark This method is automatically called by edge arrays; it should not be called manually. - * - * @param pEdgeArray is a pointer to the edge array's base; this edge array must be associated with this graph. - * @return an iterator pointing to the entry for the registered edge array in the list of registered edge arrays. - * This iterator is required for unregistering the edge array again. - */ - ListIterator registerArray(EdgeArrayBase *pEdgeArray) const; - - //! Registers an adjEntry array. - /** - * \remark This method is automatically called by adjacency entry arrays; it should not be called manually. - * - * @param pAdjArray is a pointer to the adjacency entry array's base; this adjacency entry array must be - * associated with this graph. - * @return an iterator pointing to the entry for the registered adjacency entry array in the list of registered - * adjacency entry arrays. This iterator is required for unregistering the adjacency entry array again. - */ - ListIterator registerArray(AdjEntryArrayBase *pAdjArray) const; - - //! Registers a graph observer (e.g. a ClusterGraph). - /** - * @param pStructure is a pointer to the graph observer that shall be registered; this graph observer must be - * associated with this graph. - * @return an iterator pointing to the entry for the registered graph observer in the list of registered - * graph observers. This iterator is required for unregistering the graph observer again. - */ - ListIterator registerStructure(GraphObserver *pStructure) const; - - //! Unregisters a node array. - /** - * @param it is an iterator pointing to the entry in the list of registered node arrays for the node array to - * be unregistered. - */ - void unregisterArray(ListIterator it) const; - - //! Unregisters an edge array. - /** - * @param it is an iterator pointing to the entry in the list of registered edge arrays for the edge array to - * be unregistered. - */ - void unregisterArray(ListIterator it) const; - - //! unregisters an adjEntry array. - /** - * @param it is an iterator pointing to the entry in the list of registered adjacency entry arrays for the - * adjacency entry array to be unregistered. - */ - void unregisterArray(ListIterator it) const; - - //! Unregisters a graph observer. - /** - * @param it is an iterator pointing to the entry in the list of registered graph observers for the graph - * observer to be unregistered. - */ - void unregisterStructure(ListIterator it) const; - - - //! Resets the edge id count to \a maxId. - /** - * The next edge will get edge id \a maxId+1. Use this function with caution! - * It is provided as an efficient way to reduce the edge id count. The Graph class - * increments the edge id count whenever an edge is created; free edge ids resulting - * from removing edges are not reused (there is not something like a freelist). - * - * This function is , e.g., useful, when a lot of edges has been added and - * all these edges are removed again (without creating other new edges - * meanwile). Then, it is safe to reduce the edge id count to the value it had - * before, cf. the following code snippet: - * \code - * int oldIdCount = G.maxEdgeIndex(); - * Create some edges - * ... - * Remove all these edges again - * G.resetEdgeIdCount(oldIdCount); - * \endcode - * - * Reducing the edge id count will reduce the memory consumption of edge arrays - * associated with the graph. - * - * \pre -1 \f$\leq\f$ \a maxId \f$\leq\f$ maximal edge id in the graph. - * - * @param maxId is an upper bound of the edge ids in the graph. - */ - void resetEdgeIdCount(int maxId); - - - //@} - /** - * @name Operators - */ - //@{ - //! Assignment operator. - /** - * The assignment operature assures that the adjacency lists of nodes in the - * constructed graph are in the same order as the adjacency lists in \a G. - * This is in particular important when dealing with embedded graphs. - * - * @param G is the graph to be copied. - * @return this graph. - */ - Graph &operator=(const Graph &G); - - OGDF_MALLOC_NEW_DELETE - - //@} - -public: - - //! Returns the smallest power of 2 which is >= 2^\a start and > \a idCount. - static int nextPower2(int start, int idCount); - - -protected: - void construct(const Graph &G, NodeArray &mapNode, - EdgeArray &mapEdge); - - void assign(const Graph &G, NodeArray &mapNode, - EdgeArray &mapEdge); - - //! Constructs a copy of the subgraph of \a G induced by \a nodes. - /** - * This method preserves the order in the adjacency lists, i.e., if - * \a G is embedded, its embedding induces the embedding of the copy. - */ - void constructInitByNodes( - const Graph &G, - const List &nodes, - NodeArray &mapNode, - EdgeArray &mapEdge); - - void constructInitByActiveNodes( - const List &nodes, - const NodeArray &activeNodes, - NodeArray &mapNode, - EdgeArray &mapEdge); - -private: - void copy(const Graph &G, NodeArray &mapNode, - EdgeArray &mapEdge); - void copy(const Graph &G); - - edge createEdgeElement(node v, node w, adjEntry adjSrc, adjEntry adjTgt); - node pureNewNode(); - - // moves adjacency entry to node w - void moveAdj(adjEntry adj, node w); - - void reinitArrays(); - void reinitStructures(); - void resetAdjEntryIndex(int newIndex, int oldIndex); - - bool readToEndOfLine(istream &is); -}; // class Graph - - - -//! Bucket function using the index of an edge's source node as bucket. -class OGDF_EXPORT BucketSourceIndex : public BucketFunc { -public: - //! Returns source index of \a e. - int getBucket(const edge &e) { return e->source()->index(); } -}; - -//! Bucket function using the index of an edge's target node as bucket. -class OGDF_EXPORT BucketTargetIndex : public BucketFunc { -public: - //! Returns target index of \a e. - int getBucket(const edge &e) { return e->target()->index(); } -}; - - -} //namespace - -#endif - diff --git a/ext/OGDF/ogdf/basic/GridLayout.h b/ext/OGDF/ogdf/basic/GridLayout.h deleted file mode 100644 index 6da9fb75c..000000000 --- a/ext/OGDF/ogdf/basic/GridLayout.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * $Revision: 2576 $ - * - * last checkin: - * $Author: klein $ - * $Date: 2012-07-11 07:50:24 +0200 (Mi, 11. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GridLayout. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRID_LAYOUT_H -#define OGDF_GRID_LAYOUT_H - - -#include -#include - - -namespace ogdf { - - class Layout; - - - -/** - * \brief Representation of a graph's grid layout - */ -class OGDF_EXPORT GridLayout -{ -public: - //! Creates an instance of a grid layout (associated with no graph). - GridLayout() { } - - //! Creates an instance of a grid layout associated with \a G. - GridLayout(const Graph &G) : m_x(G,0), m_y(G,0), m_bends(G) { } - - // destruction - virtual ~GridLayout() { } - - - //! Returns a reference to the array storing the x-coordinates of nodes. - const NodeArray &x() const { return m_x; } - //! Returns a reference to the array storing the x-coordinates of nodes. - NodeArray &x() { return m_x; } - - //! Returns a reference to the array storing the y-coordinates of nodes. - const NodeArray &y() const { return m_y; } - //! Returns a reference to the array storing the y-coordinates of nodes. - NodeArray &y() { return m_y; } - - //! Returns a reference to the array storing the bend points of edges. - const EdgeArray &bends() const { return m_bends; } - //! Returns a reference to the array storing the bend points of edges. - EdgeArray &bends() { return m_bends; } - - - //! Returns a reference to the x-coordinate of node \a v. - const int &x(node v) const { return m_x[v]; } - //! Returns a reference to the x-coordinate of node \a v. - int &x(node v) { return m_x[v]; } - - //! Returns a reference to the y-coordinate of node \a v. - const int &y(node v) const { return m_y[v]; } - //! Returns a reference to the y-coordinate of node \a v. - int &y(node v) { return m_y[v]; } - - - //! Returns a reference to the bend point list of edge \a e. - const IPolyline &bends(edge e) const { return m_bends[e]; } - //! Returns a reference to the bend point list of edge \a e. - IPolyline &bends(edge e) { return m_bends[e]; } - - //! Returns the polyline of edge \a e (including start and end point!). - IPolyline polyline(edge e) const; - - - //! Initializes the grid layout for graph \a G. - void init(const Graph &G) { - m_x.init(G,0); - m_y.init(G,0); - m_bends.init(G); - } - - //! Initializes the grid layout for no graph (frees memory). - void init() { - m_x.init(); - m_y.init(); - m_bends.init(); - } - - //! Returns the bend point list of edge \a e without unnecessary bends. - IPolyline getCompactBends(edge e) const; - - //! Removes all unnecessary bends. - void compactAllBends(); - - /** - * \brief Checks if the grid layout is reasonable. - * - * In particular, the following checks are performed: - * - All nodes have to be assigned to distinct grid points. - * - All bend points have to be assigned to distinct points. - * - No bend point coincides with the position of a node. - */ - bool checkLayout(); - - /** - * \brief Computes the bounding box of the grid layout. - * - * The returned bounding box is (0,0,0,0) if the associated graph is empty - * or no graph is associated with the grid layout. - * @param xmin is assigned the minimum x-coordinate in the grid layout. - * @param xmax is assigned the maximum x-coordinate in the grid layout. - * @param ymin is assigned the minimum y-coordinate in the grid layout. - * @param ymax is assigned the maximum y-coordinate in the grid layout. - */ - void computeBoundingBox(int &xmin, int &xmax, int &ymin, int &ymax); - - //! Computes the total manhattan edge length of the grid layout. - int totalManhattanEdgeLength() const; - - int maxManhattanEdgeLength() const; - int manhattanEdgeLength(edge e) const; - - //! Computes the total (euclidean) edge length of the grid layout. - double totalEdgeLength() const; - - //! Computes the total number of bends in the grid layout. - int numberOfBends() const; - - /** - * \brief Transforms the grid layout to a layout. - * - * This implementation only copies the grid coordinates to \a drawing; the - * derived class GridLayoutMapped performs the actual transformation of coordinates. - */ - virtual void remap(Layout &drawing); - - static int manhattanDistance(const IPoint &ip1, const IPoint &ip2); - static double euclideanDistance(const IPoint &ip1, const IPoint &ip2); - -protected: - NodeArray m_x; //!< The x-coordinates of nodes. - NodeArray m_y; //!< The y-coordinates of nodes. - EdgeArray m_bends; //!< The bend points of edges. - -private: - static bool isRedundant(IPoint &p1, IPoint &p2, IPoint &p3); - static void compact(IPolyline &ip); - - - OGDF_MALLOC_NEW_DELETE -}; // class GridLayout - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/GridLayoutMapped.h b/ext/OGDF/ogdf/basic/GridLayoutMapped.h deleted file mode 100644 index 83a2d3814..000000000 --- a/ext/OGDF/ogdf/basic/GridLayoutMapped.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GridLayoutMapped which extends GridLayout - * by a grid mapping mechanism. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_GRID_LAYOUT_MAPPED_H -#define OGDF_GRID_LAYOUT_MAPPED_H - - -#include - - -namespace ogdf { - - class PlanRep; - class PlanRepUML; - class OrthoRep; - - -//--------------------------------------------------------- -// GridLayoutMapped -// extends GridLayout by a grid mapping mechanism -//--------------------------------------------------------- -class OGDF_EXPORT GridLayoutMapped : public GridLayout -{ - //scaling to allow correct edge anchors - enum { cGridScale = 2 }; - -public: - - // construction (determines mapping factor) - GridLayoutMapped(const PlanRep &PG, - const OrthoRep &OR, - double separation, - double cOverhang, - int fineness = 4); - - - // writes grid layout to layout using re-mapping - void remap(Layout &drawing); - - // transforms real coordinates to grid coordinates - int toGrid(double x) const { - return cGridScale*int(m_fMapping * x + 0.5); - } - - // transforms grid coordinates to real coordinates - double toDouble(int i) const { - return (i/cGridScale) / m_fMapping; - } - - - const NodeArray &width() const { return m_gridWidth; } - // returns a reference to the array storing grid widths of nodes - NodeArray &width() { return m_gridWidth; } - - const NodeArray &height() const { return m_gridHeight; } - // returns a reference to the array storing grid heights of nodes - NodeArray &height() { return m_gridHeight; } - - const int &width(node v) const { return m_gridWidth[v]; } - // returns grid width of node v - int &width(node v) { return m_gridWidth[v]; } - - const int &height(node v) const { return m_gridWidth[v]; } - // returns grid height of node v - int &height(node v) { return m_gridWidth[v]; } - - -private: - NodeArray m_gridWidth; // grid width of nodes - NodeArray m_gridHeight; // grid heights of nodes - - const PlanRep *m_pPG; // planarized representation of grid layout - double m_fMapping; // mapping factor -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/HashArray.h b/ext/OGDF/ogdf/basic/HashArray.h deleted file mode 100644 index 5128d7118..000000000 --- a/ext/OGDF/ogdf/basic/HashArray.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of HashArray class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HASH_ARRAY_H -#define OGDF_HASH_ARRAY_H - - -#include - - -namespace ogdf { - - -//! Indexed arrays using hashing for element access. -/** - * @tparam I is the index type. - * @tparam E is the element type. - * @tparam H is the hash function type. Optional; its default uses the class DefHashFunc. - * - * A hashing array can be used like a usual array but has a general - * index type. - * - * The hashing array is only defined for a subset Idef of the - * index set (set of all elements of the index type). At construction, this set - * is empty. Whenever an index is assigned an element, this index is added - * to Idef. There are also method for testing if an index - * is defined (is in Idef). - * - *

    Example

    - * The following code snippet demonstrates how to use a hashing array. First, - * the example inserts elements into a hashing array simulating a tiny - * German–English dictionary, then it prints some elements via array - * access, and finally it iterates over all defined indices and prints the - * dictionary entries. We use a the const reference \a Hc, since we want to - * avoid that array access for undefined indices creates these elements. - * - * \code - * HashArray H("[undefined]"); - * const HashArray &Hc = H; - * - * H["Hund"] = "dog"; - * H["Katze"] = "cat"; - * H["Maus"] = "mouse"; - * - * cout << "Katze: " << Hc["Katze"] << endl; - * cout << "Hamster: " << Hc["Hamster"] << endl; - * - * cout << "\nAll elements:" << endl; - * HashConstIterator it; - * for(it = Hc.begin(); it.valid(); ++it) - * cout << it.key() << " -> " << it.info() << endl; - * \endcode - * - * The produced output is as follows: - * \code - * Katze: cat - * Hamster: [undefined] - * - * All elements: - * Hund -> dog - * Maus -> mouse - * Katze -> cat - * \endcode - */ -template > -class HashArray : private Hashing -{ - E m_defaultValue; //! The default value for elements. - -public: - //! The type of const-iterators for hash arrays. - typedef HashConstIterator const_iterator; - - //! Creates a hashing array; the default value is the default value of the element type. - HashArray() : Hashing() { } - - //! Creates a hashing array with default value \a defaultValue. - HashArray(const E &defaultValue, const H &hashFunc = H()) - : Hashing(256, hashFunc), m_defaultValue(defaultValue) { } - - //! Copy constructor. - HashArray(const HashArray &A) : Hashing(A), m_defaultValue(A.m_defaultValue) { } - - //! Returns an iterator to the first element in the list of all elements. - HashConstIterator begin() const { return Hashing::begin(); } - - //! Returns the number of defined indices (= number of elements in hash table). - int size() const { return Hashing::size(); } - - //! Returns if any indices are defined (= if the hash table is empty) - int empty() const { return Hashing::empty(); } - - - //! Returns the element with index \a i. - const E &operator[](const I &i) const { - HashElement *pElement = Hashing::lookup(i); - if (pElement) return pElement->info(); - else return m_defaultValue; - } - - //! Returns a reference to the element with index \a i. - E &operator[](const I &i) { - HashElement *pElement = Hashing::lookup(i); - if (!pElement) pElement = Hashing::fastInsert(i,m_defaultValue); - return pElement->info(); - } - - //! Returns true iff index \a i is defined. - bool isDefined(const I &i) const { - return Hashing::member(i); - } - - //! Undefines index \a i. - void undefine(const I &i) { - Hashing::del(i); - } - - //! Assignment operator. - HashArray &operator=(const HashArray &A) { - m_defaultValue = A.m_defaultValue; - Hashing::operator =(A); - return *this; - } - - //! Undefines all indices. - void clear() { Hashing::clear(); } -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/HashArray2D.h b/ext/OGDF/ogdf/basic/HashArray2D.h deleted file mode 100644 index 1ffdef7c4..000000000 --- a/ext/OGDF/ogdf/basic/HashArray2D.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class HashArray2D. - * - * This is a class implementing a 2-dimensional Hash array. - * It uses templates for the keys and the data of the objects - * stored in it. - * - * \author René Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#include -#include -#include - -#ifndef OGDF_HASH_ARRAY_2D_H -#define OGDF_HASH_ARRAY_2D_H - - -namespace ogdf { - - -//! Indexed 2-dimensional arrays using hashing for element access. -/** - * @tparam I1 is the first index type. - * @tparam I2 is the second index type. - * @tparam E is the element type. - * @tparam H1 is the hash function type for \a I1. Optional; uses the class DefHashFunc by default. - * @tparam H2 is the hash function type for \a I2. Optional; uses the class DefHashFunc by default. - * - * A 2D-hash array can be used like a usual 2-dimensional array but with a general - * index type. - */ -template< - class I1, - class I2, - class E, - class H1 = DefHashFunc, - class H2 = DefHashFunc > -class HashArray2D : private Hashing< Tuple2, E, HashFuncTuple > -{ -public: - //! The type of const-iterators for 2D-hash arrays. - typedef HashConstIterator2D const_iterator; - - //! Creates a 2D-hash array. - HashArray2D() { } - - //! Creates a 2D-hash array and sets the default value to \a x. - HashArray2D(const E &defaultValue, const H1 &hashFunc1 = H1(), const H2 &hashFunc2 = H2()) : - Hashing,E,HashFuncTuple >( - 256, - HashFuncTuple(hashFunc1,hashFunc2)), - m_defaultValue(defaultValue) { } - - //! Copy constructor. - HashArray2D(const HashArray2D &A) : - Hashing,E,HashFuncTuple >(A), - m_defaultValue(A.m_defaultValue) { } - - //! Assignment operator. - HashArray2D &operator=(const HashArray2D &A) { - m_defaultValue = A.m_defaultValue; - Hashing,E,HashFuncTuple >::operator=(A); - - return *this; - } - - ~HashArray2D() { } - - //! Returns a const reference to entry (\a i,\a j). - const E &operator()(const I1 &i, const I2 &j) const { - HashElement,E> *pElement = - Hashing,E,HashFuncTuple >::lookup(Tuple2(i,j)); - return (pElement) ? pElement->info() : m_defaultValue; - } - - //! Returns a reference to entry (\a i,\a j). - E &operator()(const I1 &i, const I2 &j) { - Tuple2 t(i,j); - HashElement,E> *pElement = - Hashing,E,HashFuncTuple >::lookup(t); - if (!pElement) - pElement = Hashing,E,HashFuncTuple >::fastInsert(t,m_defaultValue); - return pElement->info(); - } - - //! Returns true iff entry (\a i,\a j) is defined. - bool isDefined(const I1 &i, const I2 &j) const { - return Hashing,E,HashFuncTuple >::member(Tuple2(i,j)); - } - - //! Undefines the entry at index (\a i,\a j). - void undefine(const I1 &i, const I2 &j) { - return Hashing,E,HashFuncTuple >::del(Tuple2(i,j)); - } - - //! Returns an iterator pointing to the first element. - HashConstIterator2D begin() const { - return HashConstIterator2D( - Hashing,E,HashFuncTuple >::begin()); - } - - //! Returns the number of defined elements in the table. - int size() const { - return Hashing,E,HashFuncTuple >::size(); - } - - //! Returns if any indices are defined - int empty() const { - return Hashing,E,HashFuncTuple >::empty(); - } - - - //! Undefines all indices. - void clear() { - Hashing,E,HashFuncTuple >::clear(); - } - -private: - E m_defaultValue; //!< The default value of the array. -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/basic/HashIterator2D.h b/ext/OGDF/ogdf/basic/HashIterator2D.h deleted file mode 100644 index a5732f438..000000000 --- a/ext/OGDF/ogdf/basic/HashIterator2D.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class HashIterator2D. - * - * This class implements an iterator for the HashArray2D. - * - * \author René Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_HASHITERATOR2D_H -#define OGDF_HASHITERATOR2D_H - - -namespace ogdf { - - -/** - * \brief Const-iterator for 2D-hash arrays. - * - */ -template< class I1_, class I2_, class E_, - class Hash1_ = DefHashFunc, - class Hash2_ = DefHashFunc > -class HashConstIterator2D : - private HashConstIterator,E_,HashFuncTuple > -{ -public: - //! Creates an (invalid) iterator. - HashConstIterator2D() { } - - //! Copy constructor. - HashConstIterator2D(const HashConstIterator2D &it) - : HashConstIterator,E_,HashFuncTuple >(it) { } - - //! Copy constructor (from HashConstIterator). - HashConstIterator2D(const HashConstIterator,E_,HashFuncTuple > &it) - : HashConstIterator,E_,HashFuncTuple >(it) { } - - //! Assignemnt operator. - HashConstIterator2D & - operator=(const HashConstIterator2D &it) - { - HashConstIterator,E_,HashFuncTuple >::operator=(it); - return *this; - } - - //! Returns true iff the iterator points to an element. - bool valid() const { - return HashConstIterator,E_,HashFuncTuple >::valid(); - } - - //! Returns the first key of the hash element pointed to. - const I1_ &key1() const { - return HashConstIterator,E_,HashFuncTuple >::key().x1(); - } - - //! Returns the second key of the hash element pointed to. - const I2_ &key2() const { - return HashConstIterator,E_,HashFuncTuple >::key().x2(); - } - - //! Returns the information of the element pointed to. - const E_ &info() const { - return HashConstIterator,E_,HashFuncTuple >::info(); - } - - //! Sets the iterator to the next element in the 2D-hash array. - HashConstIterator2D &operator++() { - HashConstIterator,E_,HashFuncTuple >::operator++(); - return *this; - } -}; - -} - - - -#endif - diff --git a/ext/OGDF/ogdf/basic/Hashing.h b/ext/OGDF/ogdf/basic/Hashing.h deleted file mode 100644 index 66041cfc4..000000000 --- a/ext/OGDF/ogdf/basic/Hashing.h +++ /dev/null @@ -1,517 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of classes used for hashing. - * - * Declares HashingBase and HashElementBase, and declares and implements - * classes Hashing, HashElement, HashConstIterator. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HASHING_H -#define OGDF_HASHING_H - -#include -#include -#include - - -namespace ogdf { - -class HashingBase; - -/** - * \brief Base class for elements within a hash table. - * - * This class realizes only chaining of elements and maintianing hash values - * for rehashing. - */ -class HashElementBase { - friend class HashingBase; - - HashElementBase *m_next; //!< The successor in the list. - size_t m_hashValue; //!< The hash value. - -public: - //! Creates a hash element with hash value \a hashValue. - HashElementBase(size_t hashValue) : m_hashValue(hashValue) { } - - //! Returns the successor to this element in the list. - HashElementBase *next() const { return m_next; } - - //! Returns the hash value of this element. - size_t hashValue() const { return m_hashValue; } - - OGDF_NEW_DELETE -}; - - -/** - * \brief Base class for hashing with chaining and table doubling. - * - * The actual hashing is provided by the parameterized class Hashing - * which derives from HashingBase. - */ -class HashingBase { -protected: - int m_tableSize; //!< The current table size. - int m_hashMask; //!< The current table size minus one. - int m_minTableSize; //!< The minimal table size. - int m_tableSizeLow; //!< The minimal number of elements at this table size. - int m_tableSizeHigh; //!< The maximal number of elements at this table size. - int m_count; //!< The current number of elements. - HashElementBase **m_table; //!< The hash table (an array of lists). - -public: - //! Creates a hash table with minimum table size \a minTableSize. - HashingBase(int minTableSize); - - //! Copy constructor. - HashingBase(const HashingBase &H); - - // destruction - virtual ~HashingBase(); - - //! Resizes the hash table to \a newTableSize. - void resize(int newTableSize); - - //! Inserts a new element \a pElement into the hash table. - void insert(HashElementBase *pElement); - - //! Removes the element \a pElement from the hash table. - void del(HashElementBase *pElement); - - //! Removes all elements from the hash table. - void clear(); - - //! Assignment operator. - HashingBase &operator=(const HashingBase &H); - - //! Returns the number of elements in the hash table. - int size() const { return m_count; } - - //! Returns if the hash table is empty - int empty() const { return (m_count==0); } - - /** - * \brief Returns the first element in the list for elements with hash value \a hashValue. - * - * This is the list m_table[hashValue & m_hashMask]. - */ - HashElementBase *firstListElement(size_t hashValue) const { - return *(m_table + (hashValue & m_hashMask)); - } - - /** - * \brief Returns the first element in the list of all elements in the hash table. - * - * This function is used by hash iterators for iterating over all elements - * in the hash table. - * @param pList is assigned the list containing the first element. - * \return a pointer to the first element or 0 if hash table is empty. - */ - HashElementBase *firstElement(HashElementBase ***pList) const; - - /** - * \brief Returns the successor of \a pElement in the list of all elements in the hash table. - * - * This function is used by hash iterators for iterating over all elements - * in the hash table. - * @param pList is assigned the list containing the first element. - * @param pElement points to an element in the has table. - * \return a pointer to the first element or 0 if hash table is empty. - */ - HashElementBase *nextElement(HashElementBase ***pList, - HashElementBase *pElement) const; - -protected: - //! Deletes all elements in hash table (but does not free m_table!). - void destroyAll(); - - /** - * \brief Called to delete hash element. - * - * This must be done in Hashing since only this class knows the actual - * element type; alternatively, HashElementBase could have a virtual destructor. - */ - virtual void destroy(HashElementBase *pElement) = 0; - - //! Called to create a copy of the element \a pElement. - virtual HashElementBase *copy(HashElementBase *pElement) const = 0; - -private: - //! Initializes the table for given table size. - void init(int tableSize); - - //! Copies all elements from \a H to this hash table. - void copyAll(const HashingBase &H); -}; - - -template class Hashing; -template class HashArray; - - -/** - * \brief Representation of elements in a hash table. - * - * This class adds key and information members to HashElementBase. The two - * template parameters are \a K for the type of keys and \a I for the type - * of information. - */ -template -class HashElement : public HashElementBase -{ - K m_key; //!< The key value. - I m_info; //!< The information value. - -public: - //! Creates a hash element with given hash value, key, and information. - HashElement(size_t hashValue, const K &key, const I &info) : - HashElementBase(hashValue), m_key(key), m_info(info) { } - - //! Returns the successor element in the list. - HashElement *next() const { - return (HashElement *)HashElementBase::next(); - } - - //! Returns the key value. - const K &key() const { return m_key; } - - //! Returns the information value. - const I &info() const { return m_info; } - - //! Returns a refeence to the information value. - I &info() { return m_info; } - - OGDF_NEW_DELETE -}; - - -template class HashConstIterator; - -//-------------------------------------------------------------------- -// Hash function classes have to define -// int hash(const E &key) -// -// "const E &" can be replaced by "E" -//-------------------------------------------------------------------- - -/** - * \brief Default hash functions. - * - * This class implements a default hash function for various - * basic data types. - * - * \see Hashing, HashArray, HashArray2D - */ -template class DefHashFunc { - //! Returns the hash value of \a key. - public: size_t hash(const K &key) const { return size_t(key); } -}; - -//! Specialized default hash function for pointer types. -template<> class DefHashFunc { - public: size_t hash(const void * &key) const { return size_t(key && 0xffffffff); } -}; - -//! Specialized default hash function for double. -template<> class DefHashFunc { - public: size_t hash(const double &key) const { - int dummy; - return size_t(SIZE_MAX*frexp(key,&dummy)); - } -}; - - -/** - * \brief %Hashing with chaining and table doubling. - * - * The class Hashing implements a hashing table which realizes a - * mapping from a key type \a K to an information type \a I. - * - * The class requires three template parameters: - * - \a K is the type of keys. - * - \a I is the type of information. - * - \a H is the hash function type. - * The hash function type argument is optional; its default uses the class - * DefHashFunc. - */ -template > -class Hashing : private HashingBase -{ - friend class HashConstIterator; - H m_hashFunc; //!< The hash function. - -public: - //! The type of const-iterators for hash tables. - typedef HashConstIterator const_iterator; - - //! Creates a hash table for given initial table size \a minTableSize. - explicit Hashing(int minTableSize = 256, const H &hashFunc = H()) - : HashingBase(minTableSize), m_hashFunc(hashFunc) { } - - //! Copy constructor. - Hashing(const Hashing &h) : HashingBase(h) { } - - // destruction - ~Hashing() { HashingBase::destroyAll(); } - - //! Returns the number of elements in the hash table. - int size() const { return HashingBase::size(); } - - //! Returns true iff the table is empty, i.e., contains no elements. - bool empty() const { return (HashingBase::size() == 0); } - - //! Returns true iff the hash table contains an element with key \a key. - bool member(const K &key) const { return (lookup(key) != 0); } - - //! Returns an hash iterator to the first element in the list of all elements. - HashConstIterator begin() const; - - //! Returns the hash element with key \a key in the hash table; returns 0 if no such element. - HashElement *lookup(const K &key) const { - HashElement *pElement = - (HashElement *)firstListElement(m_hashFunc.hash(key)); - for (; pElement; pElement = pElement->next()) - if (pElement->key() == key) return pElement; - - return 0; - } - - //! Assignment operator. - Hashing &operator=(const Hashing &hashing) { - HashingBase::operator =(hashing); - m_hashFunc = hashing.m_hashFunc; - return *this; - } - - /** - * \brief Inserts a new element with key \a key and information \a info into the hash table. - * - * The new element will only be inserted if no element with key \a key is - * already contained; if such an element already exists the information of - * this element will be changed to \a info. - */ - HashElement *insert(const K &key, const I &info) { - HashElement *pElement = lookup(key); - - if (pElement) - pElement->info() = info; - else - HashingBase::insert(pElement = - OGDF_NEW HashElement(m_hashFunc.hash(key),key,info)); - - return pElement; - } - - /** - * \brief Inserts a new element with key \a key and information \a info into the hash table. - * - * The new element will only be inserted if no element with key \a key is - * already contained; if such an element already exists the information of - * this element remains unchanged. - */ - HashElement *insertByNeed(const K &key, const I &info) { - HashElement *pElement = lookup(key); - - if (!pElement) - HashingBase::insert(pElement = OGDF_NEW HashElement(m_hashFunc.hash(key),key,info)); - - return pElement; - } - - /** - * \brief Inserts a new element with key \a key and information \a info into the hash table. - * - * This is a faster version of insert() that assumes that no element with key - * \a key is already contained in the hash table. - */ - HashElement *fastInsert(const K &key, const I &info) { - HashElement *pElement = OGDF_NEW HashElement(m_hashFunc.hash(key),key,info); - HashingBase::insert(pElement); - return pElement; - } - - //! Removes the element with key \a key from the hash table (does nothing if no such element). - void del(const K &key) { - HashElement *pElement = lookup(key); - if (pElement) { - HashingBase::del(pElement); - delete pElement; - } - } - - //! Removes all elements from the hash table. - void clear() { HashingBase::clear(); } - -protected: - /** - * \brief Returns the first element in the list of all elements in the hash table. - * - * This function is used by hash iterators for iterating over all elements - * in the hash table. - * @param pList is assigned the list containing the first element. - * \return a pointer to the first element or 0 if hash table is empty. - */ - HashElement *firstElement(HashElement ***pList) const { - return (HashElement *)(HashingBase::firstElement((HashElementBase ***)pList)); - } - - /** - * \brief Returns the successor of \a pElement in the list of all elements in the hash table. - * - * This function is used by hash iterators for iterating over all elements - * in the hash table. - * @param pList is assigned the list containing the first element. - * @param pElement points to an element in the has table. - * \return a pointer to the first element or 0 if hash table is empty. - */ - HashElement *nextElement(HashElement ***pList, - HashElement *pElement) const - { - return (HashElement *)(HashingBase::nextElement( - (HashElementBase ***)pList,pElement)); - } - -private: - //! Deletes hash element \a pElement. - virtual void destroy(HashElementBase *pElement) { - delete (HashElement *)(pElement); - } - - //! Returns a copy of hash element \a pElement. - virtual HashElementBase *copy(HashElementBase *pElement) const { - HashElement *pX = (HashElement *)(pElement); - return OGDF_NEW HashElement(pX->hashValue(),pX->key(),pX->info()); - } -}; - - -/** - * \brief Iterators for hash tables. - * - * This class implements an iterator for iterating over all elements in - * a hash table. Hash iterators are provided by Hashing::begin(). - * - *

    Example

    - * The following code snippet demonstrates how to iterate over all elements - * of a hash table. First, the example fills a hash table with a tiny - * German–English dictionary, and then it iterates over the elements - * and prints the entries. - * \code - * Hashing H; - * - * H.fastInsert("Hund","dog"); - * H.fastInsert("Katze","cat"); - * H.fastInsert("Maus","mouse"); - * - * HashConstIterator it; - * for(it = H.begin(); it.valid(); ++it) - * cout << it.key() << " -> " << it.info() << endl; - * \endcode - */ -template > -class HashConstIterator { - HashElement *m_pElement; //!< The hash element to which the iterator points. - HashElement **m_pList; //!< The list containg the hash element. - const Hashing *m_pHashing; //!< The associated hash table. - -public: - //! Creates a hash iterator pointing to no element. - HashConstIterator() : m_pElement(0), m_pList(0), m_pHashing(0) { } - - //! Creates a hash iterator pointing to element \a pElement in list \a pList of hash table \a pHashing. - HashConstIterator(HashElement *pElement, HashElement **pList, - const Hashing *pHashing) : m_pElement(pElement), m_pList(pList), - m_pHashing(pHashing) { } - - //! Copy constructor. - HashConstIterator(const HashConstIterator &it) : m_pElement(it.m_pElement), - m_pList(it.m_pList), m_pHashing(it.m_pHashing) { } - - //! Assignment operator. - HashConstIterator &operator=(const HashConstIterator &it) { - m_pElement = it.m_pElement; - m_pList = it.m_pList; - m_pHashing = it.m_pHashing; - return *this; - } - - //! Returns true if the hash iterator points to an element. - bool valid() const { return (m_pElement != 0); } - - //! Returns the key of the hash element pointed to. - const K &key() const { return m_pElement->key(); } - - //! Returns the information of the hash element pointed to. - const I &info() const { return m_pElement->info(); } - - //! Equality operator. - friend bool operator==(const HashConstIterator &it1, - const HashConstIterator &it2) { return (it1.m_pElement == it2.m_pElement); } - - //! Inequality operator. - friend bool operator!=(const HashConstIterator &it1, - const HashConstIterator &it2) { return (it1.m_pElement != it2.m_pElement); } - - //! Moves this hash iterator to the next element (iterator gets invalid if no more elements). - HashConstIterator &operator++() { - m_pElement = m_pHashing->nextElement(&m_pList,m_pElement); - return *this; - } -}; - - -template -inline HashConstIterator Hashing::begin() const -{ - HashElement *pElement, **pList; - pElement = firstElement(&pList); - return HashConstIterator(pElement,pList,this); -} - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/HeapBase.h b/ext/OGDF/ogdf/basic/HeapBase.h deleted file mode 100644 index c1b358e84..000000000 --- a/ext/OGDF/ogdf/basic/HeapBase.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author:klein $ - * $Date:2007-10-18 17:23:28 +0200 (Thu, 18 Oct 2007) $ - ***************************************************************/ - -/** \file - * \brief Declaration of an abstract heap base class for - * priority queue implementation. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HEAP_BASE_H -#define OGDF_HEAP_BASE_H - - -#include - - -namespace ogdf { - -/** - -* \brief A data structure implementing the abstract data type -* priority queue -* A Heap is a data structure implementing the abstract data type -* priority queue, maintaining a set of elements each with an associated key value -* used for keeping the elements in a specific order. - -* It supports the following operations: -* insert(element, key) insert element with key in set -* min return element with minimum key -* extractMin remove and return element with minimum key -* decreaseKey decrease the key of a given element to a given value -* delete remove a given element fromthe structure - - -* Running times and space requirements are depending on the actual -* implementation type (e.g., binary, binomial or fibonacci heaps) - -*/ - - -class HeapEntry; - -class HeapEntryPointer; - -template -class HeapBase { - -public: - //! Constructor - HeapBase() { } - - virtual ~HeapBase() { } - - - //! build a heap out of a given set of elements - virtual void makeHeap() = 0; - - HeapObject minRet() { } - - //******************************************************* - //Modification - - //! insert a new element with priority key - virtual void insert(HeapObject, Priority /* key */) { } - //extractMin - //derived classes should decide themselves if they have - //a specific delete function - //virtual void delete() = 0; - - //! update the data structure by decreasing the key of an object - //TODO: Does not make much sense without an object parameter - virtual void decreaseKey() { } - - //******************************************************* - //constant functions - int size() const {return m_size;} - - bool empty() const {return m_size==0;} - - -protected: - int m_size; //number of elements stored in heap - -}; - - - -} //namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/HyperGraph.h b/ext/OGDF/ogdf/basic/HyperGraph.h deleted file mode 100644 index 89c449416..000000000 --- a/ext/OGDF/ogdf/basic/HyperGraph.h +++ /dev/null @@ -1,913 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of a HyperGraph - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HYPER_GRAPH_H -#define OGDF_HYPER_GRAPH_H - -#include -#include -#include - -namespace ogdf { - -class OGDF_EXPORT HyperGraph -{ - friend class HyperGraphTypes; - -public: - // forward declaration to make AdjElement pointers available - class AdjElement; - - //! Representation of node elements. - class NodeElement - { - friend class HyperGraph; - friend class HyperGraphTypes; - public: - //! Returns the index of this node. - int index() const { return m_index; } - - //! Returns the number of incident edges. - int degree() const { return m_numAdj; } - - private: - NodeElement* m_pPrev; - NodeElement* m_pNext; - AdjElement* m_pFirstAdj; - AdjElement* m_pLastAdj; - int m_numAdj; - int m_index; - }; // class NodeElement - - - //! Representation of hyper edges. - class EdgeElement - { - friend class HyperGraph; - friend class HyperGraphTypes; - public: - //! Returns the index of this edge. - int index() const { return m_index; } - - //! Returns the number of incident nodes. - int cardinality() const { return m_numAdj; } - - private: - EdgeElement* m_pPrev; - EdgeElement* m_pNext; - AdjElement* m_pFirstAdj; - AdjElement* m_pLastAdj; - int m_numAdj; - int m_index; - }; // class EdgeElement - - - //! Representation of adjacency elements. - class AdjElement - { - friend class HyperGraph; - friend class HyperGraphTypes; - public: - AdjElement() : m_pNode(0), m_pEdge(0) { } - - //! Returns the node whose adjacency list contains this adjacency entry. - NodeElement* theNode() { return m_pNode; } - - //! Returns the hyper edge associated with this adjacency entry. - EdgeElement* theEdge() { return m_pEdge; } - - //! Returns the index of this adjacency entry. - int index() const { return m_index; } - private: - - AdjElement(NodeElement* pNode, EdgeElement* pEdge) : - m_pNode(pNode), - m_pEdge(pEdge), - m_pPrev_nodeAdj(0), - m_pNext_nodeAdj(0), - m_pPrev_edgeAdj(0), - m_pNext_edgeAdj(0) - { } - - NodeElement* m_pNode; - EdgeElement* m_pEdge; - - AdjElement* m_pPrev_nodeAdj; - AdjElement* m_pNext_nodeAdj; - - AdjElement* m_pPrev_edgeAdj; - AdjElement* m_pNext_edgeAdj; - int m_index; - }; - - typedef NodeElement* node; - typedef EdgeElement* edge; - -protected: - NodeElement* m_pFirstNode; - NodeElement* m_pLastNode; - int m_numNodes; - - EdgeElement* m_pFirstEdge; - EdgeElement* m_pLastEdge; - int m_numEdges; - -protected: - EFreeListIndexPool< - NodeElement, - &NodeElement::m_pNext, - &NodeElement::m_index - > m_nodeAllocator; - - EFreeListIndexPool< - EdgeElement, - &EdgeElement::m_pNext, - &EdgeElement::m_index - > m_edgeAllocator; - - EFreeListIndexPool< - AdjElement, - &AdjElement::m_pNext_nodeAdj, // note: we just need one next pointer, nobody cares which one. - &AdjElement::m_index - > m_adjAllocator; - - - template - class GraphArrayBase - { - friend class HyperGraph; - public: - //! Interface method for resizing a graph array. - virtual void setSize(int numElements) = 0; - - GraphArrayBase* m_prev; //!> the embedded prev pointer. - GraphArrayBase* m_next; //!> the embedded next pointer. - }; - - - template - class GraphArray : protected Array, GraphArrayBase - { - friend class HyperGraph; - public: - // Creates an empty graph array not attached to a graph. - GraphArray() : m_pGraph(0), Array() { } - - //! Creates a graph array attached to \a pGraph. - GraphArray(HyperGraph* pGraph) : m_pGraph(pGraph), m_initialValue(), Array() - { - if (m_pGraph) - m_pGraph->registerArray(this); - } - - //! Creates a graph array attached to \a pGraph with default value \a initialValue. - GraphArray(HyperGraph* pGraph, const T& initialValue) : m_pGraph(pGraph), m_initialValue(initialValue), Array() - { - if (m_pGraph) - m_pGraph->registerArray(this); - } - - //! Destructor. - /** - * If the array is attached to a graph, the array will be detached before it is deallocated. - */ - virtual ~GraphArray() - { - if (m_pGraph) - m_pGraph->unregisterArray(this); - } - - //! Returns a const reference to the entry for an indexed element. - const T& operator[](const E* e) const - { - return Array::operator [](e->index()); - } - - //! Returns a reference to the entry for an indexed element. - T& operator[](const E* e) - { - return Array::operator [](e->index()); - } - - //! Returns the graph the array is attached to. - HyperGraph* graph() const - { - return m_pGraph; - } - - protected: - - //! Implementation of \a GraphArrayBase::setSize(int). - virtual void setSize(int numElements) - { - if (numElements > Array::size()) - Array::grow(numElements-Array::size(),m_initialValue); - } - - //! The graph the array is attached to. - HyperGraph* m_pGraph; - - //! The initial value for unset entries. - T m_initialValue; - - }; // end of class GraphArray - - - template class ArrayControllerTypes; - - //! Array controllers manage the graph arrays of an element. - template - class ArrayController - { - friend class ArrayControllerTypes; - public: - //! Creates a new array controller where the actual table size is zero. - ArrayController() : m_tableSize(0) - { - ArrayControllerTypes::ArrayListType::init(this); - } - - //! Frees the array controller and unregisters all remaining arrays. - ~ArrayController(); - - //! Registers a new graph array and sets the size to \a m_tableSize. - void registerArray(GraphArrayBase* pArray); - - //! Unregisters a graph array by removing it from the list. - void unregisterArray(GraphArrayBase* pArray); - - //! function to calculate the new tableSize; returns min(2^k | 2^k >= minSize) - int newTableSize(int minSize) - { - int res = 1; - while (res < minSize) - res = res << 1; - return res; - } - - //! called by the hyper graph when the amount of used entries has changed. - void numUsedIndicesChanged(int numUsedIndices); - - protected: - //! First array in the chain of attached arrays - GraphArrayBase* m_first; - - //! Last array in the chain of attached arrays - GraphArrayBase* m_last; - - //! Number of attached arrays - int m_numArrays; - - //! Current table size which corresponds to the length of all attached arrays. - int m_tableSize; - }; - - - template - class ArrayControllerTypes - { - public: - //! Type definition for the embedded list of arrays. - typedef EList< ArrayController, GraphArrayBase, - &ArrayController::m_numArrays, - &ArrayController::m_first, - &ArrayController::m_last, - &GraphArrayBase::m_prev, - &GraphArrayBase::m_next> ArrayListType; - }; - - - ArrayController m_nodeArrayController; //!< controller for node arrays - ArrayController m_edgeArrayController; //!< controller for edge arrays - ArrayController m_adjArrayController; //!< controller for adj arrays - - void registerArray(GraphArrayBase* pArray) { m_nodeArrayController.registerArray(pArray); } - void registerArray(GraphArrayBase* pArray) { m_edgeArrayController.registerArray(pArray); } - void registerArray(GraphArrayBase* pArray) { m_adjArrayController.registerArray(pArray); } - - - void unregisterArray(GraphArrayBase* pArray) { m_nodeArrayController.unregisterArray(pArray); } - void unregisterArray(GraphArrayBase* pArray) { m_edgeArrayController.unregisterArray(pArray); } - void unregisterArray(GraphArrayBase* pArray) { m_adjArrayController.unregisterArray(pArray); } - - //! Allocates a new NodeElement using the EFreeListIndexPool and lets the controller check if arrays have to be resized. - NodeElement* allocateNodeElement() - { - NodeElement* pResult = m_nodeAllocator.alloc(); - m_nodeArrayController.numUsedIndicesChanged(m_nodeAllocator.numUsedIndices()); - return pResult; - } - - //! Allocates a new EdgeElement using the EFreeListIndexPool and lets the controller check if arrays have to be resized. - EdgeElement* allocateEdgeElement() - { - EdgeElement* pResult = m_edgeAllocator.alloc(); - m_edgeArrayController.numUsedIndicesChanged(m_edgeAllocator.numUsedIndices()); - return pResult; - } - - //! Allocates a new AdjElement using the EFreeListIndexPool and lets the controller check if arrays have to be resized. - AdjElement* allocateAdjElement() - { - AdjElement* pResult = m_adjAllocator.alloc(); - m_adjArrayController.numUsedIndicesChanged(m_adjAllocator.numUsedIndices()); - return pResult; - } - - //! Frees a used NodeElement - void freeNodeElement(NodeElement* pNode) - { - m_nodeAllocator.free(pNode); - } - - //! Frees a used EdgeElement - void freeEdgeElement(EdgeElement* pEdge) - { - m_edgeAllocator.free(pEdge); - } - - //! Frees a used AdjElement - void freeAdjElement(AdjElement* pAdj) - { - m_adjAllocator.free(pAdj); - } - -public: - - //! Dynamic arrays indexed with nodes. - template - class NodeArray : public GraphArray - { - public: - NodeArray(HyperGraph* pGraph) : GraphArray(pGraph) {} - NodeArray(HyperGraph* pGraph, const T& initValue) : GraphArray(pGraph, initValue) {} - }; - - //! Dynamic arrays indexed with hyper edges. - template - class EdgeArray : public GraphArray - { - public: - EdgeArray(HyperGraph* pGraph) : GraphArray(pGraph) {} - EdgeArray(HyperGraph* pGraph, const T& initValue) : GraphArray(pGraph, initValue) {} - }; - - //! Dynamic arrays indexed with adjacency entries. - template - class AdjArray : public GraphArray - { - public: - AdjArray(HyperGraph* pGraph) : GraphArray(pGraph) {} - AdjArray(HyperGraph* pGraph, const T& initValue) : GraphArray(pGraph, initValue) {} - }; - - - //! Creates an empty hyper graph. - HyperGraph(); - - //! Creates a new node. - NodeElement* newNode(); - - //! Creates a new edge which is not incident to any nodes. - EdgeElement* newEdge(); - - //! Creates a new edge which is incident to the two nodes \a pNode1, \a pNode2. - EdgeElement* newEdge(NodeElement* pNode1, NodeElement* pNode2) - { - EdgeElement* pEdge = newEdge(); - newAdjElement( pNode1, pEdge ); - newAdjElement( pNode2, pEdge ); - return pEdge; - } - - //! Creates a new \a AdjElement which makes \a pNode and \a pEdge incident. - /** - * \note This function does not check if \a pNode and \a pEdge are already incident. - * Hypergraphs can deal with duplicate AdjElements. However, for reasons of clarity - * it is not a good idea to make use of it. - * @param pNode is the node. - * @param pEdge is the hyper edge. - */ - AdjElement* newAdjElement(NodeElement* pNode, EdgeElement* pEdge); - - //! Removes one endpoint \a pAdj from a hyper edge. - void delAdjElement(AdjElement* pAdj); - - //! Removes the endpoint \a pNode from the hyper edge \a pEdge. - void delAdjElement(NodeElement* pNode, EdgeElement* pEdge) - { - AdjElement* pAdj = findAdjElement(pNode, pEdge); - if (pAdj) delAdjElement(pAdj); - } - - //! Makes \a pNode and \a pEdge incident; returns the corresponding \a AdjElement. - AdjElement* addNode(NodeElement* pNode, EdgeElement* pEdge, bool checkIfAlreadyExists = false) - { - if (!checkIfAlreadyExists) - return newAdjElement( pNode, pEdge ); - - AdjElement* pAdj = findAdjElement(pNode, pEdge); - if (!pAdj) - pAdj = newAdjElement( pNode, pEdge ); - return pAdj; - } - - //! If \a pNode and \a pEdge are incident, the corresponding AdjElement is removed. - /** - * \note The function requires time O(min(degree(pNode), cardinality(pEdge))). - * @param pNode is the node. - * @param pEdge is the hyper edge. - * @param removeDuplicates is a flag, if it is set the function will remove any existing duplicates too. - */ - void removeNode(NodeElement* pNode, EdgeElement* pEdge, bool removeDuplicates = false) - { - AdjElement* pAdj = findAdjElement(pNode, pEdge); - if (!removeDuplicates && pAdj) - { - delAdjElement(pAdj); - } else - { - while (pAdj) - { - delAdjElement(pAdj); - pAdj = findAdjElement(pNode, pEdge); - } - } - } - - //! Returns the \a AdjElement for pNode and pEdge. - /** - * In case \a pNode and \a pEdge are not incident the function returns 0. - * \note The function requires time O(min(degree(pNode), cardinality(pEdge))). - * @param pNode is the node. - * @param pEdge is the hyper edge. - */ - AdjElement* findAdjElement(NodeElement* pNode, EdgeElement* pEdge) const; - - //! Deletes hyper edge \a pEdge. - void delEdge(EdgeElement* pEdge); - - //! Deletes node \a pNode. - void delNode(NodeElement* pNode); - - int numberOfNodes() const; - int numberOfEdges() const; - - //! Clears the graph. - void clear(); - - /* void toCliqueGraph( - Graph* pG, - NodeArray* pNodeMap = 0, - EdgeArray* pEdgeMap = 0) - { - HyperGraph::NodeArray hgNode_to_gNode(this); - for (NodeList::iterator it = HyperGraph::NodeList::begin(this); it.valid(); it++) - { - HyperGraph::NodeElement* hgNode = *it; - ogdf::node gNode = pG->newNode(); - hgNode_to_gNode[ hgNode ] = gNode; - if (pNodeMap) - (*pNodeMap)[gNode] = hgNode; - } - - for (HyperGraph::EdgeList::iterator it = HyperGraph::EdgeList::begin(this); it.valid(); it++) - { - EdgeElement* hgEdge = *it; - for (HyperGraph::EdgeAdjList::iterator adj_it = HyperGraph::EdgeAdjList::begin(hgEdge); adj_it.valid(); adj_it++) - { - for (HyperGraph::EdgeAdjList::iterator adj_it2 = adj_it.succ(); adj_it2.valid(); adj_it2++) - { - NodeElement* hgNode = (*adj_it)->theNode(); - NodeElement* hgNode2 = (*adj_it2)->theNode(); - node gNode = hgNode_to_gNode[ hgNode ]; - node gNode2 = hgNode_to_gNode[ hgNode2 ]; - - edge gEdge = pG->newEdge(gNode, gNode2); - if (pEdgeMap) - (*pEdgeMap)[gEdge] = hgEdge; - } - } - } - } - - void toStarGraph( - Graph* pG, - NodeArray* pNodeMap = 0, - EdgeArray* pEdgeMap = 0) - { - HyperGraph::NodeArray hgNode_to_gNode(this); - for (NodeList::iterator it = HyperGraph::NodeList::begin(this); it.valid(); it++) - { - NodeElement* hgNode = *it; - node gNode = pG->newNode(); - hgNode_to_gNode[ hgNode ] = gNode; - if (pNodeMap) - (*pNodeMap)[gNode] = hgNode; - } - - for (HyperGraph::EdgeList::iterator it = HyperGraph::EdgeList::begin(this); it.valid(); it++) - { - EdgeElement* hgEdge = *it; - node gNodeDummy = pG->newNode(); - if (pNodeMap) - (*pNodeMap)[gNodeDummy] = 0; - - for (HyperGraph::EdgeAdjList::iterator adj_it = HyperGraph::EdgeAdjList::begin(hgEdge); adj_it.valid(); adj_it++) - { - NodeElement* hgNode = (*adj_it)->theNode(); - node gNode = hgNode_to_gNode[ hgNode ]; - edge gEdge = pG->newEdge(gNodeDummy, gNode); - if (pEdgeMap) - (*pEdgeMap)[gEdge] = hgEdge; - } - } - } */ -}; // end of class HyperGraph - - -//! Type declarations for HyperGraph. -class HyperGraphTypes -{ -public: - //! Type definition for the embedded list of nodes. - typedef EList< - HyperGraph, HyperGraph::NodeElement, - &HyperGraph::m_numNodes, - &HyperGraph::m_pFirstNode, - &HyperGraph::m_pLastNode, - &HyperGraph::NodeElement::m_pPrev, - &HyperGraph::NodeElement::m_pNext - > NodeList; - - //! Type definition for the embedded list of edges. - typedef EList< - HyperGraph, HyperGraph::EdgeElement, - &HyperGraph::m_numEdges, - &HyperGraph::m_pFirstEdge, - &HyperGraph::m_pLastEdge, - &HyperGraph::EdgeElement::m_pPrev, - &HyperGraph::EdgeElement::m_pNext - > EdgeList; - - //! Type definition for the embedded list of AdjElement at a node. - typedef EList< - HyperGraph::NodeElement, HyperGraph::AdjElement, - &HyperGraph::NodeElement::m_numAdj, - &HyperGraph::NodeElement::m_pFirstAdj, - &HyperGraph::NodeElement::m_pLastAdj, - &HyperGraph::AdjElement::m_pPrev_nodeAdj, - &HyperGraph::AdjElement::m_pNext_nodeAdj - > NodeAdjList; - - //! Type definition for the embedded list of AdjElement at an edge. - typedef EList< - HyperGraph::EdgeElement, HyperGraph::AdjElement, - &HyperGraph::EdgeElement::m_numAdj, - &HyperGraph::EdgeElement::m_pFirstAdj, - &HyperGraph::EdgeElement::m_pLastAdj, - &HyperGraph::AdjElement::m_pPrev_edgeAdj, - &HyperGraph::AdjElement::m_pNext_edgeAdj - > EdgeAdjList; -}; - - -template -HyperGraph::ArrayController::~ArrayController() -{ - // Unregisters all arrays, but does not delete them. - while (!ArrayControllerTypes::ArrayListType::empty(this)) - unregisterArray(ArrayControllerTypes::ArrayListType::front(this)); -} - - -// Registers a new graph array and sets the size to \a m_tableSize. -template -inline void HyperGraph::ArrayController::registerArray(GraphArrayBase* pArray) -{ - ArrayControllerTypes::ArrayListType::pushBack(this, pArray); - pArray->setSize(m_tableSize); -} - - -// Unregisters an array by removing it from the list. -template -inline void HyperGraph::ArrayController::unregisterArray(GraphArrayBase* pArray) -{ - ArrayControllerTypes::ArrayListType::remove(this, pArray); - pArray->setSize(0); -} - - -template -inline void HyperGraph::ArrayController::numUsedIndicesChanged(int numUsedIndices) -{ - // check if we have to grow - if (numUsedIndices > m_tableSize) - { - // we have to resize - // calculate new table size - m_tableSize = newTableSize(numUsedIndices); - // iterate over all arrays - for (typename ArrayControllerTypes::ArrayListType::iterator it = ArrayControllerTypes::ArrayListType::begin(this); - it.valid(); it++) - { - // and resize them - (*it)->setSize(m_tableSize); - } - } -} - - -inline HyperGraph::HyperGraph() -{ - HyperGraphTypes::NodeList::init( this ); - HyperGraphTypes::EdgeList::init( this ); -} - - -inline HyperGraph::NodeElement* HyperGraph::newNode() -{ - NodeElement* pNode = allocateNodeElement(); - HyperGraphTypes::NodeList::pushBack( this, pNode ); - HyperGraphTypes::NodeAdjList::init( pNode ); - return pNode; -} - - -inline HyperGraph::EdgeElement* HyperGraph::newEdge() -{ - EdgeElement* pEdge = allocateEdgeElement(); - HyperGraphTypes::EdgeList::pushBack( this, pEdge ); - HyperGraphTypes::EdgeAdjList::init( pEdge ); - return pEdge; -} - - -inline HyperGraph::AdjElement* HyperGraph::newAdjElement(HyperGraph::NodeElement* pNode, HyperGraph::EdgeElement* pEdge) -{ - AdjElement* pAdj = allocateAdjElement(); - pAdj->m_pNode = pNode; - pAdj->m_pEdge = pEdge; - - HyperGraphTypes::NodeAdjList::pushBack( pNode, pAdj ); - HyperGraphTypes::EdgeAdjList::pushBack( pEdge, pAdj ); - return pAdj; -} - - -inline void HyperGraph::delAdjElement(HyperGraph::AdjElement* pAdj) -{ - HyperGraphTypes::EdgeAdjList::remove( pAdj->theEdge(), pAdj ); - HyperGraphTypes::NodeAdjList::remove( pAdj->theNode(), pAdj ); - freeAdjElement( pAdj ); -} - - -inline HyperGraph::AdjElement* HyperGraph::findAdjElement(HyperGraph::NodeElement* pNode, HyperGraph::EdgeElement* pEdge) const -{ - if (HyperGraphTypes::EdgeAdjList::size(pEdge) < HyperGraphTypes::NodeAdjList::size(pNode)) - { - for (HyperGraphTypes::EdgeAdjList::iterator it = HyperGraphTypes::EdgeAdjList::begin(pEdge); - it.valid(); it++) - { - if ((*it)->theNode() == pNode) return (*it); - } - } else - { - for (HyperGraphTypes::NodeAdjList::iterator it = HyperGraphTypes::NodeAdjList::begin(pNode); - it.valid(); it++) - { - if ((*it)->theEdge() == pEdge) return (*it); - } - } - return 0; -} - - -inline void HyperGraph::delEdge(HyperGraph::EdgeElement* pEdge) -{ - for (HyperGraphTypes::EdgeAdjList::iterator it = HyperGraphTypes::EdgeAdjList::begin(pEdge); it.valid();) - { - AdjElement* pAdj = *it; - HyperGraphTypes::NodeAdjList::remove( pAdj->theNode(), pAdj ); - it = HyperGraphTypes::EdgeAdjList::remove( pEdge, it ); - freeAdjElement( pAdj ); - } - HyperGraphTypes::EdgeList::remove( this, pEdge ); - freeEdgeElement( pEdge ); -} - - -void HyperGraph::delNode(HyperGraph::NodeElement* pNode) -{ - for (HyperGraphTypes::NodeAdjList::iterator it = HyperGraphTypes::NodeAdjList::begin(pNode); it.valid();) - { - AdjElement* pAdj = *it; - HyperGraphTypes::EdgeAdjList::remove( pAdj->theEdge(), pAdj ); - it = HyperGraphTypes::NodeAdjList::remove( pNode, it ); - freeAdjElement( pAdj ); - } - HyperGraphTypes::NodeList::remove( this, pNode ); - freeNodeElement( pNode ); -} - - -inline int HyperGraph::numberOfNodes() const { return HyperGraphTypes::NodeList::size(this); } - -inline int HyperGraph::numberOfEdges() const { return HyperGraphTypes::EdgeList::size(this); } - - -inline void HyperGraph::clear() -{ - while (numberOfNodes()) - { - delNode( HyperGraphTypes::NodeList::front(this) ); - } - - while (numberOfEdges()) - { - delEdge( HyperGraphTypes::EdgeList::front(this) ); - } -} - - - -template -static void writeToStream(std::ostream& outStream, ArrayType& array) -{ - for (typename ListType::iterator it = ListType::begin(array.graph()); it.valid(); it++) - { - outStream << array[*it] << std::endl; - } -} - - -template -static void readFromStream(std::istream& inStream, ArrayType& array) -{ - for (typename ListType::iterator it = ListType::begin(array.graph());it.valid(); it++) - { - inStream >> array[(*it)]; - } -} - -template -static std::ostream& operator<<(std::ostream& outStream, HyperGraph::NodeArray& array) -{ - writeToStream >(outStream, array); - return outStream; -} - -template -static std::ostream& operator<<(std::ostream& outStream, HyperGraph::EdgeArray& array) -{ - writeToStream >(outStream, array); - return outStream; -} - -template -static std::ostream& operator<<(std::ostream& outStream, HyperGraph::AdjArray& array) -{ - for (HyperGraphTypes::EdgeList::iterator it = HyperGraphTypes::EdgeList::begin(array.graph());it.valid(); it++) - { - HyperGraph::edge e = *it; - for (HyperGraphTypes::EdgeAdjList::iterator adj_it = HyperGraphTypes::EdgeAdjList::begin(e); adj_it.valid(); adj_it++) - { - outStream << array[(*adj_it)] << std::endl; - } - } - return outStream; -} - - -template -static std::istream& operator>>(std::istream& inStream, HyperGraph::NodeArray& array) -{ - readFromStream >(inStream, array); - return inStream; -} - - -template -static std::istream& operator>>(std::istream& inStream, HyperGraph::EdgeArray& array) -{ - readFromStream >(inStream, array); - return inStream; -} - - -template -static std::istream& operator>>(std::istream& inStream, HyperGraph::AdjArray& array) -{ - for (HyperGraphTypes::EdgeList::iterator it = HyperGraphTypes::EdgeList::begin(array.graph());it.valid(); it++) - { - HyperGraph::edge e = *it; - for (HyperGraphTypes::EdgeAdjList::iterator adj_it = HyperGraphTypes::EdgeAdjList::begin(e); adj_it.valid(); adj_it++) - { - inStream >> array[(*adj_it)]; - } - } - return inStream; -} - - -static std::ostream& operator<<(std::ostream& outStream, HyperGraph& graph) -{ - outStream << graph.numberOfNodes() << std::endl; - outStream << graph.numberOfEdges() << std::endl; - - HyperGraph::NodeArray packed_index(&graph); - - int i=0; - for (HyperGraphTypes::NodeList::iterator it = HyperGraphTypes::NodeList::begin(&graph);it.valid(); it++) - { - packed_index[*it] = i++; - } - - for (HyperGraphTypes::EdgeList::iterator it = HyperGraphTypes::EdgeList::begin(&graph);it.valid(); it++) - { - HyperGraph::edge e = *it; - outStream << e->cardinality() << std::endl; - for (HyperGraphTypes::EdgeAdjList::iterator adj_it = HyperGraphTypes::EdgeAdjList::begin(e); adj_it.valid(); adj_it++) - { - outStream << packed_index[(*adj_it)->theNode()] << std::endl; - } - } - return outStream; -} - - -static std::istream& operator>>(std::istream& inStream, HyperGraph& graph) -{ - int numNodes; - int numEdges; - inStream >> numNodes; - inStream >> numEdges; - - HyperGraph::node* pNodes = new HyperGraph::node[numNodes]; - for (int i=0; i> numAdj; - for (int j=0; j> packedNodeIndex; - graph.addNode(pNodes[packedNodeIndex], e); - } - } - return inStream; -} - -} // end of namespace ogdf - -#endif /* HYPERGRAPH_H_ */ diff --git a/ext/OGDF/ogdf/basic/IncNodeInserter.h b/ext/OGDF/ogdf/basic/IncNodeInserter.h deleted file mode 100644 index c4faea636..000000000 --- a/ext/OGDF/ogdf/basic/IncNodeInserter.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class IncNodeInserter. - * - * This class represents the base class for strategies - * for the incremental drawing approach to insert nodes - * (having no layout fixation) into the fixed part of - * a PlanRep. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_INCNODEINSERTER_H -#define OGDF_INCNODEINSERTER_H - - -#include -#include -#include -#include - -namespace ogdf { - - -//=============================================== -//main function(s): -// -// insertcopyNode insert a node into a face -// -//=============================================== - - -class OGDF_EXPORT IncNodeInserter -{ -public: - //creates inserter on PG - IncNodeInserter(PlanRepInc &PG) : m_planRep(&PG ) { } - - //insert copy in m_planRep for original node v - virtual void insertCopyNode(node v, CombinatorialEmbedding &E, - Graph::NodeType vTyp) = 0; - -protected: - //returns a face to insert a copy of v and a list of - //adjacency entries corresponding to the insertion adjEntries - //for the adjacent edges - virtual face getInsertionFace(node v, CombinatorialEmbedding &E) = 0; - - PlanRepInc* m_planRep; //the PlanRep that is changed -}; //incnodeinserter - -} //end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/Layout.h b/ext/OGDF/ogdf/basic/Layout.h deleted file mode 100644 index 69698c5ad..000000000 --- a/ext/OGDF/ogdf/basic/Layout.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Layout - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LAYOUT_H -#define OGDF_LAYOUT_H - - -#include - - -namespace ogdf { - - class GraphCopy; - class PlanRep; - - -/** - * \brief Stores a layout of a graph (coordinates of nodes, bend - * points of edges). - * - */ -class OGDF_EXPORT Layout -{ -public: - /** @{ - * \brief Creates a layout associated with no graph. - */ - Layout() { } - - /** - * \brief Creates a layout associated with graph \a G. - * - * The layout is initialized such that all node positions are (0,0) - * and all bend point lists of edges are empty. - * - * @param G is the corresponding graph . - */ - Layout(const Graph &G) : m_x(G,0), m_y(G,0), m_bends(G) { } - - // destruction - ~Layout() { } - - - /** @} @{ - * \brief Returns a reference to the array storing x-coordinates of nodes. - */ - const NodeArray &x() const { return m_x; } - - /** - * \brief Returns a reference to the array storing x-coordinates of nodes. - */ - NodeArray &x() { return m_x; } - - /** @} @{ - * \brief Returns a reference to the array storing y-coordinates of nodes. - */ - const NodeArray &y() const { return m_y; } - - /** - * \brief Returns a reference to the array storing y-coordinates of nodes. - */ - NodeArray &y() { return m_y; } - - - /** @} @{ - * \brief Returns the x-coordinate of node \a v. - */ - const double &x(node v) const { return m_x[v]; } - - /** - * \brief Returns the x-coordinate of node \a v. - */ - double &x(node v) { return m_x[v]; } - - /** @} @{ - * \brief Returns the y-coordinate of node \a v. - */ - const double &y(node v) const { return m_y[v]; } - - /** - * \brief Returns the y-coordinate of node \a v. - */ - double &y(node v) { return m_y[v]; } - - /** @} @{ - * \brief Returns the bend point list of edge \a e. - */ - const DPolyline &bends(edge e) const { return m_bends[e]; } - - /** - * \brief Returns the bend point list of edge \a e. - */ - DPolyline &bends(edge e) { return m_bends[e]; } - - - /** @} @{ - * \brief Returns the polyline of edge \a eOrig in \a dpl. - * - * @param GC is the input graph copy; \a GC must also be the associated graph. - * @param eOrig is an edge in the original graph of \a GC. - * @param dpl is assigned the poyline of \a eOrig. - */ - void computePolyline(GraphCopy &GC, edge eOrig, DPolyline &dpl) const; - - /** - * \brief Returns the polyline of edge \a eOrig in \a dpl and clears the - * bend points of the copies. - * - * The bend point lists of all edges in the edge path corresponding to \a eOrig are - * empty afterwards! This is a faster version of computePolyline(). - * - * @param PG is the input graph copy; \a PG must also be the associated graph. - * of this layout. - * @param eOrig is an edge in the original graph of \a GC. - * @param dpl is assigned the poyline of \a eOrig. - */ - void computePolylineClear(PlanRep &PG, edge eOrig, DPolyline &dpl); - - /** @} */ - -private: - NodeArray m_x; //!< The x-coordinates of nodes. - NodeArray m_y; //!< The y-coordinates of nodes. - EdgeArray m_bends; //!< The bend points of edges. - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/List.h b/ext/OGDF/ogdf/basic/List.h deleted file mode 100644 index e92021826..000000000 --- a/ext/OGDF/ogdf/basic/List.h +++ /dev/null @@ -1,1631 +0,0 @@ -/* - * $Revision: 2632 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-17 21:04:24 +0200 (Di, 17. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of doubly linked lists and iterators - * - * \author Carsten Gutwenger and Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LIST_H -#define OGDF_LIST_H - - -#include - - -namespace ogdf { - - -template class List; -template class ListPure; -template class ListIterator; -template class ListConstIterator; - - -//! The parameterized class \a ListElement represents the structure for elements of doubly linked lists. -template -class ListElement { - friend class ListPure; - friend class List; - friend class ListIterator; - friend class ListConstIterator; - - ListElement *m_next; //!< Pointer to successor element. - ListElement *m_prev; //!< Pointer to predecessor element. - E m_x; //!< Stores the content. - - //! Constructs a ListElement. - ListElement() : m_next(0), m_prev(0) { } - //! Constructs a ListElement. - ListElement(const E &x) : m_next(0), m_prev(0), m_x(x) { } - //! Constructs a ListElement. - ListElement(const E &x, ListElement *next, ListElement *prev) : - m_next(next), m_prev(prev), m_x(x) { } - - OGDF_NEW_DELETE -}; // class ListElement - - - -//! The parameterized class \a ListIterator encapsulates a pointer to a dlist element. -/** - * It is used in order to iterate over doubly linked lists, - * and to specify a position in a doubly linked list. It is possible that - * an iterator encapsulates a null pointer. - */ - -template class ListIterator { - ListElement *m_pX; // pointer to associated list element - - friend class ListConstIterator; - friend class ListPure; - - //! Conversion to pointer to list element. - operator ListElement *() { return m_pX; } - //! Conversion to pointer to list element. - operator const ListElement *() const { return m_pX; } - -public: - //! Constructs an iterator pointing to no element. - ListIterator() : m_pX(0) { } - //! Constructs an iterator pointing to \a pX. - ListIterator(ListElement *pX) : m_pX(pX) { } - //! Constructs an iterator that is a copy of \a it. - ListIterator(const ListIterator &it) : m_pX(it.m_pX) { } - - //! Returns true iff the iterator points to an element. - bool valid() const { return m_pX != 0; } - - //! Equality operator. - bool operator==(const ListIterator &it) const { - return m_pX == it.m_pX; - } - - //! Inequality operator. - bool operator!=(const ListIterator &it) const { - return m_pX != it.m_pX; - } - - //! Returns successor iterator. - ListIterator succ() const { return m_pX->m_next; } - - //! Returns predecessor iterator. - ListIterator pred() const { return m_pX->m_prev; } - - //! Returns a reference to the element content. - E &operator*() const { return m_pX->m_x; } - - //! Assignment operator. - ListIterator &operator=(const ListIterator &it) { - m_pX = it.m_pX; - return *this; - } - - //! Increment operator (prefix). - ListIterator &operator++() { - m_pX = m_pX->m_next; - return *this; - } - - //! Increment operator (postfix). - ListIterator operator++(int) { - ListIterator it = *this; - m_pX = m_pX->m_next; - return it; - } - - //! Decrement operator (prefix). - ListIterator &operator--() { - m_pX = m_pX->m_prev; - return *this; - } - - //! Decrement operator (postfix). - ListIterator operator--(int) { - ListIterator it = *this; - m_pX = m_pX->m_prev; - return it; - } - - OGDF_NEW_DELETE -}; // class ListIterator - - - -//--------------------------------------------------------- -// ListConstIterator -// const iterator for doubly linked lists -//--------------------------------------------------------- -//! The parameterized class \a ListIterator encapsulates a constant pointer to a list element. -/** - * It is used in order to iterate over doubly linked lists, - * and to specify a position in a doubly linked list. It is possible that - * an iterator encapsulates a null pointer. In contrast to ListIterator, - * it is not possible to change the list element pointed to. - */ - -template class ListConstIterator { - const ListElement *m_pX; // pointer to list element - - friend class ListPure; - - //! Conversion to pointer to list element. - operator const ListElement *() { return m_pX; } - -public: - //! Constructs an iterator pointing to no element. - ListConstIterator() : m_pX(0) { } - - //! Constructs an iterator pointing to \a pX. - ListConstIterator(const ListElement *pX) : m_pX(pX) { } - - //! Constructs an iterator that is a copy of \a it. - ListConstIterator(const ListIterator &it) : m_pX((const ListElement *)it) { } - //! Constructs an iterator that is a copy of \a it. - ListConstIterator(const ListConstIterator &it) : m_pX(it.m_pX) { } - - //! Returns true iff the iterator points to an element. - bool valid() const { return m_pX != 0; } - - //! Equality operator. - bool operator==(const ListConstIterator &it) const { - return m_pX == it.m_pX; - } - - //! Inequality operator. - bool operator!=(const ListConstIterator &it) const { - return m_pX != it.m_pX; - } - - //! Returns successor iterator. - ListConstIterator succ() const { return m_pX->m_next; } - - //! Returns predecessor iterator. - ListConstIterator pred() const { return m_pX->m_prev; } - - //! Returns a reference to the element content. - const E &operator*() const { return m_pX->m_x; } - - //! Assignment operator. - ListConstIterator &operator=(const ListConstIterator &it) { - m_pX = it.m_pX; - return *this; - } - - //! Increment operator (prefix). - ListConstIterator &operator++() { - m_pX = m_pX->m_next; - return *this; - } - - //! Increment operator (postfix). - ListConstIterator operator++(int) { - ListConstIterator it = *this; - m_pX = m_pX->m_next; - return it; - } - - //! Decrement operator (prefix). - ListConstIterator &operator--() { - m_pX = m_pX->m_prev; - return *this; - } - - //! Decrement operator (postfix). - ListConstIterator operator--(int) { - ListConstIterator it = *this; - m_pX = m_pX->m_prev; - return it; - } - - OGDF_NEW_DELETE -}; // class ListConstIterator - - - -//! The parameterized class \a ListPure represents doubly linked lists with content type \a E. -/** - * Elements of the list are instances of type ListElement. - * Use ListConstIterator or ListIterator in order to iterate over the list. - * - * In contrast to List, instances of \a ListPure do not store the length of the list. - * - * @tparam E is the data type stored in list elements. - */ - -template class ListPure { -protected: - - ListElement *m_head; //!< Pointer to first element. - ListElement *m_tail; //!< Pointer to last element. - -public: - //! Constructs an empty doubly linked list. - ListPure() : m_head(0), m_tail(0) { } - - //! Constructs a doubly linked list that is a copy of \a L. - ListPure(const ListPure &L) : m_head(0), m_tail(0) { - copy(L); - } - - // destruction - ~ListPure() { clear(); } - - typedef E value_type; - typedef ListElement element_type; - typedef ListConstIterator const_iterator; - typedef ListIterator iterator; - - //! Returns true iff the list is empty. - bool empty() const { return m_head == 0; } - - //! Returns the length of the list - /** - * Notice that this method requires to run through the whole list and takes linear running time! - */ - int size() const { - int count = 0; - for (ListElement *pX = m_head; pX; pX = pX->m_next) - ++count; - return count; - } - - //! Returns an iterator to the first element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - const ListConstIterator begin() const { return m_head; } - //! Returns an iterator to the first element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - ListIterator begin() { return m_head; } - - //! Returns an iterator to one-past-last element of the list. - /** - * This is always a null pointer iterator. - */ - ListConstIterator end() const { return ListConstIterator(); } - //! Returns an iterator to one-past-last element of the list. - /** - * This is always a null pointer iterator. - */ - ListIterator end() { return ListIterator(); } - - //! Returns an iterator to the last element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - const ListConstIterator rbegin() const { return m_tail; } - //! Returns an iterator to the last element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - ListIterator rbegin() { return m_tail; } - - //! Returns an iterator to one-before-first element of the list. - /** - * This is always a null pointer iterator. - */ - ListConstIterator rend() const { return ListConstIterator(); } - //! Returns an iterator to one-before-first element of the list. - /** - * This is always a null pointer iterator. - */ - ListIterator rend() { return ListIterator(); } - - //! Returns a reference to the first element. - /** - * \pre The list is not empty! - */ - const E &front() const { - OGDF_ASSERT(m_head != 0) - return m_head->m_x; - } - - //! Returns a reference to the first element. - /** - * \pre The list is not empty! - */ - E &front() { - OGDF_ASSERT(m_head != 0) - return m_head->m_x; - } - - //! Returns a reference to the last element. - /** - * \pre The list is not empty! - */ - const E &back() const { - OGDF_ASSERT(m_tail != 0) - return m_tail->m_x; - } - - //! Returns a reference to the last element. - /** - * \pre The list is not empty! - */ - E &back() { - OGDF_ASSERT(m_tail != 0) - return m_tail->m_x; - } - - //! Returns an iterator to the cyclic successor of \a it. - /** - * \pre \a it points to an element in this list! - */ - ListConstIterator cyclicSucc(ListConstIterator it) const { - const ListElement *pX = it; - return (pX->m_next) ? pX->m_next : m_head; - } - - //! Returns an iterator to the cyclic successor of \a it. - /** - * \pre \a it points to an element in this list! - */ - ListIterator cyclicSucc(ListIterator it) { - OGDF_ASSERT(it.valid()) - ListElement *pX = it; - return (pX->m_next) ? pX->m_next : m_head; - } - - //! Returns an iterator to the cyclic predecessor of \a it. - /** - * \pre \a it points to an element in this list! - */ - ListConstIterator cyclicPred(ListConstIterator it) const { - OGDF_ASSERT(it.valid()) - const ListElement *pX = it; - return (pX->m_prev) ? pX->m_prev : m_tail; - } - - //! Returns an iterator to the cyclic predecessor of \a it. - /** - * \pre \a it points to an element in this list! - */ - ListIterator cyclicPred(ListIterator it) { - OGDF_ASSERT(it.valid()) - ListElement *pX = it; - return (pX->m_prev) ? pX->m_prev : m_tail; - } - - //! Returns an iterator pointing to the element at position \a pos. - /** - * The running time of this method is linear in \a pos. - */ - ListConstIterator get(int pos) const { - ListElement *pX; - for(pX = m_head; pX != 0; pX = pX->m_next) - if (pos-- == 0) break; - return pX; - } - - //! Returns an iterator pointing to the element at position \a pos. - /** - * The running time of this method is linear in \a pos. - */ - ListIterator get(int pos) { - ListElement *pX; - for(pX = m_head; pX != 0; pX = pX->m_next) - if (pos-- == 0) break; - return pX; - } - - //! Returns the position (starting with 0) of iterator \a it in the list. - /** - * \pre \a it is a valid iterator pointing to an element in this list! - */ - int pos(ListConstIterator it) const { - OGDF_ASSERT(it.valid()) - int p = 0; - for(ListElement *pX = m_head; pX != 0; pX = pX->m_next, ++p) - if (pX == it) break; - return p; - } - - //! Returns an iterator to a random element in the list (or an invalid iterator if the list is empty) - /** - * This method takes linear time. - */ - ListConstIterator chooseIterator() const { - return empty() ? ListConstIterator() : get(randomNumber(0,size()-1)); - } - - //! Returns an iterator to a random element in the list (or an invalid iterator if the list is empty) - /** - * This method takes linear time. - */ - ListIterator chooseIterator() { - return empty() ? ListIterator() : get(randomNumber(0,size()-1)); - } - - //! Returns a random element from the list. - /** - * \pre The list is not empty! - * - * This method takes linear time. - */ - const E chooseElement() const { - OGDF_ASSERT(m_head != 0) - return *chooseIterator(); - } - - //! Returns a random element from the list. - /** - * \pre The list is not empty! - * - * This method takes linear time. - */ - E chooseElement() { - return *chooseIterator(); - } - - //! Assignment operator. - ListPure &operator=(const ListPure &L) { - clear(); copy(L); - return *this; - } - - //! Equality operator. - bool operator==(const ListPure &L) const { - ListElement *pX = m_head, *pY = L.m_head; - while(pX != 0 && pY != 0) { - if(pX->m_x != pY->m_x) - return false; - pX = pX->m_next; - pY = pY->m_next; - } - return (pX == 0 && pY == 0); - } - - //! Inequality operator. - bool operator!=(const ListPure &L) const { - return !operator==(L); - } - - //! Adds element \a x at the begin of the list. - ListIterator pushFront(const E &x) { - ListElement *pX = OGDF_NEW ListElement(x,m_head,0); - if (m_head) - m_head = m_head->m_prev = pX; - else - m_head = m_tail = pX; - return m_head; - } - - //! Adds element \a x at the end of the list. - ListIterator pushBack(const E &x) { - ListElement *pX = OGDF_NEW ListElement(x,0,m_tail); - if (m_head) - m_tail = m_tail->m_next = pX; - else - m_tail = m_head = pX; - return m_tail; - } - - //! Inserts element \a x before or after \a it. - /** - * @param x is the element to be inserted. - * @param it is a list iterator in this list. - * @param dir determines if \a x is inserted before or after \a it. - * Possible values are \c ogdf::before and \c ogdf::after. - * \pre \a it points to an element in this list. - */ - ListIterator insert(const E &x, ListIterator it, Direction dir = after) { - OGDF_ASSERT(it.valid()) - OGDF_ASSERT(dir == after || dir == before) - ListElement *pY = it, *pX; - if (dir == after) { - ListElement *pYnext = pY->m_next; - pY->m_next = pX = OGDF_NEW ListElement(x,pYnext,pY); - if (pYnext) pYnext->m_prev = pX; - else m_tail = pX; - } else { - ListElement *pYprev = pY->m_prev; - pY->m_prev = pX = OGDF_NEW ListElement(x,pY,pYprev); - if (pYprev) pYprev->m_next = pX; - else m_head = pX; - } - return pX; - } - - //! Inserts element \a x before \a it. - /** - * \pre \a it points to an element in this list. - */ - ListIterator insertBefore(const E &x, ListIterator it) { - OGDF_ASSERT(it.valid()) - ListElement *pY = it, *pX; - ListElement *pYprev = pY->m_prev; - pY->m_prev = pX = OGDF_NEW ListElement(x,pY,pYprev); - if (pYprev) pYprev->m_next = pX; - else m_head = pX; - return pX; - } - - //! Inserts element \a x after \a it. - /** - * \pre \a it points to an element in this list. - */ - ListIterator insertAfter(const E &x, ListIterator it) { - OGDF_ASSERT(it.valid()) - ListElement *pY = it, *pX; - ListElement *pYnext = pY->m_next; - pY->m_next = pX = OGDF_NEW ListElement(x,pYnext,pY); - if (pYnext) pYnext->m_prev = pX; - else m_tail = pX; - return pX; - } - - //! Removes the first element from the list. - /** - * \pre The list is not empty! - */ - void popFront() { - OGDF_ASSERT(m_head != 0) - ListElement *pX = m_head; - m_head = m_head->m_next; - delete pX; - if (m_head) m_head->m_prev = 0; - else m_tail = 0; - } - - //! Removes the first element from the list and returns it. - /** - * \pre The list is not empty! - */ - E popFrontRet() { - E el = front(); - popFront(); - return el; - } - - //! Removes the last element from the list. - /** - * \pre The list is not empty! - */ - void popBack() { - OGDF_ASSERT(m_tail != 0) - ListElement *pX = m_tail; - m_tail = m_tail->m_prev; - delete pX; - if (m_tail) m_tail->m_next = 0; - else m_head = 0; - } - - //! Removes the last element from the list and returns it. - /** - * \pre The list is not empty! - */ - E popBackRet() { - E el = back(); - popBack(); - return el; - } - - //! Removes \a it from the list. - /** - * \pre \a it points to an element in this list. - */ - void del(ListIterator it) { - OGDF_ASSERT(it.valid()) - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - delete pX; - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - } - - //! Exchanges the positions of \a it1 and \a it2 in the list. - /** - * \pre \a it1 and \a it2 point to elements in this list. - */ - void exchange(ListIterator it1, ListIterator it2) { - OGDF_ASSERT(it1.valid() && it2.valid() && it1 != it2) - ListElement *pX = it1, *pY = it2; - - std::swap(pX->m_next,pY->m_next); - std::swap(pX->m_prev,pY->m_prev); - - if(pX->m_next == pX) { - pX->m_next = pY; pY->m_prev = pX; - } - if(pX->m_prev == pX) { - pX->m_prev = pY; pY->m_next = pX; - } - - if(pX->m_prev) pX->m_prev->m_next = pX; - else m_head = pX; - - if(pY->m_prev) pY->m_prev->m_next = pY; - else m_head = pY; - - if(pX->m_next) pX->m_next->m_prev = pX; - else m_tail = pX; - - if(pY->m_next) pY->m_next->m_prev = pY; - else m_tail = pY; - } - - //! Moves \a it to the begin of the list. - /** - * \pre \a it points to an element in this list. - */ - void moveToFront(ListIterator it) { - OGDF_ASSERT(it.valid()) - // remove it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - //already at front - if (!pPrev) return; - - //update old position - if (pPrev) pPrev->m_next = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // insert it at front - pX->m_prev = 0; - pX->m_next = m_head; - m_head = m_head->m_prev = pX; - }//move - - //! Moves \a it to the end of the list. - /** - * \pre \a it points to an element in this list. - */ - void moveToBack(ListIterator it) { - OGDF_ASSERT(it.valid()) - // remove it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - //already at back - if (!pNext) return; - - //update old position - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - // insert it at back - pX->m_prev = m_tail; - pX->m_next = 0; - m_tail = m_tail->m_next = pX; - }//move - - //! Moves \a it after \a itBefore. - /** - * \pre \a it and \a itBefore point to elements in this list. - */ - void moveToSucc(ListIterator it, ListIterator itBefore) { - OGDF_ASSERT(it.valid() && itBefore.valid()) - // move it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - //the same of already in place - ListElement *pY = itBefore; - if(pX == pY || pPrev == pY) return; - - // update old position - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // move it after itBefore - ListElement *pYnext = pX->m_next = pY->m_next; - (pX->m_prev = pY)->m_next = pX; - if (pYnext) pYnext->m_prev = pX; - else m_tail = pX; - }//move - - //! Moves \a it before \a itAfter. - /** - * \pre \a it and \a itAfter point to elements in this list. - */ - void moveToPrec(ListIterator it, ListIterator itAfter) { - OGDF_ASSERT(it.valid() && itAfter.valid()) - // move it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - //the same of already in place - ListElement *pY = itAfter; - if(pX == pY || pNext == pY) return; - - // update old position - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // move it before itAfter - ListElement *pYprev = pX->m_prev = pY->m_prev; - (pX->m_next = pY)->m_prev = pX; - if (pYprev) pYprev->m_next = pX; - else m_head = pX; - }//move - - //! Moves \a it to the begin of \a L2. - /** - * \pre \a it points to an element in this list. - */ - void moveToFront(ListIterator it, ListPure &L2) { - OGDF_ASSERT(it.valid()) - OGDF_ASSERT(this != &L2) - // remove it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // insert it at front of L2 - pX->m_prev = 0; - if ((pX->m_next = L2.m_head) != 0) - L2.m_head = L2.m_head->m_prev = pX; - else - L2.m_head = L2.m_tail = pX; - } - - //! Moves \a it to the end of \a L2. - /** - * \pre \a it points to an element in this list. - */ - void moveToBack(ListIterator it, ListPure &L2) { - OGDF_ASSERT(it.valid()) - OGDF_ASSERT(this != &L2) - // remove it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // insert it at back of L2 - pX->m_next = 0; - if ((pX->m_prev = L2.m_tail) != 0) - L2.m_tail = L2.m_tail->m_next = pX; - else - L2.m_head = L2.m_tail = pX; - } - - //! Moves \a it to list \a L2 and inserts it after \a itBefore. - /** - * \pre \a it points to an element in this list, and \a itBefore - * points to an element in \a L2. - */ - void moveToSucc(ListIterator it, ListPure &L2, ListIterator itBefore) { - OGDF_ASSERT(it.valid() && itBefore.valid()) - OGDF_ASSERT(this != &L2) - // remove it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // insert it in list L2 after itBefore - ListElement *pY = itBefore; - ListElement *pYnext = pX->m_next = pY->m_next; - (pX->m_prev = pY)->m_next = pX; - if (pYnext) pYnext->m_prev = pX; - else L2.m_tail = pX; - } - - //! Moves \a it to list \a L2 and inserts it before \a itAfter. - /** - * \pre \a it points to an element in this list, and \a itAfter - * points to an element in \a L2. - */ - void moveToPrec(ListIterator it, ListPure &L2, ListIterator itAfter) { - OGDF_ASSERT(it.valid() && itAfter.valid()) - OGDF_ASSERT(this != &L2) - // remove it - ListElement *pX = it, *pPrev = pX->m_prev, *pNext = pX->m_next; - if (pPrev) pPrev->m_next = pNext; - else m_head = pNext; - if (pNext) pNext->m_prev = pPrev; - else m_tail = pPrev; - // insert it in list L2 after itBefore - ListElement *pY = itAfter; - ListElement *pYprev = pX->m_prev = pY->m_prev; - (pX->m_next = pY)->m_prev = pX; - if (pYprev) pYprev->m_next = pX; - else L2.m_head = pX; - } - - //! Appends \a L2 to this list and makes \a L2 empty. - void conc(ListPure &L2) { - OGDF_ASSERT(this != &L2) - if (m_head) - m_tail->m_next = L2.m_head; - else - m_head = L2.m_head; - if (L2.m_head) { - L2.m_head->m_prev = m_tail; - m_tail = L2.m_tail; - } - L2.m_head = L2.m_tail = 0; - } - - //! Prepends \a L2 to this list and makes \a L2 empty. - void concFront(ListPure &L2) { - OGDF_ASSERT(this != &L2) - if (m_head) - m_head->m_prev = L2.m_tail; - else - m_tail = L2.m_tail; - if (L2.m_head) { - L2.m_tail->m_next = m_head; - m_head = L2.m_head; - } - L2.m_head = L2.m_tail = 0; - } - - //! Exchanges too complete lists in O(1). - /** - * The list's content is moved to L2 and vice versa. - */ - void exchange(ListPure& L2) { - ListElement* t; - t = this->m_head; - this->m_head = L2.m_head; - L2.m_head = t; - t = this->m_tail; - this->m_tail = L2.m_tail; - L2.m_tail = t; - } - - //! Splits the list at element \a it into lists \a L1 and \a L2. - /** - * If \a it is not a null pointer and \a L = x1,...,x{k-1}, \a it,x_{k+1},xn, then - * \a L1 = x1,...,x{k-1} and \a L2 = \a it,x{k+1},...,xn if \a dir = \c before. - * If \a it is a null pointer, then \a L1 is made empty and \a L2 = \a L. Finally - * \a L is made empty if it is not identical to \a L1 or \a L2. - * - * \pre \a it points to an element in this list. - */ - - void split(ListIterator it,ListPure &L1,ListPure &L2,Direction dir = before) { - if (&L1 != this) L1.clear(); - if (&L2 != this) L2.clear(); - - if (it.valid()){ - L1.m_head = m_head; - L2.m_tail = m_tail; - if (dir == before){ - L2.m_head = it; - L1.m_tail = L2.m_head->m_prev; - } - else { - L1.m_tail = it; - L2.m_head = L1.m_tail->m_next; - } - L2.m_head->m_prev = L1.m_tail->m_next = 0; - - } else { - L1.m_head = L1.m_tail = 0; - L2.m_head = m_head; - L2.m_tail = m_tail; - } - - if (this != &L1 && this != &L2) { - m_head = m_tail = 0; - } - } - - //! Splits the list after \a it. - void splitAfter(ListIterator it, ListPure &L2) { - OGDF_ASSERT(it.valid()) - OGDF_ASSERT(this != &L2) - L2.clear(); - ListElement *pX = it; - if (pX != m_tail) { - (L2.m_head = pX->m_next)->m_prev = 0; - pX->m_next = 0; - L2.m_tail = m_tail; - m_tail = pX; - } - } - - //! Splits the list before \a it. - void splitBefore(ListIterator it, ListPure &L2) { - OGDF_ASSERT(it.valid()) - OGDF_ASSERT(this != &L2) - L2.clear(); - ListElement *pX = it; - L2.m_head = pX; L2.m_tail = m_tail; - if ((m_tail = pX->m_prev) == 0) - m_head = 0; - else - m_tail->m_next = 0; - pX->m_prev = 0; - } - - //! Reverses the order of the list elements. - void reverse() { - ListElement *pX = m_head; - m_head = m_tail; - m_tail = pX; - while(pX) { - ListElement *pY = pX->m_next; - pX->m_next = pX->m_prev; - pX = pX->m_prev = pY; - } - } - - //! Removes all elements from the list. - void clear() { - if (m_head == 0) return; - -#if (_MSC_VER == 1100) -// workaround for bug in Visual Studio 5.0 - - while (!empty()) - popFront(); - -#else - - if (doDestruction((E*)0)) { - for(ListElement *pX = m_head; pX != 0; pX = pX->m_next) - pX->m_x.~E(); - } - OGDF_ALLOCATOR::deallocateList(sizeof(ListElement),m_head,m_tail); - -#endif - - m_head = m_tail = 0; - } - - //! Sorts the list using Quicksort. - void quicksort() { - ogdf::quicksortTemplate(*this); - } - - //! Sorts the list using Quicksort and comparer \a comp. - template - void quicksort(const COMPARER &comp) { - ogdf::quicksortTemplate(*this,comp); - } - - //! Sorts the list using bucket sort. - /** - * @param l is the lowest bucket that will occur. - * @param h is the highest bucket that will occur. - * @param f returns the bucket for each element. - * \pre The bucket function \a f will only return bucket values between \a l - * and \a h for this list. - */ - void bucketSort(int l, int h, BucketFunc &f); - - //! Randomly permutes the elements in the list. - void permute() { - permute(size()); - } - - //! Scans the list for the specified element and returns its position in the list, or -1 if not found. - int search (const E& e) const { - int x = 0; - for(ListConstIterator i = begin(); i.valid(); ++i, ++x) - if(*i == e) return x; - return -1; - } - - //! Scans the list for the specified element (using the user-defined comparer) and returns its position in the list, or -1 if not found. - template - int search (const E& e, const COMPARER &comp) const { - int x = 0; - for(ListConstIterator i = begin(); i.valid(); ++i, ++x) - if(comp.equal(*i,e)) return x; - return -1; - } - -protected: - void copy(const ListPure &L) { - for(ListElement *pX = L.m_head; pX != 0; pX = pX->m_next) - pushBack(pX->m_x); - } - - void permute(const int n); - - OGDF_NEW_DELETE -}; // class ListPure - - - -//! Iteration over all iterators \a it of a list \a L, where L is of Type \c List<\a type>. -/** - * Automagically creates a \c ListConstIterator<\a type> named \a it, and runs through the List \a L. - * - *

    Example

    - * - * The following code runs through the list \a L, and prints each item - * \code - * List L; - * ... - * forall_listiterators(double, it, L) { - * cout << *it << endl; - * } - * \endcode - * - * Note that this code is equivalent to the following tedious long version - * - * \code - * List L; - * ... - * for( ListConstIterator it = L.begin(); it.valid(); ++it) { - * cout << *it << endl; - * } - * \endcode - */ -#define forall_listiterators(type, it, L) \ - for(ListConstIterator< type > it = (L).begin(); it.valid(); ++it) - -//! Iteration over all iterators \a it of a list \a L, where L is of Type \c List<\a type>, in reverse order. -/** - * Automagically creates a \c ListConstIterator<\a type> named \a it, and runs through the List \a L, in reverse order. - * See \c #forall_listiterators for an example. - */ -#define forall_rev_listiterators(type, it, L) \ - for(ListConstIterator< type > it = (L).rbegin(); it.valid(); --it) - -//! Iteration over all non-const iterators \a it of a list \a L, where L is of Type \c List<\a type>. -/** - * Automagically creates a \c ListIterator<\a type> named \a it, and runs through the List \a L. - * See \c #forall_listiterators for an example. - */ -#define forall_nonconst_listiterators(type, it, L) \ - for(ListIterator< type > it = (L).begin(); it.valid(); ++it) - -//! Iteration over all non-const iterators \a it of a list \a L, where L is of Type \c List<\a type>, in reverse order. -/** - * Automagically creates a \c ListIterator<\a type> named \a it, and runs through the List \a L, in reverse order. - * See \c #forall_listiterators for an example. - */ -#define forall_rev_nonconst_listiterators(type, it, L) \ - for(ListIterator< type > it = (L).rbegin(); it.valid(); --it) - -//! Iteration over all iterators \a it of a list \a L, where L is of Type \c SList<\a type>. -/** - * Automagically creates a \c SListConstIterator<\a type> named \a it, and runs through the SList \a L. - * See \c #forall_listiterators for an example. - */ -#define forall_slistiterators(type, it, L) \ - for(SListConstIterator< type > it = (L).begin(); it.valid(); ++it) - -//! Iteration over all non-const iterators \a it of a list \a L, where L is of Type \c SList<\a type>. -/** - * Automagically creates a \c SListIterator<\a type> named \a it, and runs through the SList \a L. - * See \c #forall_listiterators for an example. - */ -#define forall_nonconst_slistiterators(type, it, L) \ - for(SListIterator< type > it = (L).begin(); it.valid(); ++it) - - - - -//! The parameterized class \a ListPure represents doubly linked lists with content type \a E. -/** - * Elements of the list are instances of type ListElement. - * Use ListConstIterator or ListIterator in order to iterate over the list. - * - * In contrast to ListPure, instances of \a List store the length of the list. - * - * See the \c #forall_listiterators macros for the recommended way how to easily iterate through a - * list. - * - * @tparam E is the data type stored in list elements. - */ -template -class List : private ListPure { - - int m_count; //!< The length of the list. - -public: - //! Constructs an empty doubly linked list. - List() : m_count(0) { } - - //! Constructs a doubly linked list that is a copy of \a L. - List(const List &L) : ListPure(L), m_count(L.m_count) { } - - // destruction - ~List() { } - - typedef E value_type; - typedef ListElement element_type; - typedef ListConstIterator const_iterator; - typedef ListIterator iterator; - - //! Returns true iff the list is empty. - bool empty() const { return ListPure::empty(); } - - // returns length of list - int size() const { return m_count; } - - // returns first element of list (0 if empty) - const ListConstIterator begin() const { return ListPure::begin(); } - // returns first element of list (0 if empty) - ListIterator begin() { return ListPure::begin(); } - - // returns iterator to one-past-last element of list - ListConstIterator end() const { return ListConstIterator(); } - // returns iterator to one-past-last element of list - ListIterator end() { return ListIterator(); } - - // returns last element of list (0 if empty) - const ListConstIterator rbegin() const { return ListPure::rbegin(); } - // returns last element of list (0 if empty) - ListIterator rbegin() { return ListPure::rbegin(); } - - // returns iterator to one-before-first element of list - ListConstIterator rend() const { return ListConstIterator(); } - // returns iterator to one-before-first element of list - ListIterator rend() { return ListIterator(); } - - // returns reference to first element - const E &front() const { return ListPure::front(); } - // returns reference to first element - E &front() { return ListPure::front(); } - - // returns reference to last element - const E &back() const { return ListPure::back(); } - // returns reference to last element - E &back() { return ListPure::back(); } - - // returns cyclic successor - ListConstIterator cyclicSucc(ListConstIterator it) const { - return ListPure::cyclicSucc(it); - } - - // returns cyclic successor - ListIterator cyclicSucc(ListIterator it) { - return ListPure::cyclicSucc(it); - } - - // returns cyclic predecessor - ListConstIterator cyclicPred(ListConstIterator it) const { - return ListPure::cyclicPred(it); - } - - // returns cyclic predecessor - ListIterator cyclicPred(ListIterator it) { - return ListPure::cyclicPred(it); - } - - // returns the iterator at position pos. Note that this takes time linear in pos. - ListConstIterator get(int pos) const { - OGDF_ASSERT(0 <= pos && pos < m_count) - return ListPure::get(pos); - } - - // returns the iterator at position pos. Note that this takes time linear in pos. - ListIterator get(int pos) { - OGDF_ASSERT(0 <= pos && pos < m_count) - return ListPure::get(pos); - } - - //! Returns the position (starting with 0) of iterator \a it in the list. - /** - * \pre \a it is a valid iterator pointing to an element in this list! - */ - int pos(ListConstIterator it) const { - OGDF_ASSERT(it.valid()) - return ListPure::pos(it); - } - - //! Returns an iterator to a random element in the list (or an invalid iterator if the list is empty) - /** - * This method takes linear time. - */ - ListConstIterator chooseIterator() const { - return (m_count > 0) ? get(randomNumber(0,m_count-1)) : ListConstIterator(); - } - - //! Returns an iterator to a random element in the list (or an invalid iterator if the list is empty) - /** - * This method takes linear time. - */ - ListIterator chooseIterator() { - return (m_count > 0) ? get(randomNumber(0,m_count-1)) : ListIterator(); - } - - //! Returns a random element from the list. - /** - * \pre The list is not empty! - * - * This method takes linear time. - */ - const E chooseElement() const { - OGDF_ASSERT(!empty()); - return *chooseIterator(); - } - - //! Returns a random element from the list. - /** - * \pre The list is not empty! - * - * This method takes linear time. - */ - E chooseElement() { - OGDF_ASSERT(!empty()); - return *chooseIterator(); - } - - // assignment - List &operator=(const List &L) { - ListPure::operator=(L); - m_count = L.m_count; - return *this; - } - - //! Equality operator. - bool operator==(const List &L) const { - if(m_count != L.m_count) - return false; - - ListElement *pX = ListPure::m_head, *pY = L.m_head; - while(pX != 0) { - if(pX->m_x != pY->m_x) - return false; - pX = pX->m_next; - pY = pY->m_next; - } - return true; - } - - //! Inequality operator. - bool operator!=(const List &L) const { - return !operator==(L); - } - - // adds element x at beginning - ListIterator pushFront(const E &x) { - ++m_count; - return ListPure::pushFront(x); - } - - // adds element x at end - ListIterator pushBack(const E &x) { - ++m_count; - return ListPure::pushBack(x); - } - - // inserts x before or after it - ListIterator insert(const E &x, ListIterator it, Direction dir = after) { - ++m_count; - return ListPure::insert(x,it,dir); - } - - // inserts x before it - ListIterator insertBefore(const E &x, ListIterator it) { - ++m_count; - return ListPure::insertBefore(x,it); - } - - // inserts x after it - ListIterator insertAfter(const E &x, ListIterator it) { - ++m_count; - return ListPure::insertAfter(x,it); - } - - // removes first element - void popFront() { - --m_count; - ListPure::popFront(); - } - - // removes first element and returns it - E popFrontRet() { - E el = front(); - popFront(); - return el; - } - - // removes last element - void popBack() { - --m_count; - ListPure::popBack(); - } - - // removes last element and returns it - E popBackRet() { - E el = back(); - popBack(); - return el; - } - - void exchange(ListIterator it1, ListIterator it2) { - ListPure::exchange(it1,it2); - } - - //! Moves \a it to the beginning of the list - /** - * \pre \a it points to an element in the list. - */ - void moveToFront(ListIterator it) { - ListPure::moveToFront(it); - } - //! Moves \a it to the end of the list - /** - * \pre \a it points to an element in the list. - */ - void moveToBack(ListIterator it) { - ListPure::moveToBack(it); - } - //! Moves \a it after \a itBefore. - /** - * \pre \a it and \a itBefore point to elements in this list. - */ - void moveToSucc(ListIterator it, ListIterator itBefore) { - ListPure::moveToSucc(it,itBefore); - } - //! Moves \a it before \a itAfter. - /** - * \pre \a it and \a itAfter point to elements in this list. - */ - void moveToPrec(ListIterator it, ListIterator itAfter) { - ListPure::moveToPrec(it,itAfter); - } - - //! Moves \a it to the beginning of \a L2. - /** - * \pre \a it points to an element in this list. - */ - void moveToFront(ListIterator it, List &L2) { - ListPure::moveToFront(it,L2); - --m_count; ++L2.m_count; - } - //! Moves \a it to the end of \a L2. - /** - * \pre \a it points to an element in this list. - */ - void moveToBack(ListIterator it, List &L2) { - ListPure::moveToBack(it,L2); - --m_count; ++L2.m_count; - } - - //! Moves \a it to list \a L2 and inserts it after \a itBefore. - /** - * \pre \a it points to an element in this list, and \a itBefore - * points to an element in \a L2. - */ - void moveToSucc(ListIterator it, List &L2, ListIterator itBefore) { - ListPure::moveToSucc(it,L2,itBefore); - --m_count; ++L2.m_count; - } - //! Moves \a it to list \a L2 and inserts it after \a itBefore. - /** - * \pre \a it points to an element in this list, and \a itBefore - * points to an element in \a L2. - */ - void moveToPrec(ListIterator it, List &L2, ListIterator itAfter) { - ListPure::moveToPrec(it,L2,itAfter); - --m_count; ++L2.m_count; - } - - // removes it and frees memory - void del(ListIterator it) { - --m_count; - ListPure::del(it); - } - - //! Appends \a L2 to this list and makes \a L2 empty. - void conc(List &L2) { - ListPure::conc(L2); - m_count += L2.m_count; - L2.m_count = 0; - } - - //! Prepends \a L2 to this list and makes \a L2 empty. - void concFront(List &L2) { - ListPure::concFront(L2); - m_count += L2.m_count; - L2.m_count = 0; - } - - //! Exchanges too complete lists in O(1). - /** - * The list's content is moved to L2 and vice versa. - */ - void exchange(List& L2) { - ListPure::exchange(L2); - int t = this->m_count; - this->m_count = L2.m_count; - L2.m_count = t; - } - - //! Splits the list at element \a it into lists \a L1 and \a L2. - /** - * If \a it is not a null pointer and \a L = x1,...,x{k-1}, \a it,x_{k+1},xn, then - * \a L1 = x1,...,x{k-1} and \a L2 = \a it,x{k+1},...,xn if \a dir = \c before. - * If \a it is a null pointer, then \a L1 is made empty and \a L2 = \a L. Finally - * \a L is made empty if it is not identical to \a L1 or \a L2. - * - * \pre \a it points to an element in this list. - */ - void split(ListIterator it,List &L1,List &L2,Direction dir = before) { - ListPure::split(it,L1,L2,dir); - int countL = m_count, countL1 = 0; - for(ListElement *pX = L1.m_head; pX != 0; pX = pX->m_next) - ++countL1; - - L1.m_count = countL1; - L2.m_count = countL - countL1; - if (this->m_head == 0) m_count = 0; - } - - // reverses the order of the list elements - void reverse() { ListPure::reverse(); } - - // removes all elements from list - void clear() { - m_count = 0; - ListPure::clear(); - } - - //! Conversion to const SListPure. - const ListPure &getListPure() const { return *this; } - - // sorts list using quicksort - void quicksort() { - ogdf::quicksortTemplate(*this); - } - - // sorts list using quicksort and parameterized compare element comp - template - void quicksort(const COMPARER &comp) { - ogdf::quicksortTemplate(*this,comp); - } - - // sorts list using bucket sort - void bucketSort(int l, int h, BucketFunc &f) { - ListPure::bucketSort(l,h,f); - } - - // permutes elements in list randomly - void permute() { - ListPure::permute(m_count); - } - - //! Scans the list for the specified element and returns its position in the list, or -1 if not found. - int search (const E& e) const { - return ListPure::search(e); - } - - //! Scans the list for the specified element (using the user-defined comparer) and returns its position in the list, or -1 if not found. - template - int search (const E& e, const COMPARER &comp) const { - return ListPure::search(e, comp); - } - - - OGDF_NEW_DELETE -}; // class List - - - -template -void ListPure::bucketSort(int l, int h, BucketFunc &f) -{ - if (m_head == m_tail) return; - - Array *> head(l,h,0), tail(l,h); - - ListElement *pX; - for (pX = m_head; pX; pX = pX->m_next) { - int i = f.getBucket(pX->m_x); - if (head[i]) - tail[i] = ((pX->m_prev = tail[i])->m_next = pX); - else - head[i] = tail[i] = pX; - } - - ListElement *pY = 0; - for (int i = l; i <= h; i++) { - pX = head[i]; - if (pX) { - if (pY) { - (pY->m_next = pX)->m_prev = pY; - } else - (m_head = pX)->m_prev = 0; - pY = tail[i]; - } - } - - m_tail = pY; - pY->m_next = 0; -} - - -// permutes elements in list randomly; n is the length of the list -template -void ListPure::permute(const int n) -{ - Array *> A(n+2); - A[0] = A[n+1] = 0; - - int i = 1; - ListElement *pX; - for (pX = m_head; pX; pX = pX->m_next) - A[i++] = pX; - - A.permute(1,n); - - for (i = 1; i <= n; i++) { - pX = A[i]; - pX->m_next = A[i+1]; - pX->m_prev = A[i-1]; - } - - m_head = A[1]; - m_tail = A[n]; -} - - -// prints list L to output stream os using delimiter delim -template -void print(ostream &os, const ListPure &L, char delim = ' ') -{ - ListConstIterator pX = L.begin(); - if (pX.valid()) { - os << *pX; - for(++pX; pX.valid(); ++pX) - os << delim << *pX; - } -} - -// prints list L to output stream os using delimiter delim -template -void print(ostream &os, const List &L, char delim = ' ') -{ - print(os, L.getListPure(), delim); -} - -// prints list L to output stream os -template -ostream &operator<<(ostream &os, const ListPure &L) -{ - print(os,L); - return os; -} - -// prints list L to output stream os -template -ostream &operator<<(ostream &os, const List &L) -{ - return os << L.getListPure(); -} - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Logger.h b/ext/OGDF/ogdf/basic/Logger.h deleted file mode 100644 index dc8ee5744..000000000 --- a/ext/OGDF/ogdf/basic/Logger.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains logging functionality - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_LOGGER_H -#define OGDF_LOGGER_H - -#include - -namespace ogdf { - -//! Centralized global and local logging facility working on streams like cout. -/** - * The Logger class is a centralized logging environment with 2x2 different use-cases working together. - * All generated output is sent into the \a world-stream, i.e., \a cout, if not set otherwise. - * - * \b Logging \b vs. \b Statistic: - * The Logger differentiates between \a logging and \a statistic mode. - * When in logging mode, only the output written via the lout()/slout() commands is - * written to the world stream (according to loglevels). When in statistic mode, - * only the output of the sout()/ssout() commands is written. - * (Sidenote: there is also a \a forced output fout()/sfout() which is written independent on the current mode). - * - * The idea of these two modi is that one can augment the code with output which is - * interesting in the normal computation mode via lout, but the same algorithm can also be run given tabular - * statistic-lines when e.g. batch-testing the algorithm on a set of benchmark instances. - * - * \b Global \b vs. \b Local: - * You can choose to use the Logging facilities globally via the static outputs (slout(), ssout(), sfout()). - * Thereby the global log-level and statistic-mode settings are applied. - * Alternatively you can create your own Logging object with its own parameters only for your algorithm, - * and use the object methods lout(), sout(), and fout(). This allows you to turn output on for your own - * (new) algorithm, but keep the rest of the library silent. - * - * \b Global \b Settings: - * The slout command takes an (optional) parameter given the importance of the output (aka. loglevel). - * The output is written only if the globalLogLevel is not higher. The method globalStatisticMode - * turn the statistic-mode on and off (thereby disabling or enabling the logging mode). - * - * Furthermore, we have a globalMinimumLogLevel. This is used to globally forbid any output - * with too low importance written by any Logger-objects. - * - * \b Local \b Settings: - * A Logger-object has its own set of settings, i.e., its own localLogLevel and an own localLogMode, - * which can be any of the following: - * - \a LM_LOG: the object is in logging mode, using its own localLogLevel - * - \a LM_STATISTIC: the object is in statistic mode - * - \a LM_GLOBAL: the object is in the same mode as the static Logger-class (i.e., global settings) - * - \a LM_GLOBALLOG: the object is in logging mode, but uses the globalLogLevel - * - * \b Typical \b Usage:
    - * The simplest but restricted and verbose usage is to write
    - *
    - * Logger::slout() << "1+2=" << (1+2) << endl; - *
    - * - * The conceptually easiest and cleanest approach is to augment your algorithm class with a Logger. - * Multiple inheritance allows this pretty straightforwardly:
    - *
    - * class MyAlgorithm : public MyBaseClass, protected Logger {
    - *   int myMethod();
    - * }
    - *
    - * MyAlgorithm::myMethod() {
    - *   lout() << "1+2=" << (1+2) << endl;
    - * }
    - *
    - * - */ - -class OGDF_EXPORT Logger { - -public: - //! supported log-levels from lowest to highest importance - enum Level { LL_MINOR, LL_MEDIUM, LL_DEFAULT, LL_HIGH, LL_ALARM, LL_FORCE }; - //! (local) log-modes (see class description) - enum LogMode { LM_GLOBAL, LM_GLOBALLOG, LM_LOG, LM_STATISTIC }; - - // CONSTRUCTORS ////////////////////////////////////// - //! creates a new Logger-object with LM_GLOBAL and local log-level equal globalLogLevel - Logger() : - m_loglevel(m_globalloglevel), m_logmode(LM_GLOBAL) {} - //! creates a new Logger-object with given log-mode and local log-level equal globalLogLevel - Logger(LogMode m) : - m_loglevel(m_globalloglevel), m_logmode(m) {} - //! creates a new Logger-object with LM_GLOBAL and given local log-level - Logger(Level l) : - m_loglevel(l), m_logmode(LM_GLOBAL) {} - //! creates a new Logger-object with given log-mode and given local log-level - Logger(LogMode m, Level l) : - m_loglevel(l), m_logmode(m) {} - - // USAGE ////////////////////////////////////// - //! stream for logging-output (local) - std::ostream& lout(Level l = LL_DEFAULT) const { - return ((!m_globalstatisticmode && m_logmode==LM_GLOBAL) || m_logmode==LM_GLOBALLOG) - ? ( (l >= m_globalloglevel) ? *world : nirvana ) - : ( (m_logmode==LM_LOG && l >= m_loglevel && l >= m_minimumloglevel) ? *world : nirvana ); - } - //! stream for statistic-output (local) - std::ostream& sout() const { - return ((m_globalstatisticmode && m_logmode==LM_GLOBAL) || (m_logmode == LM_STATISTIC)) ? *world : nirvana; - } - //! stream for forced output (local) - std::ostream& fout() const { - return sfout(); - } - - // STATIC USAGE /////////////////////////////// - //! stream for logging-output (global) - static std::ostream& slout(Level l = LL_DEFAULT) { - return ((!m_globalstatisticmode) && l >= m_globalloglevel) ? *world : nirvana; - } - //! stream for statistic-output (global) - static std::ostream& ssout() { - return (m_globalstatisticmode) ? *world : nirvana; - } - //! stream for forced output (global) - static std::ostream& sfout() { - return *world; - } - - // LOCAL ////////////////////////////////////// - //! gives the local log-level - Level localLogLevel() const { - return m_loglevel; - } - //! sets the local log-level - void localLogLevel(Level l) { - m_loglevel = l; - } - //! gives the local log-mode - LogMode localLogMode() const { - return m_logmode; - } - //! sets the local log-mode - void localLogMode(LogMode m) { - m_logmode = m; - } - - // GLOBAL ////////////////////////////////////// - //! gives the local log-level - static Level globalLogLevel() { return m_globalloglevel; } - //! sets the global log-level - static void globalLogLevel(Level l) { if(l>=m_minimumloglevel) m_globalloglevel = l; } - - //! gives the globally minimally required log-level - static Level globalMinimumLogLevel() { return m_minimumloglevel; } - //! sets the globally minimally required log-level - static void globalMinimumLogLevel(Level l) { if(l<=m_globalloglevel) m_minimumloglevel = l; } - - //! returns true if we are globally in statistic mode - static bool globalStatisticMode() { return m_globalstatisticmode; } - //! sets whether we are globally in statistic mode - static void globalStatisticMode(bool s) { m_globalstatisticmode = s; } - - //! change the stream to which allowed output is written (by default: cout) - static void setWorldStream(std::ostream& o) { world = &o; } - - // EFFECTIVE ////////////////////////////////////// - //! obtain the effective log-level for the Logger-object (i.e., resolve the depenancies on the global settings) - Level effectiveLogLevel() const { - if(m_logmode==LM_GLOBAL || m_logmode==LM_GLOBALLOG) - return m_globalloglevel; - else - return (m_loglevel > m_minimumloglevel) ? m_loglevel : m_minimumloglevel; - } - - //! returns true if the Logger-object is effectively in statistic-mode (as this might be depending on the global settings) - bool effectiveStatisticMode() const { - return m_logmode==LM_STATISTIC || (m_logmode==LM_GLOBAL && m_globalstatisticmode); - } - - -private: - static std::ostream nirvana; - static std::ostream* world; - - static Level m_globalloglevel; - static Level m_minimumloglevel; - static bool m_globalstatisticmode; - - Level m_loglevel; - LogMode m_logmode; -}; - -} - -#endif // OGDF_LOGGER_H - diff --git a/ext/OGDF/ogdf/basic/Math.h b/ext/OGDF/ogdf/basic/Math.h deleted file mode 100644 index 15430d4e8..000000000 --- a/ext/OGDF/ogdf/basic/Math.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Mathematical Helpers - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_MATH_H -#define OGDF_MATH_H - -#include -#include - -namespace ogdf { - - -//#define DOUBLE_EPS 0.000001 - - -class OGDF_EXPORT Math { - -public: - //! The constant \f$\pi\f$. - static const double pi; - - //! The constant \f$\frac{\pi}{2}\f$. - static const double pi_2; - - //! The constant \f$\frac{\pi}{4}\f$. - static const double pi_4; - - //! The constant \f$2\pi\f$. - static const double two_pi; - - //! Euler's number. - static const double e; - - //! The constant log(2.0). - static const double log_of_2; - - //! The constant log(4.0). - static const double log_of_4; - - //! Returns the logarithm of \a x to the base 2. - static double log2(double x) { - OGDF_ASSERT(x >= 0) - return log(x) / log_of_2; - } - - //! Returns the logarithm of \a x to the base 4. - static double log4(double x) { - OGDF_ASSERT(x >= 0) - return log(x) / log_of_4; - } - - //! Returns \f$n \choose k\f$. - static int binomial(int n, int k); - - //! Returns \f$n \choose k\f$. - static double binomial_d(int n, int k); - - //! Returns \a n!. - static int factorial(int n); - - //! Returns \a n!. - static double factorial_d(int n); - - //static bool equald(double a, double b) { - // double d = a-b; - // return d < DOUBLE_EPS && d > -DOUBLE_EPS; - //} - - /*! - * \brief A fast method to obtain the rounded down binary logarithm of an 32-bit integer - * - * This is based on http://en.wikipedia.org/wiki/Binary_logarithm - * @param v The number of which the binary logarithm is to be determined - * @return The rounded down logarithm base 2 if v is positive, -1 otherwise - */ - static int floorLog2(int v) { - if (v <= 0) { - return -1; - } else { - int result = 0; - if (v >= (1 << 16)) { - v >>= 16; - result += 16; - } - if (v >= (1 << 8)) { - v >>= 8; - result += 8; - } - if (v >= (1 << 4)) { - v >>= 4; - result += 4; - } - if (v >= (1 << 2)) { - v >>= 2; - result += 2; - } - if (v >= (1 << 1)) { - result += 1; - } - return result; - } - } -}; - - -} - -#endif // OGDF_MATH_H diff --git a/ext/OGDF/ogdf/basic/MinHeap.h b/ext/OGDF/ogdf/basic/MinHeap.h deleted file mode 100644 index 72796fd56..000000000 --- a/ext/OGDF/ogdf/basic/MinHeap.h +++ /dev/null @@ -1,341 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares & Implements Binary Heap, and Top10Heap - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIN_HEAP_H -#define OGDF_MIN_HEAP_H - -#include - -namespace ogdf { - -//! Augments any data elements of type \a X with keys of type \a Score. -/** - * Also defines comparator function using the keys. - * This class is intended as a helpful convenience class for using with BinaryHeapSimple, Top10Heap,.. - */ -template class Prioritized { - X x; - Priority p; -public: - //! Constructor of empty element. Be careful! - Prioritized() : x(0), p(0) { } - //! Constructor using a key/value pair - Prioritized(X xt, Priority pt) : x(xt),p(pt) { } - //! Copy-constructor - Prioritized(const Prioritized& P) : x(P.x),p(P.p) { } - //! Returns the key of the element - Priority priority() const { return p; } - //! Returns the data of the element - X item() const { return x;} - //! Comparison oprator based on the compare-operator for the key type (\a Priority) - bool operator<(const Prioritized& P) const { return p& P) const { return p<=P.p; } - //! Comparison oprator based on the compare-operator for the key type (\a Priority) - bool operator>(const Prioritized& P) const { return p>P.p; } - //! Comparison oprator based on the compare-operator for the key type (\a Priority) - bool operator>=(const Prioritized& P) const { return p>=P.p; } - //! Comparison oprator based on the compare-operator for the key type (\a Priority) - bool operator==(const Prioritized& P) const { return p==P.p; } - //! Comparison oprator based on the compare-operator for the key type (\a Priority) - bool operator!=(const Prioritized& P) const { return p!=P.p; } -}; - - -//! Dynamically growing binary heap tuned for efficiency on a small interface (compared to BinaryHeap). -/** - * It assumes that the data-elements are themselves comparable, i.e., the compare-function - * of the items implicitly defines the keys. Hence this datastructure allows no key-changing - * operations (decreaseKey, etc.). - * - * The heap grows (using doubling) dynamically, if there are more elements added. Furthermore, - * BinaryHeapSimple allows to be directly indexed using traditional array-syntax, e.g., for iterating over - * all its elements. - * - * If your intended datastructure does not offer a (suitable) compare function, but you have - * certain key-values (scores, etc.), you may want to use the convenience-class - * Prioritized < Score,X > to bind both together and use within BinaryHeapSimple. - */ -template -class BinaryHeapSimple { -private: - Array data; // array starts at index 1 - INDEX num; -public: - //! Construtor, giving initial array size - BinaryHeapSimple(INDEX size) : data(1, size), num(0) {} - - //! Returns true if the heap is empty - bool empty() const { return num == 0; } - //! Returns the number of elements in the heap - INDEX size() const { return num; } - - //! empties the heap [O(1)] - void clear() { num = 0; } - - //! Returns a reference to the top (i.e., smallest) element of the heap. It does not remove it. [Same as getMin(), O(1)] - const X& top() const { - return data[1]; - } - //! Returns a reference to the top (i.e., smallest) element of the heap. It does not remove it. [Same as top(), O(1)] - inline const X& getMin() const { - return top(); - } - - //! Adds an element to the heap [Same as insert(), O(log n)] - void push(X& x) { - X y; - if(num == capacity()) - data.grow(capacity(),y); // double the size & init with nulls - data[++num] = x; - heapup(num); - } - //! Adds an element to the heap [Same as push(), O(log n)] - inline void insert(X& x) { - push(x); - } - - //! Returns the top (i.e., smallest) element and removed it from the heap [Same as extractMin(), O(log n)] - X pop() { - data.swap(1, num--); - heapdown(); - return data[num+1]; - } - //! Returns the top (i.e., smallest) element and removed it from the heap [Same as pop(), O(log n)] - inline X extractMin() { - return pop(); - } - - //! obtain const references to the element at index \a idx (the smallest array index is 0, as for traditional C-arrays) - const X& operator[](INDEX idx) const { - return data[idx+1]; - } - - -protected: - //! Returns the current array-size of the heap, i.e., the number of elements which can be added before the next resize occurs. - INDEX capacity() const { return data.size(); } - - void heapup(INDEX idx) { - INDEX papa; - while( (papa = idx/2) > 0) { - if( data[papa] > data[idx] ) { - data.swap(papa, idx); - idx = papa; - } else return; //done - } - } - - void heapdown() { - INDEX papa = 1; - INDEX son; - while(true) { - if( (son = 2*papa) < num && data[son+1] < data[son] ) - son++; - if( son <= num && data[son] < data[papa]) { - data.swap(papa, son); - papa = son; - } else return; - } - } -}; - -//! A variant of BinaryHeapSimple which always holds only the X (e.g. X=10) elements with the highest keys. -/** - * It assumes that the data-elements are themselves comparable, i.e., the compare-function - * of the items implicitly defines the keys. - * - * If your intended datastructure do not dorectly offer a compare function, but you have - * certain key-values (scores, etc.), you may want to use the convenience-class - * Prioritized < Priority,X > to bind both together and use within BinaryHeapSimple. - */ -template -class Top10Heap : protected BinaryHeapSimple { // favors the 10 highest values... -public: - //! The type for results of a Top10Heap::push operation - enum PushResult { Accepted, Rejected, Swapped }; - - //! Convenience function: Returns true if the PushResults states that the newly pushed element is new in the heap - static bool successful(PushResult r) { return r != Rejected; } - //! Convenience function: Returns true if the PushResults states that push caused an element to be not/no-longer in the heap - static bool returnedSomething(PushResult r) { return r != Accepted; } - - //! Constructor generating a heap which holds the 10 elements with highest value ever added to the heap - Top10Heap() : BinaryHeapSimple(10) {} - //! Constructor generating a heap which holds the \a size elements with highest value ever added to the heap - Top10Heap(INDEX size) : BinaryHeapSimple(size) {} - - //! Returns true if the heap contains no elements - bool empty() const { return BinaryHeapSimple::empty(); } - //! Returns true if the heap is completely filled (i.e. the next push operation will return something) - bool full() const { return size() == capacity(); } - //! Returns the number of elements in the heap - INDEX size() const { return BinaryHeapSimple::size(); } - //! Returns the size of the heap specified when constructing: this is the number of top elements stored. - INDEX capacity() const { return BinaryHeapSimple::capacity(); } - - //! empties the heap - void clear() { BinaryHeapSimple::clear(); } - - //! Tries to push the element \a x onto the heap (and may return a removed element as \a out). - /** - * If the heap is not yet completely filled, the pushed element is accepted and added to the heap. - * The function returns \a Accepted, and the \a out parameter is not touched. - * - * If the heap is filled and the key of the pushed element is too small to be accepted - * (i.e. the heap is filled with all larger elements), then the element if rejected: The funtion - * returns \a Rejected, and the \a out parameter is set to \a x. - * - * If the heap is filled and the key of the pushed element is large enough to belong to the top - * elements, the element is accepted and the currently smallest element in the heap is removed - * from the heap. The function returns \a Swapped and sets the \a out parameter to the element - * removed from the heap. - * - * You may want to use the convenience funtions \a successful and \a returnedSomething on the - * return-value if you are only interested certain aspects of the push. - */ - PushResult push(X& x, X& out) { // returns element that got kicked out - out is uninitialized if heap wasn't full (i.e. PushResult equals Accepted) - PushResult ret = Accepted; - if(capacity() == size()) { - if(BinaryHeapSimple::top() >= x) {// reject new item since it's too bad - out = x; - return Rejected; - } - out = BinaryHeapSimple::pop(); // remove worst first - ret = Swapped; - } - BinaryHeapSimple::push(x); - return ret; - } - //! Alternative name for push(). - inline PushResult insert(X& x, X& out) { - return push(x, out); - } - - //! Simple (and slightly faster) variant of Top10Heap::push. - /** - * The behavior is the identical to Top10Heap::push, but there is nothing reported to the outside - */ - void pushBlind(X& x) { - if(capacity() == size()) { - if(BinaryHeapSimple::top() >= x) // reject new item since it's too bad - return; - BinaryHeapSimple::pop(); // remove worst first - } - BinaryHeapSimple::push(x); - } - //! Alternative name for pushBlind(). - inline void insertBlind(X& x, X& out) { - return pushBlind(x, out); - } - - //! obtain const references to the element at index \a idx - /** - * The smallest array index is 0, as for traditional C-arrays. - * Useful, e.g., when iterating through the final heap elements. - */ - const X& operator[](INDEX idx) const { // ATTN: simulate index starting at 0, to be "traditional" to the outside!!! - return BinaryHeapSimple::operator[](idx); - } -}; - -//! A variant of Top10Heap which deletes the elements that get rejected from the heap -/** - * The datastructure of course requires the stored data-elements to be pointers (in order to be deletable when - * rejected). Hence the template parameter only specifies the data-type, without stating axplicitly that we - * considere pointers to the structure. - * - * The datastructure also allows for non-duplicate insertions, i.e., a new element can be rejected if it is - * already in the heap. Note that only the compare function has to work - */ -template, class INDEX = int > -class DeletingTop10Heap : public Top10Heap,INDEX > { -public: - //! Construct a DeletingTop10Heap of given maximal capacity - DeletingTop10Heap(int size) : Top10Heap,INDEX >(size) {} - //! Inserts the element \a x into the heap with priority \a val and deletes the element with smallest priority if the heap is full - /** - * Like the Top10Heap, this function pushes the element \a x onto the heap with priority \a val, and extracts the element with - * smallest priority if the heap was already full. In contrast to the Top10Heap, this element which leaves the heap (or \a x - * itself if its priority was below all the priorities in the heap) gets deleted, i.e., removed from memory. - */ - void pushAndDelete(X* x, Priority p) { - Prioritized vo; - Prioritized nv(x, p); - if(returnedSomething( Top10Heap,INDEX >::push(nv, vo) )) - delete vo.item(); - } - //! Alternative name for pushAndDelete(). - inline void insertAndDelete(X* x, Priority p) { - pushAndDelete(x, p); - } - //! Analogous to pushandDelete(), but furthermore rejects (and deletes) an element if an equal element is already in the heap. - /** - * This function takes linear time in the worst case, and uses the \a compare function of the specified COMP template - * paremeter class, which can be any function returning \a true if two objects should be considered equal, and \a false otherwise. - */ - void pushAndDeleteNoRedundancy(X* x, Priority p) { - for(INDEX i = Top10Heap,INDEX >::size(); i-->0;) { - X* k = Top10Heap,INDEX >::operator[](i).item(); -// OGDF_ASSERT( x ) -// OGDF_ASSERT( k ) - if(TargetComparer::equal(k,x)) { - delete x; - return; - } - } - pushAndDelete(x, p); - } - //! Alternative name for pushAndKillNoRedundancy(). - inline void insertAndDeleteNoRedundancy(X* x, Priority p) { - pushAndDeleteNoRedundancy(p, x); - } -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/MinPriorityQueue.h b/ext/OGDF/ogdf/basic/MinPriorityQueue.h deleted file mode 100644 index 610b1e4b5..000000000 --- a/ext/OGDF/ogdf/basic/MinPriorityQueue.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a base class for planar representations - * of graphs and cluster graphs. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - - -#ifndef OGDF_MIN_PRIORITY_QUEUE_H -#define OGDF_MIN_PRIORITY_QUEUE_H - -#include - - -namespace ogdf { - - -template -class HeapElement { - - template friend class MinPriorityQueue; - - private: - Score v; - X x; - int pos; // the position in the heapElement array - public: - HeapElement(){} - //copy constructor - HeapElement(const HeapElement &orig): v(orig.v), x(orig.x), pos(orig.pos) {} - HeapElement(Score vt, X xt) : v(vt), x(xt) {} - - //return the score - Score score_value() const { return v; } - // return the element - X element() const { return x;} -}; - - - -// using min heaps -// follow the pseudo code of "introduction to algorithms" -template -class MinPriorityQueue { - - private : - - HeapElement **heapElements; - - int number; // the number of elements in the Queue - int s; // size - - void swap(int pos1, int pos2) { - HeapElement *tmp = heapElements[pos1]; - heapElements[pos1] = heapElements[pos2]; - heapElements[pos2] = tmp; - // update the position - heapElements[pos2]->pos = pos2; - heapElements[pos1]->pos = pos1; - } - - void minHeapify(int pos) { - int l = getLeft(pos); - int r = getRight(pos); - int smallest; - if (l <= number && heapElements[l]->score_value() < heapElements[pos]->score_value() ) - smallest = l; - else - smallest = pos; - if (r <= number && heapElements[r]->score_value() < heapElements[smallest]->score_value()) - smallest = r; - if (smallest != pos) { - swap(pos, smallest); - minHeapify(smallest); - } - } - - int getParent(int pos) const {return pos/2;} - int getLeft(int pos) const {return pos*2;} - int getRight(int pos) const {return pos*2+1;} - - - public: - - // contructor, only fixed size - MinPriorityQueue(int _size) : number(0), s(_size) { - heapElements = new HeapElement* [_size+1]; // allocate - for (int i = 0; i < s+1; ++i) { - heapElements[i] = 0; - } - } - - - ~MinPriorityQueue() { - for (int i = 0; i < s+1; ++i) { - if (heapElements[i] != 0) { - delete heapElements[i]; - heapElements[i] = 0; - } - } - delete [] heapElements; - } - - - bool empty() const { return number == 0; } - int count() const { return number; } - int size() const { return s; } - - //return the Object with the min. score - const X & getMin() const { - return heapElements[1]->element(); - } - - - - void decreasePriority(const HeapElement *elem, // handle to the element - Score sc // new score, muss be smaller then the old score - ) { - int i = elem->pos; - OGDF_ASSERT(i <= s); - if (heapElements[i]->score_value() < sc) - throw "New key is greater than current key."; - heapElements[i]->v = sc; - while (i > 1 && (heapElements[getParent(i)]->score_value() > heapElements[i]->score_value()) ) { - swap(i, getParent(i)); - i = getParent(i); - } - } - - - // return a handle to the new inserted element - const HeapElement * insert(const HeapElement &elem) { - HeapElement *h_elem = new HeapElement(elem); // make a copy - ++number; - OGDF_ASSERT(number <= s); - h_elem->pos = number; // store the position - heapElements[number] = h_elem; - int i = number; - while ( (i > 1) && ( heapElements[getParent(i)]->score_value() > heapElements[i]->score_value()) ) { - swap(i, getParent(i)); - i = getParent(i); - } - return h_elem; - } - - - // return the smallest element and remove it from the queue - HeapElement pop() { - if (empty()) - throw "Heap underflow error!"; - HeapElement obj = *heapElements[1]; - HeapElement * p = heapElements[1]; - swap(1, number); - --number; - delete p; - minHeapify(1); - OGDF_ASSERT(number+1 <= s); - heapElements[number+1] = 0; - return obj; - } - - - - /*********************************************************************************/ - // debug - void outHeap() { - cout << "\nHeap Array: \n"; - for (int i = 0; i < s+1; i++) { - HeapElement *obj = heapElements[i]; - if (obj != NULL) - cout << "score: " << obj->score_value() << "; elem: " << obj->element() << "; index "<< i << "; pos: " << obj->pos << endl << flush; - else - cout << "index: " << i << " value: null;" << endl << flush; - } - } -}; - - -}// namespace - -#endif diff --git a/ext/OGDF/ogdf/basic/Module.h b/ext/OGDF/ogdf/basic/Module.h deleted file mode 100644 index 66d3a0c9b..000000000 --- a/ext/OGDF/ogdf/basic/Module.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares base class for all module types. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_MODULE_H -#define OGDF_MODULE_H - - -#include - -namespace ogdf { - - -/** - * \brief Base class for modules. - * - * A module represents an algorithm that implements a certain interface. - * There are various specific module types present in the OGDF, which all - * inherit Module as a base class. These module types define the interface - * implemented by the module. - * - * \sa ModuleOption - */ -class OGDF_EXPORT Module -{ -public: - //! The return type of a module. - enum ReturnType { - retFeasible, //!< The solution is feasible. - retOptimal, //!< The solution is optimal - retNoFeasibleSolution, //!< There exists no feasible solution. - retTimeoutFeasible, //!< The solution is feasible, but there was a timeout. - retTimeoutInfeasible, //!< The solution is not feasible due to a timeout. - retError //! Computation was aborted due to an error. - }; - - //! Initializes a module. - Module() { } - - virtual ~Module() { } - - //! Returns true iff \a retVal indicates that the module returned a feasible solution. - static bool isSolution(ReturnType ret) { - return ret == retFeasible || ret == retOptimal || ret == retTimeoutFeasible; - } -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/ModuleOption.h b/ext/OGDF/ogdf/basic/ModuleOption.h deleted file mode 100644 index da4b41211..000000000 --- a/ext/OGDF/ogdf/basic/ModuleOption.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of parameterized class for module options - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MODULE_OPTION_H -#define OGDF_MODULE_OPTION_H - - -#include - - -namespace ogdf { - - -/** - * \brief The parameterized base class for module options. - * - * M is type (base class) of corresponding module. Notice that module - * instances passed to set() must be allocated with new and will be - * freed by ModuleOption. - */ -template class ModuleOption { - - M *m_pModule; //!< Pointer to the module. - -public: - //! Initializes a module option; the initial module is just a 0-pointer. - ModuleOption() : m_pModule(0) { } - - // destruction - ~ModuleOption() { delete m_pModule; } - - //! Sets the module to \a pM. - /** - * This function will also free the module currently stored by the option. - */ - void set(M *pM) { - delete m_pModule; - m_pModule = pM; - } - - //! Returns true iff the option currently stores a module. - bool valid() const { return m_pModule != 0; } - - //! Returns a reference to the stored module. - /** - * It is required that the option currently stores a module, i.e., - * valid() is true. - */ - M &get() { return *m_pModule; } -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/NearestRectangleFinder.h b/ext/OGDF/ogdf/basic/NearestRectangleFinder.h deleted file mode 100644 index 79faccdd1..000000000 --- a/ext/OGDF/ogdf/basic/NearestRectangleFinder.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class NearestRectangleFinder - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_NEAREST_RECTANGLE_FINDER_H -#define OGDF_NEAREST_RECTANGLE_FINDER_H - - -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// NearestRectangleFinder -// finds in a given set of rectangles for each point in a given -// set of points the nearest rectangle -//--------------------------------------------------------- -class OGDF_EXPORT NearestRectangleFinder -{ -public: - struct RectRegion; - struct PairRectDist; - struct PairCoordId; - - NearestRectangleFinder(double mad = 20, double td = 5) { - m_maxAllowedDistance = mad; - m_toleranceDistance = td; - } - - // the maximal allowed distance between a rectangle and a point - // rectangles with a greater distance are not considered - void maxAllowedDistance(double mad) { m_maxAllowedDistance = mad; } - double maxAllowedDistance() const { return m_maxAllowedDistance; } - - // the tolerance in which rectangles are considered to be ambigous, i.e. - // if the rectangle with the minimum distance to point p has distance mindist - // and there is another rectangle with distance dist such that - // dist <= minDist + toleranceDistance, we say that the closest rectangle is not unique. - void toleranceDistance(double td) { m_toleranceDistance = td; } - double toleranceDistance() const { return m_toleranceDistance; } - - - // finds the nearest rectangles for a given set of points - // The nearest rectangles are passed in a list. If the list is empty, there - // is no rectangle within the ,aximal allowed distance. If the list contains - // more than one element, the nearest rectangle is not unique for the - // given tolerance. - void find( - const Array ®ion, // given rectangles - const Array &point, // given points - Array > &nearest); // nearest rectangles - - // trivial implementation of find(). Can be used in order to check - // correctness. Computes only rectangle with minimum distance without - // considering maxAllowedDistance and toleranceDistance. - void findSimple( - const Array ®ion, - const Array &point, - Array > &nearest); - -private: - class CoordComparer; - class YCoordComparer; - - double m_maxAllowedDistance; - double m_toleranceDistance; -}; - - -//--------------------------------------------------------- -// RectRegion -// represents a rectangle given by center point, width and height -//--------------------------------------------------------- -struct NearestRectangleFinder::RectRegion -{ - friend ostream &operator<<(ostream &os, const RectRegion &rect) { - os << "(" << rect.m_x << "," << rect.m_y << ":" << - rect.m_width << "," << rect.m_height << ")"; - return os; - } - - double m_x, m_y, m_width, m_height; -}; - - -//--------------------------------------------------------- -// PairRectDist -// represents a rectangle (given by its index) and a -// distance value -//--------------------------------------------------------- -struct OGDF_EXPORT NearestRectangleFinder::PairRectDist -{ - PairRectDist() { } - - PairRectDist(int index, double distance) { - m_index = index; - m_distance = distance; - } - - friend ostream &operator<<(ostream &os, const PairRectDist &p) { - os << "(" << p.m_index << "," << p.m_distance << ")"; - return os; - } - - int m_index; - double m_distance; -}; - - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/NodeArray.h b/ext/OGDF/ogdf/basic/NodeArray.h deleted file mode 100644 index 18152551c..000000000 --- a/ext/OGDF/ogdf/basic/NodeArray.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of NodeArray class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_ARRAY_H -#define OGDF_NODE_ARRAY_H - - -#include - - -namespace ogdf { - - -//! Abstract base class for node arrays. -/** - * Defines the interface for event handling used by the Graph class. - * Use the parameterized class NodeArray for creating node arrays. - */ -class NodeArrayBase { - /** - * Pointer to list element in the list of all registered node - * arrays which references this array. - */ - ListIterator m_it; - -public: - const Graph *m_pGraph; //!< The associated graph. - - //! Initializes an node array not associated with a graph. - NodeArrayBase() : m_pGraph(0) { } - //! Initializes an node array associated with \a pG. - NodeArrayBase(const Graph *pG) : m_pGraph(pG) { - if(pG) m_it = pG->registerArray(this); - } - - // destructor, unregisters the array - virtual ~NodeArrayBase() { - if (m_pGraph) m_pGraph->unregisterArray(m_it); - } - - // event interface used by Graph - //! Virtual function called when table size has to be enlarged. - virtual void enlargeTable(int newTableSize) = 0; - //! Virtual function called when table has to be reinitialized. - virtual void reinit(int initTableSize) = 0; - //! Virtual function called when array is disconnected from the graph. - virtual void disconnect() = 0; - - //! Associates the array with a new graph. - void reregister(const Graph *pG) { - if (m_pGraph) m_pGraph->unregisterArray(m_it); - if ((m_pGraph = pG) != 0) m_it = pG->registerArray(this); - } -}; // class NodeArrayBase - - -//! Dynamic arrays indexed with nodes. -/** - * Node arrays represent a mapping from nodes to data of type \a T. - * They adjust their table size automatically when the graph grows. - * - * @tparam T is the element type. - */ -template class NodeArray : private Array, protected NodeArrayBase { - T m_x; //!< The default value for array elements. - -public: - //! Constructs an empty node array associated with no graph. - NodeArray() : Array(), NodeArrayBase() { } - //! Constructs a node array associated with \a G. - NodeArray(const Graph &G) : Array(G.nodeArrayTableSize()), NodeArrayBase(&G) { } - //! Constructs a node array associated with \a G. - /** - * @param G is the associated graph. - * @param x is the default value for all array elements. - */ - NodeArray(const Graph &G, const T &x) : - Array(0,G.nodeArrayTableSize()-1,x), NodeArrayBase(&G), m_x(x) { } - //! Constructs a node array that is a copy of \a A. - /** - * Associates the array with the same graph as \a A and copies all elements. - */ - NodeArray(const NodeArray &A) : Array(A), NodeArrayBase(A.m_pGraph), m_x(A.m_x) { } - - //! Returns true iff the array is associated with a graph. - bool valid() const { return (Array::low() <= Array::high()); } - - //! Returns a pointer to the associated graph. - const Graph *graphOf() const { - return m_pGraph; - } - - //! Returns a reference to the element with index \a v. - const T &operator[](node v) const { - OGDF_ASSERT(v != 0 && v->graphOf() == m_pGraph) - return Array::operator [](v->index()); - } - - //! Returns a reference to the element with index \a v. - T &operator[](node v) { - OGDF_ASSERT(v != 0 && v->graphOf() == m_pGraph) - return Array::operator [](v->index()); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for a node - * in the associated graph! - */ - const T &operator[](int index) const { - return Array::operator [](index); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for a node - * in the associated graph! - */ - T &operator[](int index) { - return Array::operator [](index); - } - - //! Assignment operator. - NodeArray &operator=(const NodeArray &a) { - Array::operator =(a); - m_x = a.m_x; - reregister(a.m_pGraph); - return *this; - } - - //! Reinitializes the array. Associates the array with no graph. - void init() { - Array::init(); reregister(0); - } - - //! Reinitializes the array. Associates the array with \a G. - void init(const Graph &G) { - Array::init(G.nodeArrayTableSize()); reregister(&G); - } - - //! Reinitializes the array. Associates the array with \a G. - /** - * @param G is the associated graph. - * @param x is the default value. - */ - void init(const Graph &G, const T &x) { - Array::init(0,G.nodeArrayTableSize()-1, m_x = x); reregister(&G); - } - - //! Sets all array elements to \a x. - void fill(const T &x) { - int high = m_pGraph->maxNodeIndex(); - if(high >= 0) - Array::fill(0,high,x); - } - -private: - virtual void enlargeTable(int newTableSize) { - Array::grow(newTableSize-Array::size(),m_x); - } - - virtual void reinit(int initTableSize) { - Array::init(0,initTableSize-1,m_x); - } - - virtual void disconnect() { - Array::init(); - m_pGraph = 0; - } - - OGDF_NEW_DELETE - -}; // class NodeArray - - -} // end namespace ogdf - -#include - -#endif diff --git a/ext/OGDF/ogdf/basic/NodeComparer.h b/ext/OGDF/ogdf/basic/NodeComparer.h deleted file mode 100644 index d525a26fa..000000000 --- a/ext/OGDF/ogdf/basic/NodeComparer.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief The NodeComparer compares nodes on base of the value - * stored in a node array given as constructor parameter - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_NODECOMPARER_H -#define OGDF_NODECOMPARER_H - -#include - -namespace ogdf { - - template - class NodeComparer - { - public: - NodeComparer(NodeArray &valArray, bool ascending = true) - : m_valArray(&valArray) - { - if (ascending) - { - m_smaller = -1; -// m_greater = 1; - }//if - else - { - m_smaller = 1; -// m_greater = -1; - } - - }//constructor - - int compare(const node &v1, const node &v2) const - { - if ((*m_valArray)[v1] < (*m_valArray)[v2]) return m_smaller; - else if ((*m_valArray)[v1] > (*m_valArray)[v2]) return -m_smaller;//m_greater; - else return 0; - } - - void init(NodeArray &valArray) {m_valArray = &valArray;} - - OGDF_AUGMENT_COMPARER(node) - - private: - NodeArray *m_valArray; - int m_smaller; -// int m_greater; - - };//NodeComparer - - -}//namespace - -#endif - diff --git a/ext/OGDF/ogdf/basic/NodeSet.h b/ext/OGDF/ogdf/basic/NodeSet.h deleted file mode 100644 index f393e9011..000000000 --- a/ext/OGDF/ogdf/basic/NodeSet.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of class NodeSetSimple, - * NodeSetPure and NodeSet - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_SET_H -#define OGDF_NODE_SET_H - - -#include -#include -#include - - - -namespace ogdf { - - -//--------------------------------------------------------- -// NodeSetSimple -// maintains a subset S of the nodes contained in an associated -// graph G (only insertion of elements and clear operation) -//--------------------------------------------------------- -class OGDF_EXPORT NodeSetSimple { -public: - // creates a new empty face set associated with combinatorial embedding E - NodeSetSimple(const Graph &G) : m_isContained(G,false) { } - - // destructor - ~NodeSetSimple() { } - - // inserts node v into set S - // running time: O(1) - // Precond.: v is a node in the associated graph - void insert(node v) { - OGDF_ASSERT(v->graphOf() == m_isContained.graphOf()); - bool &isContained = m_isContained[v]; - if (isContained == false) { - isContained = true; - m_nodes.pushFront(v); - } - } - - - // removes all nodes from set S - // running time: O(|S|) - void clear() { - SListIterator it; - for(it = m_nodes.begin(); it.valid(); ++it) { - m_isContained[*it] = false; - } - m_nodes.clear(); - } - - - // returns true iff node v is contained in S - // running time: O(1) - // Precond.: v is a node in the asociated graph - bool isMember(node v) const { - OGDF_ASSERT(v->graphOf() == m_isContained.graphOf()); - return m_isContained[v]; - } - - // returns the list of nodes contained in S - const SListPure &nodes() const { - return m_nodes; - } - -private: - // m_isContained[v] is true <=> v is contained in S - NodeArray m_isContained; - // list of nodes contained in S - SListPure m_nodes; -}; - - - -//--------------------------------------------------------- -// NodeSetPure -// maintains a subset S of the nodes contained in an associated -// graph G (no efficient access to size of S) -//--------------------------------------------------------- -class OGDF_EXPORT NodeSetPure { -public: - // creates a new empty node set associated with graph G - NodeSetPure(const Graph &G) : m_it(G,ListIterator()) { } - - // destructor - ~NodeSetPure() { } - - // inserts node v into set S - // running time: O(1) - // Precond.: v is a node in the associated graph - void insert(node v) { - OGDF_ASSERT(v->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[v]; - if (!itV.valid()) - itV = m_nodes.pushBack(v); - } - - // removes node v from set S - // running time: O(1) - // Precond.: v is a node in the asociated graph - void remove(node v) { - OGDF_ASSERT(v->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[v]; - if (itV.valid()) { - m_nodes.del(itV); - itV = ListIterator(); - } - } - - - // removes all nodes from set S - // running time: O(|S|) - void clear() { - ListIterator it; - for(it = m_nodes.begin(); it.valid(); ++it) { - m_it[*it] = ListIterator(); - } - m_nodes.clear(); - } - - - // returns true iff node v is contained in S - // running time: O(1) - // Precond.: v is a node in the asociated graph - bool isMember(node v) const { - OGDF_ASSERT(v->graphOf() == m_it.graphOf()); - return m_it[v].valid(); - } - - // returns the list of nodes contained in S - const ListPure &nodes() const { - return m_nodes; - } - -private: - // m_it[v] contains list iterator pointing to v if v is contained in S, - // an invalid list iterator otherwise - NodeArray > m_it; - // list of nodes contained in S - ListPure m_nodes; -}; - - - -//--------------------------------------------------------- -// NodeSet -// maintains a subset S of the nodes contained in an associated -// graph G -//--------------------------------------------------------- -class OGDF_EXPORT NodeSet { -public: - // creates a new empty node set associated with graph G - NodeSet(const Graph &G) : m_it(G,ListIterator()) { } - - // destructor - ~NodeSet() { } - - // inserts node v into set S - // running time: O(1) - // Precond.: v is a node in the associated graph - void insert(node v) { - OGDF_ASSERT(v->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[v]; - if (!itV.valid()) - itV = m_nodes.pushBack(v); - } - - // removes node v from set S - // running time: O(1) - // Precond.: v is a node in the asociated graph - void remove(node v) { - OGDF_ASSERT(v->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[v]; - if (itV.valid()) { - m_nodes.del(itV); - itV = ListIterator(); - } - } - - - // removes all nodess from set S - // running time: O(|S|) - void clear() { - ListIterator it; - for(it = m_nodes.begin(); it.valid(); ++it) { - m_it[*it] = ListIterator(); - } - m_nodes.clear(); - } - - - // returns true iff node v is contained in S - // running time: O(1) - // Precond.: v is a node in the asociated graph - bool isMember(node v) const { - OGDF_ASSERT(v->graphOf() == m_it.graphOf()); - return m_it[v].valid(); - } - - // returns the size of set S - // running time: O(1) - int size() const { - return m_nodes.size(); - } - - // returns the list of nodes contained in S - const List &nodes() const { - return m_nodes; - } - -private: - // m_it[v] contains list iterator pointing to v if v is contained in S, - // an invalid list iterator otherwise - NodeArray > m_it; - // list of nodes contained in S - List m_nodes; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/PreprocessorLayout.h b/ext/OGDF/ogdf/basic/PreprocessorLayout.h deleted file mode 100644 index 6d2f12678..000000000 --- a/ext/OGDF/ogdf/basic/PreprocessorLayout.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Preprocessor Layout simplifies Graphs for use in other Algorithms - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PREPROCESSOR_LAYOUT_H -#define OGDF_PREPROCESSOR_LAYOUT_H - - -#include -#include - - -namespace ogdf { - - -/** \brief The PreprocessorLayout removes multi-edges and self-loops. - * - * To draw a graph using the ModularMultilevelMixer or other layouts the - * graph must be simple, i.e., contain neither multi-edges nor self-loops. - * Edges that conflict with these rules are deleted in the PreprocessorLayout. - * A secondary layout is then called that can work on the graph in required form. - * After the layout has been computed, the edges are inserted back into the - * graph, as they may have been relevant for the user. - */ -class OGDF_EXPORT PreprocessorLayout : public MultilevelLayoutModule -{ -private: - /** \brief Deleted Edges are stored in EdgeData - * - * EdgeData stores the deleted edges to allow restauration of the original - * graph after the layout has been computed. - */ - struct EdgeData - { - EdgeData(int edgeIndex, int sourceIndex, int targetIndex, double weight) - :edgeIndex(edgeIndex), sourceIndex(sourceIndex), targetIndex(targetIndex), weight(weight) - { } - - int edgeIndex; - int sourceIndex; - int targetIndex; - double weight; - }; - - ModuleOption m_secondaryLayout; - std::vector m_deletedEdges; - bool m_randomize; - - void call(Graph &G, MultilevelGraph &MLG); - -public: - - //! Constructor - PreprocessorLayout(); - - //! Destructor - ~PreprocessorLayout() { } - - - //! Calculates a drawing for the Graph \a MLG. - void call(MultilevelGraph &MLG); - - //! Calculates a drawing for the Graph \a GA. - void call(GraphAttributes &GA); - - //! Sets the secondary layout. - void setLayoutModule(LayoutModule *layout) { - m_secondaryLayout.set(layout); - } - - //! Defines whether the positions of the node are randomized before the secondary layout call. - void setRandomizePositions(bool on) { - m_randomize = on; - } -}; - - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/Queue.h b/ext/OGDF/ogdf/basic/Queue.h deleted file mode 100644 index b6df18fc4..000000000 --- a/ext/OGDF/ogdf/basic/Queue.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of list-based queues - * (classes QueuePure and Queue). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_QUEUE_H -#define OGDF_QUEUE_H - - -#include - - -namespace ogdf { - - -//! The parameterized class \a QueuePure implements list-based queues. -/** - * In contrast to Queue, instances of \a QueuePure do not store the - * number of elements contained in the queue. - * - * @tparam E is the element type. - */ -template class QueuePure : private SListPure { -public: - //! Constructs an empty queue. - QueuePure() { } - - //! Constructs a queue that is a copy of \a Q. - QueuePure(const QueuePure &Q) : SListPure(Q) { } - - // destruction - ~QueuePure() { } - - //! Returns true iff the queue is empty. - bool empty() const { return SListPure::empty(); } - - //! Returns a reference to the front element. - const E &top() const { - return SListPure::front(); - } - - //! Returns a reference to the front element. - E &top() { - return SListPure::front(); - } - - //! Returns a reference to the back element. - const E &bottom() const { - return SListPure::back(); - } - - //! Returns a reference to the back element. - E &bottom() { - return SListPure::back(); - } - - //! Assignment operator. - QueuePure &operator=(const QueuePure &Q) { - SListPure::operator=(Q); - return *this; - } - - //! Adds \a x at the end of queue. - SListIterator append(const E &x) { - return SListPure::pushBack(x); - } - - //! Removes front element and returns it. - E pop() { - E x = top(); - SListPure::popFront(); - return x; - } - - //! Makes the queue empty. - void clear() { SListPure::clear(); } - - //! Conversion to const SListPure. - const SListPure &getListPure() const { return *this; } - - OGDF_NEW_DELETE -}; // class QueuePure - - -//! The parameterized class \a Queue implements list-based queues. -/** - * In contrast to QueuePure, instances of \a Queue store the - * number of elements contained in the queue. - * - * @tparam E is the element type. - */ -template class Queue : private SList { -public: - //! Constructs an empty queue. - Queue() { } - - //! Constructs a queue that is a copy of \a Q. - Queue(const Queue &Q) : SList(Q) { } - - // destruction - ~Queue() { } - - //! Returns true iff the queue is empty. - bool empty() const { return SList::empty(); } - - //! Returns the number of elements in the queue. - int size() const { return SList::size(); } - - //! Returns a reference to the front element. - const E &top() const { - return SList::front(); - } - - //! Returns a reference to the front element. - E &top() { - return SList::front(); - } - - //! Returns a reference to the back element. - const E &bottom() const { - return SListPure::back(); - } - - //! Returns a reference to the back element. - E &bottom() { - return SListPure::back(); - } - - //! Assignment operator. - Queue &operator=(const Queue &Q) { - SList::operator=(Q); - return *this; - } - - //! Adds \a x at the end of queue. - SListIterator append(const E &x) { - return SList::pushBack(x); - } - - //! Removes front element and returns it. - E pop() { - E x = top(); - SList::popFront(); - return x; - } - - //! Makes the queue empty. - void clear() { SList::clear(); } - - //! Conversion to const SList. - const SList &getList() const { return *this; } - //! Conversion to const SListPure. - const SListPure &getListPure() const { return SList::getListPure(); } - - OGDF_NEW_DELETE -}; // class Queue - - -// prints queue to output stream os using delimiter delim -template -void print(ostream &os, const QueuePure &Q, char delim = ' ') -{ print(os,Q.getListPure(),delim); } - -// prints queue to output stream os using delimiter delim -template -void print(ostream &os, const Queue &Q, char delim = ' ') -{ print(os,Q.getListPure(),delim); } - - -// output operator -template -ostream &operator<<(ostream &os, const QueuePure &Q) -{ - print(os,Q); return os; -} - -template -ostream &operator<<(ostream &os, const Queue &Q) -{ - print(os,Q); return os; -} - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/SList.h b/ext/OGDF/ogdf/basic/SList.h deleted file mode 100644 index da7868608..000000000 --- a/ext/OGDF/ogdf/basic/SList.h +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of singly linked lists - * (SListPure and SList) and iterators (SListConstIterator - * and SListIterator). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SLIST_H -#define OGDF_SLIST_H - - -#include - - -namespace ogdf { - - -template class SListPure; -template class StackPure; -template class SListIterator; -template class SListConstIterator; - - -//! The parameterized class \a SListElement represents the structure for elements of singly linked lists. -template -class SListElement { - friend class SListPure; - friend class StackPure; - friend class SListIterator; - friend class SListConstIterator; - - SListElement *m_next; //!< Pointer to successor element. - E m_x; //!< Stores the content. - - //! Constructs an SListElement. - SListElement() : m_next(0) { } - //! Constructs an SListElement. - SListElement(const E &x) : m_next(0), m_x(x) { } - //! Constructs an SListElement. - SListElement(const E &x, SListElement *next) : - m_next(next), m_x(x) { } - - OGDF_NEW_DELETE -}; // class SListElement - - - -//! The parameterized class \a SListIterator encapsulates a pointer to an slist element. -/** - * It is used in order to iterate over singly linked lists, - * and to specify a position in a singly linked list. It is possible that - * an iterator encapsulates a null pointer. - */ - -template class SListIterator { - SListElement *m_pX; //!< Pointer to slist element. - - friend class SListConstIterator; - friend class SListPure; - - //! Conversion to pointer to slist element. - operator SListElement *() { return m_pX; } - //! Conversion to pointer to slist element. - operator const SListElement *() const { return m_pX; } - -public: - //! Constructs an iterator pointing to no element. - SListIterator() : m_pX(0) { } - //! Constructs an iterator pointing to \a pX. - SListIterator(SListElement *pX) : m_pX(pX) { } - //! Constructs an iterator that is a copy of \a it. - SListIterator(const SListIterator &it) : m_pX(it.m_pX) { } - - //! Returns true iff the iterator points to an element. - bool valid() const { return m_pX != 0; } - - //! Equality operator. - bool operator==(const SListIterator &it) const { - return m_pX == it.m_pX; - } - - //! Inequality operator. - bool operator!=(const SListIterator &it) const { - return m_pX != it.m_pX; - } - - //! Returns successor iterator. - SListIterator succ() const { return m_pX->m_next; } - - //! Returns a reference to the element content. - E &operator*() const { return m_pX->m_x; } - - //! Assignment operator. - SListIterator &operator=(const SListIterator &it) { - m_pX = it.m_pX; - return *this; - } - - //! Increment operator (prefix). - SListIterator &operator++() { - m_pX = m_pX->m_next; - return *this; - } - - //! Increment operator (postfix). - SListIterator operator++(int) { - SListIterator it = *this; - m_pX = m_pX->m_next; - return it; - } - - OGDF_NEW_DELETE -}; // class SListIterator - - - -//! The parameterized class \a SListIterator encapsulates a constant pointer to an slist element. -/** - * It is used in order to iterate over singly linked lists, - * and to specify a position in a singly linked list. It is possible that - * an iterator encapsulates a null pointer. In contrast to SListIterator, - * it is not possible to change the slist element pointed to. - */ - -template class SListConstIterator { - const SListElement *m_pX; //!< Pointer to slist element. - - friend class SListPure; - - //! Conversion to pointer to slist element. - operator const SListElement *() { return m_pX; } - -public: - //! Constructs an iterator pointing to no element. - SListConstIterator() : m_pX(0) { } - - //! Constructs an iterator pointing to \a pX. - SListConstIterator(const SListElement *pX) : m_pX(pX) { } - - //! Constructs an iterator that is a copy of \a it. - SListConstIterator(const SListIterator &it) : m_pX((const SListElement *)it) { } - //! Constructs an iterator that is a copy of \a it. - SListConstIterator(const SListConstIterator &it) : m_pX(it.m_pX) { } - - //! Returns true iff the iterator points to an element. - bool valid() const { return m_pX != 0; } - - //! Equality operator. - bool operator==(const SListConstIterator &it) const { - return m_pX == it.m_pX; - } - - //! Inequality operator. - bool operator!=(const SListConstIterator &it) const { - return m_pX != it.m_pX; - } - - //! Returns successor iterator. - SListConstIterator succ() const { return m_pX->m_next; } - - //! Returns a reference to the element content. - const E &operator*() const { return m_pX->m_x; } - - //! Assignment operator. - SListConstIterator &operator=(const SListConstIterator &it) { - m_pX = it.m_pX; - return *this; - } - - - //! Increment operator (prefix). - SListConstIterator &operator++() { - m_pX = m_pX->m_next; - return *this; - } - - //! Increment operator (postfix). - SListConstIterator operator++(int) { - SListConstIterator it = *this; - m_pX = m_pX->m_next; - return it; - } - - OGDF_NEW_DELETE -}; // class SListConstIterator - - -//! The parameterized class \a SListPure represents singly linked lists with content type \a E. -/** - * Elements of the list are instances of type SListElement. - * Use SListConstIterator or SListIterator in order to iterate over the list. - * - * In contrast to SList, instances of \a SListPure do not store the length of the list. - * - * @tparam E is the data type stored in list elements. - */ - -template class SListPure { - SListElement *m_head; //!< Pointer to first element. - SListElement *m_tail; //!< Pointer to last element. - -public: - //! Constructs an empty singly linked list. - SListPure() : m_head(0), m_tail(0) { } - - //! Constructs a singly linked list that is a copy of \a L. - SListPure(const SListPure &L) : m_head(0), m_tail(0) { - copy(L); - } - - // destruction - ~SListPure() { clear(); } - - typedef E value_type; - typedef SListElement element_type; - typedef SListConstIterator const_iterator; - typedef SListIterator iterator; - - //! Returns true iff the list is empty. - bool empty() const { return m_head == 0; } - - //! Returns the length of the list - /** - * Notice that this method requires to run through the whole list and takes linear running time! - */ - int size() const { - int count = 0; - for (SListElement *pX = m_head; pX; pX = pX->m_next) - ++count; - return count; - } - - //! Returns an iterator to the first element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - SListConstIterator begin() const { return m_head; } - - //! Returns an iterator to the first element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - SListIterator begin() { return m_head; } - - //! Returns an iterator to one-past-last element of the list. - /** - * This is always a null pointer iterator. - */ - SListConstIterator end() const { return SListConstIterator(); } - - //! Returns an iterator to one-past-last element of the list. - /** - * This is always a null pointer iterator. - */ - SListIterator end() { return SListIterator(); } - - //! Returns an iterator to the last element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - SListConstIterator rbegin() const { return m_tail; } - - //! Returns an iterator to the last element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - SListIterator rbegin() { return m_tail; } - - - //! Returns an iterator pointing to the element at position \a pos. - /** - * The running time of this method is linear in \a pos. - */ - SListConstIterator get(int pos) const { - SListElement *pX; - for(pX = m_head; pX != 0; pX = pX->m_next) - if (pos-- == 0) break; - return pX; - } - - //! Returns an iterator pointing to the element at position \a pos. - /** - * The running time of this method is linear in \a pos. - */ - SListIterator get(int pos) { - SListElement *pX; - for(pX = m_head; pX != 0; pX = pX->m_next) - if (pos-- == 0) break; - return pX; - } - - //! Returns the position (starting with 0) of \a it in the list. - /** - * Positions are numbered 0,1,... - * \pre \a it is an iterator pointing to an element in this list. - */ - int pos(SListConstIterator it) const { - OGDF_ASSERT(it.valid()) - int p = 0; - for(SListElement *pX = m_head; pX != 0; pX = pX->m_next, ++p) - if (pX == it) break; - return p; - } - - - //! Returns a reference to the first element. - /** - * \pre The list is not empty! - */ - const E &front() const { - OGDF_ASSERT(m_head != 0) - return m_head->m_x; - } - - //! Returns a reference to the first element. - /** - * \pre The list is not empty! - */ - E &front() { - OGDF_ASSERT(m_head != 0) - return m_head->m_x; - } - - //! Returns a reference to the last element. - /** - * \pre The list is not empty! - */ - const E &back() const { - OGDF_ASSERT(m_tail != 0) - return m_tail->m_x; - } - - //! Returns a reference to the last element. - /** - * \pre The list is not empty! - */ - E &back() { - OGDF_ASSERT(m_tail != 0) - return m_tail->m_x; - } - - //! Returns an iterator to the cyclic successor of \a it. - /** - * \pre \a it points to an element in this list! - */ - SListConstIterator cyclicSucc(SListConstIterator it) const { - const SListElement *pX = it; - return (pX->m_next) ? pX->m_next : m_head; - } - - //! Returns an iterator to the cyclic successor of \a it. - /** - * \pre \a it points to an element in this list! - */ - SListIterator cyclicSucc(SListIterator it) { - SListElement *pX = it; - return (pX->m_next) ? pX->m_next : m_head; - } - - //! Assignment operator. - SListPure &operator=(const SListPure &L) { - clear(); copy(L); - return *this; - } - - //! Adds element \a x at the begin of the list. - SListIterator pushFront(const E &x) { - m_head = OGDF_NEW SListElement(x,m_head); - if (m_tail == 0) m_tail = m_head; - return m_head; - } - - //! Adds element \a x at the end of the list. - SListIterator pushBack(const E &x) { - SListElement *pNew = OGDF_NEW SListElement(x); - if (m_head == 0) - m_head = m_tail = pNew; - else - m_tail = m_tail->m_next = pNew; - return m_tail; - } - - //! Inserts element \a x after \a pBefore. - /** - * \pre \a pBefore points to an element in this list. - */ - SListIterator insertAfter(const E &x, SListIterator itBefore) { - SListElement *pBefore = itBefore; - OGDF_ASSERT(pBefore != 0) - SListElement *pNew = OGDF_NEW SListElement(x,pBefore->m_next); - if (pBefore == m_tail) m_tail = pNew; - return (pBefore->m_next = pNew); - } - - //! Removes the first element from the list. - /** - * \pre The list is not empty! - */ - void popFront() { - OGDF_ASSERT(m_head != 0) - SListElement *pX = m_head; - if ((m_head = m_head->m_next) == 0) m_tail = 0; - delete pX; - } - - //! Removes the first element from the list and returns it. - /** - * \pre The list is not empty! - */ - E popFrontRet() { - E el = front(); - popFront(); - return el; - } - - //! Removes the succesor of \a pBefore. - /** - * \pre \a pBefore points to an element in this list. - */ - void delSucc(SListIterator itBefore) { - SListElement *pBefore = itBefore; - OGDF_ASSERT(pBefore != 0) - SListElement *pDel = pBefore->m_next; - OGDF_ASSERT(pDel != 0) - if ((pBefore->m_next = pDel->m_next) == 0) m_tail = pBefore; - delete pDel; - } - - //! Moves the first element of this list to the begin of list \a L2. - void moveFrontToFront(SListPure &L2) { - OGDF_ASSERT(m_head != 0) - OGDF_ASSERT(this != &L2) - SListElement *pX = m_head; - if ((m_head = m_head->m_next) == 0) m_tail = 0; - pX->m_next = L2.m_head; - L2.m_head = pX; - if (L2.m_tail == 0) L2.m_tail = L2.m_head; - } - - //! Moves the first element of this list to the end of list \a L2. - void moveFrontToBack(SListPure &L2) { - OGDF_ASSERT(m_head != 0) - OGDF_ASSERT(this != &L2) - SListElement *pX = m_head; - if ((m_head = m_head->m_next) == 0) m_tail = 0; - pX->m_next = 0; - if (L2.m_head == 0) - L2.m_head = L2.m_tail = pX; - else - L2.m_tail = L2.m_tail->m_next = pX; - } - - //! Moves the first element of this list to list \a L2 inserted after \a itBefore. - /** - * \pre \a itBefore points to an element in \a L2. - */ - void moveFrontToSucc(SListPure &L2, SListIterator itBefore) { - OGDF_ASSERT(m_head != 0) - OGDF_ASSERT(this != &L2) - SListElement *pBefore = itBefore; - SListElement *pX = m_head; - if ((m_head = m_head->m_next) == 0) m_tail = 0; - pX->m_next = pBefore->m_next; - pBefore->m_next = pX; - if (pBefore == L2.m_tail) L2.m_tail = pX; - } - - //! Removes all elements from the list. - void clear() { - if (m_head == 0) return; - -#if (_MSC_VER == 1100) -// workaround for bug in Visual Studio 5.0 - - while (!empty()) - popFront(); - -#else - - if (doDestruction((E*)0)) { - for(SListElement *pX = m_head; pX != 0; pX = pX->m_next) - pX->m_x.~E(); - } - OGDF_ALLOCATOR::deallocateList(sizeof(SListElement),m_head,m_tail); - -#endif - - m_head = m_tail = 0; - } - - //! Appends \a L2 to this list and makes \a L2 empty. - void conc(SListPure &L2) { - if (m_head) - m_tail->m_next = L2.m_head; - else - m_head = L2.m_head; - if (L2.m_tail != 0) m_tail = L2.m_tail; - L2.m_head = L2.m_tail = 0; - } - - //! Reverses the order of the list elements. - void reverse() { - SListElement *p, *pNext, *pPred = 0; - for(p = m_head; p; p = pNext) { - pNext = p->m_next; - p->m_next = pPred; - pPred = p; - } - swap(m_head,m_tail); - } - - //! Conversion to const SListPure. - const SListPure &getListPure() const { return *this; } - - //! Sorts the list using Quicksort. - void quicksort() { - ogdf::quicksortTemplate(*this); - } - - //! Sorts the list using Quicksort and comparer \a comp. - template - void quicksort(const COMPARER &comp) { - ogdf::quicksortTemplate(*this,comp); - } - - //! Sorts the list using bucket sort. - /** - * @param l is the lowest bucket that will occur. - * @param h is the highest bucket that will occur. - * @param f returns the bucket for each element. - * \pre The bucket function \a f will only return bucket values between \a l - * and \a h for this list. - */ - void bucketSort(int l, int h, BucketFunc &f); - - //! Sorts the list using bucket sort. - void bucketSort(BucketFunc &f); - - //! Randomly permutes the elements in the list. - void permute() { - permute(size()); - } - - //! Scans the list for the specified element and returns its position in the list, or -1 if not found. - int search (const E& e) const { - int x = 0; - for(SListConstIterator i = begin(); i.valid(); ++i, ++x) - if(*i == e) return x; - return -1; - } - - //! Scans the list for the specified element (using the user-defined comparer) and returns its position in the list, or -1 if not found. - template - int search (const E& e, const COMPARER &comp) const { - int x = 0; - for(SListConstIterator i = begin(); i.valid(); ++i, ++x) - if(comp.equal(*i,e)) return x; - return -1; - } - -protected: - void copy(const SListPure &L) { - for(SListElement *pX = L.m_head; pX != 0; pX = pX->m_next) - pushBack(pX->m_x); - } - - void permute(const int n); - - OGDF_NEW_DELETE -}; // class SListPure - - - -//! The parameterized class \a SList represents singly linked lists with content type \a E. -/** - * Elements of the list are instances of type SListElement. - * Use SListConstIterator or SListIterator in order to iterate over the list. - * In contrast to SListPure, instances of \a SList store the length of the list - * and thus allow constant time access to the length. - * - * @tparam E is the data type stored in list elements. - */ - -template -class SList : private SListPure { - - int m_count; //!< The length of the list. - -public: - //! Constructs an empty singly linked list. - SList() : m_count(0) { } - - //! Constructs a singly linked list that is a copy of \a L. - SList(const SList &L) : SListPure(L), m_count(L.m_count) { } - - // destruction - ~SList() { } - - typedef E value_type; - typedef SListElement element_type; - typedef SListConstIterator const_iterator; - typedef SListIterator iterator; - - //! Returns true iff the list is empty. - bool empty() const { return SListPure::empty(); } - - //! Returns the length of the list. - int size() const { return m_count; } - - //! Returns an iterator to the first element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - const SListConstIterator begin() const { return SListPure::begin(); } - - //! Returns an iterator to the first element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - SListIterator begin() { return SListPure::begin(); } - - //! Returns an iterator to one-past-last element of the list. - /** - * This is always a null pointer iterator. - */ - SListConstIterator end() const { return SListConstIterator(); } - - //! Returns an iterator to one-past-last element of the list. - /** - * This is always a null pointer iterator. - */ - SListIterator end() { return SListIterator(); } - - //! Returns an iterator to the last element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - const SListConstIterator rbegin() const { return SListPure::rbegin(); } - - //! Returns an iterator to the last element of the list. - /** - * If the list is empty, a null pointer iterator is returned. - */ - SListIterator rbegin() { return SListPure::rbegin(); } - - - //! Returns an iterator pointing to the element at position \a pos. - /** - * The running time of this method is linear in \a pos. - */ - SListConstIterator get(int pos) const { - return SListPure::get(pos); - } - - //! Returns an iterator pointing to the element at position \a pos. - /** - * The running time of this method is linear in \a pos. - */ - SListIterator get(int pos) { - return SListPure::get(pos); - } - - //! Returns the position (starting with 0) of \a it in the list. - /** - * Positions are numbered 0,1,... - * \pre \a it is an iterator pointing to an element in this list. - */ - int pos(SListConstIterator it) const { - return SListPure::pos(it);; - } - - - //! Returns a reference to the first element. - /** - * \pre The list is not empty! - */ - const E &front() const { return SListPure::front(); } - - //! Returns a reference to the first element. - /** - * \pre The list is not empty! - */ - E &front() { return SListPure::front(); } - - //! Returns a reference to the last element. - /** - * \pre The list is not empty! - */ - const E &back() const { return SListPure::back(); } - - //! Returns a reference to the last element. - /** - * \pre The list is not empty! - */ - E &back() { return SListPure::back(); } - - //! Returns an iterator to the cyclic successor of \a it. - /** - * \pre \a it points to an element in this list! - */ - SListConstIterator cyclicSucc(SListConstIterator it) const { - return SListPure::cyclicSucc(it); - } - - //! Returns an iterator to the cyclic successor of \a it. - /** - * \pre \a it points to an element in this list! - */ - SListIterator cyclicSucc(SListIterator it) { - return SListPure::cyclicSucc(it); - } - - //! Assignment operator. - SList &operator=(const SList &L) { - SListPure::operator=(L); - m_count = L.m_count; - return *this; - } - - //! Adds element \a x at the begin of the list. - SListIterator pushFront(const E &x) { - ++m_count; - return SListPure::pushFront(x); - } - - //! Adds element \a x at the end of the list. - SListIterator pushBack(const E &x) { - ++m_count; - return SListPure::pushBack(x); - } - - //! Inserts element \a x after \a pBefore. - /** - * \pre \a pBefore points to an element in this list. - */ - SListIterator insertAfter(const E &x, SListIterator itBefore) { - ++m_count; - return SListPure::insertAfter(x, itBefore); - } - - //! Removes the first element from the list. - /** - * \pre The list is not empty! - */ - void popFront() { - --m_count; - SListPure::popFront(); - } - - //! Removes the first element from the list and returns it. - /** - * \pre The list is not empty! - */ - E popFrontRet() { - E el = front(); - popFront(); - return el; - } - - //! Removes the succesor of \a pBefore. - /** - * \pre \a pBefore points to an element in this list. - */ - void delSucc(SListIterator itBefore) { - --m_count; - SListPure::delSucc(itBefore); - } - - //! Moves the first element of this list to the begin of list \a L2. - void moveFrontToFront(SList &L2) { - SListPure::moveFrontToFront(L2); - --m_count; ++L2.m_count; - } - - //! Moves the first element of this list to the end of list \a L2. - void moveFrontToBack(SList &L2) { - SListPure::moveFrontToBack(L2); - --m_count; ++L2.m_count; - } - - //! Moves the first element of this list to list \a L2 inserted after \a itBefore. - /** - * \pre \a itBefore points to an element in \a L2. - */ - void moveFrontToSucc(SList &L2, SListIterator itBefore) { - SListPure::moveFrontToSucc(L2,itBefore); - --m_count; ++L2.m_count; - } - - //! Removes all elements from the list. - void clear() { - m_count = 0; - SListPure::clear(); - } - - //! Appends \a L2 to this list and makes \a L2 empty. - void conc(SList &L2) { - SListPure::conc(L2); - m_count += L2.m_count; - L2.m_count = 0; - } - - //! Reverses the order of the list elements. - void reverse() { - SListPure::reverse(); - } - - //! Conversion to const SListPure. - const SListPure &getListPure() const { return *this; } - - //! Sorts the list using Quicksort. - void quicksort() { - ogdf::quicksortTemplate(*this); - } - - //! Sorts the list using Quicksort and comparer \a comp. - template - void quicksort(const COMPARER &comp) { - ogdf::quicksortTemplate(*this,comp); - } - - //! Sorts the list using bucket sort. - /** - * @param l is the lowest bucket that will occur. - * @param h is the highest bucket that will occur. - * @param f returns the bucket for each element. - * \pre The bucket function \a f will only return bucket values between \a l - * and \a h for this list. - */ - void bucketSort(int l, int h, BucketFunc &f) { - SListPure::bucketSort(l,h,f); - } - - //! Sorts the list using bucket sort. - void bucketSort(BucketFunc &f) { - SListPure::bucketSort(f); - } - - //! Randomly permutes the elements in the list. - void permute() { - SListPure::permute(m_count); - } - - //! Scans the list for the specified element and returns its position in the list, or -1 if not found. - int search (const E& e) const { - return SListPure::search(e); - } - - //! Scans the list for the specified element (using the user-defined comparer) and returns its position in the list, or -1 if not found. - template - int search (const E& e, const COMPARER &comp) const { - return SListPure::search(e, comp); - } - - OGDF_NEW_DELETE -}; // class SList - - - - -// sorts list L using bucket sort -// computes l and h value -template -void SListPure::bucketSort(BucketFunc &f) -{ - // if less than two elements, nothing to do - if (m_head == m_tail) return; - - int l, h; - l = h = f.getBucket(m_head->m_x); - - SListElement *pX; - for(pX = m_head->m_next; pX; pX = pX->m_next) - { - int i = f.getBucket(pX->m_x); - if (i < l) l = i; - if (i > h) h = i; - } - - bucketSort(l,h,f); -} - - -// sorts list L using bucket sort -template -void SListPure::bucketSort(int l, int h, BucketFunc &f) -{ - // if less than two elements, nothing to do - if (m_head == m_tail) return; - - Array *> head(l,h,0), tail(l,h); - - SListElement *pX; - for (pX = m_head; pX; pX = pX->m_next) { - int i = f.getBucket(pX->m_x); - if (head[i]) - tail[i] = (tail[i]->m_next = pX); - else - head[i] = tail[i] = pX; - } - - SListElement *pY = 0; - for (int i = l; i <= h; i++) { - pX = head[i]; - if (pX) { - if (pY) - pY->m_next = pX; - else - m_head = pX; - pY = tail[i]; - } - } - - m_tail = pY; - pY->m_next = 0; -} - - -// permutes elements in list randomly; n is the length of the list -template -void SListPure::permute(const int n) -{ - Array *> A(n+1); - A[n] = 0; - - int i = 0; - SListElement *pX; - for (pX = m_head; pX; pX = pX->m_next) - A[i++] = pX; - - A.permute(0,n-1); - - for (i = 0; i < n; i++) { - A[i]->m_next = A[i+1]; - } - - m_head = A[0]; - m_tail = A[n-1]; -} - -// prints list to output stream os using delimiter delim -template -void print(ostream &os, const SListPure &L, char delim = ' ') -{ - SListConstIterator pX = L.begin(); - if (pX.valid()) { - os << *pX; - for(++pX; pX.valid(); ++pX) - os << delim << *pX; - } -} - -// prints list to output stream os using delimiter delim -template -void print(ostream &os, const SList &L, char delim = ' ') -{ - print(L.getListPure(), delim); -} - -// output operator -template -ostream &operator<<(ostream &os, const SListPure &L) -{ - print(os,L); - return os; -} - -template -ostream &operator<<(ostream &os, const SList &L) -{ - return operator<<(os,L.getListPure()); -} - - -// sort array using bucket sort and bucket object f; -// the values of f must be in the interval [min,max] -template -void bucketSort(Array &a, int min, int max, BucketFunc &f) -{ - if (a.low() >= a.high()) return; - - Array > bucket(min,max); - - int i; - for(i = a.low(); i <= a.high(); ++i) - bucket[f.getBucket(a[i])].pushBack(a[i]); - - i = a.low(); - for(int j = min; j <= max; ++j) { - SListConstIterator it = bucket[j].begin(); - for(; it.valid(); ++it) - a[i++] = *it; - } -} - - - - -} // namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Skiplist.h b/ext/OGDF/ogdf/basic/Skiplist.h deleted file mode 100644 index f5f9ebf51..000000000 --- a/ext/OGDF/ogdf/basic/Skiplist.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Skiplist. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_SKIPLIST_H -#define OGDF_SKIPLIST_H - -#include - -namespace ogdf { - -template class SkiplistIterator; - -//! A randomized skiplist -/** - * The elements height is computed using the traditional coin-flip method, using a - * 50-50 chance to stop growing. The given running times of the methods below are therefore - * only expected running times. - * - * \warning The code expects the type \a X to be a pointer! If \a X is not a pointer, - * compiler errors will occur! - */ -template class Skiplist { - friend class SkiplistIterator; - friend class Element; - - //! Internal structure to hold the items and internal forward pointers of the skiplist - class Element { - friend class Skiplist; - friend class SkiplistIterator; - - X entry; // content - Element** next; // successor elements - - // construction - Element(const X &item, int height) : - entry(item) { - next = (Element**)malloc(height*sizeof(Element*)); - } - - ~Element() { - free(next); - } - - OGDF_NEW_DELETE - }; - -public: - - //! Construct an initially empty skiplist - Skiplist() : lSize(0) { - srand((unsigned int)time(NULL)); - realheight = 5; - height = 1; - start = (Element**)malloc(realheight*sizeof(Element*)); - start[0] = NULL; - } - - ~Skiplist() { - clear(); - free(start); - } - - //! Returns true if the item \a item is contained in the skiplist [O'(log n)] - bool isElement(X item) const { - int h = height - 1; - Element** cur = start; // wheeha! - while(true) { - if( cur[h] && *(cur[h]->entry) < *item ) //nxt != NULL - cur = cur[h]->next; - else if(--h < 0) - return cur[0] && *(cur[0]->entry) == *item; - } - } - - //! Adds the item \a item into the skiplist [O'(log n)] - void add(X item) { - lSize++; - - int nh = random_height(); - Element* n = OGDF_NEW Element(item, nh); - if(nh > height) - grow(nh); - - int h = height - 1; - Element** cur = start; // wheeha! - while(true) { - if( cur[h] && *(cur[h]->entry) < *item ) //nxt != NULL - cur = cur[h]->next; - else { - if(h < nh) { // add only if new element is high enough - n->next[h] = cur[h]; - cur[h] = n; - } - if(--h < 0) - return; - } - } - } - - //! Returns the current size of the skiplist, i.e., the number of elements - int size() const { return lSize; } - - //! Returns true if the skiplist contains no elements - int empty() const { return (lSize==0); } - - //! Clears the current skiplist - /** - * If \a killData is true, the items of the Skiplist (which are stored as - * pointers) are automatically deleted. - */ - void clear(bool killData = false) { - Element* item = start[0]; - Element* old; - while(item) { - old = item; - item = item->next[0]; - if(killData) - delete old->entry; - delete old; - } - lSize = 0; - height = 1; - start[0] = 0; - } - - //! returns an (forward) iterator for the skiplist - const SkiplistIterator begin() const { return start[0]; } - -private: - int lSize; - Element** start; - int height; - int realheight; - - int random_height() { - int h = 1; - while(rand() > RAND_MAX/2) h++; - return h; - } - - void grow(int newheight) { - if(newheight > realheight) { - realheight = newheight; - start = (Element**)realloc(start, realheight*sizeof(Element*)); - } - for(int i = newheight; i-->height;) { - start[i] = NULL; - } - height = newheight; - } - -}; - -//! Forward-Iterator for Skiplists -template class SkiplistIterator { - friend class Skiplist; - - const typename Skiplist::Element *el; - - SkiplistIterator(const typename Skiplist::Element *e) { el = e; } - -public: - - //! Returns the item to which the iterator points - const X &operator*() const { return el->entry; } - - bool valid() const { return (el != 0); } - - //! Move the iterator one item forward (prefix notation) - SkiplistIterator &operator++() { - el = el->next[0]; - return *this; - } - //! Move the iterator one item forward (prefix notation) - SkiplistIterator operator++(int) { - SkiplistIterator it = *this; - el = el->next[0]; - return it; - } - - //! Assignment operator - SkiplistIterator &operator=(const SkiplistIterator &it) { - el = it.el; - return *this; - } -}; - -} - -#endif /*OGDF_SKIPLIST_H*/ diff --git a/ext/OGDF/ogdf/basic/Stack.h b/ext/OGDF/ogdf/basic/Stack.h deleted file mode 100644 index fd5e9ab7e..000000000 --- a/ext/OGDF/ogdf/basic/Stack.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of list-based stacks - * (StackPure and Stack). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_STACK_H -#define OGDF_STACK_H - - -#include - - -namespace ogdf { - - -//! List-based stacks. -/** - * In contrast to Stack, instances of \a StackPure do not store the - * number of elements contained in the stack. - * - * @tparam E is the element type. - */ -template class StackPure -{ - struct Element { - Element(const E &x, Element *pNext) : m_next(pNext), m_x(x) { } - Element *m_next; - E m_x; - OGDF_NEW_DELETE - }; - - Element *m_head; - -public: - //! Constructs an empty stack. - StackPure() { m_head = 0; } - - //! Constructs a stack that is a copy of \a S. - StackPure(const StackPure &S) { - m_head = 0; - copy(S); - } - - // destruction - ~StackPure() { - clear(); - } - - //! Returns true iff the stack is empty. - bool empty() const { return m_head == 0; } - - //! Returns a reference to the top element. - const E &top() const { - return m_head->m_x; - } - - //! Returns a reference to the top element. - E &top() { - return m_head->m_x; - } - - //! Assignment operator. - StackPure &operator=(const StackPure &S) { - clear(); - copy(S); - return *this; - } - - //! Adds element \a x as top-most element to the stack. - void push(const E &x) { - m_head = OGDF_NEW Element(x,m_head); - } - - //! Removes the top-most element from the stack and returns it. - E pop() { - OGDF_ASSERT(m_head != 0) - Element *pX = m_head; - m_head = m_head->m_next; - E x = pX->m_x; - delete pX; - return x; - } - - //! Makes the stack empty. - void clear() { - while(m_head) { - Element *pX = m_head; - m_head = m_head->m_next; - delete pX; - } - } - - void print(ostream &os, char delim = ' ') const - { - Element *pX = m_head; - if (pX != 0) { - os << pX->m_x; - for(pX = pX->m_next; pX != 0; pX = pX->m_next) - os << delim << pX->m_x; - } - } - -private: - void copy(const StackPure &S) { - Element **p = &m_head; - - for(Element *q = S.m_head; q != 0; q = q->m_next) { - *p = OGDF_NEW Element(q->m_x,0); - p = &(*p)->m_next; - } - } - - OGDF_NEW_DELETE -}; // class StackPure - - -//! The parameterized class \a Stack implements list-based stacks -/** - * In contrast to StackPure, instances of \a Stack store the - * number of elements contained in the stack. - * - * @tparam E is the element type. - */ -template class Stack : private StackPure -{ - int m_count; //! The number of elements in the list. - -public: - //! Constructs an empty stack. - Stack() { m_count = 0; } - - //! Constructs a stack that is a copy of \a S. - Stack(const Stack &S) : StackPure(S) { m_count = S.m_count; } - - // destruction - ~Stack() { } - - //! Returns true iff the stack is empty. - bool empty() const { return StackPure::empty(); } - - //! Returns the number of elements contained in the stack. - int size() const { return m_count; } - - //! Returns a reference to the top element. - const E &top() const { - return StackPure::top(); - } - - //! Returns a reference to the top element. - E &top() { - return StackPure::top(); - } - - //! Assignment operator. - Stack &operator=(const Stack &S) { - StackPure::operator=(S); - m_count = S.m_count; - return *this; - } - - //! Adds element \a x as top-most element to the stack. - void push(const E &x) { - ++m_count; - return StackPure::push(x); - } - - //! Removes the top-most element from the stack and returns it. - E pop() { - --m_count; - return StackPure::pop(); - } - - //! Makes the stack empty. - void clear() { - StackPure::clear(); - m_count = 0; - } - - void print(ostream &os, char delim = ' ') const { - StackPure::print(os,delim); - } - - OGDF_NEW_DELETE -}; // class Stack - - - -template -ostream &operator<<(ostream &os, const StackPure &S) -{ - S.print(os); - return os; -} - - -template -ostream &operator<<(ostream &os, const Stack &S) -{ - S.print(os); - return os; -} - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/String.h b/ext/OGDF/ogdf/basic/String.h deleted file mode 100644 index fd5e7ecf8..000000000 --- a/ext/OGDF/ogdf/basic/String.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * $Revision: 2619 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 16:05:39 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class String. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_STRING_H -#define OGDF_STRING_H - - -#include -#include - - -#define OGDF_STRING_BUFFER_SIZE 1024 - - -namespace ogdf { - - -//! Representation of character strings. -/** - * Strings are internally stored as an Ascii character array. The positions - * within a string a numbered 0,1,... - */ -class OGDF_EXPORT String { - - char *m_pChar; //!< Pointer to characters. - size_t m_length; //!< The length of the string (number of characters). - - static char s_pBuffer[OGDF_STRING_BUFFER_SIZE]; //!< Temporary buffer used by sprintf(). - -public: - //! Constructs an empty string, i.e., a string with length 0. - String(); - //! Constructs a string consisting of a single character \a c. - String(const char c); - //! Constructs a string that is a copy of \a str. - String(const char *str); - //String(const char *format, ...); - //! Constructs a string consisting of the first \a maxLen characters of \a str. - /** - * @param maxLen is the number of characters to be copied from the begin of \a str. - * If \a str is shorter than \a maxLen, then the complete string is copied. - * @param str is the string to be copied. - */ - String(size_t maxLen, const char *str); - //! Constructs a string that is a copy of \a str. - String(const String &str); - - ~String(); - - //! Cast a string into a 0-terminated C++ string. - //operator const char *() const { return m_pChar; } - const char *cstr() const { return m_pChar; } - - //! Returns the length of the string. - size_t length() const { return m_length; } - - //! Returns a reference to the character at position \a i. - char &operator[](size_t i) { - OGDF_ASSERT(i < m_length) - return m_pChar[i]; - } - - //! Returns a reference to the character at position \a i. - const char &operator[](size_t i) const { - OGDF_ASSERT(i < m_length) - return m_pChar[i]; - } - - //! Equality operator. - friend bool operator==(const String &x, const String &y) { - return (compare(x,y) == 0); - } - //! Equality operator. - friend bool operator==(const char *x, const String &y) { - return (compare(x,y) == 0); - } - //! Equality operator. - friend bool operator==(const String &x, const char *y) { - return (compare(x,y) == 0); - } - - //! Inequality operator. - friend bool operator!=(const String &x, const String &y) { - return (compare(x,y) != 0); - } - //! Inequality operator. - friend bool operator!=(const char *x, const String &y) { - return (compare(x,y) != 0); - } - //! Inequality operator. - friend bool operator!=(const String &x, const char *y) { - return (compare(x,y) != 0); - } - - //! Less than operator. - friend bool operator<(const String &x, const String &y) { - return (compare(x,y) < 0); - } - //! Less than operator. - friend bool operator<(const char *x, const String &y) { - return (compare(x,y) < 0); - } - //! Less than operator. - friend bool operator<(const String &x, const char *y) { - return (compare(x,y) < 0); - } - - //! Less or equal than operator. - friend bool operator<=(const String &x, const String &y) { - return (compare(x,y) <= 0); - } - //! Less or equal than operator. - friend bool operator<=(const char *x, const String &y) { - return (compare(x,y) <= 0); - } - //! Less or equal than operator. - friend bool operator<=(const String &x, const char *y) { - return (compare(x,y) <= 0); - } - - //! Greater than operator. - friend bool operator>(const String &x, const String &y) { - return (compare(x,y) > 0); - } - //! Greater than operator. - friend bool operator>(const char *x, const String &y) { - return (compare(x,y) > 0); - } - //! Greater than operator. - friend bool operator>(const String &x, const char *y) { - return (compare(x,y) > 0); - } - - //! Greater or equal than operator. - friend bool operator>=(const String &x, const String &y) { - return (compare(x,y) >= 0); - } - //! Greater or equal than operator. - friend bool operator>=(const char *x, const String &y) { - return (compare(x,y) >= 0); - } - //! Greater or equal than operator. - friend bool operator>=(const String &x, const char *y) { - return (compare(x,y) >= 0); - } - - //! Assignment operator. - String &operator=(const String &str); - //! Assignment operator. - String &operator=(const char *str); - - //! Appends string \a str to this string. - String &operator+=(const String &str); - - //! Formatted assignment operator. - /** - * Behaves essentially like the C function \c printf(). - */ - void sprintf(const char *format, ...); - - //! Compare function for strings. - static int compare (const String &x, const String &y); - - //! Input operator. - friend istream& operator>>(istream& is, String &str); - - OGDF_NEW_DELETE -}; - -//! Output operator for strings. -inline ostream &operator<<(ostream &os, const String &str) { - os << str.cstr(); - return os; -} - -template<> class DefHashFunc { -public: - int hash(const String &key) const; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/System.h b/ext/OGDF/ogdf/basic/System.h deleted file mode 100644 index bd8db4670..000000000 --- a/ext/OGDF/ogdf/basic/System.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Decalration of System class which provides unified - * access to system information. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SYSTEM_H -#define OGDF_SYSTEM_H - - -#include -#if defined(OGDF_SYSTEM_OSX) -#include -#elif defined(OGDF_SYSTEM_UNIX) || defined(__MINGW32__) -#include -#endif - -// detect processor architecture we're compiling for -// -// OGDF_ARCH_X86 Intel / AMD x86 32-bit processors -// OGDF_ARCH_X64 Intel / AMD x86 64-bit processors -// OGDF_ARCH_IA64 Intel Itanium -// OGDF_ARCH_PPC PowerPC -// OGDF_ARCH_SPARC SUN SPARC -// OGDF_ARCH_SPARC_V9 SUN SPARC V9 - -#if defined(_M_X64) || defined(__x86_64__) -#define OGDF_ARCH_X64 -#elif defined(_M_IX86) || defined(__i386__) -#define OGDF_ARCH_X86 -#elif defined(_M_IA64) || defined(__ia64__) -#define OGDF_ARCH_IA64 -#elif defined(_M_MPPC) || defined(_M_PPC) || defined(__powerpc__) -#define OGDF_ARCH_PPC -#elif defined(__sparc__) -#define OGDF_ARCH_SPARC -#elif defined(__sparc_v9__) -#define OGDF_ARCH_SPARC_V9 -#endif - -// use SSE2 always if x64-platform or compiler option is set -#ifndef OGDF_USE_SSE2 -#if defined(OGDF_ARCH_X64) -#define OGDF_USE_SSE2 -#elif defined(_MSC_VER) -#if _M_IX86_FP >= 2 -#define OGDF_USE_SSE2 -#endif -#endif -#endif - -// macros to check for using special cpu features -// -// OGDF_CHECK_SSE2 returns true if SSE2 can be used - -#ifdef OGDF_USE_SSE2 -#define OGDF_CHECK_SSE2 true -#elif defined(OGDF_ARCH_X86) -#define OGDF_CHECK_SSE2 ogdf::System::cpuSupports(ogdf::cpufSSE2) -#else -#define OGDF_USE_SSE2 false -#endif - -// work-around for MinGW-w64 -#ifdef __MINGW64__ -#ifndef _aligned_free -#define _aligned_free(a) __mingw_aligned_free(a) -#endif -#ifndef _aligned_malloc -#define _aligned_malloc(a,b) __mingw_aligned_malloc(a,b) -#endif -#endif - - -namespace ogdf { - -//! Special features supported by a x86/x64 CPU. -/** - * This enumeration is used to specify spcial additional features that - * are supported by the CPU, in particular extended instruction sets - * such as SSE. - */ -enum CPUFeature { - cpufMMX, //!< Intel MMX Technology - cpufSSE, //!< Streaming SIMD Extensions (SSE) - cpufSSE2, //!< Streaming SIMD Extensions 2 (SSE2) - cpufSSE3, //!< Streaming SIMD Extensions 3 (SSE3) - cpufSSSE3, //!< Supplemental Streaming SIMD Extensions 3 (SSSE3) - cpufSSE4_1, //!< Streaming SIMD Extensions 4.1 (SSE4.1) - cpufSSE4_2, //!< Streaming SIMD Extensions 4.2 (SSE4.2) - cpufVMX, //!< Virtual Machine Extensions - cpufSMX, //!< Safer Mode Extensions - cpufEST, //!< Enhanced Intel SpeedStep Technology - cpufMONITOR //!< Processor supports MONITOR/MWAIT instructions -}; - -//! Bit mask for CPU features. -enum CPUFeatureMask { - cpufmMMX = 1 << cpufMMX, //!< Intel MMX Technology - cpufmSSE = 1 << cpufSSE, //!< Streaming SIMD Extensions (SSE) - cpufmSSE2 = 1 << cpufSSE2, //!< Streaming SIMD Extensions 2 (SSE2) - cpufmSSE3 = 1 << cpufSSE3, //!< Streaming SIMD Extensions 3 (SSE3) - cpufmSSSE3 = 1 << cpufSSSE3, //!< Supplemental Streaming SIMD Extensions 3 (SSSE3) - cpufmSSE4_1 = 1 << cpufSSE4_1, //!< Streaming SIMD Extensions 4.1 (SSE4.1) - cpufmSSE4_2 = 1 << cpufSSE4_2, //!< Streaming SIMD Extensions 4.2 (SSE4.2) - cpufmVMX = 1 << cpufVMX, //!< Virtual Machine Extensions - cpufmSMX = 1 << cpufSMX, //!< Safer Mode Extensions - cpufmEST = 1 << cpufEST, //!< Enhanced Intel SpeedStep Technology - cpufmMONITOR = 1 << cpufMONITOR //!< Processor supports MONITOR/MWAIT instructions -}; - - -//! %System specific functionality. -/** - * The class System encapsulates system specific functions - * providing unified access across different operating systems. - * The provided functionality includes: - * - Access to file system functionality (listing directories etc.). - * - Query memory usage. - * - Access to high-perfomance counter under Windows and Cygwin. - * - Query CPU specific information. - */ -class OGDF_EXPORT System { - - //friend class ::OgdfInitialization; - -public: - /** - * @name Memory usage - * These methods allow to query the amount of physical memory, as well as the - * current memory usage by both the process and OGDF's internal memory manager. - */ - //@{ - - static void *alignedMemoryAlloc16(size_t size) { - size_t alignment = 16; -#ifdef OGDF_SYSTEM_WINDOWS - return _aligned_malloc(size,alignment); -#elif defined(OGDF_SYSTEM_OSX) - // malloc returns 16 byte aligned memory on OS X. - return malloc(size); -#else - return memalign(alignment,size); -#endif - } - - static void alignedMemoryFree(void *p) { -#ifdef OGDF_SYSTEM_WINDOWS - _aligned_free(p); -#else - free(p); -#endif - } - - //! Returns the page size of virtual memory (in bytes). - static int pageSize() { return s_pageSize; } - - //! Returns the total size of physical memory (in bytes). - static long long physicalMemory(); - - //! Returns the size of available (free) physical memory (in bytes). - static long long availablePhysicalMemory(); - - //! Returns the amount of memory (in bytes) allocated by the process. - static size_t memoryUsedByProcess(); - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) - //! Returns the maximal amount of memory (in bytes) used by the process (Windows/Cygwin only). - static size_t peakMemoryUsedByProcess(); -#endif - - //! Returns the amount of memory (in bytes) allocated by OGDF's memory manager. - /** - * The memory manager allocates blocks of a fixed size from the system (via malloc()) - * and makes it available in its free lists (for allocating small pieces of memory. - * The returned value is the total amount of memory allocated from the system; - * the amount of memory currently allocated from the user is - * memoryAllocatedByMemoryManager() - memoryInFreelistOfMemoryManager(). - * - * Keep in mind that the memory manager never releases memory to the system before - * its destruction. - */ - static size_t memoryAllocatedByMemoryManager(); - - //! Returns the amount of memory (in bytes) contained in the global free list of OGDF's memory manager. - static size_t memoryInGlobalFreeListOfMemoryManager(); - - //! Returns the amount of memory (in bytes) contained in the thread's free list of OGDF's memory manager. - static size_t memoryInThreadFreeListOfMemoryManager(); - - //! Returns the amount of memory (in bytes) allocated on the heap (e.g., with malloc). - /** - * This refers to dynamically allocated memory, e.g., memory allocated with malloc() - * or new. - */ - static size_t memoryAllocatedByMalloc(); - - //! Returns the amount of memory (in bytes) contained in free chunks on the heap. - /** - * This refers to memory that has been deallocated with free() or delete, but has not - * yet been returned to the operating system. - */ - static size_t memoryInFreelistOfMalloc(); - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) - //@} - /** - * @name Measuring time - * These methods provide various ways to measure time. The high-performance - * counter (Windows and Cygwin only) can be used to measure real time - * periods with a better resolution than the standard system time function. - */ - //@{ - - //! Returns the current value of the high-performance counter in \a counter. - static void getHPCounter(LARGE_INTEGER &counter); - - //! Returns the elapsed time (in seconds) between \a startCounter and \a endCounter. - static double elapsedSeconds( - const LARGE_INTEGER &startCounter, - const LARGE_INTEGER &endCounter); -#endif - - //! Returns the elapsed time (in milliseconds) between \a t and now. - /** - * The functions sets \a t to to the current time. Usually, you first call - * usedRealTime(t) to query the start time \a t, and determine the elapsed time - * after performing some computation by calling usedRealTime(t) again; this time - * the return value gives you the elapsed time in milliseconds. - */ - static __int64 usedRealTime(__int64 &t); - - - //@} - /** - * @name Processor information - * These methods allow to query information about the current processor such as - * supported instruction sets (e.g., SSE extensions), cache size, and number of - * installed processors. - */ - //@{ - - //! Returns the bit vector describing the CPU features supported on current system. - static int cpuFeatures() { return s_cpuFeatures; } - - //! Returns true if the CPU supports \a feature. - static bool cpuSupports(CPUFeature feature) { - return (s_cpuFeatures & (1 << feature)) != 0; - } - - //! Returns the L2-cache size (in KBytes). - static int cacheSizeKBytes() { return s_cacheSize; } - - //! Returns the number of bytes in a cache line. - static int cacheLineBytes() { return s_cacheLine; } - - //! Returns the number of processors (cores) available on the current system. - static int numberOfProcessors() { return s_numberOfProcessors; } - - //@} - -private: - static unsigned int s_cpuFeatures; //!< Supported CPU features. - static int s_cacheSize; //!< Cache size in KBytes. - static int s_cacheLine; //!< Bytes in a cache line. - static int s_numberOfProcessors; //!< Number of processors (cores) available. - static int s_pageSize; //!< The page size of virtual memory. - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) - static LARGE_INTEGER s_HPCounterFrequency; //!< Frequency of high-performance counter. -#endif - -public: - //! Static initilization routine (automatically called). - static void init(); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Thread.h b/ext/OGDF/ogdf/basic/Thread.h deleted file mode 100644 index 3b442ff15..000000000 --- a/ext/OGDF/ogdf/basic/Thread.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * $Revision: 2617 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 15:46:07 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of mutexes. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_THREAD_H -#define OGDF_THREAD_H - -#include - -#ifdef OGDF_SYSTEM_WINDOWS -#include -#else -#include -#endif - -namespace ogdf { - -#ifdef OGDF_SYSTEM_WINDOWS - -class Thread -{ -public: - enum State { tsRunning, tsSuspended }; - enum Priority { - tpIdle = -15, - tpLowest = -2, - tpLow = -1, - tpNormal = 0, - tpHigh = 1, - tpHighest = 2, - tpCritical = 15 - }; - - Thread() : m_handle(0), m_id(0) { } - virtual ~Thread() { CloseHandle(m_handle); } - - bool started() const { return m_id != 0; } - - void priority(Priority p) { SetThreadPriority(m_handle,p); } - - Priority priority() const { return (Priority)GetThreadPriority(m_handle); } - - __uint64 cpuAffinity(__uint64 mask) { - return SetThreadAffinityMask(m_handle, (DWORD_PTR)mask); - } - - void start(State state = tsRunning) { - if(m_handle) - CloseHandle(m_handle); - - m_handle = (HANDLE) _beginthreadex(0, 0, threadProc, this, - (state == tsSuspended) ? CREATE_SUSPENDED : 0, &m_id); - } - - long threadID() const { return (long)m_id; } - - void start(Priority p, State state = tsRunning) { - OGDF_ASSERT(m_handle == 0); - m_handle = (HANDLE) _beginthreadex(0, 0, threadProc, this, CREATE_SUSPENDED, &m_id); - SetThreadPriority(m_handle,p); - if(state == tsRunning) - ResumeThread(m_handle); - } - - int suspend() { - return SuspendThread(m_handle); - } - - int resume() { - return ResumeThread(m_handle); - } - - void join() { - WaitForSingleObject(m_handle,INFINITE); - } - - bool join(unsigned long milliseconds) { - return (WaitForSingleObject(m_handle,milliseconds) == WAIT_OBJECT_0); - } - -protected: - virtual void doWork() = 0; - -private: - static unsigned int __stdcall threadProc(void *pParam) { - Thread *pThread = static_cast(pParam); - OGDF_ALLOCATOR::initThread(); - pThread->doWork(); - OGDF_ALLOCATOR::flushPool(); - pThread->m_id = 0; - _endthreadex(0); - return 0; - } - - HANDLE m_handle; - unsigned int m_id; -}; - - -#else - -class Thread -{ -public: - enum State { tsRunning, tsSuspended }; - enum Priority { - tpIdle = -15, - tpLowest = -2, - tpLow = -1, - tpNormal = 0, - tpHigh = 1, - tpHighest = 2, - tpCritical = 15 - }; - - Thread() : m_pt(0) { } - - virtual ~Thread() { } - - bool started() const { return m_pt != 0; } - - //void priority(Priority p) { SetThreadPriority(m_handle,p); } - - //Priority priority() const { return (Priority)GetThreadPriority(m_handle); } - - //__uint64 cpuAffinity(__uint64 mask) { - // return SetThreadAffinityMask(m_handle, (DWORD_PTR)mask); - //} - - void start(State state = tsRunning) { - OGDF_ASSERT(m_pt == 0); - pthread_create(&m_pt, NULL, threadProc, this); - } - -//#ifdef OGDF_SYSTEM_OSX - long threadID() const { - return (long)m_pt; - } -//#else -// int threadID() const { -// return (int)m_pt; -// } -//#endif - - //void start(Priority p, State state = tsRunning) { - // OGDF_ASSERT(m_handle == 0); - // m_handle = (HANDLE) _beginthreadex(0, 0, threadProc, this, CREATE_SUSPENDED, 0); - // SetThreadPriority(m_handle,p); - // if(state == tsRunning) - // ResumeThread(m_handle); - //} - - //int suspend() { - // return SuspendThread(m_handle); - //} - - //int resume() { - // return ResumeThread(m_handle); - //} - - void join() { - if(m_pt != 0) - pthread_join(m_pt,NULL); - } - - //bool join(unsigned long milliseconds) { - // return (WaitForSingleObject(m_handle,milliseconds) == WAIT_OBJECT_0); - //} - -protected: - virtual void doWork() = 0; - -private: - static void *threadProc(void *pParam) { - Thread *pThread = static_cast(pParam); - OGDF_ALLOCATOR::initThread(); - pThread->doWork(); - pthread_exit(NULL); - OGDF_ALLOCATOR::flushPool(); - pThread->m_pt = 0; - return 0; - } - - pthread_t m_pt; -}; - -#endif - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/Timeouter.h b/ext/OGDF/ogdf/basic/Timeouter.h deleted file mode 100644 index 8c93b36ab..000000000 --- a/ext/OGDF/ogdf/basic/Timeouter.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares base class for modules with timeout functionality. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_TIMEOUTER_H -#define OGDF_TIMEOUTER_H - - -#include - - -namespace ogdf { - -//! class for timeout funtionality -/** Holds a double value of the timeout time (in seconds). - * Set the value to some negative value (e.g. -1) to turn the timeout - * off. Note that 0 seconds is a perfectly feasible timeout value! - */ -class OGDF_EXPORT Timeouter -{ -public: - //! timeout is turned of by default - Timeouter() : m_timeLimit(-1) { } - - //! timeout is set to the given value (seconds) - Timeouter(double t) : m_timeLimit(t) { } - - //! timeout is turned off (false) or on (true) (with 0 second) - Timeouter(bool t) : m_timeLimit(t ? 0 : -1) { } - - Timeouter(const Timeouter &t) : m_timeLimit(t.m_timeLimit) { } - - ~Timeouter() { } - - - //! sets the time limit for the call (in seconds); <0 means no limit. - void timeLimit(double t) { - m_timeLimit = t; - } - - //! shorthand to turn timelimit off or on (with 0 seconds) - void timeLimit(bool t) { - m_timeLimit = t ? 0 : -1; - } - - //! returns the current time limit for the call - double timeLimit() const { - return m_timeLimit; - } - - //! returns whether any time limit is set or not - bool isTimeLimit() const { - return m_timeLimit >= 0; - } - -protected: - double m_timeLimit; //!< Time limit for module calls (< 0 means no limit). -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/TopologyModule.h b/ext/OGDF/ogdf/basic/TopologyModule.h deleted file mode 100644 index 8823d4d65..000000000 --- a/ext/OGDF/ogdf/basic/TopologyModule.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class TopologyModule. - * - * The TopologyModule transports the layout information from - * GraphAttributes to PlanRep on that Graph, i.e., it computes a - * combinatorial embedding for the input. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_TOPOLOGYMODULE_H -#define OGDF_TOPOLOGYMODULE_H - - - -#include -#include -#include - -namespace ogdf { - -class EdgeLeg; - -//=============================================== -//main function(s): -// setEmbeddingFromGraph(PlanRep&, GraphAttributes&) -// assumes that PG(AG) without bend nodes in PG -// -// sortEdgesFromLayout(GraphAttributes &AG) -// sort the edges in AG, no crossing insertion -//=============================================== - -class OGDF_EXPORT TopologyModule -{ -public: - TopologyModule() : m_options(opDegOneCrossings | opGenToAss | - opCrossFlip | opLoop | opFlipUML) {} - virtual ~TopologyModule() {} - - //the (pre/post)processing options - //opCrossFlip increases running time by const*n, - //opLoop increases running time by const*m - enum Options { - opDegOneCrossings = 0x0001, //should degree one node's edge be crossed - opGenToAss = 0x0002, //should generalizations be turned into associations - opCrossFlip = 0x0004, //if there is a crossing (first ~) between two edges with - //same start or end point, should there position - //at the node be flipped and the crossing be skipped? - //(postprocessing) - opFlipUML = 0x0010, //only flip if same edge type - opLoop = 0x0008 //should loops between crossings (consecutive on both - //crossing edges) be deleted (we dont check for enclosed - //CC's. Therefore it is safe to remove the crossing - }; - - void setOptions(int i) {m_options = i;} - void addOption(TopologyModule::Options o) {m_options = (m_options | o);} - //use AG layout to determine an embedding for PG. - //non-constness of AG in the following methods is only - //used when resolving problems, e.g. setting edge types - //if two generalizations cross in the input layout - - //Parameter setExternal: run over faces to compute external face - //Parameter reuseAGEmbedding: If true, the call only - //checks for a correct embedding of PG and tries to insert - //crossings detected in the given layout otherwise. - //this allows to assign already sorted UMLGraphs - //NOTE: if the sorting of the edges does not correspond - //to the layout given in AG, this cannot work correctly - //returns false if planarization fails - bool setEmbeddingFromGraph( - PlanRep &PG, - GraphAttributes &AG, - adjEntry &adjExternal, - bool setExternal = true, - bool reuseAGEmbedding = false); - - //sorts the edges around all nodes of AG corresponding to the - //layout given in AG - //there is no check of the embedding afterwards because this - //method could be used as a first step of a planarization - void sortEdgesFromLayout(Graph &G, GraphAttributes &AG); - - face getExternalFace(PlanRep &PG, const GraphAttributes &AG); - - double faceSum(PlanRep &PG, const GraphAttributes &AG, face f); - -protected: - //compute a planarization, i.e. insert crossing vertices, - //corresponding to the AG layout - void planarizeFromLayout(PlanRep &PG, - GraphAttributes &AG); - //compute crossing point and return if existing - bool hasCrossing(EdgeLeg* legA, EdgeLeg* legB, DPoint& xp); - //check if node v is a crossing of two edges with a common - //endpoint adjacent to v, crossing is removed if flip is set - bool checkFlipCrossing(PlanRep &PG,node v, bool flip = true); - - void postProcess(PlanRep &PG); - void handleImprecision(PlanRep &PG); - bool skipable(EdgeLeg* legA, EdgeLeg* legB); - -private: - //compare vectors for sorting - int compare_vectors(const double& x1, const double& y1, - const double& x2, const double& y2); - //compute and return the angle defined by p-q,p-r - double angle(DPoint p, DPoint q, DPoint r); - //we have to save the position of the inserted crossing vertices - //in order to compute the external face - NodeArray m_crossPosition; - - //we save a list of EdgeLegs for all original edges in - //AG - EdgeArray< List > m_eLegs; - - - //option settings as bits - int m_options; - -};//TopologyModule - - -//sorts EdgeLegs according to their xp distance to a reference point -class PointComparer { -public: - PointComparer(DPoint refPoint) : m_refPoint(refPoint) {} - //compares the crossing points stored in the EdgeLeg - int compare(const ListIterator &ep1, - const ListIterator &ep2) const; - OGDF_AUGMENT_COMPARER(ListIterator) - - // undefined methods to avoid automatic creation - PointComparer &operator=(const PointComparer &); - -private: - const DPoint m_refPoint; -};//PointComparer - -//helper class for the computation of crossings -//represents a part of the edge between two consecutive -//bends (in the layout, there are no bends allowed in -//the representation) or crossings -//there can be multiple EdgeLegs associated to one copy -//edge in the PlanRep because of bends -class EdgeLeg -{ -public: - EdgeLeg() : m_topDown(false) - {m_copyEdge = 0; m_xp = DPoint(0.0, 0.0);} - EdgeLeg(edge e, int number, DPoint p1, DPoint p2) : - m_xp(DPoint(0.0,0.0)), m_topDown(false), - m_copyEdge(e), m_p1(p1), m_p2(p2), m_number(number) - {} - - DPoint& start() {return m_p1;} - DPoint& end() {return m_p2;} - int& number() {return m_number;} - edge& copyEdge() { return m_copyEdge;} - - //to avoid sorting both edgelegs and crossing points, - //do not store a pair of them, but allow the xp to be - //stored in the edgeleg - DPoint m_xp; - //we store the direction of the crossed EdgeLeg, too - //if crossingEdgeLeg is horizontally left to right - bool m_topDown; - - //each edgeLeg holds an entry with a ListIterator pointing to - //its entry in a List for an original edge - ListIterator< EdgeLeg* > m_eIterator; - -private: - edge m_copyEdge; //the edge in the PlanRep copy corresponding to the EdgeLeg - DPoint m_p1, m_p2; //"Starting" and "End" point of the EdgeLeg - int m_number; //the order nuumber on the edge, starting at 0 - -};//edgeleg - - -/* -EdgeArray > m_eIterator; // position of copy edge in chain - - NodeArray m_vCopy; // corresponding node in graph copy - EdgeArray > m_eCopy; // corresponding chain of edges in graph copy - -*/ -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/UMLGraph.h b/ext/OGDF/ogdf/basic/UMLGraph.h deleted file mode 100644 index 4ea6f6ec4..000000000 --- a/ext/OGDF/ogdf/basic/UMLGraph.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class UMLGraph. - * - * \author Carsten Gutwenger and Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UML_GRAPH_H -#define OGDF_UML_GRAPH_H - - -#include -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT UMLGraph : public GraphAttributes -{ -public: - // construction - - // dummy default constructor (place-holder) - UMLGraph() : GraphAttributes(), m_pG(0) { } - - // creates UML graph in which each edge is an association - explicit UMLGraph(Graph &G, long initAttributes = 0); - - // destruction - virtual ~UMLGraph(); - - //(re)initialization - virtual void init(Graph &G, long initAttr) - { - m_pG = &G; - GraphAttributes::init(G, initAttr); - m_hierarchyParent.init(constGraph(), 0); - m_upwardEdge.init(constGraph(), false); - } - - operator const Graph &() const { return *m_pGraph; } - - //---------------------------------------------------------------------------- - //structural changes - //merge generalizations at a common superclass - void insertGenMergers(); - //insert mergers per node with given edges - node doInsertMergers(node v, SList &inGens); - void undoGenMergers(); - - //replace (dense) subgraphs given in list clique by - //inserting a center node connected to each node (=>star) - //and deleting all edges between nodes in clique - //returns center node - void replaceByStar(List< List > &cliques); - - //undo clique replacements - void undoStars(); - //boolean switches restore of all hidden edges in single clique call - void undoStar(node center, bool restoreAllEdges); - - //returns the size of a circular drawing for a clique around center v - DRect cliqueRect(node v) - { - return m_cliqueCircleSize[v]; - } - DPoint cliquePos(node v) - { - return m_cliqueCirclePos[v]; - } - - //compute circle positions for all nodes around center - //using the ordering given in this UMLGraph, calls - //ccP(List...) - //rectMin is a temporary solution until compaction with constraints allows stretching - //of rect to clique size, it gives the min(w,h) of the given fixed size rect around the clique - void computeCliquePosition(node center, double rectMin);//, const adjEntry &startAdj); - //compute positions for the nodes in adjNodes on a circle - //tries to keep the relative placement of the nodes in the clique - //rectangle (left, right,...) to avoid clique crossings of outgoing edges - void computeCliquePosition(List &adjNodes, node center, double rectMin = -1.0); - - //allow change, but should not be declared const - Graph& pureGraph() const {return *m_pG;} - - //set status value - //void setAlign(edge e, bool b) {m_alignEdge[e] = b;} - //set status of edges to be specially embedded (if alignment) - void setUpwards(adjEntry a, bool b) {m_upwardEdge[a] = b;} - bool upwards(adjEntry a) const {return m_upwardEdge[a];} - - // writes attributed graph in GML format to file fileName - void writeGML(const char *fileName); - - // writes attributed graph in GML format to output stream os - void writeGML(ostream &os); - - //adjust the parent field for all nodes after insertion of - //mergers. If insertion is done per node via doinsert, adjust - //has to be called afterwards. Otherwise, insertgenmergers calls it. - void adjustHierarchyParents(); - - //use the node position and bend position information to - //derive an ordering of the edges around each node - //this does not need to result in a correct combinatorial embedding - void sortEdgesFromLayout(); - - //------------------- - //status retrieval - //returns true if edge was inserted during clique replacement - //TODO: check here how to guarantee that value is defined, - //edgearray is only valid if there are cliques replaced - bool isReplacement(edge e) - { - return m_replacementEdge[e]; - } - - const SListPure ¢erNodes() {return m_centerNodes;} - - //default size of inserted clique replacement center nodes - void setDefaultCliqueCenterSize(double i) {m_cliqueCenterSize = max(i, 1.0);} - double getDefaultCliqueCenterSize() {return m_cliqueCenterSize;} - - //------------------------------------------------------------------------- - //modelling of association classes - class AssociationClass { - public: - AssociationClass(edge e, double width = 1.0, double height = 1.0, - double x = 0.0, double y = 0.0) - : m_width(width), m_height(height), m_x(x), m_y(y), m_edge(e), m_node(0) - { } - - double m_width; - double m_height; - double m_x; - double m_y; - edge m_edge; - node m_node; - }; - const SListPure &assClassList() const {return m_assClassList;} - - const AssociationClass* assClass(edge e) const {return m_assClass[e];} - - //adds association class to edge e - //void createAssociationClass(edge e, double width = 1.0, double height = 1.0) - node createAssociationClass(edge e, double width = 1.0, double height = 1.0) - { - AssociationClass* ac = new AssociationClass(e, width, height); - m_assClass[e] = ac; - m_assClassList.pushBack(ac); - //we already insert the node here, but not the edge - //when we always insert this node here, we can remove the associationclass - //class and information later on - node v = m_pG->newNode(); - m_height[v] = ac->m_height; - m_width[v] = ac->m_width; - m_associationClassModel[ac->m_edge] = v; - ac->m_node = v; - //guarantee correct angle at edge to edge connection - if (m_attributes & GraphAttributes::nodeType) - { - m_vType[v] = Graph::associationClass; - } - return v; - - } - //this modelling should only take place in the preprocessing steps - //of the drawing algorithms? - //insert representation for association class in underlying graph - void modelAssociationClasses() - { - SListIterator it = m_assClassList.begin(); - while (it.valid()) - { - modelAssociationClass((*it)); - it++; - }//while - } - node modelAssociationClass(AssociationClass* ac) - { - node dummy = m_pG->split(ac->m_edge)->source(); - - m_height[dummy] = 1; //just a dummy size - m_width[dummy] = 1; - OGDF_ASSERT(ac->m_node) - m_pG->newEdge(ac->m_node, dummy); - - return dummy; - } - - void undoAssociationClasses() - { - SListIterator it = m_assClassList.begin(); - while (it.valid()) - { - undoAssociationClass((*it)); - it++; - }//while - } - //remove the modeling of the association class without removing the information - void undoAssociationClass(AssociationClass* ac) - { - node v = m_associationClassModel[ac->m_edge]; - OGDF_ASSERT(v) - OGDF_ASSERT(v->degree() == 1) - if (v->degree() != 1) throw AlgorithmFailureException(afcLabel); - //save layout information - ac->m_x = x(v); - ac->m_y = y(v); - - //remove node and unsplit edge - - //run around the dummy node connected to v - adjEntry outAdj = v->firstAdj(); - adjEntry dummyAdj = outAdj->twin(); - - node dummy = dummyAdj->theNode(); - OGDF_ASSERT(dummy->degree() == 3) - - //we do not delete the node if we already inserted it in create... - //because it is a part of the graph now (in contrast to the split node) - m_pG->delEdge(v->firstAdj()->theEdge()); - OGDF_ASSERT(v->degree() == 0) - - m_pG->unsplit(dummy); - }//undoAssociationClass - - - -protected: - - node replaceByStar(List &clique, NodeArray &cliqueNum); - DRect circularBound(node center); - -private: - - Graph *m_pG; - - //information about edges that are deleted in clique processing - class CliqueInfo { - public: - CliqueInfo(node v, int i) : m_target(v), m_edgeIndex(i) {} - node m_target; //target node of deleted edge - int m_edgeIndex; //index of deleted edge, has to be restored - }; - double m_cliqueCenterSize; //default size of inserted clique replacement center nodes - - SListPure m_mergeEdges; - SListPure m_centerNodes; //center nodes introduced at clique replacement - EdgeArray m_replacementEdge; //used to mark clique replacement edges - //may be we can join this with edge type - NodeArray m_cliqueCircleSize; //save the bounding box size of the - //circular drawing of the clique at center - NodeArray m_cliqueCirclePos; //save the position of the node in the - //circular drawing of the clique - //--------------------------------------------------- - //structures for association classes - //may be replaced later by generic structures for different types - SListPure m_assClassList; //saves all accociation classes - EdgeArray m_assClass; //association class for list - EdgeArray m_associationClassModel; //modelled classes are stored - - - //*************************************************** - //the following arrays are only set and updated in insertgenmergers - //used to classify edges for embedding with alignment - AdjEntryArray m_upwardEdge; - - //used to derive edge types for alignment in PlanRepUML - //(same hierarchyparent => edge connects (half)brothers - //only set during insertgenmergers to avoid the extra computation - NodeArray m_hierarchyParent; - -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/basic.h b/ext/OGDF/ogdf/basic/basic.h deleted file mode 100644 index 24f99b2ff..000000000 --- a/ext/OGDF/ogdf/basic/basic.h +++ /dev/null @@ -1,637 +0,0 @@ -/* - * $Revision: 2618 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 15:59:09 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Basic declarations, included by all source files. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BASIC_H -#define OGDF_BASIC_H - - -/** - * \mainpage The Open Graph Drawing Framework - * - * \section sec_intro Introduction - * The Open Graph Drawing Framework (OGDF) is a C++ library containing - * implementations of various graph drawing algorithms. The library is self - * contained; optionally, additional packages like LP-solvers are required - * for some implementations. - * - * Here, you find the library's code documentation. For more general information - * on OGDF see http://www.ogdf.net. There, you can also find further explanations, - * how-tos, and example code. - * - * The OGDF project is a cooperation between - * - [Chair of Algorithm Engineering](http://ls11-www.cs.uni-dortmund.de/), Faculty of Computer Science, TU Dortmund, Germany - * - [Juniorprofessorship of Algorithm Engineering](http://www.ae.uni-jena.de/), Faculty of Mathematics and Computer Science, Friedrich-Schiller-University Jena, Germany - * - [Chair of Prof. Jünger](http://www.informatik.uni-koeln.de/ls_juenger/), Department of Computer Science, University of Cologne, Germany - * - [University of Sydney](http://sydney.edu.au/engineering/it/), Australia - * - [oreas GmbH](http://www.oreas.com/), Cologne, Germany - */ - - -//--------------------------------------------------------- -// detection of the system -//--------------------------------------------------------- - -#if defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(__APPLE__) -#define OGDF_SYSTEM_UNIX -#endif - -#if defined(__WIN32__) || defined(_WIN32) || defined(__NT__) -#define OGDF_SYSTEM_WINDOWS -#endif - -// Note: Apple OS X machines will be both OGDF_SYSTEM_UNIX and OGDF_SYSTEM_OSX -#if defined(__APPLE__) -#define OGDF_SYSTEM_OSX -#endif - - -#if defined(USE_COIN) || defined(OGDF_OWN_LPSOLVER) -#define OGDF_LP_SOLVER -#endif - -#if defined(USE_COIN) && !defined(COIN_OSI_CPX) && !defined(COIN_OSI_SYM) && !defined(COIN_OSI_CLP) -#error "Compiler-flag USE_COIN requires an additional COIN_OSI_xxx-flag to choose the LP solver backend." -#endif - - -// define minimal MS runtime version for mingw32 -#if defined(__MINGW32__) && !defined(__MINGW64__) -#ifndef __MSVCRT_VERSION__ -#define __MSVCRT_VERSION__ 0x0700 -#endif -#endif - -// include windows.h on Windows systems -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) -#define WIN32_EXTRA_LEAN -#define WIN32_LEAN_AND_MEAN -#undef NOMINMAX -#define NOMINMAX -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 -#endif -#include -#endif - - -//--------------------------------------------------------- -// assertions -//--------------------------------------------------------- - -#ifdef OGDF_DEBUG -#include -#define OGDF_ASSERT(expr) assert(expr); -#define OGDF_ASSERT_IF(minLevel,expr) \ - if (int(ogdf::debugLevel) >= int(minLevel)) { assert(expr); } else { } -#define OGDF_SET_DEBUG_LEVEL(level) ogdf::debugLevel = level; - -#else -#define OGDF_ASSERT(expr) -#define OGDF_ASSERT_IF(minLevel,expr) -#define OGDF_SET_DEBUG_LEVEL(level) -#endif - - -//--------------------------------------------------------- -// macros for optimization -//--------------------------------------------------------- - -// Visual C++ compiler -#ifdef _MSC_VER - -#define OGDF_LIKELY(x) (x) -#define OGDF_UNLIKELY(x) (x) - -#ifdef OGDF_DEBUG -#define OGDF_NODEFAULT default: assert(0); -#else -#define OGDF_NODEFAULT default: __assume(0); -#endif - -#define OGDF_DECL_ALIGN(b) __declspec(align(b)) -#define OGDF_DECL_THREAD __declspec(thread) - - -// GNU gcc compiler (also Intel compiler) -#elif defined(__GNUC__) -//// make sure that SIZE_MAX gets defined -//#define __STDC_LIMIT_MACROS -//#include - -#define OGDF_LIKELY(x) __builtin_expect((x),1) -#define OGDF_UNLIKELY(x) __builtin_expect((x),0) -#define OGDF_NODEFAULT default: ; - -#define OGDF_DECL_ALIGN(b) __attribute__ ((aligned(b))) -#define OGDF_DECL_THREAD __thread - - -// other compiler -#else -#define OGDF_LIKELY(x) (x) -#define OGDF_UNLIKELY(x) (x) -#define OGDF_NODEFAULT - -#define OGDF_DECL_ALIGN(b) -#endif - -#ifndef __SIZEOF_POINTER__ -#ifdef _M_X64 -#define __SIZEOF_POINTER__ 8 -#else -#define __SIZEOF_POINTER__ 4 -#endif -#endif - - -#if defined(__CYGWIN__) || defined(__APPLE__) || defined(__sparc__) -#define OGDF_NO_COMPILER_TLS -#elif defined(__GNUC__) -#if __GNUC__ < 4 -#define OGDF_NO_COMPILER_TLS -#endif -#endif - - -//--------------------------------------------------------- -// macros for compiling OGDF as DLL -//--------------------------------------------------------- - -#ifdef OGDF_SYSTEM_WINDOWS -#ifdef OGDF_DLL - -#ifdef OGDF_INSTALL -#define OGDF_EXPORT __declspec(dllexport) -#else -#define OGDF_EXPORT __declspec(dllimport) -#endif - -#else -#define OGDF_EXPORT -#endif - -#else -#define OGDF_EXPORT -#endif - - -//--------------------------------------------------------- -// define data types with known size -//--------------------------------------------------------- - -#if defined(_MSC_VER) - -typedef unsigned __int8 __uint8; -typedef unsigned __int16 __uint16; -typedef unsigned __int32 __uint32; -typedef unsigned __int64 __uint64; - -#else - -#undef __int8 -#undef __int16 -#undef __int32 -#undef __int64 - -typedef signed char __int8; -typedef short __int16; -typedef int __int32; -typedef long long __int64; -typedef unsigned char __uint8; -typedef unsigned short __uint16; -typedef unsigned int __uint32; -typedef unsigned long long __uint64; -#endif - - -//--------------------------------------------------------- -// common includes -//--------------------------------------------------------- - -#include -#include -#include - -using std::ios; -using std::istream; -using std::ifstream; -using std::ostream; -using std::ofstream; -using std::cin; -using std::cout; -using std::cerr; -using std::endl; -using std::flush; -using std::swap; -using std::min; -using std::max; - -#include -#include -#include -#include -#include - -#ifdef OGDF_SYSTEM_UNIX -#include -#endif -// make sure that SIZE_MAX gets defined -#ifndef SIZE_MAX -#define SIZE_MAX ((size_t)-1) -#endif - - -#include -#include -#include - - - -//--------------------------------------------------------- -// compiler adaptions -//--------------------------------------------------------- - -#ifdef _MSC_VER - -// disable useless warnings - -// missing dll-interface -#pragma warning(disable:4251) -#pragma warning(disable:4275) - -#endif - - -//! The namespace for all OGDF objects. -namespace ogdf { - -#ifndef OGDF_DLL - -/** - * The class Initialization is used for initializing global variables. - * You should never create instances of it! -*/ -class Initialization { - static int s_count; - -public: - Initialization(); - ~Initialization(); -}; - -static Initialization s_ogdfInitializer; - -#endif - - -//--------------------------------------------------------- -// global basic functions -//--------------------------------------------------------- - - // forward declarations - template class List; - class OGDF_EXPORT String; - - - enum Direction { before, after }; - - //! Returns random integer between low and high (including). - inline int randomNumber(int low, int high) { -#if RAND_MAX == 32767 - // We get only 15 random bits on some systems (Windows, Solaris)! - int r1 = (rand() & ((1 << 16) - 1)); - int r2 = (rand() & ((1 << 16) - 1)); - int r = (r1 << 15) | r2; -#else - int r = rand(); -#endif - return low + (r % (high-low+1)); - } - - //! Returns random double value between low and high. - inline double randomDouble(double low, double high) { - double val = low +(rand()*(high-low))/RAND_MAX; - OGDF_ASSERT(val >= low && val <= high); - return val; - } - - //! Returns a random double value from the normal distribution - //! with mean m and standard deviation sd - inline double randomDoubleNormal(double m, double sd) - { - double x1, x2, y1, w, rndVal; - - do { - rndVal = randomDouble(0,1); - x1 = 2.0 * rndVal - 1.0; - rndVal = randomDouble(0,1); - x2 = 2.0 * rndVal - 1.0; - w = x1*x1 + x2*x2; - } while (w >= 1.0); - - w = sqrt((-2.0 * log(w))/w) ; - y1 = x1*w; - - return(m + y1*sd); - } - - - - //! Returns used CPU time from T to current time and assigns - //! current time to T. - OGDF_EXPORT double usedTime(double& T); - - //! \a doDestruction() returns false if a data type does not require to - //! call its destructor (e.g. build-in data types). - templateinline bool doDestruction(const E *) { return true; } - - // specializations - template<>inline bool doDestruction(const char *) { return false; } - template<>inline bool doDestruction(const int *) { return false; } - template<>inline bool doDestruction(const double *) { return false; } - - - //--------------------------------------------------------- - // handling files and directories - //--------------------------------------------------------- - - //! The type of an entry in a directory. - enum FileType { - ftEntry, /**< file or directory */ - ftFile, /**< file */ - ftDirectory /**< directory */ - }; - - //! Returns true iff \a fileName is a regular file (not a directory). - OGDF_EXPORT bool isFile(const char *fileName); - - //! Returns true iff \a fileName is a directory. - OGDF_EXPORT bool isDirectory(const char *fileName); - - //! Changes current directory to \a dirName; returns true if successful. - OGDF_EXPORT bool changeDir(const char *dirName); - - //! Returns in \a files the list of files in directory \a dirName. - /** The optional argument \a pattern can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getFiles(const char *dirName, - List &files, - const char *pattern = "*"); - - //! Appends to \a files the list of files in directory \a dirName. - /** The optional argument \a pattern can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getFilesAppend(const char *dirName, - List &files, - const char *pattern = "*"); - - - //! Returns in \a subdirs the list of directories contained in directory \a dirName. - /** The optional argument \a pattern can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getSubdirs(const char *dirName, - List &subdirs, - const char *pattern = "*"); - - //! Appends to \a subdirs the list of directories contained in directory \a dirName. - /** The optional argument \a pattern can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getSubdirsAppend(const char *dirName, - List &subdirs, - const char *pattern = "*"); - - - //! Returns in \a entries the list of all entries contained in directory \a dirName. - /** Entries may be files or directories. The optional argument \a pattern - * can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getEntries(const char *dirName, - List &entries, - const char *pattern = "*"); - - //! Appends to \a entries the list of all entries contained in directory \a dirName. - /** Entries may be files or directories. The optional argument \a pattern - * can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getEntriesAppend(const char *dirName, - List &entries, - const char *pattern = "*"); - - - //! Returns in \a entries the list of all entries of type \a t contained in directory \a dirName. - /** The optional argument \a pattern can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getEntries(const char *dirName, - FileType t, - List &entries, - const char *pattern = "*"); - - //! Appends to \a entries the list of all entries of type \a t contained in directory \a dirName. - /** The optional argument \a pattern can be used to filter files. - * - * \pre \a dirName is a directory - */ - OGDF_EXPORT void getEntriesAppend(const char *dirName, - FileType t, - List &entries, - const char *pattern = "*"); - - //--------------------------------------------------------- - // handling markup formatting - //--------------------------------------------------------- - -#ifdef OGDF_DEBUG - /** We maintain a debug level in debug versions indicating how many - * internal checks (usually assertions) are done. - * Usage: Set the variable ogdf::debugLevel using the macro - * OGDF_SET_DEBUG_LEVEL(level) to the desired level - * in the calling code (e.g. main()). The debugLevel can be set - * to a higher level for critical parts (e.g., where you assume a bug) - * ensuring that other parts are not too slow. - */ - enum DebugLevel { - dlMinimal, dlExtendedChecking, dlConsistencyChecks, dlHeavyChecks - }; - extern DebugLevel debugLevel; -#endif - - -//! Abstract base class for bucket functions. -/** - * The parameterized class \a BucketFunc is an abstract base class - * for bucket functions. Derived classes have to implement \a getBucket(). - * Bucket functions are used by bucket sort functions for container types. - */ -template class BucketFunc -{ -public: - virtual ~BucketFunc() { } - - //! Returns the bucket of \a x. - virtual int getBucket(const E &x) = 0; -}; - - - -#if _MSC_VER >= 1400 - -inline int sprintf(char *buffer, size_t sizeOfBuffer, const char *format, ...) -{ - va_list args; - va_start(args, format); - - return vsprintf_s(buffer, sizeOfBuffer, format, args); -} - -inline int vsprintf(char *buffer, size_t sizeInBytes, const char *format, va_list argptr) -{ - return vsprintf_s(buffer, sizeInBytes, format, argptr); -} - -inline int strcat(char *strDest, size_t sizeOfDest, const char *strSource) -{ - return (int)strcat_s(strDest, sizeOfDest, strSource); -} - -inline int strcpy(char *strDest, size_t sizeOfDest, const char *strSource) -{ - return (int)strcpy_s(strDest, sizeOfDest, strSource); -} - -inline int strncpy(char *strDest, size_t sizeOfDest, const char *strSource, size_t count) -{ - return (int)strncpy_s(strDest, sizeOfDest, strSource, count); -} - -inline char *strtok(char *strToken, const char *strDelimit) -{ - //provide a persistent context pointer for strtok_s - static char *context; - return strtok_s(strToken, strDelimit, &context); -} - -#define scanf scanf_s -#define fscanf fscanf_s -#define sscanf sscanf_s - -inline FILE *fopen(const char *filename, const char *mode) -{ - FILE *stream; - if(fopen_s(&stream, filename, mode)) stream = 0; - return stream; -} - -inline int localtime(struct tm *ptm, const time_t *timer) -{ - return (int)localtime_s(ptm,timer); -} - -#else /////////////////////////////////////////////////////////////////////////////// - -inline int sprintf(char *buffer, size_t, const char *format, ...) -{ - va_list args; - va_start(args, format); - - return ::vsprintf(buffer, format, args); -} - - -inline int vsprintf(char *buffer, size_t, const char *format, va_list argptr) -{ - return ::vsprintf(buffer, format, argptr); -} - - -inline int strcat(char *strDest, size_t, const char *strSource) -{ - ::strcat(strDest, strSource); - return 0; -} - -inline int strcpy(char *strDest, size_t, const char *strSource) -{ - ::strcpy(strDest, strSource); - return 0; -} - -inline int strncpy(char *strDest, size_t, const char *strSource, size_t count) -{ - ::strncpy(strDest, strSource, count); - return 0; -} - -inline int localtime(struct tm *ptm, const time_t *timer) -{ - struct tm *newtime = ::localtime(timer); - if(newtime) { - *ptm = *newtime; - return 0; - } - return 1; // indicates error -} - -#endif - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/comparer.h b/ext/OGDF/ogdf/basic/comparer.h deleted file mode 100644 index 3cc8a35d7..000000000 --- a/ext/OGDF/ogdf/basic/comparer.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declarations for Comparer objects. - * - * \author Markus Chimani, Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_COMPARER_H -#define OGDF_COMPARER_H - -namespace ogdf { - -//-------------------------------------------------------------------- -// A comparer interface is has to define -// bool less (const E &x, const E &y); -// bool leq (const E &x, const E &y); -// bool equal(const E &x, const E &y); -// bool geq (const E &x, const E &y); -// bool greater (const E &x, const E &y); -// -// "const E &" can be replaced by "E" -//-------------------------------------------------------------------- - -//! Standard comparer (valid as a static comparer). -/** - * Standard comparers are used by some sorting and searching methods. - * The implementation of the generic class only provides dummies that - * always throw a NoStdComparerException. - * - * The compare operations are static, hence the StdComparer cannot - * only be used as a comparer object, but also as a static comparer - * when required. - * - * You need to specialize this class for types you want to use with - * sorting and searching methods like quicksort and binary search. There - * already exist specializations for several standard types. If your type - * already provides compare operators, you can use the macro #OGDF_STD_COMPARER - * to automatically generate the specialization based on these operators. - */ -template class StdComparer -{ -public: - static bool less(const E &x, const E &y) { OGDF_THROW(NoStdComparerException); } - static bool leq(const E &x, const E &y) { OGDF_THROW(NoStdComparerException); } - static bool greater(const E &x, const E &y) { OGDF_THROW(NoStdComparerException); } - static bool geq(const E &x, const E &y) { OGDF_THROW(NoStdComparerException); } - static bool equal(const E &x, const E &y) { OGDF_THROW(NoStdComparerException); } -}; - -//! Generates a specialization of the standard static comparer for \a type based on compare operators. -#define OGDF_STD_COMPARER(type) \ - template<> class StdComparer \ - { \ - public: \ - static bool less (const type &x, const type &y) { return x < y; } \ - static bool leq (const type &x, const type &y) { return x <= y; } \ - static bool greater(const type &x, const type &y) { return x > y; } \ - static bool geq (const type &x, const type &y) { return x >= y; } \ - static bool equal (const type &x, const type &y) { return x == y; } \ - }; - -OGDF_STD_COMPARER(int) -OGDF_STD_COMPARER(float) -OGDF_STD_COMPARER(double) - -//! Generates a specialization of the standard static comparer for booleans. -template<> class StdComparer { -public: - static bool less (const bool &x, const bool &y) { return !x && y; } - static bool leq (const bool &x, const bool &y) { return !x || y; } - static bool greater(const bool &x, const bool &y) { return x && !y; } - static bool geq (const bool &x, const bool &y) { return x || !y; } - static bool equal (const bool &x, const bool &y) { return x == y; } -}; - - -//! A static comparer which compares the target of pointers ("content"), instead of the pointer's adresses. -/** - * For the comparison of the contents, you may give your own static comparer - */ -template > -class TargetComparer { - typedef CONTENTTYPE* CONTENTPOINTER; -public: - static bool less (const CONTENTPOINTER &x, const CONTENTPOINTER &y) { return STATICCONTENTCOMPARER::less (*x,*y); } - static bool leq (const CONTENTPOINTER &x, const CONTENTPOINTER &y) { return STATICCONTENTCOMPARER::leq (*x,*y); } - static bool greater(const CONTENTPOINTER &x, const CONTENTPOINTER &y) { return STATICCONTENTCOMPARER::greater(*x,*y); } - static bool geq (const CONTENTPOINTER &x, const CONTENTPOINTER &y) { return STATICCONTENTCOMPARER::geq (*x,*y); } - static bool equal (const CONTENTPOINTER &x, const CONTENTPOINTER &y) { return STATICCONTENTCOMPARER::equal (*x,*y); } -}; - - -//! Add this macro to your class to turn it into a full comparer. -/** - * It is assumed that your class has a method "compare(const type &x, const type &y)", which - * returns 0 if the two elements are equal, a negative value if \a x is smaller, and a positive - * value if \a x is greater. - * - * Note: If the compare function of your class requires no additional data other than the - * two elements to compare, your should usually use the more general #OGDF_AUGMENT_STATICCOMPARER: - * A static comparer is also always valid as a normal comparer. - * - * Usage in Definition: - * \code - * class MyComparer { - * private: - * Oracle oracle; - * public: - * MyComparer(Oracle o) : oracle(o) {} - * int compare(const MyStuff& x1, const MyStuff& x2) const { - * return ... //compare x1 with x2, using oracle - * } - * OGDF_AUGMENT_COMPARER(MyStuff) - * } - * \endcode - * - * Use the Comparer: - * \code - * MyStuff a=...; - * MyStuff b=...; - * Oracle or; - * MyComparer comp(or); - * if( comp.less(a,b) ) - * ... // do something - * ... - * Array ay(10); - * ... // fill array - * ay.quicksort(comp); // sort the array using the MyComparer comp - * \endcode - */ -#define OGDF_AUGMENT_COMPARER(type) \ - public: \ - bool less(const type &x, const type &y) const { return compare(x,y) < 0; } \ - bool leq(const type &x, const type &y) const { return compare(x,y) <= 0; } \ - bool greater(const type &x, const type &y) const { return compare(x,y) > 0; } \ - bool geq(const type &x, const type &y) const { return compare(x,y) >= 0; } \ - bool equal(const type &x, const type &y) const { return compare(x,y) == 0; } - -//! Add this macro to your class to turn it into a full static comparer. -/** - * It is assumed that your class has a *static* method "compare(const type &x, const type &y)", which - * returns 0 if the two elements are equal, a negative value if \a x is smaller, and a positive - * value if \a x is greater. - * - * Note: You should use this macro instead of #OGDF_AUGMENT_COMPARER whenever your compare function - * requires no additional data stored in the object, other than the two elements to compare. - * A static comparer is also always valid as a normal comparer. - * - * Usage in Definition: - * \code - * class MyComparer { - * public: - * static int comparer(const MyStuff& x1, const MyStuff& x2) { - * return ... //compare x1 with x2 - * } - * OGDF_AUGMENT_STATICCOMPARER(MyStuff) - * } - * \endcode - * - * Use the Comparer: - * \code - * MyStuff a=...; - * MyStuff b=...; - * MyComparer comp; - * if( MyComparer.less(a,b) ) // use it statically on the class - * ... // do something - * if( comp.less(a,b) ) // use it on the object - * ... // do something - * ... - * Array ay(10); - * ... // fill array - * ay.quicksort(comp); // sort the array using the MyComparer comp - * \endcode - */ -#define OGDF_AUGMENT_STATICCOMPARER(type) \ - public: \ - static bool less(const type &x, const type &y) { return compare(x,y) < 0; } \ - static bool leq(const type &x, const type &y) { return compare(x,y) <= 0; } \ - static bool greater(const type &x, const type &y) { return compare(x,y) > 0; } \ - static bool geq(const type &x, const type &y) { return compare(x,y) >= 0; } \ - static bool equal(const type &x, const type &y) { return compare(x,y) == 0; } - - -//! Abstract base class for comparer classes. -/** - * The parameterized class \a VComparer is an abstract base class for - * encapsulating compare functions for type \a E. Implementations derive - * from this class and implement at least the compare() method. - * - * The methods of this class are all \a virtual, which comes with a - * certain performance penalty. Its advantage is that if you require - * multiple Comparers for the same class \a E, functions using - * compareres on \a E are not generated multiple times, which means - * smaller code. - * - * If size is not an issue, but speed is, use a Comparer with - * non-virtual functions. You may want to use the convenience classes - * StdComparer and TargetComparer, or the convenience macros - * #OGDF_AUGMENT_COMPARER, #OGDF_AUGMENT_STATICCOMPARER, #OGDF_STD_COMPARER to - * obtain non-virtual classes with few effort. - */ -template class VComparer { -public: - //! Initializes a comparer. - VComparer() { } - - virtual ~VComparer() { } - - //! Compares \a x and \a y and returns the result as an integer. - /** The returns value is - * - < 0 iff x < y, - * - = 0 iff x = y, - * - > 0 iff x > y - */ - virtual int compare(const E &x, const E &y) const = 0; - - //! Returns true iff \a x < \a y - virtual bool less(const E &x, const E &y) const { - return compare(x,y) < 0; - } - - //! Returns true iff \a x <= \a y - virtual bool leq(const E &x, const E &y) const { - return compare(x,y) <= 0; - } - - //! Returns true iff \a x > \a y - virtual bool greater(const E &x, const E &y) const { - return compare(x,y) > 0; - } - - //! Returns true iff \a x >= \a y - virtual bool geq(const E &x, const E &y) const { - return compare(x,y) >= 0; - } - - //! Returns true iff \a x = \a y - virtual bool equal(const E &x, const E &y) const { - return compare(x,y) == 0; - } -}; // class VComparer - -} //namespace - -#endif /*OGF_COMPARER_H*/ diff --git a/ext/OGDF/ogdf/basic/exceptions.h b/ext/OGDF/ogdf/basic/exceptions.h deleted file mode 100644 index 32f36a951..000000000 --- a/ext/OGDF/ogdf/basic/exceptions.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definition of exception classes - * - * \author Carsten Gutwenger, Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#include -#include - - -#ifndef OGDF_EXCEPTIONS_H -#define OGDF_EXCEPTIONS_H - - -namespace ogdf { - -#ifdef OGDF_DEBUG -/** - * If this flag is set the #OGDF_THROW macros pass the location where the - * exception is thrown (file name and line number) to the exception - * constructor, otherwise not. - */ -#define OGDF_THROW_WITH_INFO -#endif - -#ifdef OGDF_THROW -#undef OGDF_THROW -#endif - -#ifndef OGDF_THROW_WITH_INFO -#define OGDF_THROW_PARAM(CLASS, PARAM) throw CLASS ( PARAM ) -#define OGDF_THROW(CLASS) throw CLASS ( ) -#else -//! Replacement for \c throw. -/** - * This macro is used to throw an exception and pass the file name - * and line number of the location in the source file. - * @param CLASS is the name of the exception class. - * @param PARAM is an additional parameter (like the error code) required - * by the exception calls. - */ -#define OGDF_THROW_PARAM(CLASS, PARAM) throw CLASS ( PARAM , __FILE__ , __LINE__ ) -//! Replacement for \c throw. -/** - * This macro is used to throw an exception and pass the file name - * and line number of the location in the source file. - * @param CLASS is the name of the exception class. - */ -#define OGDF_THROW(CLASS) throw CLASS ( __FILE__ , __LINE__ ) -#endif - - - //! Error code for a violated precondition. - /** - * \see PreconditionViolatedException - */ - enum PreconditionViolatedCode { - pvcUnknown, - pvcSelfLoop, //!< graph contains a self-loop - pvcTreeHierarchies, //!< hierarchies are not only trees - pvcAcyclicHierarchies,//!< hierarchies are not acyclic - pvcSingleSource, //!< graph has not a single source - pvcUpwardPlanar, //!< graph is not upward planar - pvcTree, //!< graph is not a rooted tree - pvcForest, //!< graph is not a rooted forest - pvcOrthogonal, //!< layout is not orthogonal - pvcPlanar, //!< graph is not planar - pvcClusterPlanar, //!< graph is not c-planar - pvcNoCopy, //!< graph is not a copy of the corresponding graph - pvcConnected, //!< graph is not connected - pvcBiconnected, //!< graph is not twoconnected - pvcSTOP // INSERT NEW CODES BEFORE pvcSTOP! - }; // enum PreconditionViolatedCode - - - //! Code for an internal failure condition - /** - * \see AlgorithmFailureException - */ - enum AlgorithmFailureCode { - afcUnknown, - afcIllegalParameter, //!< function parameter is illegal - afcNoFlow, //!< min-cost flow could not find a legal flow - afcSort, //!< sequence not sorted - afcLabel, //!< labelling failed - afcExternalFace, //!< external face not correct - afcForbiddenCrossing,//!< crossing forbidden but necessary - afcTimelimitExceeded,//!< it took too long - afcNoSolutionFound, //!< couldn't solve the problem - afcSTOP // INSERT NEW CODES BEFORE afcSTOP! - }; // enum AlgorithmFailureCode - - - - //! Code for the library which was intended to get used, but its use is not supported. - /** - * \see LibraryNotSupportedException - */ - enum LibraryNotSupportedCode { - lnscUnknown, - lnscCoin, //!< COIN not supported - lnscAbacus, //!< ABACUS not supported - lnscFunctionNotImplemented, //!< the used library doesn't support that function - lnscMissingCallbackImplementation, // - lnscSTOP // INSERT NEW CODES BEFORE nscSTOP! - }; // enum AlgorithmFailureCode - - - - //! Base class of all ogdf exceptions. - class OGDF_EXPORT Exception { - - private: - - const char *m_file; //!< Source file where exception occurred. - int m_line; //!< Line number where exception occurred. - - public: - //! Constructs an exception. - /** - * @param file is the name of the source file where exception was thrown. - * @param line is the line number in the source file where the exception was thrown. - */ - Exception(const char *file = NULL, int line = -1) : - m_file(file), - m_line(line) - { } - - //! Returns the name of the source file where exception was thrown. - /** - * Returns a null pointer if the name of the source file is unknown. - */ - const char *file() { return m_file; } - - //! Returns the line number where the exception was thrown. - /** - * Returns -1 if the line number is unknown. - */ - int line() { return m_line; } - }; - - - //! %Exception thrown when result of cast is 0. - class OGDF_EXPORT DynamicCastFailedException : public Exception { - - public: - //! Constructs a dynamic cast failed exception. - DynamicCastFailedException(const char *file = NULL, int line = -1) : Exception(file, line) {} - }; - - - //! %Exception thrown when not enough memory is available to execute an algorithm. - class OGDF_EXPORT InsufficientMemoryException : public Exception { - - public: - //! Constructs an insufficient memory exception. - InsufficientMemoryException(const char *file = NULL, int line = -1) : Exception(file, line) {} - }; - - - //! %Exception thrown when a required standard comparer has not been specialized. - /** - * The default implementation of StdComparer throws this exception, since it - * provides no meaningful implementation of comparer methods. You need to specialize - * this class for the types you want to use with sorting and searching methods (like - * quicksort and binary search). - */ - class OGDF_EXPORT NoStdComparerException : public Exception { - - public: - //! Constructs a no standard comparer available exception. - NoStdComparerException(const char *file = NULL, int line = -1) : Exception(file, line) {} - }; - - - //! %Exception thrown when preconditions are violated. - class OGDF_EXPORT PreconditionViolatedException : public Exception - { - public: - //! Constructs a precondition violated exception. - PreconditionViolatedException(PreconditionViolatedCode code, - const char *file = NULL, - int line = -1) : - Exception(file, line), - m_exceptionCode(code) - {} - - //! Constructs a precondition violated exception. - PreconditionViolatedException( - const char *file = NULL, - int line = -1) : - Exception(file, line), - m_exceptionCode(pvcUnknown) - {} - - //! Returns the error code of the exception. - PreconditionViolatedCode exceptionCode() const { return m_exceptionCode; } - - private: - PreconditionViolatedCode m_exceptionCode; //!< The error code specifying the exception. - }; // class PreconditionViolatedException - - - - //! %Exception thrown when an algorithm realizes an internal bug that prevents it from continuing. - class OGDF_EXPORT AlgorithmFailureException : public Exception - { - public: - - //! Constructs an algorithm failure exception. - AlgorithmFailureException(AlgorithmFailureCode code, - const char *file = NULL, - int line = -1) : - Exception(file, line), - m_exceptionCode(code) - {} - - //! Constructs an algorithm failure exception. - AlgorithmFailureException( - const char *file = NULL, - int line = -1) : - Exception(file, line), - m_exceptionCode(afcUnknown) - {} - - //! Returns the error code of the exception. - AlgorithmFailureCode exceptionCode() const { return m_exceptionCode; } - - private: - AlgorithmFailureCode m_exceptionCode; //!< The error code specifying the exception. - }; // class AlgorithmFailureException - - - - //! %Exception thrown when an external library shall be used which is not supported. - class OGDF_EXPORT LibraryNotSupportedException : public Exception { - public: - //! Constructs a library not supported exception. - LibraryNotSupportedException(LibraryNotSupportedCode code, - const char *file = NULL, - int line = -1) : - Exception(file, line), - m_exceptionCode(code) - {} - - //! Constructs a library not supported exception. - LibraryNotSupportedException( - const char *file = NULL, - int line = -1) : - Exception(file, line), - m_exceptionCode(lnscUnknown) - {} - - //! Returns the error code of the exception. - LibraryNotSupportedCode exceptionCode() const { return m_exceptionCode; } - - private: - LibraryNotSupportedCode m_exceptionCode; //!< The error code specifying the exception. - }; // class LibraryNotSupportedException - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/extended_graph_alg.h b/ext/OGDF/ogdf/basic/extended_graph_alg.h deleted file mode 100644 index 93774c656..000000000 --- a/ext/OGDF/ogdf/basic/extended_graph_alg.h +++ /dev/null @@ -1,421 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of extended graph algorithms - * - * \author Sebastian Leipert, Karsten Klein, Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EXTENDED_GRAPH_ALG_H -#define OGDF_EXTENDED_GRAPH_ALG_H - - -#include -#include -#include -#include - -namespace ogdf { - - -//--------------------------------------------------------- -// Methods for induced subgraphs -//--------------------------------------------------------- - -//! Computes the subgraph induced by a list of nodes. -/** - * @tparam NODELISTITERATOR is the type of iterators for the input list of nodes. - * @param G is the input graph. - * @param start is a list iterator pointing to the first element in a list of nodes, for which - * an induced subgraph shall be computed. - * @param subGraph is assigned the computed subgraph. - */ -template -void inducedSubGraph(const Graph &G, LISTITERATOR start, Graph &subGraph) -{ - NodeArray nodeTableOrig2New; - inducedSubGraph(G,start,subGraph,nodeTableOrig2New); -} - -//! Computes the subgraph induced by a list of nodes (plus a mapping from original nodes to new copies). -/** - * @tparam NODELISTITERATOR is the type of iterators for the input list of nodes. - * @param G is the input graph. - * @param start is a list iterator pointing to the first element in a list of nodes, for which - * an induced subgraph shall be computed. - * @param subGraph is assigned the computed subgraph. - * @param nodeTableOrig2New is assigned a mapping from the nodes in \a G to the nodes in \a subGraph. - */ -template -void inducedSubGraph( - const Graph &G, - LISTITERATOR start, - Graph &subGraph, - NodeArray &nodeTableOrig2New) -{ - subGraph.clear(); - nodeTableOrig2New.init(G,0); - - EdgeArray mark(G,false); - - LISTITERATOR its; - for (its = start; its.valid(); its++) - { - node w = (*its); - OGDF_ASSERT(w != 0 && w->graphOf() == &G); - nodeTableOrig2New[w] = subGraph.newNode(); - - adjEntry adj = w->firstAdj(); - forall_adj(adj,w) - { - edge e = adj->theEdge(); - if (nodeTableOrig2New[e->source()] && nodeTableOrig2New[e->target()] && !mark[e]) - { - subGraph.newEdge(nodeTableOrig2New[e->source()],nodeTableOrig2New[e->target()]); - mark[e] = true; - } - } - } -} - - -//! Computes the subgraph induced by a list of nodes (plus mappings from original nodes and edges to new copies). -/** - * @tparam NODELISTITERATOR is the type of iterators for the input list of nodes. - * @param G is the input graph. - * @param start is a list iterator pointing to the first element in a list of nodes, for which - * an induced subgraph shall be computed. - * @param subGraph is assigned the computed subgraph. - * @param nodeTableOrig2New is assigned a mapping from the nodes in \a G to the nodes in \a subGraph. - * @param edgeTableOrig2New is assigned a mapping from the edges in \a G to the egdes in \a subGraph. - */ -template -void inducedSubGraph( - const Graph &G, - LISTITERATOR start, - Graph &subGraph, - NodeArray &nodeTableOrig2New, - EdgeArray &edgeTableOrig2New) -{ - subGraph.clear(); - nodeTableOrig2New.init(G,0); - edgeTableOrig2New.init(G,0); - - EdgeArray mark(G,false); - - LISTITERATOR its; - for (its = start; its.valid(); its++) - { - node w = (*its); - OGDF_ASSERT(w != 0 && w->graphOf() == &G); - nodeTableOrig2New[w] = subGraph.newNode(); - - adjEntry adj = w->firstAdj(); - forall_adj(adj,w) - { - edge e = adj->theEdge(); - if (nodeTableOrig2New[e->source()] && - nodeTableOrig2New[e->target()] && - !mark[e]) - { - edgeTableOrig2New[e] = - subGraph.newEdge( - nodeTableOrig2New[e->source()], - nodeTableOrig2New[e->target()]); - mark[e] = true; - } - } - } -} - - -//! Computes the edges in a node-induced subgraph. -/** - * @tparam NODELISTITERATOR is the type of iterators for the input list of nodes. - * @tparam EDGELIST is the type of the returned edge list. - * @param G is the input graph. - * @param it is a list iterator pointing to the first element in a list of nodes, whose - * induced subgraph is considered. - * @param E is assigned the list of edges in the node-induced subgraph. - */ -template -void inducedSubgraph(Graph &G, NODELISTITERATOR &it, EDGELIST &E) -{ - NODELISTITERATOR itBegin = it; - NodeArray mark(G,false); - - for (;it.valid();it++) - mark[(*it)] = true; - it = itBegin; - for (;it.valid();it++) - { - node v = (*it); - adjEntry adj; - forall_adj(adj,v) - { - edge e = adj->theEdge(); - if (mark[e->source()] && mark[e->target()]) - E.pushBack(e); - } - } -} - - -//--------------------------------------------------------- -// Methods for clustered graphs -//--------------------------------------------------------- - - -//! Returns true iff cluster graph \a C is c-connected. -OGDF_EXPORT bool isCConnected(const ClusterGraph &C); - -//! Makes a cluster graph c-connected by adding edges. -/** - * @param C is the input cluster graph. - * @param G is the graph associated with the cluster graph \a C; the function adds new edges to this graph. - * @param addedEdges is assigned the list of newly created edges. - * @param simple selects the method used: If set to true, a simple variant that does not guarantee to preserve - * planarity is used. - */ -OGDF_EXPORT void makeCConnected( - ClusterGraph& C, - Graph& G, - List& addedEdges, - bool simple = true); - - - - -//--------------------------------------------------------- -// Methods for st-numbering -//--------------------------------------------------------- - - -//! Computes an st-Numbering of \a G. -/** - * \pre \a G must be biconnected and simple, with the exception that - * the graph is allowed to have isolated nodes. If both \a s and \a t - * are set to nodes (both are not 0), they must be adjacent. - * - * @param G is the input graph. - * @param numbering is assigned the st-number for each node. - * @param s is the source node for the st-numbering. - * @param t is the target node for the st-numbering. - * @param randomized is only used when both \a s and \a t are not set (both are 0); - * in this case a random edge (s,t) is chosen; otherwise the first node s with degree - * > 0 is chosen and its first neighbor is used as t. - * @return the number assigned to \a t, or 0 if no st-numbering could be computed. - */ -OGDF_EXPORT int stNumber(const Graph &G, - NodeArray &numbering, - node s = 0, - node t = 0, - bool randomized = false); - -//! Tests, whether a numbering of the nodes is an st-numbering. -/** - * \pre \a G must be biconnected and simple, with the exception that - * the graph is allowed to have isolated nodes. - */ -OGDF_EXPORT bool testSTnumber(const Graph &G, NodeArray &st_no,int max); - - -//--------------------------------------------------------- -// Methods for minimum spanning tree computation -//--------------------------------------------------------- - -//! Computes a minimum spanning tree using Prim's algorithm -/** - * @tparam T is the numeric type for edge weights. - * @param G is the input graph. - * @param weight is an edge array with the edge weights. - * @param isInTree is assigned the result, i.e. \a isInTree[\a e] is true iff edge \a e is in the computed MST. - * @return the sum of the edge weights in the computed tree. - **/ -template -T computeMinST(const Graph &G, const EdgeArray &weight, EdgeArray &isInTree) { - NodeArray pred(G, 0); - return computeMinST(G.firstNode(), G, weight, pred, isInTree); -} - - -//! Computes a minimum spanning tree (MST) using Prim's algorithm -/** - * @tparam T is the numeric type for edge weights. - * @param G is the input graph. - * @param weight is an edge array with the edge weights. - * @param isInTree is assigned the result, i.e. \a isInTree[\a e] is true iff edge \a e is in the computed MST. - * @param pred is assigned for each node the edge from its parent in the MST. - * @return the sum of the edge weights in the computed tree. - **/ -template -T computeMinST(const Graph &G, const EdgeArray &weight, NodeArray &pred, EdgeArray &isInTree) { - return computeMinST(G.firstNode(), G, weight, pred, isInTree); -} - - -//! Computes a minimum spanning tree (MST) using Prim's algorithm -/** - * @tparam T is the numeric type for edge weights. - * @param s is the start node for Prim's algorithm and will be the root of the MST. - * @param G is the input graph. - * @param weight is an edge array with the edge weights. - * @param isInTree is assigned the result, i.e. \a isInTree[\a e] is true iff edge \a e is in the computed MST. - * @param pred is assigned for each node the edge from its parent in the MST. - * @return the sum of the edge weights in the computed tree. - **/ -template -T computeMinST(node s, const Graph &G, const EdgeArray &weight, NodeArray &pred, EdgeArray &isInTree) -{ - //our priority queue storing the front vertices - BinaryHeap2 pq; - - //initialize tree flag for edges - edge e; - forall_edges(e, G) - { - isInTree[e] = false; - } - - //array to save the position information from pq - int* pqpos = new int[G.numberOfNodes()]; - - int i = 0; - NodeArray vIndex(G); - //array that tells us if node is already processed - NodeArray processed(G); - //predecessor of node v is given by an edge (w,v) - - //insert nodes into pr - node v = G.firstNode(); - T prio = std::numeric_limits::max();; - while (v != 0) - { - vIndex[v] = i; - pq.insert(v, prio, &(pqpos[i++])); - processed[v] = false; - pred[v] = 0; - v = v->succ(); - }//while all nodes - // decrease start node - pq.decreaseKey(pqpos[vIndex[s]], 0.0); - - //extract the nodes again along a minimum ST - while (!pq.empty()) - { - v = pq.extractMin(); - processed[v] = true; - forall_adj_edges(e, v) - { - node w = e->opposite(v); - - int posofw = pqpos[vIndex[w]]; - if ((!processed[w]) && (weight[e] < pq.getPriority(posofw))) - { - pq.decreaseKey(posofw, weight[e]); - pred[w] = e; - }//if improvement - } - }//while pq - - //only for connected graphs - int rootcount = 0; - T treeWeight = 0.0; - forall_nodes(v, G) - { - if (pred[v] == 0) rootcount++; - else - { - isInTree[pred[v]] = true; - treeWeight += weight[pred[v]]; - } - } - OGDF_ASSERT(rootcount == 1); - - delete[] pqpos; - return treeWeight; -}//computeMinST - - -//! Returns true, if G is planar, false otherwise. -/** - * This is a shortcut for BoyerMyrvold::isPlanar(). - * - * @param G is the input graph. - * @return true if \a G is planar, false otherwise. - */ -inline bool isPlanar(const Graph &G) { - return BoyerMyrvold().isPlanar(G); -} - - -//! Returns true, if G is planar, false otherwise. If true is returned, G will be planarly embedded. -/** - * This is a shortcut for BoyerMyrvold::planarEmbed - * - * @param G is the input graph. - * @return true if \a G is planar, false otherwise. - */ -inline bool planarEmbed(Graph &G) { - return BoyerMyrvold().planarEmbed(G); -} - - -//! Constructs a planar embedding of G. It assumes that \a G is planar! -/** - * This routine is slightly faster than planarEmbed(), but requires \a G to be planar. - * If \a G is not planar, the graph will be destroyed while trying to embed it! - * - * This is a shortcut for BoyerMyrvold::planarEmbedPlanarGraph(). - * - * @param G is the input graph. - * @return true if the embedding was successful; false, if the given graph was non-planar (in this case - * the graph will be left in an at least partially deleted state). - * - */ -inline bool planarEmbedPlanarGraph(Graph &G) { - return BoyerMyrvold().planarEmbedPlanarGraph(G); -} - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/geometry.h b/ext/OGDF/ogdf/basic/geometry.h deleted file mode 100644 index 2d50f9ff9..000000000 --- a/ext/OGDF/ogdf/basic/geometry.h +++ /dev/null @@ -1,791 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of classes DPoint, DPolyline, DLine, DRect, DScaler. - * - * \author Joachim Kupke - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GEOMETRY_H -#define OGDF_GEOMETRY_H - -#include -#include -#include -#include - -#define OGDF_GEOM_EPS 1e-06 - - -namespace ogdf { - -//! Determines the orientation in hierarchical layouts. -enum Orientation { - topToBottom, //!< Edges are oriented from top to bottom. - bottomToTop, //!< Edges are oriented from bottom to top. - leftToRight, //!< Edges are oriented from left to right. - rightToLeft //!< Edges are oriented from right to left. -}; - - -// Important: be careful, if compared values are (+/-)DBL_MAX !!! -inline - bool DIsEqual(const double &a, const double &b, const double eps = OGDF_GEOM_EPS) -{ - return (a < (b + eps) && a > (b - eps)); -} - -inline - bool DIsGreaterEqual(const double &a, const double &b, const double eps = OGDF_GEOM_EPS) -{ - return (a > (b - eps)); -} - -inline - bool DIsGreater(const double &a, const double &b, const double eps = OGDF_GEOM_EPS) -{ - return (a > (b + eps)); -} - -inline - bool DIsLessEqual(const double &a, const double &b, const double eps = OGDF_GEOM_EPS) -{ - return (a < (b + eps)); -} - -inline - bool DIsLess(const double &a, const double &b, const double eps = OGDF_GEOM_EPS) -{ - return (a < (b - eps)); -} - -inline - double DRound(const double &d, int prec = 0) -{ - if (prec == 0) - return floor(d + 0.5); - double factor = pow(10.0, ((double) prec)); - return DRound(d * factor, 0) / factor; -} - -/** - * \brief Parameterized base class for points. - * - * This class serves as base class for two-dimensional points with specific - * coordinate types like integer points (IPoint) and real points (DPoint). - * The template parameter NUMBER is the type for the coordinates of the point - * and has to support assignment and equality/inequality operators. - */ -template -class GenericPoint -{ -public: - //! The type for coordinates of the point. - typedef NUMBER numberType; - - NUMBER m_x; //!< The x-coordinate. - NUMBER m_y; //!< The y-coordinate. - - //! Creates a generic point. - /** - * \warning Does not assign something like zero to the coordinates, - * since we do not require that 0 can be casted to a NUMBER. - */ - GenericPoint() { } - - //! Creates a generic point (\a x,\a y). - GenericPoint(NUMBER x, NUMBER y) : m_x(x), m_y(y) { } - - //! Copy constructor. - GenericPoint(const GenericPoint &ip) : m_x(ip.m_x), m_y(ip.m_y) { } - - //! Assignment operator. - GenericPoint operator=(const GenericPoint &ip) { - m_x = ip.m_x; - m_y = ip.m_y; - return *this; - } - - //! Equality operator. - bool operator==(const GenericPoint &ip) const { - return m_x == ip.m_x && m_y == ip.m_y; - } - - //! Inequality operator. - bool operator!=(const GenericPoint &ip) const { - return m_x != ip.m_x || m_y != ip.m_y; - } - -};//class GenericPoint - - -/** - * \brief Integer points. - * - * This class represent a two-dimensional point with integer coordinates. - */ -class OGDF_EXPORT IPoint : public GenericPoint -{ -public: - //! Creates an integer point (0,0). - IPoint() : GenericPoint(0,0) { } - - //! Creates an integer point (\a x,\a y). - IPoint(int x, int y) : GenericPoint(x,y) { } - - //! Copy constructor. - IPoint(const IPoint &ip) : GenericPoint(ip) { } - - //! Returns the euclidean distance between \a p and this point. - double distance(const IPoint &p) const; -};//class IPoint - - -//! Output operator for integer points. -OGDF_EXPORT ostream &operator<<(ostream &os, const IPoint &ip); - - -template<> class DefHashFunc -{ -public: - int hash(const IPoint &ip) const { - return 7*ip.m_x + 23*ip.m_y; - } -}; - - -/** - * \brief Polylines with integer coordinates. - * - * This class represents integer polylines by a list of integer points. - * Such polylines are, e.g., used in layouts for representing bend - * point lists. Note that in this case, only the bend points are in the - * list and neither the start nor the end point. - */ -class OGDF_EXPORT IPolyline : public List { -public: - //! Creates an empty integer polyline. - IPolyline() { } - - //! Copy constructor. - IPolyline(const IPolyline &ipl) : List(ipl) { } - - //! Assignment operator. - IPolyline &operator=(const IPolyline &ipl) { - List::operator =(ipl); - return *this; - } - - //! Returns the euclidean length of the polyline. - double length() const; -}; - - - -/** - * \brief Real points. - * - * This class represent a two-dimensional point with real coordinates. - */ -class OGDF_EXPORT DPoint : public GenericPoint -{ -public: - //! Creates a real point (0,0). - DPoint() : GenericPoint(0,0) { } - - //! Creates a real point (\a x,\a y). - DPoint(double x, double y) : GenericPoint(x,y) { } - - //! Copy constructor. - DPoint(const DPoint &dp) : GenericPoint(dp) { } - - //! Relaxed equality operator. - bool operator==(const DPoint &dp) const { - return DIsEqual(m_x, dp.m_x) && DIsEqual(m_y,dp.m_y); - } - - //! Returns the norm of the point. - double norm() const { - return sqrt(m_x*m_x + m_y*m_y); - } - - //! Addition of real points. - DPoint operator+(const DPoint &p) const; - - //! Subtraction of real points. - DPoint operator-(const DPoint &p) const; - - //! Returns the euclidean distance between \a p and this point. - double distance(const DPoint &p) const; -}; - -//! Output operator for real points. -OGDF_EXPORT ostream &operator<<(ostream &os, const DPoint &dp); - - -/** - * \brief Vectors with real coordinates. - */ -class OGDF_EXPORT DVector : public DPoint { -public: - - //! Creates a vector (0,0). - DVector() : DPoint() { } - - //! Creates a vector (\a x,\a y). - DVector(double x, double y) : DPoint(x, y) { } - - //! Copy constructor. - DVector(const DVector &dv) : DPoint(dv) { } - - //! Assignment operator. - DVector operator=(const DPoint &ip) { - if (this != &ip) - { - m_x = ip.m_x; - m_y = ip.m_y; - } - return *this; - } - - //! Multiplies all coordinates with \a val. - DVector operator*(const double val) const; - - //! Divides all coordinates by \a val. - DVector operator/(const double val) const; - - //! Returns the length of the vector. - double length() const; - - //! Returns the determinante of the vector. - double operator^(const DVector &dv) const; - - //! Returns the scalar product of this vecor and \a dv. - double operator*(const DVector &dv) const; - - /** - * \brief Returns a vector that is orthogonal to this vector. - * - * Returns the vector \f$(y/x,1)\f$ if \f$x\neq 0\f$, or \f$(1,0)\f$ - * otherwise, where \f$(x,y)\f$ is this vector. - */ - DVector operator++() const; - - /** - * \brief Returns a vector that is orthogonal to this vector. - * - * Returns the vector \f$(-y/x,-1)\f$ if \f$x\neq 0\f$, or \f$(-1,0)\f$ - * otherwise, where \f$(x,y)\f$ is this vector. - */ - DVector operator--() const; -}; - - - -/** - * \brief Polylines with real coordinates. - * - * This class represents real polylines by a list of real points. - * Such polylines are, e.g., used in layouts for representing bend - * point lists. - */ -class OGDF_EXPORT DPolyline : public List { - static const double s_prec; //!< The conversion-precision. -public: - //! Creates an empty integer polyline. - DPolyline() { } - - //! Copy constructor. - DPolyline(const DPolyline &dpl) : List(dpl) { } - - //! Assignment operator. - DPolyline &operator=(const DPolyline &dpl) { - List::operator =(dpl); - return *this; - } - - //! Returns the euclidean length of the polyline. - double length() const; - - /** - * \brief Returns a point on the polyline which is \a fraction * \a len - * away from the start point. - * - * @param fraction defines the fraction of \a lento be considered. - * @param len is the given length, or the length of the polyline if \a len < 0. - */ - DPoint position(const double fraction, double len = -1.0) const; - - //! Writes the polyline as graph in gml-format to file \a filename. - void writeGML(const char* filename) const; - - //! Writes the polyline as graph in gml-format to output stream \a stream. - void writeGML(ostream &stream) const; - - //! Deletes all successive points with equal coordinates. - void unify(); - - //! Deletes all redundant points on the polyline that lie on a straight line given by their adajcent points. - void normalize(); - - //! Deletes all redundant points on the polyline that lie on a straight line given by their adajcent points. - void normalize(DPoint src, //start point of the edge - DPoint tgt); //end point of the edge - - //! Converts all coordinates rounded to \a s_prec decimal digits. - void convertToInt(); - - //void reConvertToDouble(); -}; - - -/** - * \brief Lines with real coordinates. - */ -class OGDF_EXPORT DLine { - -protected: - DPoint m_start; //!< The start point of the line. - DPoint m_end; //!< The end point of the line. - -public: - - //! Creates an empty line. - DLine() : m_start(), m_end() {} - - //! Creates a line with start point \a p1 and end point \a p2. - DLine(const DPoint &p1, const DPoint &p2) : m_start(p1), m_end(p2) {} - - //! Copy constructor. - DLine(const DLine &dl) : m_start(dl.m_start), m_end(dl.m_end) {} - - //! Creates a line with start point (\a x1,\a y1) and end point (\a x2,\a y2). - DLine(double x1, double y1, double x2, double y2) { - m_start.m_x = x1; m_start.m_y = y1; m_end.m_x = x2; m_end.m_y = y2; - } - - //! Equality operator. - bool operator==(const DLine &dl) const { - return m_start == dl.m_start && m_end == dl.m_end; - } - - //! Inequality operator. - bool operator!=(const DLine &dl) const { - return !(*this == dl); - } - - //! Assignment operator. - DLine &operator= (const DLine &dl) { - if (this != &dl) { // don't assign myself - m_start = dl.m_start; - m_end = dl.m_end; - } - return *this; - } - - //! Returns the start point of the line. - const DPoint &start() const { return m_start; } - - //! Returns the end point of the line. - const DPoint &end() const { return m_end; } - - //! Returns the x-coordinate of the difference (end point - start point). - double dx() const { return m_end.m_x - m_start.m_x; } - - //! Returns the y-coordinate of the difference (end point - start point). - double dy() const { return m_end.m_y - m_start.m_y; } - - //! Returns the slope of the line. - double slope() const { return (dx() == 0) ? DBL_MAX : dy()/dx(); } - - //! Returns the value y' such that (0,y') lies on the unlimited straight-line define dby this line. - double yAbs() const { return (dx() == 0) ? DBL_MAX : m_start.m_y - (slope() * m_start.m_x); } - - //! Returns true iff this line runs vertically. - bool isVertical() const { return (DIsEqual(dx(), 0.0)); } - - //! Returns true iff this line runs horizontally. - bool isHorizontal() const { return (DIsEqual(dy(), 0.0)); } - - /** - * \brief Returns true iff \a line and this line intersect. - * - * @param line is the second line. - * @param inter is assigned the intersection point if true is returned. - * @param endpoints determines if common endpoints are treated as intersection. - */ - bool intersection(const DLine &line, DPoint &inter, bool endpoints = true) const; - - //! Returns true iff \a p lie on this line. - bool contains(const DPoint &p) const; - - //! Returns the length (euclidean distance between start and edn point) of this line. - double length() const { - return m_start.distance(m_end); - } - - /** - * \brief Computes the intersection between this line and the horizontal line through y = \a horAxis. - * - * @param horAxis defines the horizontal line. - * @param crossing is assigned the x-coordinate of the intersection point. - * - * \return the number of intersection points (0 = none, 1 = one, 2 = this - * line lies on the horizontal line through y = \a horAxis). - */ - int horIntersection(const double horAxis, double &crossing) const; - - // gives the intersection with the vertical axis 'verAxis', returns the number of intersections - // 0 = no, 1 = one, 2 = infinity or both end-points, e.g. parallel on this axis - /** - * \brief Computes the intersection between this line and the vertical line through x = \a verAxis. - * - * @param verAxis defines the vertical line. - * @param crossing is assigned the y-coordinate of the intersection point. - * - * \return the number of intersection points (0 = none, 1 = one, 2 = this - * line lies on the vertical line through x = \a verAxis). - */ - int verIntersection(const double verAxis, double &crossing) const; -}; - -//! Output operator for lines. -ostream &operator<<(ostream &os, const DLine &dl); - - -/** - * \brief Rectangles with real coordinates. - */ -class OGDF_EXPORT DRect { - -private: - DPoint m_p1; //!< The lower left point of the rectangle. - DPoint m_p2; //!< The upper right point of the rectangle. - -public: - //! Creates a rectangle with lower left and upper right point (0,0). - DRect() : m_p1(), m_p2() {} - - //! Creates a rectangle with lower left point \a p1 and upper right point \a p2. - DRect(const DPoint &p1, const DPoint &p2) : m_p1(p1), m_p2(p2) - { normalize(); } - - //! Creates a rectangle with lower left point (\a x1,\a y1) and upper right point (\a x1,\a y2). - DRect(double x1, double y1, double x2, double y2) { - m_p1.m_x = x1; m_p1.m_y = y1; m_p2.m_x = x2; m_p2.m_y = y2; - normalize(); - } - - //! Creates a rectangle defined by the end points of line \a dl. - DRect(const DLine &dl) : m_p1(dl.start()), m_p2(dl.end()) - { normalize(); } - - //! Copy constructor. - DRect(const DRect &dr) : m_p1(dr.m_p1), m_p2(dr.m_p2) - { normalize(); } - - //! Equality operator. - bool operator==(const DRect &dr) const { - return m_p1 == dr.m_p1 && m_p2 == dr.m_p2; - } - - //! Inequality operator. - bool operator!=(const DRect &dr) const { - return !(*this == dr); - } - - //! Assignment operator. - DRect &operator= (const DRect &dr) { - if (this != &dr) { // don't assign myself - m_p1 = dr.m_p1; - m_p2 = dr.m_p2; - } - return *this; - } - - //! Returns the width of the rectangle. - double width() const { - return m_p2.m_x - m_p1.m_x; - } - - //! Returns the height of the rectangle. - double height() const { - return m_p2.m_y - m_p1.m_y; - } - - /** - * \brief Normalizes the rectangle. - * - * Makes sure that the lower left point lies below and left of the upper - * right point. - */ - void normalize() { - if (width() < 0) swap(m_p2.m_x, m_p1.m_x); - if (height() < 0) swap(m_p2.m_y, m_p1.m_y); - } - - //! Returns the lower left point of the rectangle. - const DPoint &p1() const { return m_p1; } - - //! Returns the upper right point of the rectangle. - const DPoint &p2() const { return m_p2; } - - //! Returns the top side of the rectangle. - const DLine topLine() const { - return DLine( DPoint(m_p1.m_x, m_p2.m_y), DPoint(m_p2.m_x, m_p2.m_y)); - } - - //! Returns the right side of the rectangle. - const DLine rightLine() const { - return DLine( DPoint(m_p2.m_x, m_p2.m_y), DPoint(m_p2.m_x, m_p1.m_y)); - } - - //! Returns the left side of the rectangle. - const DLine leftLine() const { - return DLine( DPoint(m_p1.m_x, m_p1.m_y), DPoint(m_p1.m_x, m_p2.m_y)); - } - - //! Returns the bottom side of the rectangle. - const DLine bottomLine() const { - return DLine( DPoint(m_p2.m_x, m_p1.m_y), DPoint(m_p1.m_x, m_p1.m_y)); - } - - //! Swaps the y-coordinates of the two points. - void yInvert() { swap(m_p1.m_y, m_p2.m_y); } - - //! Swaps the x-coordinates of the two points. - void xInvert() { swap(m_p1.m_x, m_p2.m_x); } - - //! Returns true iff \a p lies within this rectangle. - bool contains(const DPoint &p) const { - if (DIsLess (p.m_x, m_p1.m_x) || - DIsGreater(p.m_x, m_p2.m_x) || - DIsLess (p.m_y, m_p1.m_y) || - DIsGreater(p.m_y, m_p2.m_y)) - return false; - return true; - } -}; - -//! Output operator for rectangles. -OGDF_EXPORT ostream &operator<<(ostream &os, const DRect &dr); - - -/** -* \brief Scaling between coordinate systems. -*/ -class OGDF_EXPORT DScaler { - -private: - - const DRect *m_from; //!< Rectangluar area in source coordinate system. - const DRect *m_to; //!< Rectangluar area in target coordinate system. - - double m_factorX; //!< The scaling factor for the x-coordinates. - double m_factorY; //!< The scaling factor for the y-coordinates. - double m_offsetX; //!< The offset for the x-coordinates. - double m_offsetY; //!< The offset for the y-coordinates. - -public: - //! Creates a scaler for scaling from area \a from to area \a to. - DScaler(const DRect &from, const DRect &to) : - m_from(&from), - m_to(&to), - m_factorX(to.width()/from.width()), - m_factorY(to.height()/from.height()), - m_offsetX(to.p1().m_x - from.p1().m_x * m_factorX), - m_offsetY(to.p1().m_y - from.p1().m_y * m_factorY) { } - - ~DScaler() {} - - //! Returns the rectangle in the source coordinate system. - const DRect &from() const { return *m_from; } - - //! Returns the rectangle in the target coordinate system. - const DRect &to() const { return *m_to; } - - //! Transforms x-coordinates from source to target coordinate system. - double scaleToX(double x) { return x * m_factorX + m_offsetX; } - - //! Transforms y-coordinates from source to target coordinate system. - double scaleToY(double y) { return y * m_factorY + m_offsetY; } - - //! Scales a horizontal length from source to target coordinate system. - double scaleWidth(double width) { return width * m_to->width() /m_from->width(); } - - //! Scales a vertical length from source to target coordinate system. - double scaleHeight(double height) { return height * m_to->height()/m_from->height(); } -}; - - -//! Output operator for scalers. -OGDF_EXPORT ostream &operator<<(ostream &os, const DScaler &ds); - - -/** - * \brief Line segments with real coordinates. - */ -class OGDF_EXPORT DSegment : public DLine { - -protected: - -public: - - //! Creates an empty line segment. - DSegment() : DLine() {} - - //! Creates a line segment from \a p1 to \a p2. - DSegment(const DPoint &p1, const DPoint &p2) : DLine(p1, p2) {} - - //! Creates a line segment defined by the start and end point of line \a dl. - DSegment(const DLine &dl) : DLine(dl) {} - - //! Creates a line segment from (\a x1,\a y1) to (\a x2,\a y2). - DSegment(double x1, double y1, double x2, double y2) : DLine(x1, y1, x2, y2) {} - - //! Copy constructor. - DSegment(const DSegment &ds) : DLine(ds) {} - - - /** - * \brief Determines if \a segment is left or right of this segment. - * - * \return a positve number if \a segment is left of this segment, and a - * a negative number if \a segment is right of this segment. - */ - double det(const DSegment &segment) const { - return (dx() * segment.dy() - dy() * segment.dx()); - } -}; - - -/** - * \brief Polygons with real coordinates. - */ -class OGDF_EXPORT DPolygon : public DPolyline { - -protected: - - bool m_counterclock; //!< If true points are given in conter-clockwise order. - -public: - /** - * \brief Creates an empty polygon. - * - * @param cc determines in which order the points will be given; true means - * counter-clockwise, false means clockwise. - */ - DPolygon(bool cc = true) : m_counterclock(cc) { } - - //! Creates a polgon from a rectangle. - DPolygon(const DRect &rect, bool cc = true) : m_counterclock(cc) { - operator=(rect); - } - - //! Copy constructor. - DPolygon(const DPolygon &dop) : DPolyline(dop), m_counterclock(dop.m_counterclock) { } - - //! Returns true iff points are given in counter-clockwise order. - bool counterclock() { return m_counterclock; } - - //! Assignment operator. - DPolygon &operator=(const DPolygon &dop) { - List::operator =(dop); - m_counterclock = dop.m_counterclock; - return *this; - } - - //! Assignment operator (for assigning from a rectangle). - DPolygon &operator=(const DRect &rect); - - //! Returns the line segment that starts at position \a it. - DSegment segment(ListConstIterator it) const; - - - //! Inserts point \a p, that must lie on a polygon segment. - ListIterator insertPoint(const DPoint &p) { - return insertPoint(p, begin(), begin()); - } - - /** - * \brief Inserts point \a p, but just searching from point \a p1 to \a p2. - * - * That is, from the segment starting at \a p1 to the segment ending at \a p2. - */ - ListIterator insertPoint(const DPoint &p, - ListIterator p1, - ListIterator p2); - - //! Inserts point p on every segment (a,b) with \a p in the open range ]a, b[. - void insertCrossPoint(const DPoint &p); - - //! Returns the list of intersection points of this polygon with \a p. - int getCrossPoints(const DPolygon &p, List &crossPoints) const; - - //! Deletes all consecutive points that are equal. - void unify(); - - //! Deletes all points, which are not facets. - void normalize(); - - //! Writes the polygon as graph in gml-format to file \a filename. - void writeGML(const char* filename) const; - - //! Writes the polygon as graph in gml-format to output stream \a stream. - void writeGML(ostream &stream) const; - - /** - * \brief Checks wether a Point /a p is inside the Poylgon or not. - * \note Polygons with crossings have inner areas that count as outside! - * \par p the Point to check. - * return true if Point is inside. - */ - bool containsPoint(DPoint &p) const; -}; - -//! Output operator for polygons. -OGDF_EXPORT ostream &operator<<(ostream &os, const DPolygon &dop); - - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/graph_generators.h b/ext/OGDF/ogdf/basic/graph_generators.h deleted file mode 100644 index 7dd0caf67..000000000 --- a/ext/OGDF/ogdf/basic/graph_generators.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of graph generators. - * - * \author Carsten Gutwenger, Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRAPH_GENERATORS_H -#define OGDF_GRAPH_GENERATORS_H - - -#include -#include - -namespace ogdf { - -//! Creates a random graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the generated graph. - * @param m is the number of edges of the generated graph. - */ -OGDF_EXPORT void randomGraph(Graph &G, int n, int m); - -//! Creates a random simple graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the generated graph. - * @param m is the number of edges of the generated graph. - */ -OGDF_EXPORT bool randomSimpleGraph(Graph &G, int n, int m); - -//! Creates a random biconnected graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the generated graph. - * @param m is the number of edges of the generated graph. - */ -OGDF_EXPORT void randomBiconnectedGraph(Graph &G, int n, int m); - -//! Creates a connected (simple) planar (embedded) graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the generated graph. - * @param m is the number of edges of the generated graph. - */ -OGDF_EXPORT void planarConnectedGraph(Graph &G, int n, int m); - -//! Creates a planar biconnected (embedded) graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the generated graph. - * @param m is the number of edges of the generated graph. - * @param multiEdges determines if the generated graph may contain - * multi-edges. - */ -OGDF_EXPORT void planarBiconnectedGraph(Graph &G, int n, int m, bool multiEdges = false); - -//! Creates a planar graph, that is connected, but not biconnected. -/* @param n is the max. number of nodes in each biconencted component - * @param m is the max. number of edges in each biconnected component - * @param b is the number of biconnected components - */ -OGDF_EXPORT void planarCNBGraph(Graph &G, int n, int m, int b); - -//! Creates a random triconnected (and simple) graph. -/** - * The graph generator proceeds as follows. It starts with a \f$K_4\f$ and performs - * then \a n-4 split node operations on randomly selected nodes of the graph - * constructed so far. Each such operation splits a node \a v into two nodes - * \a x and \a y and distributes \a v's neighbors to the two nodes such that each - * node gets at least two neighbors. Additionally, the edge (\a x,\a y) is inserted. - * - * The neighbors are distributed such that a neighbor of \a v becomes - * - only a neighbor of \a x with probability \a p1; - * - only a neighbor of \a y with probability \a p1; - * - a neighbor of both \a x and \a y with probability 1.0 - \a p1 - \a p2. - * - * @param G is assigned the generated graph. - * @param n is the number of nodes in the generated graph. - * @param p1 is the probability that an edge is moved only to the left - * node after splitting a node. - * @param p2 is the probability that an edge is moved only to the right - * node after splitting a node. - * - * The probability for a neighbor to be moved to both split nodes is - * 1.0 - \a p1 - \a p2. The higher this probability, the higher the density - * of the resulting graph. - * - * \pre The probabilities \a p1 and \a p2 must lie between 0.0 and 1.0, and - * \a p1 + \a p2 \f$\leq\f$ 1.0. - */ -OGDF_EXPORT void randomTriconnectedGraph(Graph &G, int n, double p1, double p2); - -//! Creates a planar triconnected (and simple) graph. -/** - * This graph generator works in two steps. - * -# A planar triconnected 3-regular graph is constructed using successive - * splitting of pairs of nodes. The constructed graph has \a n nodes and - * 1.5\a n edges. - * -# The remaining edges are inserted by successive splitting of faces - * with degree four or greater. - * The resulting graph also represents a combinatorial embedding. - * - * @param G is assigned the generated graph. - * @param n is the number of nodes in the generated graph. - * @param m is the number of edges in the generated graph. - * - * \pre - * - \a n \f$\geq\f$ 4 and \a n must be even; otherwise, \a n is adjusted - * to the next feasible integer. - * - 1.5\a n \f$\leq\f$ \a m \f$\leq\f$ 3\a n-6; otherwise, \a m is adjusted - * to a feasible value. - */ -OGDF_EXPORT void planarTriconnectedGraph(Graph &G, int n, int m); - -//! Creates a planar triconnected (and simple) graph. -/** - * This graph generator creates a planar triconnected graph by successive - * node splitting. It starts with the \f$K_4\f$ and performs \a n-4 node - * splits. Each such split operation distributes a node's neighbors to the - * two nodes resulting from the split. Aftewards, two further edges can be - * added; the probability for adding these edges is given by \a p1 and \a p2. - * The higher these probabilities, the denser the resulting graph. Note that - * a simple planar triconnected graph has between 1.5\a n and 3\a n-6 edges. - * - * \pre 0.0 \f$\le\f$ \a p1, \a p2 \f$\le\f$ 1.0. - * - * @param G is assigned the generated graph. - * @param n is the number of nodes in the generated graph. - * @param p1 is the probability for the first additional edge to be added. - * @param p2 is the probability for the second additional edge to be added. - */ -OGDF_EXPORT void planarTriconnectedGraph(Graph &G, int n, double p1, double p2); - -//! Creates a random tree (simpler version. -/** - * @param G is assigned the tree. - * @param n is the number of nodes of the tree. - */ -OGDF_EXPORT void randomTree(Graph& G, int n); - -//! Creates a random tree. -/** - * @param G is assigned the tree. - * @param n is the number of nodes of the tree. - * @param maxDeg is the maximal allowed node degree; 0 means no restriction. - * @param maxWidth is the maximal allowed width of a level; 0 means no restriction. - */ -OGDF_EXPORT void randomTree(Graph &G, int n, int maxDeg, int maxWidth); - -//! Creates a regular tree. -/** - * @param G is assigned the tree. - * @param n is the number of nodes of the tree. - * @param children is the number of children per node. root has index 0, the next level has - * indizes 1...children, the children of node 1 have indizes children+1...2*children, etc. - * if number of nodes does not allow a regular node, the "last" node will have fewer children. - */ -void regularTree(Graph& G, int n, int children); - - - -//! Creates a random hierarchical graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes. - * @param m is the number of edges. - * @param planar determines if the resulting graph is (level-)planar. - * @param singleSource determines if the graph is a single-source graph. - * @param longEdges determines if the graph has long edges (spanning 2 layers - * or more); otherwise the graph is proper. - */ -OGDF_EXPORT void randomHierarchy( - Graph &G, - int n, - int m, - bool planar, - bool singleSource, - bool longEdges); - -//! Assigns random clusters to a given graph \a G. -/** - * This function is called with a graph \a G and creates randomly clusters. - * The resulting cluster graph is always c-connected and, - * if G is planar, also c-planar. - * @param G is the input graph. - * @param C is a cluster graph for \a G. - * @param cNum is the maximal number of Clusters introduced. - * \pre \a G is connected and not empty and \a C is initialized with \a G. - */ -OGDF_EXPORT void randomClusterPlanarGraph(ClusterGraph &C,Graph &G,int cNum); - -//! Assigns random clusters to a given graph \a G. -/** - * This function is called with a graph \a G and creates randomly clusters. - * @param G is the input graph. - * @param C is a cluster graph for \a G. - * @param cNum is the maximal number of clusters introduced. - * \pre \a G is connected and not empty and \a C is initialized with \a G. - */ -OGDF_EXPORT void randomClusterGraph(ClusterGraph &C,Graph &G,int cNum); - - -//! Assigns a specified cluster-structure to a given graph \a G, and assigns vertices to clusters. -/** - * This function is called with a graph \a G and the root of a second graph, resembling a tree, - * that gives the cluster structure. Then, the vertices of G are randomly assigned to the clusters, - * where we can guarantee that any leaf-cluster has (on average) moreInLeaves-times more vertices - * than a non-leaf cluster. (E.g. if \a moreInLeaves = 5, any leaf will contain roughly 5 times more vertices than - * an inner cluster) - * @param C is a cluster graph for \a G, to be assigned the solution. - * @param G is the input graph. - * @param root is a node in some other graph (say \a T). \a T is a tree that we will consider rooted at \a root. - * \a T is the pattern for the cluster hierarchy. - * @param moreInLeaves is a factor such that leaf-clusters have on average moreInLeaves-times more - * vertices than inner clusters - * \pre \a G contains at least twice as many nodes as \a T has leaves. - */ -OGDF_EXPORT void randomClusterGraph(ClusterGraph& C, const Graph& G, const node root, int moreInLeaves); - - -//! Creates the complete graph \f$K_n\f$. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the generated graph. - */ -OGDF_EXPORT void completeGraph(Graph &G, int n); - -//! Creates t complete bipartite graph \f$K_{n,m}\f$. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes of the first partition set. - * @param m is the number of nodes of the second partition set. - */ -OGDF_EXPORT void completeBipartiteGraph(Graph &G, int n, int m); - -//! Creates the graph \f$W_n^{(d)}\f$: A wheel graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes on the rim of the wheel (W_n). - */ -OGDF_EXPORT void wheelGraph(Graph &G, int n); - -//! Creates the graph \f$Q^n\f$: A n-cube graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of the cube's dimensions (n>=0). - */ -OGDF_EXPORT void cubeGraph(Graph &G, int n); - -//! Modifies \a G by adding its n-th suspension. -/** - * @param G is the graph to extend. - * @param s is the suspension. - */ -OGDF_EXPORT void suspension(Graph &G, int s); - -//! Creates a (toroidal) grid graph on \a n x \a m nodes. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes on first axis. - * @param m is the number of nodes on second axis. - * @param loopN if the grid is cyclic on first axis - * @param loopM if the grid is cyclic on second axis - */ -OGDF_EXPORT void gridGraph(Graph &G, int n, int m, bool loopN, bool loopM); - -//! Creates a generalized Petersen graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes on outer cycle. - * @param m is the number of jumps. - */ -OGDF_EXPORT void petersenGraph(Graph &G, int n, int m); - -//! Creates a random (simple) directed graph. -/** - * @param G is assigned the generated graph. - * @param n is the number of nodes in the generated graph. - * @param p is the probability that an edge is created (for each node pair) - */ -OGDF_EXPORT void randomDiGraph(Graph &G, int n, double p); - - - -} - - -#endif diff --git a/ext/OGDF/ogdf/basic/memory.h b/ext/OGDF/ogdf/basic/memory.h deleted file mode 100644 index e1efb5553..000000000 --- a/ext/OGDF/ogdf/basic/memory.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of memory manager for allocating small - * pieces of memory - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MEMORY_H -#define OGDF_MEMORY_H - - -#include -#include - - -//--------------------------------------------------------------------- -// configuration of memory-manager (can also be set by compiler flag) -// -// the good old pool allocator (not thread-safe) -//#define OGDF_MEMORY_POOL_NTS -// -// just using malloc/free (thread-safe) -//#define OGDF_MEMORY_MALLOC_TS -// -// new buffered-pool allocator per thread pool (thread-safe) -//#define OGDF_MEMORY_POOL_TS -// -// default (nothing defined): depending on system / compiler -//--------------------------------------------------------------------- - -// By default, we use the non-thread safe variant on cygwin and g++ 3.x -// since thread-local storage is not working there, and a thread-safe -// pool allocator otherwise. -#if !defined(OGDF_MEMORY_POOL_NTS) && !defined(OGDF_MEMORY_MALLOC_TS) && !defined(OGDF_MEMORY_POOL_TS) -#define OGDF_MEMORY_POOL_TS -#endif - -#include -#include - - -namespace ogdf { - -#define OGDF_MM(Alloc) \ -public: \ -static void *operator new(size_t nBytes) { \ - if(OGDF_LIKELY(Alloc::checkSize(nBytes))) \ - return Alloc::allocate(nBytes); \ - else \ - return MallocMemoryAllocator::allocate(nBytes); \ -} \ -\ -static void operator delete(void *p, size_t nBytes) { \ - if(OGDF_LIKELY(p != 0)) { \ - if(OGDF_LIKELY(Alloc::checkSize(nBytes))) \ - Alloc::deallocate(nBytes, p); \ - else \ - MallocMemoryAllocator::deallocate(nBytes, p); \ - } \ -} \ -static void *operator new(size_t, void *p) { return p; } \ -static void operator delete(void *, void *) { } - - -#define OGDF_NEW new - -#ifdef OGDF_MEMORY_MALLOC_TS -#define OGDF_ALLOCATOR ogdf::MallocMemoryAllocator -#else -#define OGDF_ALLOCATOR ogdf::PoolMemoryAllocator -#endif - -//! Creates new and delete operators in a class using ogdf's memory allocator. -#define OGDF_NEW_DELETE OGDF_MM(OGDF_ALLOCATOR) - -//! Creates new and delete operators in a class using the malloc memory allocator. -#define OGDF_MALLOC_NEW_DELETE OGDF_MM(MallocMemoryAllocator) - -} // namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/basic/precondition.h b/ext/OGDF/ogdf/basic/precondition.h deleted file mode 100644 index 25f9aca54..000000000 --- a/ext/OGDF/ogdf/basic/precondition.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of functions for drawing module precondition - * handling. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PRECONDITION_H -#define OGDF_PRECONDITION_H - - -#include - - -namespace ogdf { - -//descent the hierarchy tree at "sink" v recursively -bool dfsGenTreeRec( - UMLGraph& UG, - EdgeArray &used, - NodeArray &hierNumber, //number of hierarchy tree - // A node is visited if its hierNumber != 0 - int hierNum, - node v, - List& fakedGens, //temporary - bool fakeTree) -{ - OGDF_ASSERT(hierNumber[v] == 0); - hierNumber[v] = hierNum; - - bool returnValue = true; - - edge e; - forall_adj_edges(e,v) { - if (e->source() == v) continue; - if (!(UG.type(e) == Graph::generalization)) continue; - if (used[e]) continue; //error ?? - used[e] = true; - - node w = e->opposite(v); - - if (hierNumber[w]) { - //temporarily fake trees - //if (hierNumber[w] == hierNum) //forward search edge - if (fakeTree) - { - //UG.type(e) = Graph::association; - fakedGens.pushBack(e); - continue; - } - else return false;//reached w over unused edge => no tree - } - - returnValue = dfsGenTreeRec(UG, used, hierNumber, hierNum, w, fakedGens, fakeTree); - //shortcut - if (!returnValue) return false; - } - - return returnValue; -} - -edge firstOutGen(UMLGraph& UG, node v, EdgeArray& /* used */) -{ - //pruefen: kann es hier bereits ausgehende besuchte Kanten geben??? - edge e; - forall_adj_edges(e, v) - { - if (e->target() == v) continue; - if (UG.type(e) == Graph::generalization) - { - //OGDF_ASSERT(!used[e]); - return e; - } - else continue; - }//forall - return 0; -}//firstOutGen - -bool dfsGenTree( - UMLGraph& UG, - List& fakedGens, - bool fakeTree) -{ - edge e; - EdgeArray used(UG, false); - //NodeArray visited(UG,false); - NodeArray hierNumber(UG, 0); - - int hierNum = 0; //number of hierarchy tree - - const Graph& G = UG; - forall_edges(e, G) - { - //descent in the hierarchy containing e - if ((!used[e]) && (UG.type(e) == Graph::generalization)) - { - hierNum++; //current hierarchy tree - //first we search for the sink - node sink = e->target(); - edge sinkPath = firstOutGen(UG, e->target(), used); - int cycleCounter = 0; - while (sinkPath) - { - sink = sinkPath->target(); - sinkPath = firstOutGen(UG, sinkPath->target(), used); - cycleCounter++; - //if theres no sink, ?throw errGenCycle?, or convert Gens to Ass and draw - if (cycleCounter > G.numberOfEdges()) - { - //versuche workaround: eigentlich werden die Typen erst spaeter - //gesetzt, damit es nicht zu Fehlern bei der Erkennung kommt, aber - //zum Abbruch wird hier bereits eine gesetzt (geht es auch ohne?) - UG.type(sinkPath) = Graph::association; - fakedGens.pushBack(sinkPath); - sink = sinkPath->source(); - sinkPath = 0; - //throw OgdfException(errGenCycle); //vorlaeufig - } - } - - //now sink is the hierarchy sink - - //used is set in dfsGenTreeRec - bool isTree = dfsGenTreeRec(UG, used, hierNumber, hierNum, sink, fakedGens, fakeTree); - if (!isTree) return false; - } - - }//forall_edges - - return true; -} - -}//end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/simple_graph_alg.h b/ext/OGDF/ogdf/basic/simple_graph_alg.h deleted file mode 100644 index 8e21d7d47..000000000 --- a/ext/OGDF/ogdf/basic/simple_graph_alg.h +++ /dev/null @@ -1,800 +0,0 @@ -/* - * $Revision: 2593 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 15:33:53 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of simple graph algorithms. - * - * \author Carsten Gutwenger and Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SIMPLE_GRAPH_ALG_H -#define OGDF_SIMPLE_GRAPH_ALG_H - - -#include -#include -#include - -namespace ogdf { - - -//--------------------------------------------------------- -// Methods for loops -//--------------------------------------------------------- - -//! Returns true iff \a G contains no self-loop. -/** - * @param G is the input graph. - * @return true if \a G contains no self-loops (edges whose two endpoints are the same), false otherwise. - */ -OGDF_EXPORT bool isLoopFree(const Graph &G); - -//! Removes all self-loops from \a G and returns all nodes with self-loops in \a L. -/** - * @tparam NODELIST is the type of the node list for returning the nodes with self-loops. - * @param G is the input graph. - * @param L is assigned the list of nodes with self-loops. - */ -template -void makeLoopFree(Graph &G, NODELIST &L) -{ - L.clear(); - - edge e, eNext; - for (e = G.firstEdge(); e; e = eNext) { - eNext = e->succ(); - if (e->isSelfLoop()) { - L.pushBack(e->source()); - G.delEdge(e); - } - } -} - - -//! Removes all self-loops from \a G. -/** - * @param G is the input graph. - */ -OGDF_EXPORT void makeLoopFree(Graph &G); - - -//--------------------------------------------------------- -// Methods for parallel edges -//--------------------------------------------------------- - -//! Sorts the edges of \a G such that parallel edges come after each other in the list. -/** - * @param G is the input graph. - * @param edges is assigned the list of sorted edges. - */ -OGDF_EXPORT void parallelFreeSort(const Graph &G, SListPure &edges); - - -//! Returns true iff \a G contains no paralle edges. -/** - * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in - * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to - * test if a graph contains no undirected parallel edges, use isParallelFreeUndirected(). - * - * @param G is the input graph. - * @return true if \a G contains no multi-edges (edges with the same source and target). - */ -OGDF_EXPORT bool isParallelFree(const Graph &G); - - -//! Returns the number of parallel edges in \a G. -/** - * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in - * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to - * also take reversal edges into account, use numParallelEdgesUndirected(). - * - * @param G is the input graph. - * @return is the number of parallel edges: for each bundle of parallel edges between two nodes - * v and w, all but one are counted. - */ -OGDF_EXPORT int numParallelEdges(const Graph &G); - - -//! Removes all but one of each bundle of parallel edges. -/** - * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in - * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not multi-edges. If you want to - * remove parallel and reversal edges, use makeParallelFreeUndirected(Graph&,EDGELIST&). - * - * @tparam EDGELIST is the type of edge list that will be assigned the list of parallel edges. - * @param G is the input graph. - * @param parallelEdges is assigned the list of remaining edges in \a G that were part of a - * bundle of parallel edges in the input graph. - */ -template -void makeParallelFree(Graph &G, EDGELIST ¶llelEdges) -{ - parallelEdges.clear(); - if (G.numberOfEdges() <= 1) return; - - SListPure edges; - parallelFreeSort(G,edges); - - SListConstIterator it = edges.begin(); - edge ePrev = *it++, e; - bool bAppend = true; - while(it.valid()) { - e = *it++; - if (ePrev->source() == e->source() && ePrev->target() == e->target()) { - G.delEdge(e); - if (bAppend) { parallelEdges.pushBack(ePrev); bAppend = false; } - } else { - ePrev = e; bAppend = true; - } - } -} - - -//! Removes all but one edge of each bundle of parallel edges in \a G. -/** - * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in - * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to - * remove parallel and reversal edges, use makeParallelFreeUndirected(Graph&). - * - * @param G is the input graph. - */ -inline void makeParallelFree(Graph &G) { - List parallelEdges; - makeParallelFree(G,parallelEdges); -} - - - -//! Sorts the edges of \a G such that undirected parallel edges come after each other in the list. -/** - * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v) - * in the graph. - * - * @param G is the input graph. - * @param edges is assigned the list of sorted edges. - * @param minIndex is assigned for each edge (v,w) the index min(index(v),index(w)). - * @param maxIndex is assigned for each edge (v,w) the index max(index(v),index(w)). - */ -OGDF_EXPORT void parallelFreeSortUndirected( - const Graph &G, - SListPure &edges, - EdgeArray &minIndex, - EdgeArray &maxIndex); - - -//! Returns true iff \a G contains no undirected parallel edges. -/** - * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v) - * in the graph. - * - * @param G is the input graph. - * @return true if \a G contains no undirected parallel edges. - */ -OGDF_EXPORT bool isParallelFreeUndirected(const Graph &G); - - -//! Returns the number of undirected parallel edges in \a G. -/** - * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v) - * in the graph. - * - * @param G is the input graph. - * @return the number of undirected parallel edges; for each unordered pair {v,w} of nodes, all - * but one of the edges with endpoints v and w (in any order) are counted. - */ -OGDF_EXPORT int numParallelEdgesUndirected(const Graph &G); - - -//! Removes all but one of each bundle of undirected parallel edges. -/** - * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v) - * in the graph. The function removes unordered pair {v,w} of nodes all but one of the edges with - * endpoints v and w (in any order). - * - * @tparam EDGELIST is the type of edge list that will be assigned the list of edges. - * @param G is the input graph. - * @param parallelEdges is assigned the list of remaining edges that were part of a bundle - * of undirected parallel edges in the input graph. - */ -template -void makeParallelFreeUndirected(Graph &G, EDGELIST ¶llelEdges) -{ - parallelEdges.clear(); - if (G.numberOfEdges() <= 1) return; - - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G,edges,minIndex,maxIndex); - - SListConstIterator it = edges.begin(); - edge ePrev = *it++, e; - bool bAppend = true; - while(it.valid()) { - e = *it++; - if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) { - G.delEdge(e); - if (bAppend) { parallelEdges.pushBack(ePrev); bAppend = false; } - } else { - ePrev = e; bAppend = true; - } - } -} - - -//! Removes all but one of each bundle of undirected parallel edges. -/** - * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v) - * in the graph. The function removes unordered pair {v,w} of nodes all but one of the edges with - * endpoints v and w (in any order). - * - * @param G is the input graph. - */ -inline void makeParallelFreeUndirected(Graph &G) { - List parallelEdges; - makeParallelFreeUndirected(G,parallelEdges); -} - - -//! Removes all but one of each bundle of undirected parallel edges. -/** - * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v) - * in the graph. The function removes unordered pair {v,w} of nodes all but one of the edges with - * endpoints v and w (in any order). - * - * @tparam EDGELIST is the type of edge list that is assigned the list of edges. - * @param G is the input graph. - * @param parallelEdges is assigned the list of remaining edges that were - * part of a bundle of undirected parallel edges in the input graph. - * @param cardPositive contains for each edge the number of removed undirected parallel edges - * pointing in the same direction. - * @param cardNegative contains for each edge the number of removed undirected parallel edges - * pointing in the opposite direction. - */ -template -void makeParallelFreeUndirected( - Graph &G, - EDGELIST ¶llelEdges, - EdgeArray &cardPositive, - EdgeArray &cardNegative) -{ - parallelEdges.clear(); - cardPositive.fill(0); - cardNegative.fill(0); - if (G.numberOfEdges() <= 1) return; - - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G,edges,minIndex,maxIndex); - - SListConstIterator it = edges.begin(); - edge ePrev = *it++, e; - bool bAppend = true; - int counter = 0; - while(it.valid()) - { - e = *it++; - if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) - { - if (ePrev->source() == e->source() && ePrev->target() == e->target()) - cardPositive[ePrev]++; - else if (ePrev->source() == e->target() && ePrev->target() == e->source()) - cardNegative[ePrev]++; - G.delEdge(e); - if (bAppend) - { - parallelEdges.pushBack(ePrev); - bAppend = false; - } - } - else - { - ePrev = e; bAppend = true; - } - } -} - - -//! Computes the bundles of undirected parallel edges in \a G. -/** - * Stores for one (arbitrarily chosen) reference edge all edges belonging to the same bundle of - * undirected parallel edges; no edge is removed from the graph. - * - * @tparam EDGELIST is the type of edge list that is assigned the list of edges. - * @param G is the input graph. - * @param parallelEdges is assigned for each reference edge the list of edges belonging to the - * bundle of undirected parallel edges. - */ -template -void getParallelFreeUndirected(const Graph &G, EdgeArray ¶llelEdges) -{ - if (G.numberOfEdges() <= 1) return; - - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G,edges,minIndex,maxIndex); - - SListConstIterator it = edges.begin(); - edge ePrev = *it++, e; - while(it.valid()) - { - e = *it++; - if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) - parallelEdges[ePrev].pushBack(e); - else - ePrev = e; - } -} - - -//--------------------------------------------------------- -// Methods for simple graphs -//--------------------------------------------------------- - - -//! Returns true iff \a G contains neither self-loops nor parallel edges. -/** - * @param G is the input graph. - * @return true if \a G is simple, i.e. contains neither self-loops nor parallel edges, false otherwise. - */ -inline bool isSimple(const Graph &G) { - return isLoopFree(G) && isParallelFree(G); -} - - -//! Removes all self-loops and all but one edge of each bundle of parallel edges. -/** - * @param G is the input graph. - */ -inline void makeSimple(Graph &G) { - makeLoopFree(G); - makeParallelFree(G); -} - - -//! Returns true iff \a G contains neither self-loops nor undirected parallel edges. -/** - * @param G is the input graph. - * @return true if \a G is (undirected) simple, i.e. contains neither self-loops - * nor undirected parallel edges, false otherwise. - */ -inline bool isSimpleUndirected(const Graph &G) { - return isLoopFree(G) && isParallelFreeUndirected(G); -} - - -//! Removes all self-loops and all but one edge of each bundle of undirected parallel edges. -/** - * @param G is the input graph. - */ -inline void makeSimpleUndirected(Graph &G) { - makeLoopFree(G); - makeParallelFreeUndirected(G); -} - - - -//--------------------------------------------------------- -// Methods for connectivity -//--------------------------------------------------------- - -//! Returns true iff \a G is connected. -/** - * @param G is the input graph. - * @return true if \a G is connected, false otherwise. - */ -OGDF_EXPORT bool isConnected(const Graph &G); - - -//! Makes \a G connected by adding a minimum number of edges. -/** - * @param G is the input graph. - * @param added is assigned the added edges. - */ -OGDF_EXPORT void makeConnected(Graph &G, List &added); - - -//! makes \a G connected by adding a minimum number of edges. -/** - * @param G is the input graph. - */ -inline void makeConnected(Graph &G) { - List added; - makeConnected(G,added); -} - - -//! Computes the connected components of \a G. -/** - * Assigns component numbers (0, 1, ...) to the nodes of \a G. The component number of each - * node is stored in the node array \a component. - * - * @param G is the input graph. - * @param component is assigned a mapping from nodes to component numbers. - * @return the number of connected components. - */ -OGDF_EXPORT int connectedComponents(const Graph &G, NodeArray &component); - - -//! Computes the connected components of \a G and returns the list of isolated nodes. -/** - * Assigns component numbers (0, 1, ...) to the nodes of \a G. The component number of each - * node is stored in the node array \a component. - * - * @param G is the input graph. - * @param isolated is assigned the list of isolated nodes. An isolated - * node is a node without incident edges. - * @param component is assigned a mapping from nodes to component numbers. - * @return the number of connected components. - */ -OGDF_EXPORT int connectedIsolatedComponents( - const Graph &G, - List &isolated, - NodeArray &component); - - -//! Returns true iff \a G is biconnected. -/** - * @param G is the input graph. - * @param cutVertex If false is returned, \a cutVertex is assigned either 0 if \a G is not connected, - * or a cut vertex in \a G. - */ -OGDF_EXPORT bool isBiconnected(const Graph &G, node &cutVertex); - - -//! Returns true iff \a G is biconnected. -/** - * @param G is the input graph. - */ -inline bool isBiconnected(const Graph &G) { - node cutVertex; - return isBiconnected(G,cutVertex); -} - - -//! Makes \a G biconnected by adding edges. -/** - * @param G is the input graph. - * @param added is assigned the list of inserted edges. - */ -OGDF_EXPORT void makeBiconnected(Graph &G, List &added); - - -//! Makes \a G biconnected by adding edges. -/** - * @param G is the input graph. - */ -inline void makeBiconnected(Graph &G) { - List added; - makeBiconnected(G,added); -} - - -//! Computes the biconnected components of \a G. -/** - * Assigns component numbers (0, 1, ...) to the edges of \ G. The component number of each edge - * is stored in the edge array \a component. - * - * @param G is the input graph. - * @param component is assigned a mapping from edges to component numbers. - * @return the number of biconnected components (including isolated nodes). - */ -OGDF_EXPORT int biconnectedComponents(const Graph &G, EdgeArray &component); - - -//! Returns true iff \a G is triconnected. -/** - * If true is returned, then either - * - \a s1 and \a s2 are either both 0 if \a G is not connected; or - * - \a s1 is a cut vertex and \a s2 = 0 if \a G is not biconnected; or - * - \a s1 and \a s2 are a separation pair otherwise. - * - * @param G is the input graph. - * @param s1 is assigned a cut vertex of one node of a separation pair, if \a G is not triconnected (see above). - * @param s2 is assigned one node of a separation pair, if \a G is not triconnected (see above). - * @return true if \a G is triconnected, false otherwise. - */ -OGDF_EXPORT bool isTriconnected(const Graph &G, node &s1, node &s2); - - -//! Returns true iff \a G is triconnected. -/** - * @param G is the input graph. - * @return true if \a G is triconnected, false otherwise. - */ -inline bool isTriconnected(const Graph &G) { - node s1, s2; - return isTriconnected(G,s1,s2); -} - - -//! Returns true iff \a G is triconnected (using a quadratic time algorithm!). -/** - * If true is returned, then either - * - \a s1 and \a s2 are either both 0 if \a G is not connected; or - * - \a s1 is a cut vertex and \a s2 = 0 if \a G is not biconnected; or - * - \a s1 and \a s2 are a separation pair otherwise. - * - * \warning This method has quadratic running time. An efficient linear time - * version is provided by isTriconnected(). - * - * @param G is the input graph. - * @param s1 is assigned a cut vertex of one node of a separation pair, if \a G is not triconnected (see above). - * @param s2 is assigned one node of a separation pair, if \a G is not triconnected (see above). - * @return true if \a G is triconnected, false otherwise. - */ -OGDF_EXPORT bool isTriconnectedPrimitive(const Graph &G, node &s1, node &s2); - - -//! Returns true iff \a G is triconnected (using a quadratic time algorithm!). -/** - * \warning This method has quadratic running time. An efficient linear time - * version is provided by isTriconnected(). - * - * @param G is the input graph. - * @return true if \a G is triconnected, false otherwise. - */ -inline bool isTriconnectedPrimitive(const Graph &G) { - node s1, s2; - return isTriconnectedPrimitive(G,s1,s2); -} - - -//! Triangulates a planarly embedded graph \a G by adding edges. -/** - * The result of this function is that \a G is made maximally planar by adding new edges. - * \a G will also be planarly embedded such that each face is a triangle. - * - * \pre \a G is planar, simple and represents a combinatorial embedding (i.e. \a G is planarly embedded). - * - * @param G is the input graph to which edges will be added. - */ -void triangulate(Graph &G); - - -//--------------------------------------------------------- -// Methods for directed graphs -//--------------------------------------------------------- - -//! Returns true iff the digraph \a G is acyclic. -/** - * @param G is the input graph - * @param backedges is assigned the backedges of a DFS-tree. - * @return true if \a G contains no directed cycle, false otherwise. - */ -OGDF_EXPORT bool isAcyclic(const Graph &G, List &backedges); - - -//! Returns true iff the digraph \a G is acyclic. -/** - * @param G is the input graph - * @return true if \a G contains no directed cycle, false otherwise. - */ -inline bool isAcyclic(const Graph &G) { - List backedges; - return isAcyclic(G,backedges); -} - - -//! Returns true iff the undirected graph \a G is acyclic. -/** - * @param G is the input graph - * @param backedges is assigned the backedges of a DFS-tree. - * @return true if \a G contains no undirected cycle, false otherwise. - */ -OGDF_EXPORT bool isAcyclicUndirected(const Graph &G, List &backedges); - - -//! Returns true iff the undirected graph \a G is acyclic. -/** - * @param G is the input graph - * @return true if \a G contains no undirected cycle, false otherwise. - */ -inline bool isAcyclicUndirected(const Graph &G) { - List backedges; - return isAcyclicUndirected(G,backedges); -} - - -//! Makes the digraph \a G acyclic by removing edges. -/** - * The implementation removes all backedges of a DFS tree. - * - * @param G is the input graph - */ -OGDF_EXPORT void makeAcyclic(Graph &G); - - -//! Makes the digraph G acyclic by reversing edges. -/** - * \remark The implementation ignores self-loops and reverses - * the backedges of a DFS-tree. - * - * @param G is the input graph - */ -OGDF_EXPORT void makeAcyclicByReverse(Graph &G); - - -//! Returns true iff the digraph \a G contains exactly one source node (or is empty). -/** - * @param G is the input graph. - * @param source is assigned the single source if true is returned, or 0 otherwise. - * @return true if \a G has a single source, false otherwise. - */ -OGDF_EXPORT bool hasSingleSource(const Graph &G, node &source); - - -//! Returns true iff the digraph \a G contains exactly one source node (or is empty). -/** - * @param G is the input graph. - * @return true if \a G has a single source, false otherwise. - */ -inline bool hasSingleSource(const Graph &G) { - node source; - return hasSingleSource(G,source); -} - - -//! Returns true iff the digraph \a G contains exactly one sink node (or is empty). -/** - * @param G is the input graph. - * @param sink is assigned the single sink if true is returned, or 0 otherwise. - * @return true if \a G has a single sink, false otherwise. - */ -OGDF_EXPORT bool hasSingleSink(const Graph &G, node &sink); - - -//! Returns true iff the digraph \a G contains exactly one sink node (or is empty). -/** - * @param G is the input graph. - * @return true if \a G has a single sink, false otherwise. - */ -inline bool hasSingleSink(const Graph &G) { - node sink; - return hasSingleSink(G,sink); -} - - -//! Returns true iff \a G is an st-digraph. -/** - * A directed graph is an st-digraph if it is acyclic, contains exactly one source s - * and one sink t, and the edge (s,t). - * - * @param G is the input graph. - * @param s is assigned the single source (if true is returned). - * @param t is assigned the single sink (if true is returned). - * @param st is assigned the edge (s,t) (if true is returned). - * @return true if \a G is an st-digraph, false otherwise. - */ -OGDF_EXPORT bool isStGraph(const Graph &G, node &s, node &t, edge &st); - - -//! Returns true if \a G is an st-digraph. -/** - * A directed graph is an st-digraph if it is acyclic, contains exactly one source s - * and one sink t, and the edge (s,t). - * @param G is the input graph. - * @return true if \a G is an st-digraph, false otherwise. - */ -inline bool isStGraph(const Graph &G) { - node s, t; - edge st; - return isStGraph(G,s,t,st); -} - - -//! Computes a topological numbering of an acyclic digraph \a G. -/** - * \pre \a G is an acyclic directed graph. - * - * @param G is the input graph. - * @param num is assigned the topological numbering (0, 1, ...). - */ -OGDF_EXPORT void topologicalNumbering(const Graph &G, NodeArray &num); - - -//! Computes the strongly connected components of the digraph \a G. -/** - * The function implements the algorithm by Tarjan. - * - * @param G is the input graph. - * @param component is assigned a mapping from nodes to component numbers (0, 1, ...). - * @return the number of strongly connected components. - */ -OGDF_EXPORT int strongComponents(const Graph& G, NodeArray& component); - - - -//--------------------------------------------------------- -// Methods for trees and forests -//--------------------------------------------------------- - -//! Returns true iff \a G is a free forest, i.e. contains no undirected cycle. -/** - * @param G is the input graph. - * @return true if \ G is contains no undirected cycle, false otherwise. - */ -OGDF_EXPORT bool isFreeForest(const Graph &G); - - -//! Returns true iff \a G represents a forest, i.e., a collection of rooted trees. -/** - * @param G is the input graph. - * @param roots is assigned the list of root nodes of the trees in the forest. - * @return true if \a G represents a forest, false otherwise. - */ -OGDF_EXPORT bool isForest(const Graph& G, List &roots); - - -//! Returns true iff \a G represents a forest, i.e. a collection of rooted trees. -/** - * @param G is the input graph. - * @return true if \a G represents a forest, false otherwise. - */ -inline bool isForest(const Graph &G) -{ - List roots; - return isForest(G,roots); -} - - -//! Returns true iff \a G represents a tree -/** - * @param G is the input graph. - * @param root is assigned the root node (if true is returned). - * @return true if \a G represents a tree, false otherwise. - */ -OGDF_EXPORT bool isTree (const Graph& G, node &root); - - -//! Returns true iff \a G represents a tree -/** - * @param G is the input graph. - * @return true if \a G represents a tree, false otherwise. - */ -inline bool isTree(const Graph &G) { - node root; - return isTree(G,root); -} - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/basic/tuples.h b/ext/OGDF/ogdf/basic/tuples.h deleted file mode 100644 index ac0203fcf..000000000 --- a/ext/OGDF/ogdf/basic/tuples.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of class Tuple2, Tuple3 - * and Tuple4. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_TUPLE_H -#define OGDF_TUPLE_H - - -#include -#include - - -namespace ogdf { - -//! Tuples of two elements (2-tuples). -/** - * @tparam E1 is the data type for the first element. - * @tparam E2 is the data type for the second element. - */ -template class Tuple2 { -public: - E1 m_x1; //!< The first element. - E2 m_x2; //!< The second element. - - //! Constructs a 2-tuple using default constructors. - Tuple2() { } - //! Constructs a 2-tuple for given values. - Tuple2(const E1 &y1, const E2 &y2) : m_x1(y1), m_x2(y2) { } - //! Constructs a 2-tuple that is a copy of \a t2. - Tuple2(const Tuple2 &t2) : m_x1(t2.m_x1), m_x2(t2.m_x2) { } - - //! Returns a reference the first element. - const E1 &x1() const { return m_x1; } - //! Returns a reference the second element. - const E2 &x2() const { return m_x2; } - - //! Returns a reference the first element. - E1 &x1() { return m_x1; } - //! Returns a reference the second element. - E2 &x2() { return m_x2; } - - // default assignment operator - - OGDF_NEW_DELETE -}; - -//! Equality operator for 2-tuples -template -bool operator==(const Tuple2 &t1, const Tuple2 &t2) -{ - return t1.x1() == t2.x1() && t1.x2() == t2.x2(); -} - -//! Inequality operator for 2-tuples -template -bool operator!=(const Tuple2 &t1, const Tuple2 &t2) -{ - return t1.x1() != t2.x1() || t1.x2() != t2.x2(); -} - -//! Output operator for 2-tuples. -template -ostream &operator<<(ostream &os, const Tuple2 &t2) -{ - os << "(" << t2.x1() << " " << t2.x2() << ")"; - return os; -} - - -//! Tuples of three elements (3-tuples). -/** - * @tparam E1 is the data type for the first element. - * @tparam E2 is the data type for the second element. - * @tparam E3 is the data type for the third element. - */ -template class Tuple3 { -public: - E1 m_x1; //!< The first element. - E2 m_x2; //!< The second element. - E3 m_x3; //!< The third element. - - //! Constructs a 3-tuple using default constructors. - Tuple3() { } - //! Constructs a 3-tuple for given values. - Tuple3(const E1 &y1, const E2 &y2, const E3 &y3) : - m_x1(y1), m_x2(y2), m_x3(y3) { } - //! Constructs a 3-tuple that is a copy of \a t3. - Tuple3(const Tuple3 &t3) : - m_x1(t3.m_x1), m_x2(t3.m_x2), m_x3(t3.m_x3) { } - - //! Returns a reference the first element. - const E1 &x1() const { return m_x1; } - //! Returns a reference the second element. - const E2 &x2() const { return m_x2; } - //! Returns a reference the third element. - const E3 &x3() const { return m_x3; } - - //! Returns a reference the first element. - E1 &x1() { return m_x1; } - //! Returns a reference the second element. - E2 &x2() { return m_x2; } - //! Returns a reference the third element. - E3 &x3() { return m_x3; } - - // default assignment operator - - OGDF_NEW_DELETE -}; - -//! Equality operator for 3-tuples -template -bool operator==(const Tuple3 &t1, const Tuple3 &t2) -{ - return t1.x1() == t2.x1() && t1.x2() == t2.x2() && t1.x3() == t2.x3(); -} - -//! Inequality operator for 3-tuples -template -bool operator!=(const Tuple3 &t1, const Tuple3 &t2) -{ - return t1.x1() != t2.x1() || t1.x2() != t2.x2() || t1.x3() != t2.x3(); -} - -//! Output operator for 3-tuples -template -ostream &operator<<(ostream &os, const Tuple3 &t3) -{ - os << "(" << t3.x1() << " " << t3.x2() << " " << t3.x3() << ")"; - return os; -} - - -//! Tuples of four elements (4-tuples). -/** - * @tparam E1 is the data type for the first element. - * @tparam E2 is the data type for the second element. - * @tparam E3 is the data type for the third element. - * @tparam E4 is the data type for the fourth element. - */ -template class Tuple4 { -public: - E1 m_x1; //!< The first element. - E2 m_x2; //!< The second element. - E3 m_x3; //!< The third element. - E4 m_x4; //!< The fourth element. - - //! Constructs a 4-tuple using default constructors. - Tuple4() { } - //! Constructs a 4-tuple for given values. - Tuple4(const E1 &y1, const E2 &y2, const E3 &y3, const E4 &y4) : - m_x1(y1), m_x2(y2), m_x3(y3), m_x4(y4) { } - //! Constructs a 4-tuple that is a copy of \a t4. - Tuple4(const Tuple4 &t4) : - m_x1(t4.m_x1), m_x2(t4.m_x2), m_x3(t4.m_x3), m_x4(t4.m_x4) { } - - //! Returns a reference the first element. - const E1 &x1() const { return m_x1; } - //! Returns a reference the second element. - const E2 &x2() const { return m_x2; } - //! Returns a reference the third element. - const E3 &x3() const { return m_x3; } - //! Returns a reference the fourth element. - const E4 &x4() const { return m_x4; } - - //! Returns a reference the first element. - E1 &x1() { return m_x1; } - //! Returns a reference the second element. - E2 &x2() { return m_x2; } - //! Returns a reference the third element. - E3 &x3() { return m_x3; } - //! Returns a reference the fourth element. - E4 &x4() { return m_x4; } - - // default assignment operator - - OGDF_NEW_DELETE -}; - -//! Equality operator for 4-tuples -template -bool operator==(const Tuple4 &t1, const Tuple4 &t2) -{ - return t1.x1() == t2.x1() && t1.x2() == t2.x2() && - t1.x3() == t2.x3() && t1.x4() == t2.x4(); -} - -//! Inequality operator for 4-tuples -template -bool operator!=(const Tuple4 &t1, const Tuple4 &t2) -{ - return t1.x1() != t2.x1() || t1.x2() != t2.x2() || - t1.x3() != t2.x3() || t1.x4() != t2.x4(); -} - -//! Output operator for 4-tuples -template -ostream &operator<<(ostream &os, const Tuple4 &t4) -{ - os << "(" << t4.x1() << " " << t4.x2() << " " << - t4.x3() << " " << t4.x4() << ")"; - return os; -} - -template, - typename Hash2_ = DefHashFunc > -class HashFuncTuple -{ -public: - HashFuncTuple() { } - - HashFuncTuple(const Hash1_ &hash1, const Hash2_ &hash2) - : m_hash1(hash1), m_hash2(hash2) { } - - size_t hash(const Tuple2 &key) const { - return 23*m_hash1.hash(key.x1()) + 443*m_hash2.hash(key.x2()); - } - -private: - Hash1_ m_hash1; - Hash2_ m_hash2; -}; - -} // namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/CPlanarEdgeInserter.h b/ext/OGDF/ogdf/cluster/CPlanarEdgeInserter.h deleted file mode 100644 index 5ecd8cab1..000000000 --- a/ext/OGDF/ogdf/cluster/CPlanarEdgeInserter.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares CPlanarEdgeInserter class. - * - * Reinsertion of deleted edges in embedded subgraph with - * modeled cluster boundaries. - * The inserter class computes a shortest path on the dual - * graph of the input to find an insertion path - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CPLANAR_EDGE_INSERTER_H -#define OGDF_CPLANAR_EDGE_INSERTER_H - - -#include - -namespace ogdf { - -class NodePair -{ -public: - node m_src, m_tgt; -}; - -class OGDF_EXPORT CPlanarEdgeInserter -{ - //postprocessing options - enum PostProcessType {ppNone, ppRemoveReinsert}; - -public: - - CPlanarEdgeInserter() { } - - virtual ~CPlanarEdgeInserter() { } - - void call( - ClusterPlanRep& CPR, - CombinatorialEmbedding& E, - Graph& G, - const List& origEdges, - List& newEdges); - - void setPostProcessing(PostProcessType p) - { - m_ppType = p; - } - - PostProcessType getPostProcessing() { return m_ppType; } - -protected: - - void constructDualGraph( - ClusterPlanRep& CPR, - CombinatorialEmbedding& E, - EdgeArray& arcRightToLeft, - EdgeArray& arcLeftToRight, - FaceArray& nodeOfFace, - //NodeArray& faceOfNode, - EdgeArray& arcTwin); - - void findShortestPath( - const CombinatorialEmbedding &E, - node s, //edge startpoint - node t, //edge endpoint - node sDummy, //representing s in network - node tDummy, //representing t in network - SList &crossed, - FaceArray& nodeOfFace); - - edge insertEdge( - ClusterPlanRep &CPR, - CombinatorialEmbedding &E, - const NodePair& np, - FaceArray& nodeOfFace, - EdgeArray& arcRightToLeft, - EdgeArray& arcLeftToRight, - EdgeArray& arcTwin, - NodeArray& clusterOfFaceNode, - const SList &crossed); - - void setArcStatus( - edge eArc, - node oSrc, - node oTgt, - const ClusterGraph& CG, - NodeArray& clusterOfFaceNode, - EdgeArray& arcTwin); - - //use heuristics to improve the result if possible - void postProcess(); - -private: - - Graph* m_originalGraph; - Graph m_dualGraph; - EdgeArray m_eStatus; //status of dual graph arcs - EdgeArray m_arcOrig; //original edges adj entry - PostProcessType m_ppType; //defines which kind of postprocessing to use - - //compute for every face the cluster that surrounds it - void deriveFaceCluster( - ClusterPlanRep& CPR, - CombinatorialEmbedding& E, - const ClusterGraph& CG, - FaceArray& nodeOfFace, - NodeArray& clusterOfFaceNode); - - - //debug - void writeDual(const char *fileName); - void writeGML(ostream &os, const Layout &drawing); -};//class CPlanarEdgeInserter - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/CPlanarSubClusteredGraph.h b/ext/OGDF/ogdf/cluster/CPlanarSubClusteredGraph.h deleted file mode 100644 index 14fe7904d..000000000 --- a/ext/OGDF/ogdf/cluster/CPlanarSubClusteredGraph.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of CPlanarSubClusteredGraph class. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CPLANAR_SUBCLUSTERED_GRAPH_H -#define OGDF_CPLANAR_SUBCLUSTERED_GRAPH_H - - -#include -#include - -namespace ogdf { - -//! Constructs a c-planar subclustered graph of the input on base of a spanning tree -class OGDF_EXPORT CPlanarSubClusteredGraph -{ - -public: - - CPlanarSubClusteredGraph() { } - - virtual void call(const ClusterGraph& CG, EdgeArray& inSub); - - virtual void call( - const ClusterGraph& CGO, - EdgeArray& inSub, - List& leftOver); - - //! Uses \a edgeWeight to compute clustered planar subgraph - virtual void call( - const ClusterGraph& CGO, - EdgeArray& inSub, - List& leftOver, - EdgeArray& edgeWeight); - -private: - - //**************************************************** - //data fields - - //store status of original edge: in subclustered graph? - //also used to check spanning tree - EdgeArray m_edgeStatus; - -};//cplanarsubclusteredgraph - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/CconnectClusterPlanar.h b/ext/OGDF/ogdf/cluster/CconnectClusterPlanar.h deleted file mode 100644 index dc5f7613c..000000000 --- a/ext/OGDF/ogdf/cluster/CconnectClusterPlanar.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author:klein $ - * $Date:2007-10-18 17:23:28 +0200 (Thu, 18 Oct 2007) $ - ***************************************************************/ - -/** \file - * \brief Cluster Planarity tests and Cluster Planar embedding - * for C-connected Cluster Graphs - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CCONNECT_CLUSTER_PLANAR_H -#define OGDF_CCONNECT_CLUSTER_PLANAR_H - - -#include -#include -#include - -namespace ogdf { - -class OGDF_EXPORT CconnectClusterPlanar{ - -public: - - //aus CCCPE oder CCCP wieder entfernen - enum ccErrorCode { - none = 0, - nonConnected = 1, - nonCConnected = 2, - nonPlanar = 3, - nonCPlanar = 4 - }; - ccErrorCode errCode() {return m_errorCode;} - - - //! Constructor. - CconnectClusterPlanar(); - - //! Destructor. - virtual ~CconnectClusterPlanar(); - - //! Tests if a ClusterGraph is C-planar. - virtual bool call(ClusterGraph &C); - - //! Tests if a ClusterGraph is C-planar. - //! Specifies reason for non planarity. - bool call(ClusterGraph &C, char (&code)[124]); - - //! Tests if a const ClusterGraph is C-planar. - virtual bool call(const ClusterGraph &C); - -private: - - //! Recursive planarity test for clustered graph induced by \a act. - bool planarityTest(ClusterGraph &C, cluster &act, Graph &G); - //! Preprocessing that initializes data structures, used in call. - bool preProcess(ClusterGraph &C,Graph &G); - //! Prepares the planarity test for one cluster. - bool preparation(Graph &G,cluster &C,node superSink); - //! Performs a planarity test on a biconnected component. - bool doTest(Graph &G, - NodeArray &numbering, - cluster &cl, - node superSink, - EdgeArray &edgeTable); - - void prepareParallelEdges(Graph &G); - - //! Constructs the replacement wheel graphs - void constructWheelGraph(ClusterGraph &C, - Graph &G, - cluster &parent, - PlanarPQTree* T, - EdgeArray &outgoingTable); - - - //private Members for handling parallel edges - EdgeArray > m_parallelEdges; - EdgeArray m_isParallel; - ClusterArray m_clusterPQTree; - int m_parallelCount; - char errorCode[124]; - ccErrorCode m_errorCode; - - -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/CconnectClusterPlanarEmbed.h b/ext/OGDF/ogdf/cluster/CconnectClusterPlanarEmbed.h deleted file mode 100644 index c2f68e366..000000000 --- a/ext/OGDF/ogdf/cluster/CconnectClusterPlanarEmbed.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Cluster planarity tests and cluster planar embedding - * for c-connected clustered graphs. Based on the algorithm - * by Cohen, Feng and Eades which uses PQ-trees. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CCONNECT_CLUSTER_PLANAR_EMBED_H -#define OGDF_CCONNECT_CLUSTER_PLANAR_EMBED_H - - -#include -#include -#include -#include - -namespace ogdf { - -class OGDF_EXPORT CconnectClusterPlanarEmbed { - - -public: - - - enum ccErrorCode { - none = 0, - nonConnected = 1, - nonCConnected = 2, - nonPlanar = 3, - nonCPlanar = 4 - }; - ccErrorCode errCode() {return m_errorCode;} - - - //************************************************************************* - // Constructor - CconnectClusterPlanarEmbed(); - - // Destructor - virtual ~CconnectClusterPlanarEmbed(); - - // Tests if a ClusterGraph is C-planar and embedds it. - virtual bool embed(ClusterGraph &C,Graph &G); - - // Tests if a ClusterGraph is C-planar and embedds it. - // Specifies reason for non planarity - virtual bool embed(ClusterGraph &C,Graph &G, char (&code)[124]); - - -private: - - bool planarityTest(ClusterGraph &C, cluster &act, Graph &G); - - bool preProcess(ClusterGraph &Ccopy,Graph &Gcopy); - - bool preparation(Graph &subGraph,cluster &origCluster,node superSink); - - bool doEmbed(Graph *biconComp, - NodeArray &numbering, - cluster &origCluster, - node superSink, - Graph &subGraph, - EdgeArray &tableEdgesBiComp2SubGraph, - EdgeArray &tableEdgesSubGraph2BiComp, - NodeArray &tableNodesBiComp2SubGraph); - - - - - void entireEmbed(Graph &biconComp, - NodeArray > &entireEmbedding, - NodeArray > &adjMarker, - NodeArray &mark, - node v); - - void recursiveEmbed(ClusterGraph &Ccopy,Graph &Gcopy); - - void prepareParallelEdges(Graph &G); - - - void constructWheelGraph(ClusterGraph &C, - Graph &G, - cluster &parent, - cluster &origCl, - EmbedPQTree* T, - EdgeArray &outgoingTable, - node superSink); - - void hubControl(Graph &G,NodeArray &hubs); - - void nonPlanarCleanup(ClusterGraph &Ccopy,Graph &Gcopy); - - void copyEmbedding(ClusterGraph &Ccopy,Graph &Gcopy,ClusterGraph &C,Graph &G); - -//--------------------------------------------------------- -// private member variables for testing a cluster graph -//--------------------------------------------------------- - - // Stores for every cluster the PQTree corresponding - // to the biconnected component containing the outgoing - // edges of the cluster. - ClusterArray m_clusterPQTree; - - //save errorcode for postprocessing if not c-planar - ccErrorCode m_errorCode; - // For debugging purposes. Stores the reason for - // non cluster planarity. - char errorCode[124]; - - - //private Members for handling parallel edges - EdgeArray > m_parallelEdges; - EdgeArray m_isParallel; - int m_parallelCount; - - - -//--------------------------------------------------------- -// private member variables for embedding a cluster graph -//--------------------------------------------------------- - - ClusterGraph *m_instance; //The graph that has to be embedded - - - // Stores for every cluster the (partial) embedding of the - // biconnected components not having outgoing - // edges of the cluster. - // The NodeArrays are associated with the subgraphs. - // The ClusterArray is associtated with the original graph. - ClusterArray >*> m_clusterEmbedding; - - // Stores for every cluster the subgraph constructed to test - // the planarity of the cluster - // The ClusterArray is associated with the original graph. - ClusterArray m_clusterSubgraph; - - // Marks for every subgraph of a cluster the nodes that are - // hubs as true. - // The NodeArrays are associated with the subgraphs. - // The ClusterArray is associated with the original graph. - ClusterArray *> m_clusterSubgraphHubs; - - - // Stores for every node of every subgraph of a cluster - // if this node belongs to a wheel graph, corresponding to - // a child cluster - // The NodeArrays are associated with the subgraphs. - // The ClusterArray is associated with the original graph. - ClusterArray *> m_clusterSubgraphWheelGraph; - - - // Stores for every mode of every subgraph of a cluster its - // corresponding node on the original graph G, if there exists one. - ClusterArray *> m_clusterNodeTableNew2Orig; - - - ClusterArray m_clusterClusterGraph; - ClusterArray*>m_clusterClusterTableOrig2New; - - // When constructing a wheel graph, we store here for - // every wheel graph node the corresponding cluster - // Array is associated with the cluster graph copy. - NodeArray m_wheelGraphNodes; - - // Stores for every node in the current graph, if - // it is a hub. - // Array is associated with the cluster graph copy. - NodeArray m_currentHubs; - - - // Stores for every cluster of Ccopy the corresponding cluster - // in the original graph. A key variable, since we track - // all information via the original clusters. - ClusterArray m_clusterTableCopy2Orig; - - // Needed to construct the ClusterArray m_clusterTableCopy2Orig. - ClusterArray m_clusterTableOrig2Copy; - - // Stores for every subgraph the super sink of the subgraph. - ClusterArray m_clusterSuperSink; - - - // Stores for every node in Gcopy its corresponding node - // in the original graph unless the node belongs to - // a wheel graph. - // The NodeArray is associated with Gcopy. - NodeArray m_nodeTableCopy2Orig; - - // Needed to construct the NodeArray m_nodeTableCopy2Orig. - NodeArray m_nodeTableOrig2Copy; - - - EdgeArray*> m_outgoingEdgesAnker; - ClusterArray*>*> m_clusterOutgoingEdgesAnker; - - // Stores for every original cluster all information on - // the PQ-Tree that is necessary to construct the embedding. - ClusterArray m_clusterPQContainer; - - // Stores the clusters in calling order of the testing algorithm - // The stack stores the clusters of the original graph. - // Needed for recursive embed. - Stack m_callStack; - - // Is true for every original cluster, if the cluster does not - // have a correspondand in the copy of the cluster graph. - // This is the case if: - // a. cluster is son of root cluster and does have exactly one - // childcluster and no nodes; - // b. recursive version of a; - // c. cluster does have no child clusters and no nodes; - // d. recursive version of c. - ClusterArray m_unsatisfiedCluster; - - -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterArray.h b/ext/OGDF/ogdf/cluster/ClusterArray.h deleted file mode 100644 index 3b0e142ec..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterArray.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of ClusterArray class. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTER_ARRAY_H -#define OGDF_CLUSTER_ARRAY_H - - -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// ClusterArrayBase -// base class for ClusterArray, defines interface for event handling -// used by Graph -//--------------------------------------------------------- -//! Abstract base class for cluster arrays. -/** - * Defines the interface for event handling used by the ClusterGraph class. - * Use the paramiterized class ClusterArray for creating edge arrays. - */ -class ClusterArrayBase { - /** - * Pointer to list element in the list of all registered cluster - * arrays which references this array. - */ - ListIterator m_it; - -public: - const ClusterGraph *m_pClusterGraph; //!< The associated cluster graph. - - //! Initializes a cluster array not associated with a cluster graph. - ClusterArrayBase() : m_pClusterGraph(0) { } - //! Initializes a cluster array associated with \a pC. - ClusterArrayBase(const ClusterGraph *pC) : m_pClusterGraph(pC) { - if(pC) m_it = pC->registerArray(this); - } - - // destructor, unregisters the array - virtual ~ClusterArrayBase() { - if (m_pClusterGraph) m_pClusterGraph->unregisterArray(m_it); - } - - // event interface used by Graph - //! Virtual function called when table size has to be enlarged. - virtual void enlargeTable(int newTableSize) = 0; - //! Virtual function called when table has to be reinitialized. - virtual void reinit(int initTableSize) = 0; - //! Virtual function called when array is disconnected from the cluster graph. - virtual void disconnect() = 0; - - //! Associates the array with a new cluster graph. - void reregister(const ClusterGraph *pC) { - if (m_pClusterGraph) m_pClusterGraph->unregisterArray(m_it); - if ((m_pClusterGraph = pC) != 0) m_it = pC->registerArray(this); - } -}; // class ClusterArrayBase - - -//! Dynamic arrays indexed with clusters. -/** - * Cluster arrays adjust their table size automatically - * when the cluster graph grows. - */ -template class ClusterArray : private Array, protected ClusterArrayBase { - T m_x; //!< The default value for array elements. - -public: - //! Constructs an empty cluster array associated with no graph. - ClusterArray() : Array(), ClusterArrayBase() { } - //! Constructs a cluster array associated with \a C. - ClusterArray(const ClusterGraph &C) : - Array(C.clusterArrayTableSize()), - ClusterArrayBase(&C) { } - //! Constructs a cluster array associated with \a C. - /** - * @param C is the associated cluster graph. - * @param x is the default value for all array elements. - */ - ClusterArray(const ClusterGraph &C, const T &x) : - Array(0,C.clusterArrayTableSize()-1,x), - ClusterArrayBase(&C), m_x(x) { } - //! Constructs a cluster array associated with \a C and a given - //! size (for static use). - /** - * @param C is the associated cluster graph. - * @param x is the default value for all array elements. - * @param size is the size of the array. - */ - ClusterArray(const ClusterGraph &C, const T &x, int size) : - Array(0,size-1,x), - ClusterArrayBase(&C), m_x(x) { } - - //! Constructs a cluster array that is a copy of \a A. - /** - * Associates the array with the same cluster graph as \a A and copies all elements. - */ - ClusterArray(const ClusterArray &A) : - Array(A), - ClusterArrayBase(A.m_pClusterGraph), m_x(A.m_x) { } - - //! Returns true iff the array is associated with a graph. - bool valid() const { return (Array::low() <= Array::high()); } - - //! Returns a pointer to the associated cluster graph. - const ClusterGraph *graphOf() const { - return m_pClusterGraph; - } - - //! Returns a reference to the element with index \a c. - const T &operator[](cluster c) const { - OGDF_ASSERT(c != 0 && c->graphOf() == m_pClusterGraph) - return Array::operator [](c->index()); - } - - //! Returns a reference to the element with index \a c. - T &operator[](cluster c) { - OGDF_ASSERT(c != 0 && c->graphOf() == m_pClusterGraph) - return Array::operator [](c->index()); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for a cluster - * in the associated cluster graph! - */ - const T &operator[](int index) const { - return Array::operator [](index); - } - - //! Returns a reference to the element with index \a index. - /** - * \attention Make sure that \a index is a valid index for a cluster - * in the associated cluster graph! - */ - T &operator[](int index) { - return Array::operator [](index); - } - - //! Assignment operator. - ClusterArray &operator=(const ClusterArray &a) { - Array::operator =(a); - m_x = a.m_x; - reregister(a.m_pClusterGraph); - return *this; - } - - //! Reinitializes the array. Associates the array with no cluster graph. - void init() { - Array::init(); reregister(0); - } - - //! Reinitializes the array. Associates the array with \a C. - void init(const ClusterGraph &C) { - Array::init( C.clusterArrayTableSize() ); reregister(&C); - } - - //! Reinitializes the array. Associates the array with \a C. - /** - * @param C is the associated cluster graph. - * @param x is the default value. - */ - void init(const ClusterGraph &C, const T &x) { - Array::init(0,C.clusterArrayTableSize()-1, m_x = x); reregister(&C); - } - - //! Sets all array elements to \a x. - void fill(const T &x) { - int high = m_pClusterGraph->maxClusterIndex(); - if(high >= 0) - Array::fill(0,high,x); - } - -private: - virtual void enlargeTable(int newTableSize) { - Array::grow(newTableSize-Array::size(),m_x); - } - - virtual void reinit(int initTableSize) { - Array::init(0,initTableSize-1,m_x); - } - - virtual void disconnect() { - Array::init(); - m_pClusterGraph = 0; - } - - OGDF_NEW_DELETE - -}; // class ClusterArray - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterGraph.h b/ext/OGDF/ogdf/cluster/ClusterGraph.h deleted file mode 100644 index a9d30a2d9..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterGraph.h +++ /dev/null @@ -1,822 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Derived class of GraphObserver providing additional functionality - * to handle clustered graphs. - * - * \author Sebastian Leipert, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CLUSTER_GRAPH_H -#define OGDF_CLUSTER_GRAPH_H - -#include -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT ClusterGraph; -class OGDF_EXPORT ClusterGraphObserver; - -//! Representation of clusters in a clustered graph. -/** - * \see ClusterGraph - */ -class OGDF_EXPORT ClusterElement : private GraphElement { - - friend class OGDF_EXPORT ClusterGraph; - friend class GraphList; - - int m_id; //!< The index of this cluster. - int m_depth; //!< The depth of this cluster in the cluster tree. - List m_entries; //!< The nodes in this cluster. - List m_children; //!< The child clusters of this cluster. - ClusterElement *m_parent; //!< The parent of this cluster. - ClusterElement *m_pPrev; //!< The postorder predecessor of this cluster. - ClusterElement *m_pNext; //!< The postorder successor of this cluster. - ListIterator m_it; //!< The position of this cluster within children list of its parent. - - List m_adjEntries; //!< The adjacency list. - // Don't use a GraphList ! - // This messes with the adjacency - // list of the underlying graph - - #ifdef OGDF_DEBUG - // we store the graph containing this cluster for debugging purposes - const ClusterGraph *m_pClusterGraph; - #endif - - - void init(List &nodes) { - while (!nodes.empty()) - m_entries.pushBack(nodes.popFrontRet()); - } - - List &getChildren(){ - return m_children; - } - - List &getNodes(){ - return m_entries; - } - - //! Traverses the inclusion tree and adds nodes to \a clusterNodes. - /** - * Invoked by public function getClusterNodes(List &clusterNodes). - */ - void getClusterInducedNodes(List &clusterNodes); - void getClusterInducedNodes(NodeArray &clusterNode, int& num); - - -public: - - //! Creates a new cluster element. - #ifdef OGDF_DEBUG - ClusterElement(const ClusterGraph *pClusterGraph,int id): - m_id(id),m_depth(0),m_parent(0),m_pPrev(0),m_pNext(0),m_it(0), - m_pClusterGraph(pClusterGraph) { } - #else - ClusterElement(int id): - m_id(id), m_depth(0),m_parent(0),m_pPrev(0),m_pNext(0),m_it(0) { } - #endif - - - #ifdef OGDF_DEBUG - const ClusterGraph *graphOf() const { return m_pClusterGraph; } - #endif - - - //! Returns the (unique) index of the cluster. - int index() const { return m_id; } - //! Returns the depth of the cluster in the cluster tree. - int depth() const { return m_depth; } - int& depth() { return m_depth; } - //! Returns the successor of the cluster in the list of all clusters. - ClusterElement* succ() const { return (ClusterElement*)m_next; } - //! Returns the predecessor of the cluster in the list of all clusters. - ClusterElement* pred() const { return (ClusterElement*)m_prev; } - - //! Returns the postorder successor of the cluster in the list of all clusters. - ClusterElement* pSucc() const { return m_pNext; } - //! Returns the postorder predecessor of the cluster in the list of all clusters. - ClusterElement* pPred() const { return m_pPrev; } - - // Iteration over tree structures. - - //! Returns the first element in the list of child clusters. - ListConstIterator cBegin() const{ return m_children.begin();} - //! Returns the last element in the list of child clusters. - ListConstIterator crBegin() const{ return m_children.rbegin();} - //! Returns the number of child clusters. - int cCount(){ return m_children.size();} - //! Returns the first element in list of child nodes. - ListIterator nBegin(){ return m_entries.begin();} - //! Returns the first element in list of child nodes. - ListConstIterator nBegin() const{ return m_entries.begin();} - //! Returns the number of child nodes. - int nCount(){ return m_entries.size();} - - //! Returns the parent of the cluster. - ClusterElement* parent(){return m_parent;} - - - //! Returns the first adjacency entry in the list of outgoing edges. - ListConstIterator firstAdj() const { return m_adjEntries.begin(); } - //! Returns the first adjacency entry in the list of outgoing edges. - ListIterator firstAdj() { return m_adjEntries.begin(); } - //! Returns the last adjacency entry in the list of outgoing edges. - ListConstIterator lastAdj () const { return m_adjEntries.rbegin(); } - //! Returns the last adjacency entry in the list of outgoing edges. - ListIterator lastAdj () { return m_adjEntries.rbegin(); } - - //! Returns the list of nodes in the cluster, i.e., all nodes in the subtree rooted at this cluster. - /** - * Recursively traverses the cluster tree starting at this cluster. - */ - void getClusterNodes(List &clusterNodes); - //! Sets the entry for each node v to true if v is a member of - //! the subgraph induced by the ClusterElement. - //! All other entries remain unchanged! - //! Returns the number of entries set to true. - //! Precondition: clusterNode is a NodeArray initialized on the clustergraph - //! the ClusterElement belongs to. - int getClusterNodes(NodeArray &clusterNode); - - OGDF_NEW_DELETE - -};// class ClusterElement - - - - -typedef ClusterElement *cluster; //!< The type of clusters. - - -#define forall_cluster_adj(adj,c)\ -for(ogdf::ListIterator ogdf_loop_var=(c)->firstAdj();\ - ogdf::test_forall_adj_entries_of_cluster(ogdf_loop_var,(adj));\ - ogdf_loop_var=ogdf_loop_var.succ()) - -#define forall_cluster_rev_adj(adj,c)\ -for(ogdf::ListIterator ogdf_loop_var=(c)->lastAdj();\ - ogdf::test_forall_adj_entries_of_cluster(ogdf_loop_var,(adj));\ - ogdf_loop_var=ogdf_loop_var.pred()) - -#define forall_cluster_adj_edges(e,c)\ -for(ogdf::ListIterator ogdf_loop_var=(c)->firstAdj();\ - ogdf::test_forall_adj_edges_of_cluster(ogdf_loop_var,(e));\ - ogdf_loop_var=ogdf_loop_var.succ()) - - - -inline bool test_forall_adj_entries_of_cluster(ListIterator &it, adjEntry &adj) -{ - if (it.valid()) { adj = (*it);return true; } - else return false; -} - -inline bool test_forall_adj_edges_of_cluster(ListIterator &it, edge &e) -{ - adjEntry adj = (*it); - if (adj) { e = adj->theEdge(); return true; } - else return false; -} - -inline bool test_forall_adj_edges_of_cluster(adjEntry &adj, edge &e) -{ - if (adj) { e = adj->theEdge(); return true; } - else return false; -} - - -class ClusterArrayBase; -templateclass ClusterArray; - -//--------------------------------------------------------- -// iteration macros -//--------------------------------------------------------- - -//! Iteration over all clusters \a c of cluster graph \a C. -#define forall_clusters(c,C) for((c)=(C).firstCluster(); (c); (c)=(c)->succ()) -//! Iteration over all clusters \a c of cluster graph \a C (in postorder). -#define forall_postOrderClusters(c,C)\ -for((c)=(C).firstPostOrderCluster(); (c); (c)=(c)->pSucc()) - - - - -//! Representation of clustered graphs. -/** - * This class is derived from GraphObserver and handles hierarchical - * clustering of the nodes in a graph, providing additional functionality. - */ -class OGDF_EXPORT ClusterGraph : public GraphObserver -{ - GraphList m_clusters; //!< The list of all clusters. - - const Graph *m_pGraph; //!< The associated graph. - - int m_nClusters; //!< The number of clusters. - int m_clusterIdCount; //!< The index assigned to the next created cluster. - int m_clusterArrayTableSize; //!< The current table size of cluster arrays. - - mutable cluster m_postOrderStart; //!< The first cluster in postorder. - cluster m_rootCluster; //!< The root cluster. - - bool m_adjAvailable; //! True if the adjacency list for each cluster is available. - bool m_allowEmptyClusters; //! Defines if empty clusters are deleted immediately if generated by operations. - - NodeArray m_nodeMap; //!< Stores the cluster of each node. - //! Stories for every node its position within the children list of its cluster. - NodeArray > m_itMap; - - mutable ListPure m_regClusterArrays; //!< The registered cluster arrays. - mutable ListPure m_regObservers; //!< The registered graph observers. - -public: - - //! Creates a cluster graph associated with no graph. - ClusterGraph(); - - //! Creates a cluster graph associated with graph \a G. - /** - * All nodes in \a G are assigned to the root cluster. - */ - ClusterGraph(const Graph &G); - - //! Copy constructor. - ClusterGraph(const ClusterGraph &C); - - //! Constructs a clustered graph that is a copy of clustered graph C. - /** - * The underlying graph \a G is made a copy of C.getGraph(). - */ - ClusterGraph(const ClusterGraph &C,Graph &G); - - //! Constructs a clustered graph that is a copy of clustered graph C. - /** - * The underlying graph \a G is made a copy of C.getGraph(). Stores the - * new copies of the original nodes and clusters in the arrays - * \a originalNodeTable and \a originalClusterTable. - */ - ClusterGraph( - const ClusterGraph &C, - Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable); - - //! Constructs a clustered graph that is a copy of clustered graph C. - /** - * The underlying graph \a G is made a copy of C.getGraph(). Stores the - * new copies of the original nodes, edges, and clusters in the arrays - * \a originalNodeTable, \a edgeCopy, and \a originalClusterTable. - */ - ClusterGraph( - const ClusterGraph &C, - Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable, - EdgeArray &edgeCopy); - - virtual ~ClusterGraph(); - - //! Returns the maximal used cluster index. - int maxClusterIndex() const { return m_clusterIdCount-1; } - - //! Clears all cluster data. - void clear(); - - //! Clears all data but does not delete root cluster. - void semiClear(); - - //! Clears all cluster data and then reinitializes the instance with underlying graph \a G. - void init(const Graph &G); - - //! Conversion to const Graph reference. - operator const Graph &() const { return *m_pGraph; } - - //! Assignment operator. - ClusterGraph &operator=(const ClusterGraph &C); - - //! Removes all clusters from the cluster subtree rooted at cluster C except for cluster C itself. - void clearClusterTree(cluster C); - - //! Returns a reference to the underlying graph. - //TODO should be named getConstGraph - const Graph & getGraph() const {return *m_pGraph;} - - //! Inserts a new cluster; makes it a child of the cluster \a parent. - cluster newCluster(cluster parent, int id = -1); - - //! Creates an empty cluster with index \a clusterId and parent \a parent. - cluster createEmptyCluster(const cluster parent = 0, int clusterId = -1); - - //! Creates a new cluster containing the nodes given by \a nodes; makes it a child of the cluster \a parent. - /** - * The nodes are reassigned to the new cluster. If you turn off - * \a m_allowEmptyclusters, an emptied cluster is deleted except if all - * nodes are put into the same cluster. - * @param nodes are the nodes that will be reassigned to the new cluster. - * @param parent is the parent of the new cluster. - * \return the created cluster. - */ - cluster createCluster(SList& nodes, const cluster parent = 0); - - //! Deletes cluster \a c. - /** - * All subclusters become children of parent cluster of \a c. - * \pre \a c is not the root cluster. - */ - void delCluster(cluster c); - - //! Returns the root cluster. - cluster rootCluster() const { return m_rootCluster; } - - //! Returns the cluster to which a node belongs. - inline cluster clusterOf(node v) const{ - OGDF_ASSERT(v->graphOf() == m_pGraph) - return m_nodeMap[v]; - } - - //! Returns number of clusters. - int numberOfClusters() const { return m_nClusters; } - //! Returns upper bound for cluster indices. - int clusterIdCount() const { return m_clusterIdCount;} - - //! Returns table size of cluster arrays associated with this graph. - int clusterArrayTableSize() const { return m_clusterArrayTableSize; } - - //! Moves cluster \a c to a new parent \a newParent. - void moveCluster(cluster c, cluster newParent); - - - //! Reassigns node \a v to cluster \ c. - void reassignNode(node v, cluster c); - - //! Clear cluster info structure, reinitializes with underlying graph \a G. - //inserted mainly for use in gmlparser. - void reInit(Graph& G) - { - reinitGraph(G); - } - - //--------------------------- - //tree queries / depth issues - - //! Turns automatic update of node depth values on or off. - void setUpdateDepth(bool b) const - { - m_updateDepth = b; - //make sure that depth cant be used anymore - //(even if it may still be valid a little while) - if (!b) m_depthUpToDate = false; - } - - //! Updates depth information in subtree after delCluster. - void pullUpSubTree(cluster c); - - //! Computes depth of cluster tree, running time O(C). - //maybe later we should provide a permanent depth member update - int treeDepth() const - { - //initialize depth at first call - if (m_updateDepth && !m_depthUpToDate) - computeSubTreeDepth(rootCluster()); - if (!m_updateDepth) OGDF_THROW(AlgorithmFailureException); - int l_depth = 1; - cluster c; - forall_clusters(c, *this) - { - if (c->depth() > l_depth) l_depth = c->depth(); - } - - return l_depth; - } - //! Computes depth of cluster tree hanging at \a c. - void computeSubTreeDepth(cluster c) const; - //! Returns depth of cluster c in cluster tree, starting with root depth 1. - //should be called instead of direct c->depth call to assure - //valid depth - int& clusterDepth(cluster c) const - { - // updateDepth must be set to true if depth info shall be used - OGDF_ASSERT(m_updateDepth); - - //initialize depth at first call - if (!m_depthUpToDate) - computeSubTreeDepth(rootCluster()); - OGDF_ASSERT(c->depth() != 0) - return c->depth(); - } - - //! Returns lowest common cluster of nodes in list \a nodes. - cluster commonCluster(SList& nodes); - - //! Returns the lowest common cluster of \a v and \a w in the cluster tree - /** - * \pre \a v and \a w are nodes in the graph. - */ - cluster commonCluster(node v, node w) const; - - //! Returns the lowest common cluster lca and the highest ancestors on the path to lca. - cluster commonClusterLastAncestors( - node v, - node w, - cluster& c1, - cluster& c2) const; - //! Returns lca of \a v and \a w and stores corresponding path in \a eL. - - cluster commonClusterPath( - node v, - node w, - List& eL) const; - - //! Returns lca of \a v and \a w, stores corresponding path in \a eL and ancestors in \a c1, \a c2. - cluster commonClusterAncestorsPath( - node v, - node w, - cluster& c1, - cluster& c2, - List& eL) const; - - //! Registers a cluster array. - ListIterator registerArray(ClusterArrayBase *pClusterArray) const; - - //! Unregisters a cluster array. - void unregisterArray(ListIterator it) const; - - //! Registers a ClusterGraphObserver. - ListIterator registerObserver(ClusterGraphObserver *pObserver) const; - - //! Unregisters a ClusterGraphObserver. - void unregisterObserver(ListIterator it) const; - - //! Returns the list of clusters that are empty or only contain empty clusters. - /** - * The list is constructed in an order that allows deletion and reinsertion. - * We never set rootcluster to be one of the empty clusters!! - * if checkClusters is given, only list elements are checked - * to allow efficient checking in the case - * that you know which clusters were recently changed (e.g. node reass.) - */ - void emptyClusters(SList& emptyCluster, SList* checkCluster = 0); - - //! Returns true if cluster \a c has only one node and no children. - inline bool emptyOnNodeDelete(cluster c) //virtual? - { - //if (!c) return false; //Allows easy use in loops - return (c->nCount() == 1) && (c->cCount() == 0); - } - - //! Returns true if cluster \a c has only one child and no nodes. - inline bool emptyOnClusterDelete(cluster c) //virtual? - { - //if (!c) return false; //Allows easy use in loops - return (c->nCount() == 0) && (c->cCount() == 1); - } - - //! Returns the first cluster in the list of all clusters. - cluster firstCluster() const { return m_clusters.begin (); } - //! Returns the last cluster in the list of all cluster. - cluster lastCluster () const { return m_clusters.rbegin(); } - //! Returns the first cluster in the list of post ordered clusters. - cluster firstPostOrderCluster() const { - if (!m_postOrderStart) postOrder(); - return m_postOrderStart; - } - - //! Returns the list of all clusters in \a clusters. - template - void allClusters(CLUSTERLIST &clusters) const { - clusters.clear(); - for (cluster c = m_clusters.begin(); c; c = c->succ()) - clusters.pushBack(c); - } - - //! Collapses all nodes in the list \a nodes to the first node; multi-edges are removed. - template - void collaps(NODELIST &nodes,Graph &G){ - OGDF_ASSERT(&G == m_pGraph); - m_adjAvailable = false; - - m_postOrderStart = 0; - node v = nodes.popFrontRet(); - while (!nodes.empty()) - { - node w = nodes.popFrontRet(); - adjEntry adj = w->firstAdj(); - while (adj !=0) - { - adjEntry succ = adj->succ(); - edge e = adj->theEdge(); - if (e->source() == v || e->target() == v) - G.delEdge(e); - else if (e->source() == w) - G.moveSource(e,v); - else - G.moveTarget(e,v); - adj = succ; - } - //because nodes can already be unassigned (they are always - //unassigned if deleted), we have to check this - /* - if (m_nodeMap[w]) - { - cluster c = m_nodeMap[w]; - c->m_entries.del(m_itMap[w]); - } - */ - //removeNodeAssignment(w); - G.delNode(w); - } - } - - //! Returns the list of all edges adjacent to cluster \a c in \a edges. - template - void adjEdges(cluster c, EDGELIST &edges) const { - edges.clear(); - edge e; - if (m_adjAvailable) - { - forall_cluster_adj_edges(e,c) - edges.pushBack(e); - } - } - - //! Returns the list of all adjacency entries adjacent to cluster \a c in \a entries. - template - void adjEntries(cluster c, ADJLIST &entries) const { - entries.clear(); - adjEntry adj; - if (m_adjAvailable) - { - forall_cluster_adj(adj,c) - entries.pushBack(adj); - } - } - - //! Computes the adjacency entry list for cluster \a c. - template - void makeAdjEntries(cluster c,LISTITERATOR start){ - adjEntry adj; - c->m_adjEntries.clear(); - LISTITERATOR its; - for (its = start; its.valid(); its++) - { - adj = (*its); - c->m_adjEntries.pushBack(adj); - } - } - - //************************** - //file output - - //! Writes the cluster graph in GML format to file \a fileName. - void writeGML(const char *fileName); - - //! Writes the cluster graph in GML format to output stream \a os. - void writeGML(ostream &os); - - - //************************** - //file input - //! reading graph, attributes, cluster structure from file - bool readClusterGML(const char* fileName, Graph& G); - //! reading graph, attributes, cluster structure from stream - bool readClusterGML(istream& is, Graph& G); - - // read Cluster Graph from OGML file - //bool readClusterGraphOGML(const char* fileName, ClusterGraph& CG, Graph& G); - - //! Checks the consistency of the data structure. - // (for debugging purposes only) - bool consistencyCheck(); - - //! Checks the combinatorial cluster planar embedding. - // (for debugging purposes only) - bool representsCombEmbedding(); - - //! Sets the availability status of the adjacency entries. - void adjAvailable(bool val){ m_adjAvailable = val; } - -protected: - //! Creates new cluster containing nodes in parameter list - //! with index \a clusterid. - cluster doCreateCluster(SList& nodes, - const cluster parent, int clusterId = -1); - //! Creates new cluster containing nodes in parameter list and - //! stores resulting empty clusters in list, cluster has index \a clusterid. - cluster doCreateCluster(SList& nodes, - SList& emptyCluster, - const cluster parent, int clusterId = -1); - - mutable ClusterArray* m_lcaSearch; //!< Used to save last search run number for commoncluster. - mutable int m_lcaNumber;//!< Used to save last search run number for commoncluster. - mutable ClusterArray* m_vAncestor;//!< Used to save last search run number for commoncluster. - mutable ClusterArray* m_wAncestor;//!< Used to save last search run number for commoncluster. - - //! Copies lowest common ancestor info to copy of clustered graph. - void copyLCA(const ClusterGraph &C, ClusterArray* clusterCopy=0); - //int m_treeDepth; //should be implemented and updated in operations? - - mutable bool m_updateDepth; //!< Depth of clusters is always updated if set to true. - mutable bool m_depthUpToDate; //!< Status of cluster depth information. - - //! Adjusts the post order structure for moved clusters. - //we assume that c is inserted via pushback in newparent->children - void updatePostOrder(cluster c, cluster oldParent, cluster newParent); - - //! Computes new predecessor for SUBTREE at moved cluster c. - //0 if c==root - cluster postOrderPredecessor(cluster c) const; - //! Leftmost cluster in subtree rooted at c, gets predecessor of subtree. - cluster leftMostCluster(cluster c) const; - - //--------------------------------------- - //functions inherited from GraphObserver: - //define how to cope with graph changes - - //! Implementation of inherited method: Updates data if node deleted. - virtual void nodeDeleted(node v) - { - bool cRemove = false; - cluster c = clusterOf(v); - if (!c) return; - //never allow totally empty cluster - //if ((emptyOnNodeDelete(c)) && - // (c != rootCluster()) ) cRemove = true; - unassignNode(v); - if (cRemove && !m_allowEmptyClusters) //parent exists - { - cluster nonEmpty = c->parent(); - cluster cRun = nonEmpty; - delCluster(c); - while ((cRun != rootCluster()) && (cRun->nCount() + cRun->cCount() == 0)) - { - nonEmpty = cRun->parent(); - delCluster(cRun); - cRun = nonEmpty; - } - - } - } - //! Implementation of inherited method: Updates data if node added. - virtual void nodeAdded(node v) - { - assignNode(v, rootCluster()); - } - //! Implementation of inherited method: Updates data if edge deleted. - virtual void edgeDeleted(edge /* e */) { } - //! Implementation of inherited method: Updates data if edge added. - virtual void edgeAdded(edge /* e */) { } - //! Currently does nothing. - virtual void reInit() { } - //! Clears cluster data without deleting root when underlying graphs' clear method is called. - virtual void cleared() - { - //we don't want a complete clear, as the graph still exists - //and can be updated from input stream - semiClear(); - }//Graph cleared - -private: - //! Assigns node \a v to cluster \a c (\a v not yet assigned!). - void assignNode(node v, cluster C); - - //! Unassigns node \a v from its cluster. - void unassignNode(node v); - - //! Remove the assignment entries for nodes. - //! Checks if node is currently not assigned. - void removeNodeAssignment(node v) - { - if (m_nodeMap[v]) //iff == 0, itmap == 0 !!? - { - cluster C2 = m_nodeMap[v]; - C2->m_entries.del(m_itMap[v]); - m_nodeMap[v] = 0; - m_itMap[v] = 0; - } - } - - //! Performs a copy of the cluster structure of C, - //! the underlying graph stays the same. - void shallowCopy(const ClusterGraph &C); - - //! Perform a deep copy on C, C's underlying - //! graph is copied into G. - void deepCopy(const ClusterGraph &C,Graph &G); - - //! Perform a deep copy on C, C's underlying - //! graph is copied into G. Stores associated nodes in \a originalNodeTable. - - void deepCopy( - const ClusterGraph &C,Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable); - - //! Perform a deep copy on C, C's underlying - //! graph is copied into G. Stores associated nodes in \a originalNodeTable - //! and edges in \a edgeCopy. - void deepCopy( - const ClusterGraph &C,Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable, - EdgeArray &edgeCopy); - - - void clearClusterTree(cluster c,List &attached); - - void initGraph(const Graph &G); - - //! Reinitializes instance with graph \a G. - void reinitGraph(const Graph &G); - - //! Creates new cluster with given id, precondition: id not used - cluster newCluster(int id); - //! Creates new cluster. - cluster newCluster(); - - //! Create postorder information in cluster tree. - void postOrder() const; - //! Check postorder information in cluster tree. - void checkPostOrder() const; - - void postOrder(cluster c,SListPure &S) const; - - void reinitArrays(); - - - //! Recursively write the cluster structure in GML. - void writeCluster( - ostream &os, - NodeArray &nId, - ClusterArray & cId, - int &nextId, - cluster c, - String ttt); - - //! Recursively write the cluster structure in GraphWin GML. - void writeGraphWinCluster( - ostream &os, - NodeArray &nId, - NodeArray &nStr, - ClusterArray &cId, - ClusterArray &cStr, - int &nextId, - cluster c, - String ttt); - -}; - - - - - -ostream &operator<<(ostream &os, ogdf::cluster c); - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterGraphAttributes.h b/ext/OGDF/ogdf/cluster/ClusterGraphAttributes.h deleted file mode 100644 index 934efb871..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterGraphAttributes.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares ClusterGraphAttributes, an extension of class - * GraphAttributes, to store clustergraph layout informations - * like cluster cage positions and sizes that can be accessed - * over the cluster/cluster ID - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTER_GRAPH_ATTRIBUTES_H -#define OGDF_CLUSTER_GRAPH_ATTRIBUTES_H - -#include -#include - -#include -#include - - -namespace ogdf { - - class GmlParser; - - /** - * \brief Stores information associated with a cluster. - * - */ - class OGDF_EXPORT ClusterInfo - { - public: - ClusterInfo() - { - //&m_fillPattern = GraphAttributes::bpNone; //NoBrush - m_lineStyle = GraphAttributes::esSolid; - } - - double m_x, m_y; //position of lower left corner - double m_w, m_h; //width and height - - double m_lineWidth; //width of rectangle border line - - String m_color; //color of rectangle - String m_fillColor; //color of fill area - String m_backColor; //background color - GraphAttributes::EdgeStyle m_lineStyle; //rectangle line style - GraphAttributes::BrushPattern m_fillPattern; //brush pattern of fill area - String m_label; //name label - - int m_clusterID; //the ID of the cluster of which the info is stored - }; - - - /** - * \brief Stores additional attributes of a clustered graph (like layout information). - * - * Attributes are simply stored in node or edge arrays; for memory consumption - * reasons, only a subset of these arrays is in fact initialized for the graph; - * non-initialized arrays require only a few bytes of extra memory. - * - * Which arrays are initialized is specified by a bit vector; each bit in this - * bit vector corresponds to one or more attributes. E.g., \a #nodeGraphics - * corresponds to the attributes \a #m_x, \a #m_y, \a #m_width, and \a #m_height; - * whereas \a #edgeDoubleWeight only corresponds to the attribute \a #m_doubleWeight. - * - */ - class OGDF_EXPORT ClusterGraphAttributes : public GraphAttributes - { - private: - ClusterArray m_clusterTemplate; //!< Name of cluster template. - - public: - //! Initializes new instance of class ClusterGraphAttributes. - ClusterGraphAttributes() : GraphAttributes(), m_pClusterGraph(0) { } - - //! Initializes new instance of class ClusterGraphAttributes. - //! Uses \a initAttributes, which are enriched by node and edge - //! graphics. - ClusterGraphAttributes(ClusterGraph& cg, long initAttributes = 0); - - virtual ~ClusterGraphAttributes() { } - - //! Initializes the instance with ClusterGraph \a cg. - //! Sets the attributes to \a initAttributes - virtual void init(ClusterGraph &cg, long initAttributes = 0); - - //! Initializes the attributes according to \a initAttributes. - virtual void initAtt(long initAttributes = 0) { - GraphAttributes::initAttributes(initAttributes); - } - -// operator const ClusterGraph& () const {return *m_pClusterGraph;} -// operator const Graph& () const {return m_pClusterGraph->getGraph();} - - //! Returns the ClusterGraph. - const ClusterGraph& constClusterGraph() const { return *m_pClusterGraph; } - - //! Returns the index of the parent cluster of node \a v. - int clusterID(node v) { return m_pClusterGraph->clusterOf(v)->index(); } - - //! Returns the parent cluster of node \a v. - cluster clusterOf(node v) { return m_pClusterGraph->clusterOf(v); } - - //! Returns the maximum cluster index used. - int maxClusterID() const { return m_pClusterGraph->clusterIdCount()-1; } - - //! Updates positions of cluster boundaries wrt to children and child clusters - void updateClusterPositions(double boundaryDist = 1.0); - - //***************************************************************** - //data access by ID - - //! Returns x position of the cluster cages lower left corner. - double clusterXPos(int clusterID) const { return m_clusterInfo[clusterID].m_x; } - - //! Returns x position of the cluster cages lower left corner. - double& clusterXPos(int clusterID) { return m_clusterInfo[clusterID].m_x; } - - //! Returns y position of the cluster cages lower left corner. - double clusterYPos(int clusterID) const { return m_clusterInfo[clusterID].m_y; } - - //! Returns y position of the cluster cages lower left corner. - double& clusterYPos(int clusterID) { return m_clusterInfo[clusterID].m_y; } - - //! Returns cluster cage height. - double clusterHeight(int clusterID) const { return m_clusterInfo[clusterID].m_h; } - - //! Returns cluster cage height. - double& clusterHeight(int clusterID) { return m_clusterInfo[clusterID].m_h; } - - //! Returns cluster cage width. - double clusterWidth(int clusterID) const { return m_clusterInfo[clusterID].m_w; } - - //! Returns cluster cage width. - double& clusterWidth(int clusterID) { return m_clusterInfo[clusterID].m_w; } - - //! Returns cluster line width. - double clusterLineWidth(int clusterID) const { - return m_clusterInfo[clusterID].m_lineWidth; - } - - //! Returns cluster line width. - double& clusterLineWidth(int clusterID) { - return m_clusterInfo[clusterID].m_lineWidth; - } - - //! Returns cluster fill color. - const String &clusterFillColor(int clusterID) const { - return m_clusterInfo[clusterID].m_fillColor; - } - - //! Returns cluster fill color. - String& clusterFillColor(int clusterID) { - return m_clusterInfo[clusterID].m_fillColor; - } - - //! Returns cluster fill pattern. - GraphAttributes::BrushPattern clusterFillPattern(int clusterID) const { - return m_clusterInfo[clusterID].m_fillPattern; - } - - //! Returns cluster fill pattern. - GraphAttributes::BrushPattern& clusterFillPattern(int clusterID) { - return m_clusterInfo[clusterID].m_fillPattern; - } - - //! Returns label of cluster c. - const String &clusterLabel(int clusterID) const { - return m_clusterInfo[clusterID].m_label; - } - - //! Returns label of cluster c. - String &clusterLabel(int clusterID) { - return m_clusterInfo[clusterID].m_label; - } - - //! Returns structure containing information on cluster with ID \a clusterID. - const ClusterInfo& clusterInfo(int clusterID) const { - return m_clusterInfo[clusterID]; - } - - //! Returns structure containing information on cluster with ID \a clusterID. - ClusterInfo& clusterInfo(int clusterID) { return m_clusterInfo[clusterID]; } - - - //***************************************************************** - //data access by cluster - - //! Returns x position of the cluster cages lower left corner. - double clusterXPos(cluster c) const { return m_clusterInfo[c->index()].m_x; } - - //! Returns x position of the cluster cages lower left corner. - double& clusterXPos(cluster c) { return m_clusterInfo[c->index()].m_x; } - - //! Returns y position of the cluster cages lower left corner. - double clusterYPos(cluster c) const { return m_clusterInfo[c->index()].m_y; } - - //! Returns y position of the cluster cages lower left corner. - double& clusterYPos(cluster c) { return m_clusterInfo[c->index()].m_y; } - - //! Returns cluster cage height. - double clusterHeight(cluster c) const { return m_clusterInfo[c->index()].m_h; } - - //! Returns cluster cage height. - double& clusterHeight(cluster c) { return m_clusterInfo[c->index()].m_h; } - - //! Returns cluster cage width. - double clusterWidth(cluster c) const { return m_clusterInfo[c->index()].m_w; } - - //! Returns cluster cage width. - double& clusterWidth(cluster c) { return m_clusterInfo[c->index()].m_w; } - - //! Returns label of cluster c. - const String &clusterLabel(cluster c) const { - return m_clusterInfo[c->index()].m_label; - } - - //! Returns label of cluster c. - String &clusterLabel(cluster c) { - return m_clusterInfo[c->index()].m_label; - } - - //! Returns const reference to template of cluster c. - const String &templateCluster(cluster c) const { return m_clusterTemplate[c]; } - - //! Returns reference to template of cluster c. - String &templateCluster(cluster c) { return m_clusterTemplate[c]; } - - //! Returns const reference to structure containing information on cluster \a c. - const ClusterInfo& clusterInfo(cluster c) const { return m_clusterInfo[c->index()]; } - - //! Returns reference to structure containing information on cluster \a c. - ClusterInfo& clusterInfo(cluster c) { return m_clusterInfo[c->index()]; } - - //! Returns line color stored for cluster \a c in string format. - const String &clusterColor(cluster c) const { - return m_clusterInfo[c->index()].m_color; - } - - //! Returns line color of cluster \a c in string format. - String &clusterColor(cluster c) { - return m_clusterInfo[c->index()].m_color; - } - - //Returns const reference to fill color of cluster \a c. - const String &clusterFillColor(cluster c) const { - return m_clusterInfo[c->index()].m_fillColor; - } - - //Returns reference to fill color of cluster \a c. - String &clusterFillColor(cluster c) { - return m_clusterInfo[c->index()].m_fillColor; - } - - //Returns const reference to background color of cluster \a c. - const String &clusterBackColor(cluster c) const { - return m_clusterInfo[c->index()].m_backColor; - } - - //Returns reference to background color of cluster \a c. - String &clusterBackColor(cluster c) { - return m_clusterInfo[c->index()].m_backColor; - } - - - //pen and brush styles - - //! Returns edge style of cluster \a c. - const GraphAttributes::EdgeStyle &clusterLineStyle(cluster c) const { - return m_clusterInfo[c->index()].m_lineStyle; - } - - //! Returns line style of cluster \a c. - GraphAttributes::EdgeStyle &clusterLineStyle(cluster c) { - return m_clusterInfo[c->index()].m_lineStyle; - } - - //! Returns brush pattern of cluster \a c. - const GraphAttributes::BrushPattern &clusterFillPattern(cluster c) const { - return m_clusterInfo[c->index()].m_fillPattern; - } - - //! Returns brush pattern of cluster c. - GraphAttributes::BrushPattern &clusterFillPattern(cluster c) { - return m_clusterInfo[c->index()].m_fillPattern; - } - - //! Returns line width of cluster \a c. - const double &clusterLineWidth(cluster c) const { - return m_clusterInfo[c->index()].m_lineWidth; - } - - //! Returns line width of cluster c. - double &clusterLineWidth(cluster c) { - return m_clusterInfo[c->index()].m_lineWidth; - } - - //! Set fill pattern \a i for cluster \a c. - void setClusterFillPattern(cluster c, int i) { - m_clusterInfo[c->index()].m_fillPattern = intToPattern(i); - } - - //! Set style \a i for cluster \a c. - void setClusterLineStyle(cluster c, int i) { - m_clusterInfo[c->index()].m_lineStyle = intToStyle(i); - } - - //! Returns bounding box. - const DRect boundingBox() const; - - //! Writes attributed clustergraph in GML format to file fileName. - void writeGML(const char *fileName); - - //! Writes attributed clustergraph in GML format to output stream \a os. - void writeGML(ostream& os); - - //we don't have GraphConstraints yet - //! Writes attributed clustergraph in OGML format to file fileName - void writeOGML(const char * fileName);//, GraphConstraints & GC); - - //! Writes attributed clustergraph in OGML format to output stream \a os. - void writeOGML(ostream & os);//, GraphConstraints & GC); - - //! Reads attributed clustergraph in GML format from file fileName. - bool readClusterGML( - const char* fileName, - ClusterGraph& CG, - Graph& G); - - //! Reads attributed clustergraph in GML format from input stream \a is. - bool readClusterGML( - istream& is, - ClusterGraph& CG, - Graph& G); - - //! Reads clustered graph from OGML-file. - bool readClusterGraphOGML( - const char* fileName, - ClusterGraph& CG, - Graph& G); - - protected: - const ClusterGraph* m_pClusterGraph;//!< Only points to existing graphs. - - private: - //! Information on the cluster positions, index is cluster ID. - HashArray m_clusterInfo; - - //! Reads Cluster Graph with Attributes, base graph \a G, from \a fileName - //! with a given gmlparser \a gml (has objecttree). - //! Input stream given by parser. - bool readClusterGraphGML( - const char* fileName, - ClusterGraph& CG, - Graph& G, - GmlParser& gml); - - //! Reads clustered graph from input stream of GmlParser. - bool readClusterGraphGML( - ClusterGraph& CG, - Graph& G, - GmlParser& gml); - - //! Recursively writes the cluster structure in GML format into output stream \a os. - void writeCluster( - ostream &os, - NodeArray &nId, - ClusterArray & cId, - int &nextId, - cluster c, - String indent); - - //! Recursively writes the cluster structure in GraphWin GML format. - void writeGraphWinCluster( - ostream &os, - NodeArray &nId, - int &nextId, - cluster c, - String indent); - - //! Recursively writes the cluster structure in OGML. - void writeClusterOGML( - ostream &os, - std::ostringstream & osS, // string stream for styles block - int & nextLabelId, - cluster cluster, - int & indentDepth, // indent depth for structure block - int indentDepthS); // indent depth for styles block - - }; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterGraphCopyAttributes.h b/ext/OGDF/ogdf/cluster/ClusterGraphCopyAttributes.h deleted file mode 100644 index 9941ee379..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterGraphCopyAttributes.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares ClusterGraphCopyAttributes, which manages access - * on copy of an attributed clustered graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_A_CLUSTER_GRAPH_COPY_H -#define OGDF_A_CLUSTER_GRAPH_COPY_H - - - -#include -#include - - -namespace ogdf { - -/** - * \brief Manages access on copy of an attributed clustered graph - */ -class OGDF_EXPORT ClusterGraphCopyAttributes { - - const ExtendedNestingGraph *m_pH; - ClusterGraphAttributes *m_pACG; - NodeArray m_x, m_y; - -public: - //! Initializes instance of class ClusterGraphCopyAttributes. - ClusterGraphCopyAttributes( - const ExtendedNestingGraph &H, - ClusterGraphAttributes &ACG) : - m_pH(&H), m_pACG(&ACG), m_x(H,0), m_y(H,0) { } - - ~ClusterGraphCopyAttributes() { } - - //! Returns corresponding ClusterGraphAttributes. - const ClusterGraphAttributes &getClusterGraphAttributes() const { return *m_pACG; } - - //! Returns width of node v. - double getWidth(node v) const { - node vOrig = m_pH->origNode(v); - return (vOrig == 0) ? 0.0 : m_pACG->width(vOrig); - } - - //! Returns height of node v. - double getHeight(node v) const { - node vOrig = m_pH->origNode(v); - return (vOrig == 0) ? 0.0 : m_pACG->height(vOrig); - } - - //! Returns reference to x-coord. of node v. - const double &x(node v) const { - return m_x[v]; - } - - //! Returns reference to x-coord. of node v. - double &x(node v) { - return m_x[v]; - } - - //! Returns reference to y-coord. of node v. - const double &y(node v) const { - return m_y[v]; - } - - //! Returns reference to y-coord. of node v. - double &y(node v) { - return m_y[v]; - } - - //! Returns coordinate of upper cluster boundary of original cluster \a cOrig. - double top(cluster cOrig) const { - return m_pACG->clusterYPos(cOrig); - } - //! Returns coordinate of lower cluster boundary of original cluster \a cOrig. - double bottom(cluster cOrig) const { - return m_pACG->clusterYPos(cOrig) + m_pACG->clusterHeight(cOrig); - } - - //! Sets the position of the cluster rectangle for original cluster \a cOrig. - void setClusterRect( - cluster cOrig, - double left, - double right, - double top, - double bottom) - { - m_pACG->clusterXPos (cOrig) = left; - m_pACG->clusterYPos (cOrig) = top; - m_pACG->clusterWidth (cOrig) = right-left; - m_pACG->clusterHeight(cOrig) = bottom-top; - } - - void setClusterLeftRight( - cluster cOrig, - double left, - double right) - { - m_pACG->clusterXPos (cOrig) = left; - m_pACG->clusterWidth (cOrig) = right-left; - } - - void setClusterTopBottom( - cluster cOrig, - double top, - double bottom) - { - m_pACG->clusterYPos (cOrig) = top; - m_pACG->clusterHeight(cOrig) = bottom-top; - } - - //! Sets attributes for the original graph in attributed graph. - void transform(); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterGraphObserver.h b/ext/OGDF/ogdf/cluster/ClusterGraphObserver.h deleted file mode 100644 index 2dc3242b8..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterGraphObserver.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Abstract base class for structures on graphs, that need - * to be informed about cluster graph changes. - * - * Follows the observer pattern: cluster graphs are observable - * objects that can inform observers on changes made to their - * structure. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTER_GRAPH_OBSERVER_H -#define OGDF_CLUSTER_GRAPH_OBSERVER_H - - -#include -#include - -namespace ogdf { - - -//---------------------------------------------------------- -// GraphObserver -// abstract base class -// derived classes have to overload nodeDeleted, nodeAdded -// edgeDeleted, edgeAdded -// these functions should be called by Graph before (delete) -// and after (add) its structure -//---------------------------------------------------------- -class OGDF_EXPORT ClusterGraphObserver { - friend class ClusterGraph; - -public: - ClusterGraphObserver() : m_pClusterGraph(0) {} - - ClusterGraphObserver(const ClusterGraph* CG) : m_pClusterGraph(CG) - { - m_itCGList = CG->registerObserver(this); - }//constructor - - virtual ~ClusterGraphObserver() - { - if (m_pClusterGraph) m_pClusterGraph->unregisterObserver(m_itCGList); - }//destructor - - // associates structure with different graph - void reregister(const ClusterGraph *pCG) { - //small speedup: check if == m_pGraph - if (m_pClusterGraph) m_pClusterGraph->unregisterObserver(m_itCGList); - if ((m_pClusterGraph = pCG) != 0) m_itCGList = pCG->registerObserver(this); - } - - virtual void clusterDeleted(cluster v) = 0; - virtual void clusterAdded(cluster v) = 0; - //virtual void reInit() = 0; - //virtual void cleared() = 0;//Graph cleared - - const ClusterGraph* getGraph() const { return m_pClusterGraph;} - -protected: - const ClusterGraph* m_pClusterGraph; //underlying clustergraph - - //List entry in cluster graphs list of all registered observers - ListIterator m_itCGList; -}; - -} // end of namespace - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterOrthoLayout.h b/ext/OGDF/ogdf/cluster/ClusterOrthoLayout.h deleted file mode 100644 index 5a5cd729c..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterOrthoLayout.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares ClusterOrthoLayout which represents an orthogonal - * planar drawing algorithm for c-planar c-connected Clustergraphs. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CLUSTER_ORTHO_LAYOUT_H -#define OGDF_CLUSTER_ORTHO_LAYOUT_H - - -#include -#include -#include -#include - - -namespace ogdf { - - enum OrthoDir; - - -//--------------------------------------------------------- -// ClusterOrthoLayout -// represents planar orthogonal drawing algorithm for -// c-planar c-connected Clustergraphs -//--------------------------------------------------------- -class OGDF_EXPORT ClusterOrthoLayout : public LayoutClusterPlanRepModule -{ -public: - //! Initializes an instance of class ClusterOrthoLayout - ClusterOrthoLayout(); - - - /** \brief Calls planar UML layout algorithm. - * - * Input is a planarized representation \a PG of a connected component - * of the graph, output is a layout of the (modified) planarized - * representation in \a drawing. - */ - void call(ClusterPlanRep &PG, adjEntry adjExternal, Layout &drawing); - //! Call method for non c-planar graphs - void call( - ClusterPlanRep &PG, - adjEntry adjExternal, - Layout &drawing, - List& npEdges, - List& newEdges, - Graph& originalGraph); - - //void call(PlanRepUML & /* PG */, adjEntry /* adjExternal */, Layout & /* drawing */) {} - - // - // options - - //! Returns the minimum distance between edges and vertices. - double separation() const { - return m_separation; - } - //! Sets the minimum distance between edges and vertices. - void separation(double sep) { - m_separation = sep; - } - - //! Returns cOverhang, where cOverhang * separation defines the minimum - //distance between the glue point of an edge and a corner of the vertex boundary - double cOverhang() const { - return m_cOverhang; - } - //! Sets cOverhang value - void cOverhang(double c) { - m_cOverhang = c; - } - - - //! Returns the distance from the tight bounding box to the boundary of the drawing. - double margin() const { - return m_margin; - } - //! Sets the distance from the tight bounding box to the boundary of the drawing. - void margin(double m) { - m_margin = m; - } - - - //! Returns the preferred direction of generalizations - OrthoDir preferedDir() const { - return m_preferedDir; - } - //! Sets the preferred direction of generalizations - void preferedDir(OrthoDir dir) { - m_preferedDir = dir; - } - - //! Returns cost of associations which is used in the compactions step. - int costAssoc() const { - return m_costAssoc; - } - //! Sets cost of associations which is used in the compactions step. - void costAssoc(int c) { - m_costAssoc = c; - } - - //! Returns cost of generalizations. - int costGen() const { - return m_costGen; - } - //! Sets cost of generalizations. - void costGen(int c) { - m_costGen = c; - } - - //! Sets the option profile, thereby fixing a set of drawing options. - void optionProfile(int i) {m_optionProfile = i;} - - //! Sets alignment option. - void align(bool b) {m_align = b;} - - //! Sets scaling option for compaction step. - void scaling(bool b) {m_useScalingCompaction = b;} - - //! Sets generic options by setting field bits. - //Necessary to allow setting over base class pointer - //bit 0 = alignment - //bit 1 = scaling - //bit 2 = progressive/traditional - //=> 0 is standard - virtual void setOptions(int optionField) - { - if (optionField & 1) m_align = true; - else m_align = false; - if (optionField & 2) m_useScalingCompaction = true; - else m_useScalingCompaction = false; - if (optionField & 4) m_orthoStyle = 1; - else m_orthoStyle = 0; //traditional - } - - -private: - // compute bounding box and move final drawing such that it is 0 aligned - // respecting margins - void computeBoundingBox(const ClusterPlanRep &PG, Layout &drawing); - - - // options - double m_separation;//!< Minimum distance between edges and vertices. - double m_cOverhang; //!< Factor for minimum distance between vertex corner an adjacent edges. - double m_margin; //!< Distance between bounding box and drawing boundary. - OrthoDir m_preferedDir; //!< Preferred direction of generalizations (obsolete). - int m_optionProfile; - int m_costAssoc; //!< Compaction cost of association type edges. - int m_costGen; //!< Compaction cost of generalizations type edges. - //align merger sons on same level - bool m_align; //!< Horizontal alignment option. - //settings for scaling compaction - bool m_useScalingCompaction; //!< Switches scaling improvement during compaction. - int m_scalingSteps; //!< Number of scaling steps during compaction. - int m_orthoStyle; //!< Type of style (traditional/progressive) used for shape step. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterOrthoShaper.h b/ext/OGDF/ogdf/cluster/ClusterOrthoShaper.h deleted file mode 100644 index deea78081..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterOrthoShaper.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes the Orthogonal Representation of a Planar - * Representation of a UML Graph using the simple flow - * approach. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CLUSTER_ORTHO_SHAPER_H -#define OGDF_CLUSTER_ORTHO_SHAPER_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT ClusterOrthoShaper -{ - -public: - - enum BendCost { defaultCost, topDownCost, bottomUpCost }; - enum n_type { low, high, inner, outer }; //types of network nodes: - //nodes and faces - - ClusterOrthoShaper() { - m_distributeEdges = true; //try to distribute edges to all node sides - m_fourPlanar = true; //do not allow zero degree angles at high degree - m_allowLowZero = false; //do allow zero degree at low degree nodes - m_multiAlign = true; //true; //start/end side of multi edges match - m_traditional = true; //true; //prefer 3/1 flow at degree 2 (false: 2/2) - m_deg4free = false; //allow free angle assignment at degree four - m_align = false; //align nodes on same hierarchy level - m_topToBottom = defaultCost; //bend costs depend on edges cluster depth - }; - - ~ClusterOrthoShaper() { } - - // Given a planar representation for a UML graph and its planar - // combinatorial embedding, call() produces an orthogonal - // representation using Tamassias bend minimization algorithm - // with a flow network where every flow unit defines 90 degree angle - // in traditional mode. - // A maximum number of bends per edge can be specified in - // startBoundBendsPerEdge. If the algorithm is not successful in - // producing a bend minimal representation subject to - // startBoundBendsPerEdge, it successively enhances the bound by - // one trying to compute an orthogonal representation. - // - // Using startBoundBendsPerEdge may not produce a bend minimal - // representation in general. - void call(ClusterPlanRep &PG, - CombinatorialEmbedding &E, - OrthoRep &OR, - int startBoundBendsPerEdge = 0, - bool fourPlanar = true); - - - // returns option distributeEdges - bool distributeEdges() { return m_distributeEdges; } - // sets option distributeEdges to b - void distributeEdges(bool b) { m_distributeEdges = b; } - - // returns option multiAlign - bool multiAlign() { return m_multiAlign; } - // sets option multiAlign to b - void multiAlign(bool b) { m_multiAlign = b; } - - // returns option traditional - bool traditional() { return m_traditional; } - // sets option traditional to b - void traditional(bool b) { m_traditional = b; } - - //returns option deg4free - bool fixDegreeFourAngles() { return m_deg4free; } - //sets option deg4free - void fixDegreeFourAngles(bool b) { m_deg4free = b; } - - //alignment of brothers in hierarchies - void align(bool al) { m_align = al; } - bool align() { return m_align; } - - void bendCostTopDown(BendCost i) { m_topToBottom = i; } - - //return cluster dependant bend cost for standard cost pbc - int clusterProgBendCost(int clDepth, int treeDepth, int pbc) - { - int cost = 1; - switch (m_topToBottom) - { - case topDownCost: - cost = pbc*(clDepth+1); //safeInt - break; - case bottomUpCost: - cost = pbc*(treeDepth - clDepth + 1); //safeInt - break; - default: //defaultCost - cost = pbc; - break; - } - -// cout<<" Cost/pbc: "< 4 - bool m_fourPlanar; // should the input graph be four planar - // (no zero degree) - bool m_allowLowZero; // allow low degree nodes zero degree - // (to low for zero...) - bool m_multiAlign; // multi edges aligned on the same side - bool m_deg4free; // allow degree four nodes free angle assignment - bool m_traditional; // do not prefer 180 degree angles, - // traditional is not tamassia, - // traditional is a kandinsky - ILP - like network with node supply 4, - // not traditional interprets angle flow zero as 180 degree, "flow - // through the node" - bool m_align; //try to achieve an alignment in hierarchy levels - - BendCost m_topToBottom; //change bend costs on cluster hierarchy levels - - //set angle boundary - //warning: sets upper AND lower bounds, therefore may interfere with existing bounds - void setAngleBound( - edge netArc, - int angle, - EdgeArray& lowB, - EdgeArray& upB, - EdgeArray& aTwin, - bool maxBound = true) - { - //vorlaeufig - OGDF_ASSERT(!m_traditional); - if (m_traditional) - { - switch (angle) - { - case 0: - case 90: - case 180: - break; - OGDF_NODEFAULT - }//switch - }//trad - else - { - switch (angle) - { - case 0: - if (maxBound) - { - upB[netArc] = lowB[netArc] = 2; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = lowB[e2] = 0; - } - } - else - { - upB[netArc] = 2; lowB[netArc] = 0; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = 2; - lowB[e2] = 0; - } - - } - break; - case 90: - if (maxBound) - { - lowB[netArc] = 1; - upB[netArc] = 2; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = lowB[e2] = 0; - } - } - else - { - upB[netArc] = 1; - lowB[netArc] = 0; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = 2; - lowB[e2] = 0; - } - - } - break; - case 180: - if (maxBound) - { - lowB[netArc] = 0; - upB[netArc] = 2; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = lowB[e2] = 0; - } - } - else - { - upB[netArc] = 0; - lowB[netArc] = 0; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = 2; - lowB[e2] = 0; - } - - } - break; - OGDF_NODEFAULT - }//switch - }//progressive - - }//setAngle -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterPlanRep.h b/ext/OGDF/ogdf/cluster/ClusterPlanRep.h deleted file mode 100644 index cbe3f7f8c..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterPlanRep.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of ClusterPlanRep class, allowing cluster - * boundary insertion and shortest path edge insertion - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTER_PLAN_REP_H -#define OGDF_CLUSTER_PLAN_REP_H - - - -#include -#include -#include -#include - -#include - - -namespace ogdf { - - -class OGDF_EXPORT ClusterPlanRep : public PlanRep -{ - -public: - - ClusterPlanRep( - const ClusterGraphAttributes &acGraph, - const ClusterGraph &clusterGraph); - - virtual ~ClusterPlanRep() { } - - void initCC(int i); - - //edge on the cluster boundary, adjSource - void setClusterBoundary(edge e) { - setEdgeTypeOf(e, edgeTypeOf(e) | clusterPattern()); - } - bool isClusterBoundary(edge e) { - return ((edgeTypeOf(e) & clusterPattern()) == clusterPattern()); - } - const ClusterGraph &getClusterGraph() const { - return *m_pClusterGraph; - } - - /** re-inserts edge eOrig by "crossing" the edges in crossedEdges; - * splits each edge in crossedEdges - * Precond.: eOrig is an edge in the original graph, - * the edges in crossedEdges are in this graph, - * cluster boundaries are modelled as edge paths - * \param eOrig: Original edge to be inserted - * \param crossedEdges: Edges that are crossed by this insertion - * \param E: The embedding in which the edge is inserted - */ - void insertEdgePathEmbedded( - edge eOrig, - CombinatorialEmbedding &E, - const SList &crossedEdges); - - void ModelBoundaries(); - - //rootadj is set by ModelBoundaries - adjEntry externalAdj() { return m_rootAdj; } - - - //************************************************************************* - //structural alterations - - // Expands nodes with degree > 4 and merge nodes for generalizations - virtual void expand(bool lowDegreeExpand = false); - - virtual void expandLowDegreeVertices(OrthoRep &OR); - - //splits edge e, updates clustercage lists if necessary and returns new edge - virtual edge split(edge e) - { - edge eNew = PlanRep::split(e); - - //update edge to cluster info - m_edgeClusterID[eNew] = m_edgeClusterID[e]; - m_nodeClusterID[eNew->source()] = m_edgeClusterID[e]; - - return eNew; - }//split - - - //returns cluster of edge e - //edges only have unique numbers if clusters are already modelled - //we derive the edge cluster from the endnode cluster information - cluster clusterOfEdge(edge e) - { - - OGDF_ASSERT(m_clusterOfIndex.isDefined(ClusterID(e->source()))) - OGDF_ASSERT(m_clusterOfIndex.isDefined(ClusterID(e->target()))) - - OGDF_ASSERT( - (ClusterID(e->source()) == ClusterID(e->target())) || - (clusterOfIndex(ClusterID(e->source())) == - clusterOfIndex(ClusterID(e->target()))->parent()) || - (clusterOfIndex(ClusterID(e->target())) == - clusterOfIndex(ClusterID(e->source()))->parent()) || - (clusterOfIndex(ClusterID(e->target()))->parent() == - clusterOfIndex(ClusterID(e->source()))->parent()) - ) - - if (ClusterID(e->source()) == ClusterID(e->target())) - return clusterOfIndex(ClusterID(e->target())); - if (clusterOfIndex(ClusterID(e->source())) == - clusterOfIndex(ClusterID(e->target()))->parent()) - return clusterOfIndex(ClusterID(e->source())); - if (clusterOfIndex(ClusterID(e->target())) == - clusterOfIndex(ClusterID(e->source()))->parent()) - return clusterOfIndex(ClusterID(e->target())); - if (clusterOfIndex(ClusterID(e->target()))->parent() == - clusterOfIndex(ClusterID(e->source()))->parent()) - return clusterOfIndex(ClusterID(e->source()))->parent(); - - OGDF_THROW(AlgorithmFailureException); - //return 0; - }//clusterOfEdge - - inline int ClusterID(node v) const {return m_nodeClusterID[v];} - inline int ClusterID(edge e) const {return m_edgeClusterID[e];} - cluster clusterOfIndex(int i) {return m_clusterOfIndex[i];} - - inline cluster clusterOfDummy(node v) - { - OGDF_ASSERT(!original(v)) - OGDF_ASSERT(ClusterID(v) != -1) - return clusterOfIndex(ClusterID(v)); - } - - //output functions - void writeGML(const char *fileName, const Layout &drawing); - void writeGML(const char *fileName); - void writeGML(ostream &os, const Layout &drawing); - - -protected: - - //insert boundaries for all given clusters - void convertClusterGraph(cluster act, - AdjEntryArray& currentEdge, - AdjEntryArray& outEdge); - - //insert edges to represent the cluster boundary - void insertBoundary(cluster C, - AdjEntryArray& currentEdge, - AdjEntryArray& outEdge, - bool clusterIsLeaf); - - //reinsert edges to planarize the graph after convertClusterGraph - void reinsertEdge(edge e); - -private: - - const ClusterGraph *m_pClusterGraph; - - edgeType clusterPattern() { return etcSecCluster << etoSecondary; } - - adjEntry m_rootAdj; //connects cluster on highest level with non cluster or - //same level - - - //****************** - EdgeArray m_edgeClusterID; - NodeArray m_nodeClusterID; - //we maintain an array of index to cluster mappings (CG is const) - //cluster numbers don't need to be consecutive - HashArray m_clusterOfIndex; -}; - - -}//namespace - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterPlanarizationLayout.h b/ext/OGDF/ogdf/cluster/ClusterPlanarizationLayout.h deleted file mode 100644 index 2e788a047..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterPlanarizationLayout.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class ClusterPlanarizationLayout - * Planarization approach for cluster graphs - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTER_PLANARIZATION_LAYOUT_H -#define OGDF_CLUSTER_PLANARIZATION_LAYOUT_H - - -#include -#include -#include - - -namespace ogdf { - - -//! The cluster planarization layout algorithm. -/** - * The class ClusterPlanarizationLayout implements the planarization - * approach for drawing clustered graphs. Its implementation is based - * on the following publication: - * - * Giuseppe Di Battista, Walter Didimo, A. Marcandalli: Planarization - * of Clustered Graphs. LNCS 2265 (Proc. %Graph Drawing 2001), pp. 60-74. - * - *

    Optional parameters

    - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    pageRatiodouble1.0 - * Specifies the desired ration of width / height of the computed - * layout. It is currently only used when packing connected components. - *
    - * - *

    %Module options

    - * The algorithm provides the following module options: - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    planarLayouterLayoutClusterPlanRepModuleClusterOrthoLayout - * The c-planar layout algorithm used to compute a c-planar layout - * of the c-planarized representation resulting from the crossing minimization step. - *
    packerCCLayoutPackModuleTileToRowsCCPacker - * The packer module used for arranging connected components. - *
    - */ -class OGDF_EXPORT ClusterPlanarizationLayout -{ -public: - //! Creates an instance of cluster planarization layout. - ClusterPlanarizationLayout(); - - // Destruction - virtual ~ClusterPlanarizationLayout() { } - - - - //! Calls cluster planarization layout with cluster-graph attributes \a acGraph. - /** - * @param G is the input graph. - * @param acGraph is assigned the computed layout. - * @param cGraph is the input cluster graph. - * @param simpleCConnect If set to true, c-connectivity is achieved by adding arbitrary edges (fast). - */ - virtual void call( - Graph& G, - ClusterGraphAttributes& acGraph, - ClusterGraph& cGraph, - bool simpleCConnect = true); - //! Calls cluster planarization layout with cluster-graph attributes \a acGraph. - /** - * @param G is the input graph. - * @param acGraph is assigned the computed layout. - * @param cGraph is the input cluster graph. - * @param edgeWeight allows to prefer lightweight edges for planar subgraph computation. - * @param simpleCConnect If set to true, c-connectivity is achieved by adding arbitrary edges (fast). - */ - virtual void call( - Graph& G, - ClusterGraphAttributes& acGraph, - ClusterGraph& cGraph, - EdgeArray& edgeWeight, - bool simpleCConnect = true); - - - //! Returns the current page ratio (= desired width / height of layout). - double pageRatio() const { - return m_pageRatio; - } - - //! Sets the page ratio to \a ratio. - void pageRatio(double ratio) { - m_pageRatio = ratio; - } - - //! Sets the module option for the planar layout algorithm to \a pPlanarLayouter. - void setPlanarLayouter(LayoutClusterPlanRepModule *pPlanarLayouter) { - m_planarLayouter.set(pPlanarLayouter); - } - - //! Sets the module option for the arrangement of connected components to \a pPacker. - void setPacker(CCLayoutPackModule *pPacker) { - m_packer.set(pPacker); - } - - ////! Returns the number of crossings in the layout produced in last call. - //int numberOfCrossings() const { - // return m_nCrossings; - //} - - -protected: - struct ClusterPosition - { - double m_minx, m_maxx, m_miny, m_maxy, m_width, m_height; - }; - - void computeClusterPositions( - ClusterPlanRep& CP, - Layout drawing, - HashArray& CA); - - -private: - ModuleOption m_planarLayouter; //!< The planar layouter. - ModuleOption m_packer; //!< The packing algorithm. - - double m_pageRatio; //!< The page ratio. - - int m_nCrossings;//!< The number of crossings (not yet used!). -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/ClusterSet.h b/ext/OGDF/ogdf/cluster/ClusterSet.h deleted file mode 100644 index b555df18b..000000000 --- a/ext/OGDF/ogdf/cluster/ClusterSet.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of class ClusterSetSimple, - * ClusterSetPure and ClusterSet - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_SET_H -#define OGDF_NODE_SET_H - - -#include -#include - - - -namespace ogdf { - - -//--------------------------------------------------------- -// ClusterSetSimple -// maintains a subset S of the clusters contained in an associated -// cluster graph G (only insertion of elements and clear operation) -//--------------------------------------------------------- -class OGDF_EXPORT ClusterSetSimple { -public: - // creates a new empty cluster set associated with cluster graph CG - ClusterSetSimple(const ClusterGraph &CG) : m_isContained(CG,false) { } - - // destructor - ~ClusterSetSimple() { } - - // inserts cluster c into set S - // running time: O(1) - // Precond.: c is a cluster in the associated graph - void insert(cluster c) { - OGDF_ASSERT(c->graphOf() == m_isContained.graphOf()); - bool &isContained = m_isContained[c]; - if (isContained == false) { - isContained = true; - m_clusters.pushFront(c); - } - } - - - // removes all clusters from set S - // running time: O(|S|) - void clear() { - SListIterator it; - for(it = m_clusters.begin(); it.valid(); ++it) { - m_isContained[*it] = false; - } - m_clusters.clear(); - } - - - // returns true iff cluster c is contained in S - // running time: O(1) - // Precond.: c is a cluster in the asociated graph - bool isMember(cluster c) const { - OGDF_ASSERT(c->graphOf() == m_isContained.graphOf()); - return m_isContained[c]; - } - - // returns the list of clusters contained in S - const SListPure &clusters() const { - return m_clusters; - } - -private: - // m_isContained[c] is true <=> c is contained in S - ClusterArray m_isContained; - // list of clusters contained in S - SListPure m_clusters; -}; - - - -//--------------------------------------------------------- -// ClusterSetPure -// maintains a subset S of the clusters contained in an associated -// graph G (no efficient access to size of S) -//--------------------------------------------------------- -class OGDF_EXPORT ClusterSetPure { -public: - // creates a new empty cluster set associated with graph G - ClusterSetPure(const ClusterGraph &G) : m_it(G,ListIterator()) { } - - // destructor - ~ClusterSetPure() { } - - // inserts cluster c into set S - // running time: O(1) - // Precond.: c is a cluster in the associated graph - void insert(cluster c) { - OGDF_ASSERT(c->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[c]; - if (!itV.valid()) - itV = m_clusters.pushBack(c); - } - - // removes cluster c from set S - // running time: O(1) - // Precond.: c is a cluster in the asociated graph - void remove(cluster c) { - OGDF_ASSERT(c->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[c]; - if (itV.valid()) { - m_clusters.del(itV); - itV = ListIterator(); - } - } - - - // removes all clusters from set S - // running time: O(|S|) - void clear() { - ListIterator it; - for(it = m_clusters.begin(); it.valid(); ++it) { - m_it[*it] = ListIterator(); - } - m_clusters.clear(); - } - - - // returns true iff cluster c is contained in S - // running time: O(1) - // Precond.: c is a cluster in the asociated graph - bool isMember(cluster c) const { - OGDF_ASSERT(c->graphOf() == m_it.graphOf()); - return m_it[c].valid(); - } - - // returns the list of clusters contained in S - const ListPure &clusters() const { - return m_clusters; - } - -private: - // m_it[c] contains list iterator pointing to c if c is contained in S, - // an invalid list iterator otherwise - ClusterArray > m_it; - // list of clusters contained in S - ListPure m_clusters; -}; - - - -//--------------------------------------------------------- -// ClusterSet -// maintains a subset S of the clusters contained in an associated -// graph G -//--------------------------------------------------------- -class OGDF_EXPORT ClusterSet { -public: - // creates a new empty cluster set associated with graph G - ClusterSet(const ClusterGraph &G) : m_it(G,ListIterator()) { } - - // destructor - ~ClusterSet() { } - - // inserts cluster c into set S - // running time: O(1) - // Precond.: c is a cluster in the associated graph - void insert(cluster c) { - OGDF_ASSERT(c->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[c]; - if (!itV.valid()) - itV = m_clusters.pushBack(c); - } - - // removes cluster c from set S - // running time: O(1) - // Precond.: c is a cluster in the asociated graph - void remove(cluster c) { - OGDF_ASSERT(c->graphOf() == m_it.graphOf()); - ListIterator &itV = m_it[c]; - if (itV.valid()) { - m_clusters.del(itV); - itV = ListIterator(); - } - } - - - // removes all clusterss from set S - // running time: O(|S|) - void clear() { - ListIterator it; - for(it = m_clusters.begin(); it.valid(); ++it) { - m_it[*it] = ListIterator(); - } - m_clusters.clear(); - } - - - // returns true iff cluster c is contained in S - // running time: O(1) - // Precond.: c is a cluster in the asociated graph - bool isMember(cluster c) const { - OGDF_ASSERT(c->graphOf() == m_it.graphOf()); - return m_it[c].valid(); - } - - // returns the size of set S - // running time: O(1) - int size() const { - return m_clusters.size(); - } - - // returns the list of clusters contained in S - const List &clusters() const { - return m_clusters; - } - -private: - // m_it[c] contains list iterator pointing to c if c is contained in S, - // an invalid list iterator otherwise - ClusterArray > m_it; - // list of clusters contained in S - List m_clusters; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/cluster/MaximumCPlanarSubgraph.h b/ext/OGDF/ogdf/cluster/MaximumCPlanarSubgraph.h deleted file mode 100644 index 9881d6835..000000000 --- a/ext/OGDF/ogdf/cluster/MaximumCPlanarSubgraph.h +++ /dev/null @@ -1,278 +0,0 @@ - /* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of an exact c-planar subgraph algorithm, i.e., - * a maximum c-planar subgraph is computed using a branch and cut approach. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MAXIMUM_CPLANAR_SUBGRAPH_H -#define OGDF_MAXIMUM_CPLANAR_SUBGRAPH_H - -#include -#include - -#include -#include -#include - -#include - -namespace ogdf { - -/** - * MaximumCPlanarSubgraph - * \brief Exact computation of a maximum c-planar subgraph. - */ -class OGDF_EXPORT MaximumCPlanarSubgraph : public CPlanarSubgraphModule -{ - -#ifndef USE_ABACUS -protected: - ReturnType doCall( - const ClusterGraph &G, - List &delEdges, - List &addedEdges) - { - THROW_NO_ABACUS_EXCEPTION; - return retError; - } - - virtual ReturnType doCall( - const ClusterGraph &G, - List &delEdges) - { - THROW_NO_ABACUS_EXCEPTION; - return retError; - } -}; -#else // USE_ABACUS - -public: - //! Construction - MaximumCPlanarSubgraph() : m_heuristicLevel(1), - m_heuristicRuns(1), - m_heuristicOEdgeBound(0.4), - m_heuristicNPermLists(5), - m_kuratowskiIterations(10), - m_subdivisions(10), - m_kSupportGraphs(10), - m_kuratowskiHigh(0.8), - m_kuratowskiLow(0.8), - m_perturbation(false), - m_branchingGap(0.4), - m_time("00:20:00"), - m_pricing(true), - m_checkCPlanar(false), - m_numAddVariables(15), - m_strongConstraintViolation(0.3), - m_strongVariableViolation(0.3), - m_ol(ABA_MASTER::Silent), - m_totalTime(-1.0), - m_heurTime(-1.0), - m_lpTime(-1.0), - m_lpSolverTime(-1.0), - m_sepTime(-1.0), - m_totalWTime(-1.0), - m_numCCons(-1), - m_numKCons(-1), - m_numLPs(-1), - m_numBCs(-1), - m_numSubSelected(-1), - m_portaOutput(false) {} - //destruction - ~MaximumCPlanarSubgraph() {} - - //! Computes set of edges delEdges, which have to be deleted - //! in order to get a c-planar subgraph and also returns - //! a set of edges that augments the subgraph to be - //! completely connected. - //! For pure c-planarity testing, the computation can be sped - //! up by setting setCheckCPlanar(2). Then, in case G is not c-planar, - //! the list of deleted edges does not need to correspond - //! to a valid solution, it just indicates the result. - ReturnType call(const ClusterGraph &G, List &delEdges, - List &addedEdges) { - return doCall(G, delEdges, addedEdges); - } - //setter methods for the module parameters - void setHeuristicLevel(int i) {m_heuristicLevel = i;} - void setHeuristicRuns(int i) {m_heuristicRuns = i;} - void setHeuristicBound(double d) {m_heuristicOEdgeBound = d;} - void setNumberOfPermutations(int i) {m_heuristicNPermLists = i;} - void setNumberOfKuraIterations(int i) {m_kuratowskiIterations = i;} - void setNumberOfSubDivisions(int i) {m_subdivisions = i;} - void setNumberOfSupportGraphs(int i) {m_kSupportGraphs = i;} - void setUpperRounding(double d) {m_kuratowskiHigh = d;} - void setLowerRounding(double d) {m_kuratowskiLow = d;} - void setPerturbation(bool b) {m_perturbation = b;} - void setBranchingGap(double d) {m_branchingGap = d;} - void setTimeLimit(String s) {m_time = s.cstr();} - void setOutputLevel(ABA_MASTER::OUTLEVEL o) {m_ol = o;} - void setPortaOutput(bool b) {m_portaOutput = b;} - void setPricing(bool b) { m_pricing = b;} - void setCheckCPlanar(bool b) {m_checkCPlanar = b;} - void setNumAddVariables(int n) { m_numAddVariables = n;} - void setStrongConstraintViolation(double d) { m_strongConstraintViolation=d;} - void setStrongVariableViolation(double d) { m_strongVariableViolation=d;} - //! Use default abacus master cut pool or dedicated connectivity and - //! kuratowski cut pools - bool & useDefaultCutPool() {return m_defaultCutPool;} - - //getter methods for results - double getTotalTime() {return m_totalTime;} - double getHeurTime() {return m_heurTime;} - double getLPTime() {return m_lpTime;} - double getLPSolverTime() {return m_lpSolverTime;} - double getSeparationTime() {return m_sepTime;} - double getTotalWTime() {return m_totalWTime;} - //! Returns number of connectivity constraints added during computation - int getNumCCons() {return m_numCCons;} - //! Returns number of Kuratowski constraints added during computation - int getNumKCons() {return m_numKCons;} - //! Returns number of optimized LPs (only LP-relaxations) - int getNumLPs() {return m_numLPs;} - //! Returns number of generated LPs - int getNumBCs() {return m_numBCs;} - //! Returns number of subproblems selected by ABACUS - int getNumSubSelected() {return m_numSubSelected;} - //! Returns number of global variables. Todo: Real number from ABACUS - int getNumVars() {return m_numVars;} - - //! Writes feasible solutions as a file in PORTA format - void writeFeasible(const String &filename, Master &master, - ABA_MASTER::STATUS &status); -#ifdef OGDF_DEBUG - bool getSolByHeuristic(){return m_solByHeuristic;} -#endif - - -protected: - //! Computes a maximum c-planar subgraph, returns the - //! set of edges that have to be deleted in delEdges - //! if delEdges is empty on return, the clustered - //! graph G is c-planar - virtual ReturnType doCall(const ClusterGraph &G, - List &delEdges) - { - List addEdges; - return doCall(G, delEdges, addEdges); - } - - //as above, also returns the set of edges that were - //added to construct a completely connected planar - //graph that contains the computed c-planar subgraph - virtual ReturnType doCall(const ClusterGraph &G, - List &delEdges, - List &addedEdges); - - double getDoubleTime(const ABA_TIMER &act) - { - long tempo = act.centiSeconds()+100*act.seconds()+6000*act.minutes()+360000*act.hours(); - return ((double) tempo)/ 100.0; - }//getdoubletime - - //! Stores clusters in subtree at c in bottom up order in theList - void getBottomUpClusterList(const cluster c, List< cluster > & theList); - -private: - //Abacus Master class settings in order of appearance - int m_heuristicLevel, m_heuristicRuns; - double m_heuristicOEdgeBound; - int m_heuristicNPermLists, m_kuratowskiIterations; - int m_subdivisions, m_kSupportGraphs; - double m_kuratowskiHigh, m_kuratowskiLow; - bool m_perturbation; - double m_branchingGap; - const char *m_time; - bool m_pricing;// *connCon, - ABA_STANDARDPOOL *stdVar); - - //results - double m_totalTime; // - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BC_TREE_H -#define OGDF_BC_TREE_H - -#include -#include -#include -#include - -namespace ogdf { - -/** - * \brief Static BC-trees. - * - * This class provides static BC-trees.\n - * The data structure consists of three parts: - * - The original graph itself (\e G) is represented by an ordinary ogdf::Graph - * structure. - * - The BC-tree (\e B) is represented by an ogdf::Graph structure, each - * vertex representing a B-component or a C-component. - * - The biconnected components graph (\e H), which contains a set of copies of - * the biconnected components and the cut-vertices of the original graph, - * combined but not interconnected within a single ogdf::Graph structure. - */ -class OGDF_EXPORT BCTree { - -public: - -/** \enum GNodeType - * \brief Enumeration type for characterizing the vertices of the original - * graph. - */ -/** \var GNodeType ogdf::BCTree::Normal - * denotes an ordinary vertex, i.e. not a cut-vertex. - */ -/** \var GNodeType ogdf::BCTree::CutVertex - * denotes a cut-vertex. - */ - enum GNodeType { Normal, CutVertex }; -/** \enum BNodeType - * \brief Enumeration type for characterizing the BC-tree-vertices. - */ -/** \var BNodeType ogdf::BCTree::BComp - * denotes a vertex representing a B-component. - */ -/** \var BNodeType ogdf::BCTree::CComp - * denotes a vertex representing a C-component. - */ - enum BNodeType { BComp, CComp }; - -protected: - -/** - * \brief The original graph. - */ - Graph& m_G; -/** - * \brief The BC-tree. - * - * Each vertex is representing a biconnected component (B-component) or a - * cut-vertex (C-component) of the original graph. - */ - Graph m_B; -/** - * \brief The biconnected components graph. - * - * This graph contains copies of the the biconnected components (B-components) - * and the cut-vertices (C-components) of the original graph. The copies of the - * B- and C-components of the original graph are not interconnected, i.e. the - * biconnected components graph is representing B-components as isolated - * biconnected subgraphs and C-components as isolated single vertices. Thus the - * copies of the edges and non-cut-vertices of the original graph are - * unambiguous, but each cut-vertex of the original graph being common to a - * C-component and several B-components appears multiple times. - */ - mutable Graph m_H; - -/** @{ - * \brief The number of B-components. - */ - int m_numB; -/** - * \brief The number of C-components. - */ - int m_numC; - -/** @} @{ - * \brief Array of marks for the vertices of the original graph. - * - * They are needed during the generation of the BC-tree by DFS method. - */ - NodeArray m_gNode_isMarked; -/** - * \brief An injective mapping vertices(\e G) -> vertices(\e H). - * - * For each vertex \e vG of the original graph: - * - If \e vG is not a cut-vertex, then m_gNode_hNode[\e vG] is the very vertex - * of the biconnected components graph corresponding to \e vG. - * - If \e vG is a cut-vertex, then m_gNode_hNode[\e vG] is the very vertex of - * the biconnected components graph representing the C-component, which \e vG - * is belonging to, as a single isolated vertex. - */ - NodeArray m_gNode_hNode; -/** - * \brief A bijective mapping edges(\e G) -> edges(\e H). - * - * For each edge \e eG of the original graph, m_gEdge_hEdge[\e eG] is the very - * edge of the biconnected components graph corresponding to \e eG. - */ - EdgeArray m_gEdge_hEdge; - -/** @} @{ - * \brief Array that contains the type of each BC-tree-vertex. - */ - NodeArray m_bNode_type; -/** - * \brief Array of marks for the BC-tree-vertices. - * - * They are needed for searching for the nearest common ancestor of two - * vertices of the BC-tree. - */ - mutable NodeArray m_bNode_isMarked; -/** - * \brief Array that contains for each BC-tree-vertex the representant of its - * parent within the subgraph in the biconnected components graph belonging to - * the biconnected component represented by the respective BC-tree-vertex. - * - * For each vertex \e vB of the BC-tree: - * - If \e vB is representing a B-component and \e vB is the root of the - * BC-tree, then m_bNode_hRefNode[\e vB] is \e NULL. - * - If \e vB is representing a B-component and \e vB is not the root of the - * BC-tree, then m_bNode_hRefNode[\e vB] is the very vertex of the - * biconnected components graph which is the duplicate of the cut-vertex - * represented by the parent of \e vB in the copy of the B-component - * represented by \e vB. - * - If \e vB is representing a C-component, then m_bNode_hRefNode[\e vB] - * is the single isolated vertex of the biconnected components graph - * corresponding to the cut-vertex which the C-component consists of, - * irrespective of whether \e vB is the root of the BC-tree or not. - */ - NodeArray m_bNode_hRefNode; -/** - * \brief Array that contains for each BC-tree-vertex the representant of - * itself within the subgraph in the biconnected components graph belonging to - * the biconnected component represented by the parent of the respective - * BC-tree-vertex. - * - * - If \e vB is the root of the BC-tree, then m_bNode_hParNode[\e vB] is - * \e NULL. - * - If \e vB is representing a B-component and \e vB is not the root of the - * BC-tree, then m_bNode_hParNode[\e vB] is the single isolated vertex - * of the biconnected components graph corresponding to the very cut-vertex, - * which the C-component represented by the parent of \e vB consists - * of. - * - If \e vB is representing to a C-component and \e vB is not the root of the - * BC-tree, then m_bNode_hParNode[\e vB] is the very vertex of the - * biconnected components graph, which is the duplicate of the cut-vertex, - * which the C-component consists of, in the copy of the B-component - * represented by the parent of \e vB. - */ - NodeArray m_bNode_hParNode; -/** - * \brief Array that contains for each BC-tree-vertex a linear list of the - * edges of the biconnected components graph belonging to the biconnected - * component represented by the respective BC-tree-vertex. - * - * For each vertex \e vB of the BC-tree: - * - If \e vB is representing a B-component, then m_bNode_hEdges[\e vB] is a - * linear list of the edges of the biconnected components graph corresponding - * to the edges of the original graph belonging to the B-component. - * - If \e vB is representing a C-component, then m_bNode_hEdges[\e vB] is an - * empty list. - */ - NodeArray > m_bNode_hEdges; -/** - * \brief Array that contains for each BC-tree-vertex the number of vertices - * belonging to the biconnected component represented by the respective - * BC-tree-vertex. - * - * For each vertex \e vB of the BC-tree: - * - If \e vB is representing a B-component, then m_bNode_numNodes[\e vB] is - * the number of vertices belonging to the B-component, cut-vertices - * inclusive. - * - If \e vB is representing a C-component, then m_bNode_numNodes[\e vB] is 1. - */ - NodeArray m_bNode_numNodes; - -/** @} @{ - * \brief A surjective mapping vertices(\e H) -> vertices(\e B). - * - * For each vertex \e vH of the biconnected components graph, - * m_hNode_bNode[\e vH] is the very BC-tree-vertex representing the B- or - * C-component with respect to the copy of the very block or representation - * of a cut-vertex, which vH is belonging to. - */ - mutable NodeArray m_hNode_bNode; -/** - * \brief A surjective mapping edges(\e H) -> vertices(\e B). - * - * For each edge \e eH of the biconnected components graph, - * m_hEdge_bNode[\e eH] is the very BC-tree-vertex representing the unambiguous - * B-component, which \e eH is belonging to. - */ - mutable EdgeArray m_hEdge_bNode; -/** - * \brief A surjective mapping vertices(\e H) -> vertices(\e G). - * - * For each vertex \e vH of the biconnected components graph, - * m_hNode_gNode[\e vH] is the vertex of the original graph which \e vH is - * corresponding to. - */ - NodeArray m_hNode_gNode; -/** - * \brief A bijective mapping edges(\e H) -> edges(\e G). - * - * For each edge \e eH of the biconnected components graph, - * m_hEdge_gEdge[\e eH] is the edge of the original graph which \e eH is - * corresponding to. - */ - EdgeArray m_hEdge_gEdge; - -/** @} @{ - * \brief Temporary variable. - * - * It is needed for the generation of the BC-tree by DFS method. It has to be a - * member of class BCTree due to recursive calls to biComp(). - */ - int m_count; -/** - * \brief Temporary array. - * - * It is needed for the generation of the BC-tree by DFS method. It has to be a - * member of class BCTree due to recursive calls to biComp(). -*/ - NodeArray m_number; -/** - * \brief Temporary array. - * - * It is needed for the generation of the BC-tree by DFS method. It has to be a - * member of class BCTree due to recursive calls to biComp(). - */ - NodeArray m_lowpt; -/** - * \brief Temporary stack. - * - * It is needed for the generation of the BC-tree by DFS method. It has to be a - * member of class BCTree due to recursive calls to biComp(). - */ - BoundedStack m_eStack; -/** - * \brief Temporary array. - * - * It is needed for the generation of the BC-tree by DFS method. It has to be a - * member of class BCTree due to recursive calls to biComp(). - */ - NodeArray m_gtoh; -/** - * \brief Temporary list. - * - * It is needed for the generation of the BC-tree by DFS method. It has to be a - * member of class BCTree due to recursive calls to biComp(). - */ - SList m_nodes; - -/** @} - * \brief Initialization. - * - * initializes all data structures and generates the BC-tree and the - * biconnected components graph by call to biComp(). - * \param vG is the vertex of the original graph which the DFS algorithm starts - * with. - */ - void init (node vG); - -/** @} - * \brief Initialization for not connected graphs - * - * initializes all data structures and generates a forest of BC-trees and the - * biconnected components graph by call to biComp(). - * \param vG is the vertex of the original graph which the DFS algorithm starts - * first with. - */ - void initNotConnected (node vG); -/** - * \brief generates the BC-tree and the biconnected components graph - * recursively. - * - * The DFS algorithm is based on J. Hopcroft and R. E. Tarjan: Algorithm 447: - * Efficient algorithms for graph manipulation. Comm. ACM, 16:372-378 - * (1973). - */ - void biComp (adjEntry adjuG, node vG); - -/** @{ - * \brief returns the parent of a given BC-tree-vertex. - * \param vB is a vertex of the BC-tree or \e NULL. - * \return the parent of \a vB in the BC-tree structure, if \a vB is not the - * root of the BC-tree, and \e NULL, if \a vB is \e NULL or the root of the - * BC-tree. - */ - virtual node parent (node vB) const; -/** - * \brief calculates the nearest common ancestor of two vertices of the - * BC-tree. - * \param uB is a vertex of the BC-tree. - * \param vB is a vertex of the BC-tree. - * \return the nearest common ancestor of \a uB and \a vB. - */ - node findNCA (node uB, node vB) const; - -public: - -/** @} - * \brief A constructor. - * - * This constructor does only call init() or initNotConnected(). - * BCTree(\a G) is equivalent to BCTree(G,G.firstNode()). - * \param G is the original graph. - * \param callInitConnected decides which init is called, default call is init() - */ - BCTree (Graph& G, bool callInitConnected = false) : m_G(G), m_eStack(G.numberOfEdges()) { - if (!callInitConnected) - init(G.firstNode()); - else initNotConnected(G.firstNode()); - } - -/** - * \brief A constructor. - * - * This constructor does only call init() or initNotConnected(). - * \param G is the original graph. - * \param vG is the vertex of the original graph which the DFS algorithm starts - * \param callInitConnected decides which init is called, default call is init() - */ - BCTree (Graph& G, node vG, bool callInitConnected = false) : m_G(G), m_eStack(G.numberOfEdges()) { - if (!callInitConnected) - init(vG); - else initNotConnected(vG); - } - -/** - * \brief Virtual destructor. - */ - virtual ~BCTree () { } - -/** @{ - * \brief returns the original graph. - * \return the original graph. - */ - const Graph& originalGraph () const { return m_G; } -/** - * \brief returns the BC-tree graph. - * \return the BC-tree graph. - */ - const Graph& bcTree () const { return m_B; } -/** - * \brief returns the biconnected components graph. - * \return the biconnected components graph. - */ - const Graph& auxiliaryGraph () const { return m_H; } - -/** @} @{ - * \brief returns the number of B-components. - * \return the number of B-components. - */ - int numberOfBComps () const { return m_numB; } -/** - * \brief returns the number of C-components. - * \return the number of C-components. - */ - int numberOfCComps () const { return m_numC; } - -/** @} @{ - * \brief returns the type of a vertex of the original graph. - * \param vG is a vertex of the original graph. - * \return the type of \a vG. - */ - GNodeType typeOfGNode (node vG) const { return m_bNode_type[m_hNode_bNode[m_gNode_hNode[vG]]]==BComp ? Normal : CutVertex; } -/** - * \brief returns a BC-tree-vertex representing a biconnected component which a - * given vertex of the original graph is belonging to. - * \param vG is a vertex of the original graph. - * \return a vertex of the BC-tree: - * - If \a vG is not a cut-vertex, then typeOfGNode(\a vG) returns the very - * vertex of the BC-tree representing the unambiguous B-component which \a vG - * is belonging to. - * - If \a vG is a cut-vertex, then typeOfGNode(\a vG) returns the very vertex - * of the BC-tree representing the unambiguous C-component which \a vG is - * belonging to. - */ - virtual node bcproper (node vG) const { return m_hNode_bNode[m_gNode_hNode[vG]]; } -/** - * \brief returns the BC-tree-vertex representing the biconnected component - * which a given edge of the original graph is belonging to. - * \param eG is an edge of the original graph. - * \return the vertex of the BC-tree representing the B-component which \a eG - * is belonging to. - */ - virtual node bcproper (edge eG) const { return m_hEdge_bNode[m_gEdge_hEdge[eG]]; } -/** - * \brief returns a vertex of the biconnected components graph corresponding to - * a given vertex of the original graph. - * \param vG is a vertex of the original graph. - * \return a vertex of the biconnected components graph: - * - If \a vG is not a cut-vertex, then rep(\a vG) returns the very vertex of - * the biconnected components graph corresponding to \a vG. - * - If \a vG is a cut-vertex, then rep(\a vG) returns the very vertex of the - * biconnected components graph representing the C-component which \a vG is - * belonging to. - */ - node rep (node vG) const { return m_gNode_hNode[vG]; } -/** - * \brief returns the edge of the biconnected components graph corresponding to - * a given edge of the original graph. - * \param eG is an edge of the original graph. - * \return the edge of the biconnected components graph corresponding to \a eG. - */ - edge rep (edge eG) const { return m_gEdge_hEdge[eG]; } - -/** @} @{ - * \brief returns the vertex of the original graph which a given vertex of the - * biconnected components graph is corresponding to. - * \param vH is a vertex of the biconnected components graph. - * \return the vertex of the original graph which \a vH is corresponding to. - */ - node original (node vH) { return m_hNode_gNode[vH]; } -/** - * \brief returns the edge of the original graph which a given edge of the - * biconnected components graph is corresponding to. - * \param eH is an edge of the biconnected components graph. - * \return the edge of the original graph which \a eH is corresponding to. - */ - edge original (edge eH) const { return m_hEdge_gEdge[eH]; } - -/** @} @{ - * \brief returns the type of the biconnected component represented by a given - * BC-tree-vertex. - * \param vB is a vertex of the BC-tree. - * \return the type of the biconnected component represented by \a vB. - */ - BNodeType typeOfBNode (node vB) const { return m_bNode_type[vB]; } -/** - * \brief returns a linear list of the edges of the biconnected components - * graph belonging to the biconnected component represented by a given - * BC-tree-vertex. - * \param vB is a vertex of the BC-tree. - * \return a linear list of edges of the biconnected components graph: - * - If \a vB is representing a B-component, then the edges in the list are the - * copies of the edges belonging to the B-component. - * - If \a vB is representing a C-component, then the list is empty. - */ - const SList& hEdges (node vB) const { return m_bNode_hEdges[vB]; } -/** - * \brief returns the number of edges belonging to the biconnected component - * represented by a given BC-tree-vertex. - * \param vB is a vertex of the BC-tree. - * \return the number of edges belonging to the B- or C-component represented - * by \a vB, particularly 0 if it is a C-component. - */ - int numberOfEdges (node vB) const { return m_bNode_hEdges[vB].size(); } -/** - * \brief returns the number of vertices belonging to the biconnected component - * represented by a given BC-tree-vertex. - * \param vB is a vertex of the BC-tree. - * \return the number of vertices belonging to the B- or C-component - * represented by \a vB, cut-vertices inclusive, particularly 1 if it is a - * C-component. - */ - int numberOfNodes (node vB) const { return m_bNode_numNodes[vB]; } - -/** @} @{ - * \brief returns the BC-tree-vertex representing the B-component which two - * given vertices of the original graph are belonging to. - * \param uG is a vertex of the original graph. - * \param vG is a vertex of the original graph. - * \return If \a uG and \a vG are belonging to the same B-component, the very - * vertex of the BC-tree representing this B-component is returned. Otherwise, - * \e NULL is returned. This member function returns the representant of the - * correct B-component even if \a uG or \a vG or either are cut-vertices and - * are therefore belonging to C-components, too. - */ - node bComponent (node uG, node vG) const; - -/** - * \brief calculates a path in the BC-tree. - * \param sG is a vertex of the original graph. - * \param tG is a vertex of the original graph. - * \return the path from bcproper(\a sG) to bcproper(\a tG) in the BC-tree as a - * linear list of vertices. - * \post The SList instance is created by this function and has to be - * destructed by the caller! - */ - SList& findPath (node sG, node tG) const; - -/** - * \brief calculates a path in the BC-tree. - * \param sB is a vertex of the BC-tree. - * \param tB is a vertex of the BC-tree. - * \return the path from (\a sB) to bcproper(\a tB) in the BC-tree as a - * linear list of vertices. - * \post The SList instance is created by this function and has to be - * destructed by the caller! - */ - SList* findPathBCTree (node sB, node tB) const; - -/** - * \brief returns a vertex of the biconnected components graph corresponding to - * a given vertex of the original graph and belonging to the representation of - * a certain biconnected component given by a vertex of the BC-tree. - * \param uG is a vertex of the original graph. - * \param vB is a vertex of the BC-tree. - * \return a vertex of the biconnected components graph: - * - If \a uG is belonging to the biconnected component represented by \a vB, - * then repVertex(\a uG,\a vB) returns the very vertex of the biconnected - * components graph corresponding to \a uG within the representation of - * \a vB. - * - Otherwise, repVertex(\a uG,\a vB) returns \e NULL. - */ - virtual node repVertex (node uG, node vB) const; -/** - * \brief returns the copy of a cut-vertex in the biconnected components graph - * which belongs to a certain B-component and leads to another B-component. - * - * If two BC-tree-vertices are neighbours, then the biconnected components - * represented by them have exactly one cut-vertex in common. But there are - * several copies of this cut-vertex in the biconnected components graph, - * namely one copy for each biconnected component which the cut-vertex is - * belonging to. The member function rep() had been designed for returning the - * very copy of the cut-vertex belonging to the copy of the unambiguous - * C-component which it is belonging to, whereas this member function is - * designed to return the very copy of the cut-vertex connecting two - * biconnected components which belongs to the copy of the second one. - * \param uB is a vertex of the BC-tree. - * \param vB is a vertex of the BC-tree. - * \return a vertex of the biconnected components graph: - * - If \a uB == \a vB and they are representing a B-component, then - * cutVertex(\a uB,\a vB) returns \e NULL. - * - If \a uB == \a vB and they are representing a C-component, then - * cutVertex(\a uB,\a vB) returns the single isolated vertex of the - * biconnected components graph which is the copy of the C-component. - * - If \a uB and \a vB are \e neighbours in the BC-tree, then there exists - * a cut-vertex leading from the biconnected component represented by \a vB - * to the biconnected component represented by \a uB. cutVertex(\a uB,\a vB) - * returns the very copy of this vertex within the biconnected components - * graph which belongs to the copy of the biconnected component represented - * by \a vB. - * - Otherwise, cutVertex(\a uB,\a vB) returns \e NULL. - */ - virtual node cutVertex (node uB, node vB) const; - -/** @} - */ -private: - // avoid automatic creation of assignment operator - - //! Copy constructor is undefined! - BCTree(const BCTree &); - - //! Assignment operator is undefined! - BCTree &operator=(const BCTree &); -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/decomposition/DynamicBCTree.h b/ext/OGDF/ogdf/decomposition/DynamicBCTree.h deleted file mode 100644 index a1f045d0d..000000000 --- a/ext/OGDF/ogdf/decomposition/DynamicBCTree.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class DynamicBCTree - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DYNAMIC_BC_TREE_H -#define OGDF_DYNAMIC_BC_TREE_H - -#include - -namespace ogdf { - -/** - * \brief Dynamic BC-trees. - * - * This class provides dynamic BC-trees.\n - * The main difference of the dynamic BC-tree structure compared to the static - * one implemented by the class BCTree is, that B- and C-components are not any - * longer represented by single vertices of a BC-tree graph structure but by - * root vertices of UNION/FIND-trees. This allows path condensation within the - * BC-tree, when edges are inserted into the original graph. Path condensation - * is done by gathering BC-tree-vertices into a UNION/FIND-tree. However, the - * original vertices of the BC-tree remain in the \e m_B graph, but only those - * being the roots of their respective UNION/FIND-tree are proper representants - * of the biconnected components of the original graph. - */ -class OGDF_EXPORT DynamicBCTree : public BCTree { - -friend class PlanarAugmentation; -friend class PlanarAugmentationFix; - -protected: - -/** - * \brief Array that contains for each BC-tree-vertex its parent in its - * UNION/FIND-tree structure. - * - * For each vertex \e vB of the BC-tree structure: - * - If \e vB is representing a biconnected component, then - * m_bNode_owner[\e vB] points to the vertex \e vB itself. - * - If \e vB is not any longer representing a biconnected component due to - * path condensation, then m_bNode_owner[\e vB] points to the parent of \e vB - * in its UNION/FIND-tree. - */ - mutable NodeArray m_bNode_owner; -/** - * \brief Array that contains for each proper BC-tree-vertex its degree. - * - * For each vertex \e vB of the BC-tree structure: - * - If \e vB is representing a biconnected component, then - * m_bNode_degree[\e vB] is the degree of the vertex of the BC-tree. - * - If \e vB is not any longer representing a biconnected component due to - * path condensation, then m_bNode_degree[\e vB] is undefined. - * This array is necessary, because the edges of the BC-tree are not updated - * during path condensation for efficiency reasons. Thus, vB->degree() - * != m_bNode_degree[\e vB] - */ - NodeArray m_bNode_degree; - -/** @{ - * \brief Initialization of \e m_bNode_owner and \e m_bNode_degree. - */ - void init (); - -/** @} @{ - * \brief The UNION function of the UNION/FIND structure. - * \param uB is a vertex of the BC-tree representing a B-component. - * \param vB is a vertex of the BC-tree representing a C-component. - * \param wB is a vertex of the BC-tree representing a B-component. - * \pre \a uB and \a vB and \a wB have to be proper representants of their - * B-components, i.e. they have to be the root vertices of their respective - * UNION/FIND-trees. - * \pre \a uB and \a wB have to be adjacent to \a vB. - * \return the vertex properly representing the condensed B-component. - */ - node unite (node uB, node vB, node wB); -/** - * \brief The FIND function of the UNION/FIND structure. - * \param vB is any vertex of \e m_B. - * \return the owner of \a vB properly representing a biconnected component, - * i.e. the root of the UNION/FIND-tree of \a vB. - */ - node find (node vB) const; - -/** @} @{ - * \brief returns the parent of a given BC-tree-vertex. - * \param vB is any vertex of \e m_B or \e NULL. - * \return the parent of \a vB in the BC-tree structure, if \a vB is not the - * root of the BC-tree, and \e NULL, if \a vB is \e NULL or the root of the - * BC-tree. The UNION/FIND-tree structures are considered. - */ - node parent (node vB) const; -/** - * \brief performs path condensation. - * - * This member function condenses the path from bcproper(\a sG) to - * bcproper(\a tG) in the BC-tree into one single B-component by calling - * findPath() and subsequently unite(). - * \param sG is a vertex of the original graph. - * \param tG is a vertex of the original graph. - * \return the proper representant of the resulting B-component. - */ - node condensePath (node sG, node tG); - -public: - -/** @} @{ - * \brief A constructor. - * - * This constructor does only call BCTree::BCTree() and DynamicBCTree::init(). - * DynamicBCTree(\a G) is equivalent to DynamicBCTree(G, - * G.firstNode()). - * \param G is the original graph. - * \param callInitConnected decides which init is called, default call is init(). - */ - DynamicBCTree (Graph& G, bool callInitConnected = false) : BCTree(G, callInitConnected) { init(); } -/** - * \brief A constructor. - * - * This constructor does only call BCTree::BCTree() and DynamicBCTree::init(). - * \param G is the original graph. - * \param vG is the vertex of the original graph which the DFS algorithm starts with. - * \param callInitConnected decides which init is called, default call is init(). - */ - DynamicBCTree (Graph& G, node vG, bool callInitConnected = false) : BCTree(G,vG, callInitConnected) { init(); } - -/** @} @{ - * \brief returns a BC-tree-vertex representing a biconnected component which a - * given vertex of the original graph is belonging to. - * \param vG is a vertex of the original graph. - * \return a vertex of the BC-tree: - * - If \a vG is not a cut-vertex, then typeOfGNode(\a vG) returns the very - * vertex of the BC-tree representing the unambiguous B-component which \a vG - * is belonging to. - * - If \a vG is a cut-vertex, then typeOfGNode(\a vG) returns the very vertex - * of the BC-tree representing the unambiguous C-component which \a vG is - * belonging to. - * - * The difference between BCTree::bcproper() and DynamicBCTree::bcproper() is, - * that the latter one considers the UNION/FIND-tree structures. - */ - node bcproper (node vG) const; -/** - * \brief returns the BC-tree-vertex representing the biconnected component - * which a given edge of the original graph is belonging to. - * \param eG is an edge of the original graph. - * \return the vertex of the BC-tree representing the B-component which \a eG - * is belonging to. - * - * The difference between BCTree::bcproper() and DynamicBCTree::bcproper() is, - * that the latter one considers the UNION/FIND-tree structures. - */ - node bcproper (edge eG) const; - -/** @} @{ - * \brief returns a vertex of the biconnected components graph corresponding to - * a given vertex of the original graph and belonging to the representation of - * a certain biconnected component given by a vertex of the BC-tree. - * \param uG is a vertex of the original graph. - * \param vB is any vertex of \e m_B. - * \return a vertex of the biconnected components graph: - * - If \a uG is belonging to the biconnected component represented by \a vB, - * then rep(\a uG,\a vB) returns the very vertex of the biconnected - * components graph corresponding to \a uG within the representation of - * \a vB. - * - Otherwise, \e NULL is returned. - * - * The difference between BCTree::repVertex() and DynamicBCTree::repVertex() - * is, that the latter one considers the UNION/FIND-tree structures. - */ - node repVertex (node uG, node vB) const { return BCTree::repVertex(uG,find(vB)); } -/** - * \brief returns the copy of a cut-vertex in the biconnected components graph - * which belongs to a certain B-component and leads to another B-component. - * - * If two BC-tree-vertices are neighbours, then the biconnected components - * represented by them have exactly one cut-vertex in common. But there are - * several copies of this cut-vertex in the biconnected components graph, - * namely one copy for each biconnected component which the cut-vertex is - * belonging to. The member function rep() had been designed for returning the - * very copy of the cut-vertex belonging to the copy of the unambiguous - * C-component which it is belonging to, whereas this member function is - * designed to return the very copy of the cut-vertex connecting two - * biconnected components which belongs to the copy of the second one. - * \param uB is any vertex of \e m_B. - * \param vB is any vertex of \e m_B. - * \return a vertex of the biconnected components graph: - * - If \a uB == \a vB and they are representing a B-component, then - * cutVertex(\a uB,\a vB) returns \e NULL. - * - If \a uB == \a vB and they are representing a C-component, then - * cutVertex(\a uB,\a vB) returns the single isolated vertex in the - * biconnected components graph which is the copy of the C-component. - * - If \a uB and \a vB are \e neighbours in the BC-tree, then there exists - * a cut-vertex leading from the biconnected component represented by \a vB - * to the biconnected component represented by \a uB. cutVertex(\a uB,\a vB) - * returns the very copy of this vertex within the biconnected components - * graph which belongs to the copy of the biconnected component represented - * by \a vB. - * - Otherwise, cutVertex(\a uB,\a vB) returns \e NULL. - * - * The difference between BCTree::cutVertex() and DynamicBCTree::cutVertex() - * is, that the latter one considers the UNION/FIND-tree structures. - */ - node cutVertex (node uB, node vB) const { return BCTree::cutVertex(find(uB),find(vB)); } - -/** @} @{ - * \brief Update of the dynamic BC-tree after edge insertion into the original - * graph. - * - * This member function performs on-line maintenance of the dynamic BC-tree - * according to J. Westbrook and R. E. Tarjan, Maintaining Bridge-Connected and - * Biconnected Components On-Line, Algorithmica (1992) 7:433-464. - * \param eG is a newly inserted edge of the original graph. - * - * After a new edge has been inserted into the original graph by calling - * Graph::newEdge(), this member function updates the corresponding BC-tree in - * \f$O(\alpha(k,n))\f$ amortized time and the coponents graph in - * \f$O(1 + n/k)\f$ amortized time per insertEdge() operation, where k is the - * number of such operations. - * \return the new edge of the original graph. - */ - virtual edge updateInsertedEdge (edge eG); -/** - * \brief Update of the dynamic BC-tree after vertex insertion into the - * original graph. - * - * This member function performs on-line maintenance of the dynamic BC-tree - * according to J. Westbrook and R. E. Tarjan, Maintaining Bridge-Connected and - * Biconnected Components On-Line, Algorithmica (1992) 7:433-464. - * \param eG is the incoming edge of the newly inserted vertex which has been - * generated by a Graph::split() operation. - * \param fG is the outgoing edge of the newly inserted vertex which has been - * generated by a Graph::split() operation. - * - * After a new vertex has been inserted into an edge of the original graph by - * splitting the edge, all data structures of the DynamicBCTree class are - * updated by this member funtion. It takes \f$O(1)\f$ time. - * \return the new vertex of the original graph. - */ - virtual node updateInsertedNode (edge eG, edge fG); - -/** - * \brief inserts a new edge into the original graph and updates the BC-tree. - * - * This member function inserts a new edge between \a sG and \a tG into the - * original graph and then calls updateInsertedEdge(). - * \param sG is a vertex of the original graph. - * \param tG is a vertex of the original graph. - * \return the new edge of the original graph. - */ - edge insertEdge (node sG, node tG) { return updateInsertedEdge(m_G.newEdge(sG,tG)); } -/** - * \brief inserts a new vertex into the original graph and updates the BC-tree. - * - * This member function inserts a new vertex into the original graph by - * splitting the edge \a eG and then calls updateInsertedNode(). - * \param eG is an edge of the original graph. - * \return the new vertex of the original graph. - */ - node insertNode (edge eG) { return updateInsertedNode(eG,m_G.split(eG)); } - -/** @} @{ - * \brief returns the BC-tree-vertex representing the B-component which two - * given vertices of the original graph are belonging to. - * \param uG is a vertex of the original graph. - * \param vG is a vertex of the original graph. - * \return If \a uG and \a vG are belonging to the same B-component, the very - * vertex of the BC-tree representing this B-component is returned. Otherwise, - * \e NULL is returned. This member function returns the representant of the - * correct B-component even if \a uG or \a vG or either are cut-vertices and - * are therefore belonging to C-components, too. - * - * The difference between BCTree::bComponent() and DynamicBCTree::bComponent() - * is, that the latter one considers the UNION/FIND-tree structures. - */ -node bComponent (node uG, node vG) const; - -/** @} - */ -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/decomposition/DynamicPlanarSPQRTree.h b/ext/OGDF/ogdf/decomposition/DynamicPlanarSPQRTree.h deleted file mode 100644 index 6600ee1be..000000000 --- a/ext/OGDF/ogdf/decomposition/DynamicPlanarSPQRTree.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class DynamicPlanarSPQRTree. - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_DYNAMIC_PLANAR_SPQR_TREE_H -#define OGDF_DYNAMIC_PLANAR_SPQR_TREE_H - - -#include -#include - - -namespace ogdf { - - -template class Array; -template class Tuple2; - - -//--------------------------------------------------------- -// DynamicPlanarSPQRTree -// extension of class DynamicSPQRTree for support of embedded graphs -//--------------------------------------------------------- - -//! SPQR-trees of planar graphs. -/** - * The class DynamicPlanarSPQRTree maintains the triconnected components of a - * planar biconnected graph G and represents all possible embeddings - * of G. Each skeleton graph is embedded. - * - * The current embeddings of the skeletons define an embedding of G. - * There are two basic operations for obtaining another embedding - * of G: reverse(v), which flips the skeleton of an R-node v - * around its poles, and swap(v,e_1,e_2), which exchanges the - * positions of the edges e_1 and e_2 in the skeleton of a P-node v. - */ - -class OGDF_EXPORT DynamicPlanarSPQRTree : public DynamicSPQRTree, public PlanarSPQRTree -{ -public: - - // constructors - - //! Creates an SPQR tree \a T for planar graph \a G rooted at the first edge of \a G. - /** - * If \a isEmbedded is set to true, \a G must represent a combinatorial - * embedding, i.e., the counter-clockwise order of the adjacency entries - * around each vertex defines an embedding. - * \pre \a G is planar and biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - DynamicPlanarSPQRTree(Graph &G, bool isEmbedded = false) : - DynamicSPQRTree(G) - { - PlanarSPQRTree::init(isEmbedded); - } - - //! Creates an SPQR tree \a T for planar graph \a G rooted at edge \a e. - /** - * If \a isEmbedded is set to true, \a G must represent a combinatorial - * embedding, i.e., the counter-clockwise order of the adjacency entries - * around each vertex defines an embedding. - * \pre \a e is an edge in \a G, and \a G is planar and biconnected and - * contains at least 3 nodes, or \a G has exactly 2 nodes and at least 3 - * edges. - */ - DynamicPlanarSPQRTree(Graph &G, edge e, bool isEmbedded = false) : - DynamicSPQRTree(G,e) - { - PlanarSPQRTree::init(isEmbedded); - } -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/DynamicSPQRForest.h b/ext/OGDF/ogdf/decomposition/DynamicSPQRForest.h deleted file mode 100644 index a47f6766b..000000000 --- a/ext/OGDF/ogdf/decomposition/DynamicSPQRForest.h +++ /dev/null @@ -1,400 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class DynamicSPQRForest - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DYNAMIC_SPQR_FOREST_H -#define OGDF_DYNAMIC_SPQR_FOREST_H - -#include -#include - -namespace ogdf { - -/** - * \brief Dynamic SPQR-forest. - * - * This class is an extension of DynamicBCTree.\n - * It provides a set of SPQR-trees for each B-component of a BC-tree. - * These SPQR-trees are dynamic, i.e. there are member functions for - * dynamic updates (edge insertion and node insertion). - */ -class OGDF_EXPORT DynamicSPQRForest : public DynamicBCTree { - -public: - -/** \enum TNodeType - * \brief Enumeration type for characterizing the SPQR-tree-vertices. - */ -/** \var TNodeType ogdf::DynamicSPQRForest::SComp - * denotes a vertex representing an S-component. - */ -/** \var TNodeType ogdf::DynamicSPQRForest::PComp - * denotes a vertex representing a P-component. - */ -/** \var TNodeType ogdf::DynamicSPQRForest::RComp - * denotes a vertex representing an R-component. - */ - enum TNodeType { - SComp = SPQRTree::SNode, - PComp = SPQRTree::PNode, - RComp = SPQRTree::RNode - }; - -protected: - -/** - * \brief A \e Graph structure containing all SPQR-trees. - */ - mutable Graph m_T; - -/** @{ - * \brief The root vertices of the SPQR-trees. - * - * For each vertex of the BC-tree representing a B-component, this - * array contains the root vertex of the respective SPQR-tree, or - * \e NULL, if the SPQR-tree does not exist. - */ - mutable NodeArray m_bNode_SPQR; -/** - * \brief The numbers of S-components. - * - * For each vertex of the BC-tree representing a B-component, - * this array contains the number of S-components of the respective - * SPQR-tree. If the SPQR-tree does not exist, then the array member - * is undefined. - */ - mutable NodeArray m_bNode_numS; -/** - * \brief The numbers of P-components. - * - * For each vertex of the BC-tree representing a B-component, - * this array contains the number of P-components of the respective - * SPQR-tree. If the SPQR-tree does not exist, then the array member - * is undefined. - */ - mutable NodeArray m_bNode_numP; -/** - * \brief The numbers of R-components. - * - * For each vertex of the BC-tree representing a B-component, - * this array contains the number of R-components of the respective - * SPQR-tree. If the SPQR-tree does not exist, then the array member - * is undefined. - */ - mutable NodeArray m_bNode_numR; - -/** @} @{ - * \brief The types of the SPQR-tree-vertices. - */ - mutable NodeArray m_tNode_type; -/** - * \brief The owners of the SPQR-tree-vertices in the UNION/FIND - * structure. - */ - mutable NodeArray m_tNode_owner; -/** - * \brief The virtual edges leading to the parents of the - * SPQR-tree-vertices. - */ - mutable NodeArray m_tNode_hRefEdge; -/** - * \brief Lists of real and virtual edges belonging to - * SPQR-tree-vertices. - */ - mutable NodeArray > m_tNode_hEdges; - -/** @} @{ - * \brief The positions of real and virtual edges in their - * \e m_tNode_hEdges lists. - */ - mutable EdgeArray > m_hEdge_position; -/** - * \brief The SPQR-tree-vertices which the real and virtual edges - * are belonging to. - */ - mutable EdgeArray m_hEdge_tNode; -/** - * \brief The partners of virtual edges (\e NULL if real). - */ - mutable EdgeArray m_hEdge_twinEdge; - -/** @} @{ - * \brief Auxiliary array used by \e createSPQR(). - */ - mutable NodeArray m_htogc; -/** - * \brief Auxiliary array used by \e findNCASPQR() - */ - mutable NodeArray m_tNode_isMarked; - -/** @} - * \brief Initialization. - */ - void init (); -/** - * \brief creates the SPQR-tree for a given B-component of the - * BC-tree. - * - * An SPQR-tree belonging to a B-component of the BC-tree is only - * created on demand, i.e. this member function is only called by - * findSPQRTree() and - under certain circumstances - by - * updateInsertedEdge(). - * \param vB is a vertex of the BC-tree representing a B-component. - * \pre \a vB has to be the proper representative of its B-component, - * i.e. it has to be the root vertex of its respective - * UNION/FIND-tree. - * \pre The B-component represented by \a vB must contain at least - * 3 edges. - */ - void createSPQR (node vB) const; - -/** @{ - * \brief unites two SPQR-tree-vertices (UNION part of UNION/FIND). - * \param vB is a vertex of the BC-tree representing a B-component. - * \param sT is a vertex of the SPQR-tree belonging to \a vB. - * \param tT is a vertex of the SPQR-tree belonging to \a vB. - * \pre \a vB has to be the proper representative of its B-component, - * i.e. it has to be the root vertex of its respective - * UNION/FIND-tree. - * \pre \a sT and \a tT have to be proper representatives of their - * triconnected components, i.e. they have to be the root vertices of - * their respective UNION/FIND-trees. - * \return the proper representative of the united SPQR-tree-vertex. - */ - node uniteSPQR (node vB, node sT, node tT); -/** - * \brief finds the proper representative of an SPQR-tree-vertex (FIND - * part of UNION/FIND). - * \param vT is any vertex of \e m_T. - * \return the owner of \a vT properly representing a triconnected - * component, i.e. the root of the UNION/FIND-tree of \a vT. - */ - node findSPQR (node vT) const; - -/** @} @{ - * \brief finds the nearest common ancestor of \a sT and \a tT. - * \param sT is a vertex of an SPQR-tree. - * \param tT is a vertex of an SPQR-tree. - * \pre \a sT and \a tT must belong to the same SPQR-tree. - * \pre \a sT and \a tT have to be proper representatives of their - * triconnected components, i.e. they have to be the root vertices of - * their respective UNION/FIND-trees. - * \return the proper representative of the nearest common ancestor of - * \a sT and \a tT. - */ - node findNCASPQR (node sT, node tT) const; -/** - * \brief finds the shortest path between the two sets of - * SPQR-tree-vertices which \a sH and \a tH are belonging to. - * \param sH is a vertex of \e m_H. - * \param tH is a vertex of \e m_H. - * \param rT is a reference! It is set to the very vertex of - * the found path which is nearest to the root vertex of the SPQR-tree. - * \pre \a sH and \a tH must belong to the same B-component, i.e. to - * the same SPQR-tree. This SPQR-tree must exist! - * \return the path in the SPQR-tree as a linear list of vertices. - * \post The SList instance is created by this function and - * has to be destructed by the caller! - */ - SList& findPathSPQR (node sH, node tH, node& rT) const; - -/** @} @{ - * \brief updates an SPQR-tree after a new edge has been inserted into - * the original graph. - * \param vB is a BC-tree-vertex representing a B-component. The - * SPQR-tree, which is to be updated is identified by it. - * \param eG is a new edge in the original graph. - * \pre \a vB has to be the proper representative of its B-component, - * i.e. it has to be the root vertex of its respective - * UNION/FIND-tree. - * \pre Both the source and the target vertices of \a eG must belong - * to the same B-component represented by \a vB. - * \return the new edge of the original graph. - */ - edge updateInsertedEdgeSPQR (node vB, edge eG); -/** - * \brief updates an SPQR-tree after a new vertex has been inserted - * into the original graph by splitting an edge into \a eG and \a fG. - * \param vB is a BC-tree-vertex representing a B-component. The - * SPQR-tree, which is to be updated is identified by it. - * \param eG is the incoming edge of the newly inserted vertex which - * has been generated by a Graph::split() operation. - * \param fG is the outgoing edge of the newly inserted vertex which - * has been generated by a Graph::split() operation. - * \pre The split edge must belong to the B-component which is - * represented by \a vB. - * \return the new vertex of the original graph. - */ - node updateInsertedNodeSPQR (node vB, edge eG, edge fG); - -public: - -/** @} @{ - * \brief A constructor. - * - * This constructor does only create the dynamic BC-tree rooted at the first - * edge of \a G. The data structure is prepared for dealing with SPQR-trees, - * but they will only be created on demand. Cf. member functions findPathSPQR() - * and updateInsertedEdge(). - * \param G is the original graph. - */ - DynamicSPQRForest (Graph& G) : DynamicBCTree(G) { init(); } - -/** @} @{ - * \brief finds the proper representative of the SPQR-tree-vertex which - * a given real or virtual edge is belonging to. - * - * This member function has to be used carefully (see Precondition)! - * \param eH is an edge of \e m_H. - * \pre The respective SPQR-tree belonging to the B-component represented by - * the BC-tree-vertex bcproper(\a eH) must exist! Notice, that this condition - * is fulfilled, if \a eH is a member of a list gained by the hEdgesSPQR() - * member function, because that member function needs an SPQR-tree-vertex as - * parameter, which might have been found (and eventually created) by the - * findPathSPQR() member function. - * \return the proper representative of the SPQR-tree-vertex which \a eH - * is belonging to. - */ - node spqrproper (edge eH) const { return m_hEdge_tNode[eH] = findSPQR(m_hEdge_tNode[eH]); } -/** - * \brief returns the twin edge of a given edge of \e m_H, if it is - * virtual, or \e NULL, if it is real. - * \param eH is an edge of \e m_H. - * \return the twin edge of \a eH, if it is virtual, or \e NULL, if it - * is real. - */ - edge twinEdge (edge eH) const { return m_hEdge_twinEdge[eH]; } - -/** @} @{ - * \brief returns the type of the triconnected component represented by - * a given SPQR-tree-vertex. - * \param vT is a vertex of an SPQR-tree. - * \pre \a vT has to be the proper representative of its triconnected - * component, i.e. it has to be the root vertex of its respective - * UNION/FIND-tree. This condition is particularly fulfilled if \a vT - * is a member of a list gained by the findPathSPQR() member function. - * \return the type of the triconnected component represented by \a vT. - */ - TNodeType typeOfTNode (node vT) const { return m_tNode_type[vT]; } -/** - * \brief returns a linear list of the edges in \e m_H belonging to - * the triconnected component represented by a given SPQR-tree-vertex. - * \param vT is a vertex of an SPQR-tree. - * \pre \a vT has to be the proper representative of its triconnected - * component, i.e. it has to be the root vertex of its respective - * UNION/FIND-tree. This condition is particularly fulfilled if \a vT - * is a member of a list gained by the findPathSPQR() member function. - * \return a linear list of the edges in \e m_H belonging to the - * triconnected component represented by \a vT. - */ - const List& hEdgesSPQR (node vT) const { return m_tNode_hEdges[vT]; } -/** - * \brief finds the shortest path between the two sets of - * SPQR-tree-vertices which \a sH and \a tH are belonging to. - * \param sH is a vertex of \e m_H. - * \param tH is a vertex of \e m_H. - * \pre \a sH and \a tH must belong to the same B-component, i.e. to - * the same SPQR-tree. This SPQR-tree does not need to exist. If it - * it does not exist, it will be created. - * \return the path in the SPQR-tree as a linear list of vertices. - * \post The SList instance is created by this function and - * has to be destructed by the caller! - */ - SList& findPathSPQR (node sH, node tH) const; -/** - * \brief returns the virtual edge which leads from one vertex of an - * SPQR-tree to another one. - * \param vT is a vertex of an SPQR-tree. - * \param wT is a vertex of an SPQR-tree. - * \pre \a vT and \a wT must belong to the same SPQR-tree and must be - * adjacent. - * \pre \a vT and \a wT have to be proper representatives of their - * triconnected components, i.e. they have to be the root vertices of - * their respective UNION/FIND-trees. This condition is particularly - * fulfilled if \a vT and \a wT are members of a list gained by the - * findPathSPQR() member function. - * \return the virtual edge in \e m_H which belongs to \a wT and - * leads to \a vT. - */ - edge virtualEdge (node vT, node wT) const; - -/** @} @{ - * \brief updates the whole data structure after a new edge has been - * inserted into the original graph. - * - * This member function generally updates both BC- and SPQR-trees. If - * any SPQR-tree of the B-components of the insertion path through - * the BC-tree exists, the SPQR-tree data structure of the resulting - * B-component will be valid afterwards. If none of the SPQR-trees - * does exist in advance, then only the BC-tree is updated and no - * SPQR-tree is created. - * \param eG is a new edge in the original graph. - * \return the new edge of the original graph. - */ - edge updateInsertedEdge (edge eG); -/** - * \brief updates the whole data structure after a new vertex has been - * inserted into the original graph by splitting an edge into \a eG - * and \a fG. - * - * This member function updates the BC-tree at first. If the SPQR-tree - * of the B-component which the split edge is belonging to does exist, - * then it is updated, too. If it does not exist, it is not created. - * \param eG is the incoming edge of the newly inserted vertex which - * has been generated by a Graph::split() operation. - * \param fG is the outgoing edge of the newly inserted vertex which - * has been generated by a Graph::split() operation. - * \return the new vertex of the original graph. - */ - node updateInsertedNode (edge eG, edge fG); - -/** @} - */ -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/decomposition/DynamicSPQRTree.h b/ext/OGDF/ogdf/decomposition/DynamicSPQRTree.h deleted file mode 100644 index fae31838d..000000000 --- a/ext/OGDF/ogdf/decomposition/DynamicSPQRTree.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class DynamicSPQRTree - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_DYNAMIC_SPQR_TREE_H -#define OGDF_DYNAMIC_SPQR_TREE_H - - -#include -#include -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// DynamicSPQRTree -// SPQR-tree data structure (dynamic environment) -//--------------------------------------------------------- - -/** - * \brief Linear-time implementation of dynamic SPQR-trees. - * - * The class DynamicSPQRTree maintains the arrangement of the triconnected - * components of a biconnected multi-graph \e G [Hopcroft, Tarjan 1973] - * as a so-called SPQR tree \e T [Fi Battista, Tamassia, 1996]. We - * call \e G the original graph of \e T. - * The class DynamicSPQRTree supports the statical construction of - * an SPQR-tree for a given graph G, and supports dynamic updates, - * too. - * - * Each node of the tree has an associated type (represented by - * SPQRTree::NodeType), which is either SNode, PNode, or - * RNode, and a skeleton (represented by the class DynamicSkeleton). - * The skeletons of the nodes of \e T are in one-to-one - * correspondence to the triconnected components of \e G, i.e., - * S-nodes correspond to polygons, P-nodes to bonds, and - * R-nodes to triconnected graphs. - * - * In our representation of SPQR-trees, Q-nodes are omitted. Instead, - * the skeleton S of a node \e v in \e T contains two types of edges: - * real edges, which correspond to edges in \e G, and virtual edges, which - * correspond to edges in \e T having \e v as an endpoint. - * There is a special edge \e er in G at which \e T is rooted, i.e., the - * root node of \e T is the node whose skeleton contains the real edge - * corresponding to \e er. - * - * The reference edge of the skeleton of the root node is \e er, the - * reference edge of the skeleton \e S of a non-root node \e v is the virtual - * edge in \e S that corresponds to the tree edge (parent(\e v),\e v). - */ -class OGDF_EXPORT DynamicSPQRTree : public virtual SPQRTree, public DynamicSPQRForest -{ -public: - - friend class DynamicSkeleton; - - - // constructors - - /** - * \brief Creates an SPQR tree \e T for graph \a G rooted at the first edge of \a G. - * \pre \a G is biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - DynamicSPQRTree (Graph& G) : DynamicSPQRForest(G) { init(G.firstEdge()); } - - /** - * \brief Creates an SPQR tree \e T for graph \a G rooted at the edge \a e. - * \pre \a e is in \a G, \a G is biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - DynamicSPQRTree (Graph& G, edge e) : DynamicSPQRForest(G) { init(e); } - - - // destructor - - ~DynamicSPQRTree(); - - - // - // a) Access operations - // - - //! Returns a reference to the original graph \e G. - const Graph& originalGraph () const { return m_G; } - - //! Returns a reference to the tree \e T. - const Graph& tree () const { return m_T; } - - //! Returns the edge of \e G at which \e T is rooted. - edge rootEdge () const { return m_rootEdge; } - - //! Returns the root node of \e T. - node rootNode () const { return findSPQR(m_bNode_SPQR[m_B.firstNode()]); } - - //! Returns the number of S-nodes in \e T. - int numberOfSNodes () const { return m_bNode_numS[m_B.firstNode()]; } - - //! Returns the number of P-nodes in \e T. - int numberOfPNodes () const { return m_bNode_numP[m_B.firstNode()]; } - - //! Returns the number of R-nodes in \e T. - int numberOfRNodes () const { return m_bNode_numR[m_B.firstNode()]; } - - /** - * \brief Returns the type of node \a v. - * \pre \a v is a node in \e T - */ - NodeType typeOf (node v) const - { - return (NodeType)m_tNode_type[findSPQR(v)]; - } - - //! Returns the list of all nodes with type \a t. - List nodesOfType (NodeType t) const; - - //! Finds the shortest path between the two sets of vertices of \e T which \a s and \a t of \e G belong to. - SList& findPath (node s, node t) { return findPathSPQR(m_gNode_hNode[s],m_gNode_hNode[t]); } - - /** - * \brief Returns the skeleton of node \a v. - * \pre \a v is a node in \e T - */ - Skeleton& skeleton (node v) const - { - v = findSPQR(v); - if (!m_sk[v]) return createSkeleton(v); - return *m_sk[v]; - } - - /** - * \brief Returns the skeleton that contains the real edge \a e. - * \pre \a e is an edge in \e G - */ - const Skeleton& skeletonOfReal (edge e) const { return skeleton(spqrproper(m_gEdge_hEdge[e])); } - - /** - * \brief Returns the skeleton edge that corresponds to the real edge \a e. - * \pre \a e is an edge in \e G - */ - edge copyOfReal (edge e) const - { - e = m_gEdge_hEdge[e]; - skeleton(spqrproper(e)); - return m_skelEdge[e]; - } - - /** - * \brief Returns the virtual edge in the skeleton of \a w that - * corresponds to the tree edge between \a v and \a w. - * \pre \a v and \a w are adjacent nodes in \e T - */ - edge skeletonEdge (node v, node w) const - { - edge e = virtualEdge(v,w); - if (!e) return e; - skeleton(w); - return m_skelEdge[e]; - } - - - // - // b) Update operations - // - - /** - * \brief Roots \e T at edge \a e and returns the new root node of \e T. - * \pre \a e is an edge in \e G - */ - node rootTreeAt (edge e); - - /** - * \brief Roots \e T at node \a v and returns \a v. - * \pre \a v is a node in \e T - */ - node rootTreeAt (node v); - - /** - * \brief Updates the whole data structure after a new edge \a e has - * been inserted into \e G. - */ - edge updateInsertedEdge (edge e); - - /** - * \brief Updates the whole data structure after a new vertex has been - * inserted into \e G by splitting an edge into \a e and \a f. - */ - node updateInsertedNode (edge e, edge f); - - -protected: - - //! Initialization (called by constructors). - void init (edge e); - - //! Creates the skeleton graph belonging to a given vertex \a vT of \e T. - DynamicSkeleton& createSkeleton (node vT) const; - - /** - * \brief Recursively performs the task of adding edges (and nodes) - * to the pertinent graph \a Gp for each involved skeleton graph. - */ - void cpRec (node v, PertinentGraph& Gp) const - { - v = findSPQR(v); - for (ListConstIterator i=m_tNode_hEdges[v].begin(); i.valid(); ++i) { - edge e = m_hEdge_gEdge[*i]; - if (e) cpAddEdge(e,Gp); - else if (*i!=m_tNode_hRefEdge[v]) cpRec(spqrproper(*i),Gp); - } - } - - - edge m_rootEdge; //!< edge of \e G at which \e T is rooted - - mutable NodeArray m_sk; //!< pointer to skeleton of a node in \e T - mutable EdgeArray m_skelEdge; //!< copies of real and virtual edges in their skeleton graphs (invalid, if the skeleton does not actually exist) - mutable NodeArray m_mapV; //!< temporary array used by \e createSkeleton() - -}; // class DynamicSPQRTree - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/DynamicSkeleton.h b/ext/OGDF/ogdf/decomposition/DynamicSkeleton.h deleted file mode 100644 index 9bf786d6b..000000000 --- a/ext/OGDF/ogdf/decomposition/DynamicSkeleton.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class DynamicSkeleton. - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_DYNAMIC_SKELETON_H -#define OGDF_DYNAMIC_SKELETON_H - - -#include - - -namespace ogdf { - - class DynamicSPQRTree; - - -//! %Skeleton graphs of nodes in a dynamic SPQR-tree. -/** - * The class DynamicSkeleton maintains the skeleton \a S of a node \a vT in a dynamic SPQR-tree - * \a T. We call \a T the owner tree of \a S and \a vT the corresponding tree node. Let - * \a G be the original graph of \a T. - * - * \a S consists of an undirected multi-graph \a M. If the owner tree of \a S is - * a PlanarSPQRTree, then \a M represents a combinatorial embedding. - * The vertices in \a M correspond to vertices in \a G. The edges in \a M are of - * two types: Real edges correspond to edges in \a G and virtual edges correspond - * to tree-edges in \a T having \a vT as an endpoint. - * - * Let \a e in \a M be a virtual edge and \a eT be the corresponding tree-edge. - * Then there exists exactly one edge \a e' in another skeleton \a S' of \a T that - * corresponds to \a eT as well. We call \a e' the twin edge of \a e. - */ -class OGDF_EXPORT DynamicSkeleton : public Skeleton -{ - friend class DynamicSPQRTree; - -public: - - // constructor - - //! Creates a skeleton \a S with owner tree \a T and corresponding node \a vT. - /** - * \pre \a vT is a node in \a T - * - * \remarks Skeletons are created by the constructor of DynamicSPQRTree - * and can be accessed with the skeleton() function of DynamicSPQRTree. - */ - DynamicSkeleton(const DynamicSPQRTree *T, node vT); - - - // destructor - ~DynamicSkeleton() { } - - - //! Returns the owner tree \a T. - const SPQRTree &owner() const; - - //! Returns the vertex in the original graph \a G that corresponds to \a v. - /** - * \pre \a v is a node in \a M. - */ - node original (node v) const; - - //! Returns the real edge that corresponds to skeleton edge \a e - /** - * If \a e is virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - edge realEdge (edge e) const; - - //! Returns true iff \a e is a virtual edge. - /** - * \pre \a e is an edge in \a M - */ - bool isVirtual (edge e) const { - return !realEdge(e); - } - - //! Returns the twin edge of skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - edge twinEdge (edge e) const; - - //! Returns the tree node in T containing the twin edge of skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - node twinTreeNode (edge e) const; - - OGDF_NEW_DELETE - -protected: - const DynamicSPQRTree *m_owner; //!< owner tree - NodeArray m_origNode; //!< corresp. original node - EdgeArray m_origEdge; //!< corresp. original edge -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/PertinentGraph.h b/ext/OGDF/ogdf/decomposition/PertinentGraph.h deleted file mode 100644 index 2b6a01728..000000000 --- a/ext/OGDF/ogdf/decomposition/PertinentGraph.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PertinentGraph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PERTINENT_GRAPH_H -#define OGDF_PERTINENT_GRAPH_H - - -namespace ogdf { - - class OGDF_EXPORT SPQRTree; - - -//--------------------------------------------------------- -// PertinentGraph -// pertinent graph of a node in an SPQR-tree -//--------------------------------------------------------- -//! Pertinent graphs of nodes in an SPQR-tree. -/** - * The class PertinentGraph represents the pertinent graph \a G(\a vT) - * of a node \a vT in an SPQR-tree \a T with original graph \a G. - * - * The expansion graph E(\a e) of a virtual skeleton edge \a e is the skeleton graph - * of the twin \a e' of \a e without \a e', where each virtual edge \a eV again is - * replaced by its expansion graph E(\a eV). The pertinent graph \a G(\a vT) of a tree - * node \a vT is obtained from the skeleton \a S of \a vT, where each edge except for - * the reference edge of \a S is replaced by its expansion graph. Hence, if \a vT - * is not the root node of \a T, all but one edge in \a G(\a vT) correspond to real - * edges, otherwise all edges correspond to real edges. - * - * If \a P is the pertinent graph of a PlanarSPQRTree, the underlying graph - * represents the combinatorial embedding which is implied by the embeddings - * of the skeletons of \a T. - */ - -class OGDF_EXPORT PertinentGraph -{ - friend class OGDF_EXPORT SPQRTree; - -public: - - // constructor - // Remark: Pertinent graphs are created by the pertinentGraph() - // function of SPQRTree. - - //! Creates an empty instance of type PertinentGraph. - /** - * \remarks Pertinent graphs are created by the pertinentGraph() - * function of SPQRTree. - */ - PertinentGraph() : m_vT(0) { } - - //! Initialization of a pertinent graph of tree node \a vT. - void init(node vT) { - m_P = Graph(); - m_vT = vT; - m_vEdge = m_skRefEdge = 0; - m_origV.init(m_P,0); - m_origE.init(m_P,0); - } - - - //! Returns the tree node \a vT in \a T whose pertinent graph is this one. - node treeNode() const { - return m_vT; - } - - //! Returns a reference to \a G(\a vT). - const Graph &getGraph() const { - return m_P; - } - - //! Returns a reference to \a G(\a vT). - Graph &getGraph() { - return m_P; - } - - //! Returns the edge in \a G(\a vT) corresponding to the reference edge in skeleton of \a vT. - /** - * If \a vT is the root of \a T, then 0 is returned. - */ - edge referenceEdge() const { - return m_vEdge; - } - - //! Returns the reference edge in skeleton of \a vT. - /** - * Notice that this edge may differ from the current reference edge in skeleton - * of \a vT if \a T has been rerooted after the construction of \a P. - */ - edge skeletonReferenceEdge() const { - return m_skRefEdge; - } - - //! Returns the vertex in \a G that corresponds to \a v. - /** - * \pre \a v is a node in \a G(\a vT) - */ - node original(node v) const { - return m_origV[v]; - } - - //! Returns the edge in \a G that corresponds to \a e. - /** - * If \a e is the reference edge, then 0 is returned. - * \pre \a e is an edge in \a G(\a vT) - */ - edge original(edge e) const { - return m_origE[e]; - } - -protected: - node m_vT; //!< corresponding tree node - Graph m_P; //!< actual graph - edge m_vEdge; //!< reference edge (in \a m_P) - edge m_skRefEdge; //!< reference edge (in skeleton(\a m_vT)) - - NodeArray m_origV; //!< corresp. original node - EdgeArray m_origE; //!< corresp. original edge -}; - - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/PlanarSPQRTree.h b/ext/OGDF/ogdf/decomposition/PlanarSPQRTree.h deleted file mode 100644 index 25473bc9e..000000000 --- a/ext/OGDF/ogdf/decomposition/PlanarSPQRTree.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarSPQRTree - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLANAR_SPQR_TREE_H -#define OGDF_PLANAR_SPQR_TREE_H - - -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// PlanarSPQRTree -// extension of class SPQRTree for support of embedded graphs -//--------------------------------------------------------- - -//! SPQR-trees of planar graphs. -/** - * The class PlanarSPQRTree maintains the triconnected components of a - * planar biconnected graph G and represents all possible embeddings - * of G. Each skeleton graph is embedded. - * - * The current embeddings of the skeletons define an embedding of G. - * There are two basic operations for obtaining another embedding - * of G: reverse(v), which flips the skeleton of an R-node v - * around its poles, and swap(v,e_1,e_2), which exchanges the - * positions of the edges e_1 and e_2 in the skeleton of a P-node v. - */ - -class OGDF_EXPORT PlanarSPQRTree : public virtual SPQRTree -{ -public: - - // - // a) Access operations - // - - //! Returns the number of possible embeddings of G. - double numberOfEmbeddings() const { - return numberOfEmbeddings(rootNode()); - } - - //! Returns the number of possible embeddings of the pertinent graph of node \a v. - /** - * \pre \a v is a node in \a T - */ - double numberOfEmbeddings(node v) const; - - - // - // b) Update operations - // - - //! Flips the skeleton \a S of \a vT around its poles. - /** - * Reverses the order of adjacency entries of each vertex in \a S. - * \pre \a vT is an R- or P-node in \a T - */ - void reverse(node vT); - - //! Exchanges the positions of edges \a e1 and \a e2 in skeleton of \a vT. - /** - * \pre \a vT is a P-node in \a T and \a e1 and \a e2 are in edges in - * skeleton(\a vT) - */ - void swap(node vT, edge e1, edge e2); - - //! Exchanges the positions of the two edges corresponding to \a adj1 and \a adj2 in skeleton of \a vT. - /** - * \pre \a vT is a P-node in \a T and \a adj1 and \a adj2 are in adjacency entries - * in skeleton(\a vT) at the same owner node. - */ - void swap(node vT, adjEntry adj1, adjEntry adj2); - - //! Embeds \a G according to the current embeddings of the skeletons of \a T. - /** - * \pre \a G is the graph passed to the constructor of \a T - */ - void embed(Graph &G); - - //! Embeds all skeleton graphs randomly. - void randomEmbed(); - - //! Embeds all skeleton graphs randomly and embeds \a G according to the embeddings of the skeletons. - /** - * \pre \a G is the graph passed to the constructor of \a T - */ - void randomEmbed(Graph &G) { - randomEmbed(); - embed(G); - } - - -protected: - //! Initialization (adaption of embeding). - void init(bool isEmbedded); - void adoptEmbedding(); - void setPosInEmbedding( - NodeArray > &adjEdges, - NodeArray ¤tCopy, - NodeArray &lastAdj, - SListPure ¤t, - const Skeleton &S, - adjEntry adj); - - // Embeda original graph according to embeddings of skeletons. - void expandVirtualEmbed(node vT, - adjEntry adjVirt, - SListPure &adjEdges); - void createInnerVerticesEmbed(Graph &G, node vT); - -}; // class PlanarSPQRTree - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/SPQRTree.h b/ext/OGDF/ogdf/decomposition/SPQRTree.h deleted file mode 100644 index 20b80c202..000000000 --- a/ext/OGDF/ogdf/decomposition/SPQRTree.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class SPQRTree - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_SPQR_TREE_H -#define OGDF_SPQR_TREE_H - - -#include -#include -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// SPQRTree -// SPQR-tree data structure -//--------------------------------------------------------- - -/** - * \brief Linear-time implementation of static SPQR-trees. - * - * The class SPQRTree maintains the arrangement of the triconnected - * components of a biconnected multi-graph \a G [Hopcroft, Tarjan 1973] - * as a so-called SPQR tree \a T [Di Battista, Tamassia, 1996]. We - * call \a G the original graph of \a T. - * - * Each node of the tree has an associated type (represented by - * SPQRTree::NodeType), which is either SNode, PNode, or - * RNode, and a skeleton (represented by the class Skeleton). - * The skeletons of the nodes of \a T are in one-to-one - * correspondence to the triconnected components of \a G, i.e., - * S-nodes correspond to polygons, P-nodes to bonds, and - * R-nodes to triconnected graphs. - * - * In our representation of SPQR-trees, Q-nodes are omitted. Instead, - * the skeleton S of a node \a v in \a T contains two types of edges: - * real edges, which correspond to edges in \a G, and virtual edges, which - * correspond to edges in \a T having \a v as an endpoint. - * There is a special edge \a er in G at which \a T is rooted, i.e., the - * root node of \a T is the node whose skeleton contains the real edge - * corresponding to \a er. - * - * The reference edge of the skeleton of the root node is \a er, the - * reference edge of the skeleton \a S of a non-root node \a v is the virtual - * edge in \a S that corresponds to the tree edge (parent(\a v),\a v). - */ - -class OGDF_EXPORT SPQRTree -{ -public: - - //! The type of a tree node in T. - enum NodeType { SNode, PNode, RNode }; - - - // destructor - - virtual ~SPQRTree() { } - - - // - // a) Access operations - // - - //! Returns a reference to the original graph \a G. - virtual const Graph &originalGraph() const=0; - - //! Returns a reference to the tree \a T. - virtual const Graph &tree() const=0; - - //! Returns the edge of \a G at which \a T is rooted. - virtual edge rootEdge() const=0; - - //! Returns the root node of \a T. - virtual node rootNode() const=0; - - //! Returns the number of S-nodes in \a T. - virtual int numberOfSNodes() const=0; - - //! Returns the number of P-nodes in \a T. - virtual int numberOfPNodes() const=0; - - //! Returns the number of R-nodes in \a T. - virtual int numberOfRNodes() const=0; - - /** - * \brief Returns the type of node \a v. - * \pre \a v is a node in \a T - */ - virtual NodeType typeOf(node v) const=0; - - //! Returns the list of all nodes with type \a t. - virtual List nodesOfType(NodeType t) const=0; - - /** - * \brief Returns the skeleton of node \a v. - * \pre \a v is a node in \a T - */ - virtual Skeleton &skeleton(node v) const=0; - - /** - * \brief Returns the skeleton that contains the real edge \a e. - * \pre \a e is an edge in \a G - */ - virtual const Skeleton &skeletonOfReal(edge e) const=0; - - /** - * \brief Returns the skeleton edge that corresponds to the real edge \a e. - * \pre \a e is an edge in \a G - */ - virtual edge copyOfReal(edge e) const=0; - - /** - * \brief Returns the pertinent graph of tree node \a v in \a Gp. - * \pre \a v is a node in \a T - */ - void pertinentGraph(node v, PertinentGraph &Gp) const - { - if (m_cpV == 0) m_cpV = OGDF_NEW NodeArray(originalGraph(),0); - NodeArray &cpV = *m_cpV; - - Gp.init(v); - cpRec(v,Gp); - - const Skeleton &S = skeleton(v); - - edge e = Gp.m_skRefEdge = S.referenceEdge(); - if (e != 0) e = Gp.m_P.newEdge(cpV[S.original(e->source())],cpV[S.original(e->target())]); - Gp.m_vEdge = e; - - while (!m_cpVAdded.empty()) cpV[m_cpVAdded.popFrontRet()] = 0; - } - - - // - // b) Update operations - // - - /** - * \brief Roots \a T at edge \a e and returns the new root node of \a T. - * \pre \a e is an edge in \a G - */ - virtual node rootTreeAt(edge e) =0; - - /** - * \brief Roots \a T at node \a v and returns \a v. - * \pre \a v is a node in \a T - */ - virtual node rootTreeAt(node v) =0; - - - void directSkEdge(node vT, edge e, node src) - { - OGDF_ASSERT(e != 0 && (src == e->source() || src == e->target())) - - if(e->source() != src) skeleton(vT).getGraph().reverseEdge(e); - } - - void replaceSkEdgeByPeak(node vT, edge e) - { - Graph &M = skeleton(vT).getGraph(); - M.reverseEdge(M.split(e)); - } - - -protected: - - /** - * \brief Recursively performs the task of adding edges (and nodes) - * to the pertinent graph \a Gp for each involved skeleton graph. - */ - virtual void cpRec(node v, PertinentGraph &Gp) const=0; - - //! Add an edge to \a Gp corresponding to \a eOrig. - edge cpAddEdge(edge eOrig, PertinentGraph &Gp) const - { - edge eP = Gp.m_P.newEdge(cpAddNode(eOrig->source(),Gp),cpAddNode(eOrig->target(),Gp)); - Gp.m_origE[eP] = eOrig; - return eP; - } - - //! Add a node to \a Gp corresponding to \a vOrig if required. - node cpAddNode(node vOrig, PertinentGraph &Gp) const - { - node &vP = (*m_cpV)[vOrig]; - if (vP == 0) { - m_cpVAdded.pushBack(vOrig); - Gp.m_origV[vP = Gp.m_P.newNode()] = vOrig; - } - return vP; - } - - - // auxiliary members used for computing pertinent graphs - mutable NodeArray *m_cpV; //!< node in pertinent graph corresponding to an original node (auxiliary member) - mutable SList m_cpVAdded; //!< list of added nodes (auxiliary member) - -}; // class SPQRTree - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/Skeleton.h b/ext/OGDF/ogdf/decomposition/Skeleton.h deleted file mode 100644 index a8256b9ad..000000000 --- a/ext/OGDF/ogdf/decomposition/Skeleton.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Skeleton. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_SKELETON_H -#define OGDF_SKELETON_H - - -#include -#include - - -namespace ogdf { - - class OGDF_EXPORT SPQRTree; - - -//! %Skeleton graphs of nodes in an SPQR-tree. -/** - * The class Skeleton maintains the skeleton \a S of a node \a vT in an SPQR-tree - * \a T. We call \a T the owner tree of \a S and \a vT the corresponding tree node. Let - * \a G be the original graph of \a T. - * - * \a S consists of an undirected multi-graph \a M. If the owner tree of \a S is - * a PlanarSPQRTree, then \a M represents a combinatorial embedding. - * The vertices in \a M correspond to vertices in \a G. The edges in \a M are of - * two types: Real edges correspond to edges in \a G and virtual edges correspond - * to tree-edges in \a T having \a vT as an endpoint. - * - * Let \a e in \a M be a virtual edge and \a eT be the corresponding tree-edge. - * Then there exists exactly one edge \a e' in another skeleton \a S' of \a T that - * corresponds to \a eT as well. We call \a e' the twin edge of \a e. - */ -class OGDF_EXPORT Skeleton -{ -public: - - // constructor - - //! Creates a skeleton \a S with owner tree \a T and corresponding node \a vT. - /** - * \pre \a vT is a node in \a T - * - * \remarks Skeletons are created by the constructor of SPQRTree - * and can be accessed with the skeleton() function of SPQRTree. - */ - Skeleton(node vT) : m_treeNode(vT) { } - - - // destructor - virtual ~Skeleton() { } - - - //! Returns the owner tree \a T. - virtual const SPQRTree &owner() const=0; - - //! Returns the corresponding node in the owner tree \a T to which \a S belongs. - node treeNode() const { - return m_treeNode; - } - - //! Returns the reference edge of \a S in \a M. - /** - * The reference edge is a real edge if \a S is the skeleton of the root node - * of \a T, and a virtual edge otherwise. - */ - edge referenceEdge() const { - return m_referenceEdge; - } - - //! Returns a reference to the skeleton graph \a M. - const Graph &getGraph() const { - return m_M; - } - - //! Returns a reference to the skeleton graph \a M. - Graph &getGraph() { - return m_M; - } - - //! Returns the vertex in the original graph \a G that corresponds to \a v. - /** - * \pre \a v is a node in \a M. - */ - virtual node original (node v) const=0; - - //! Returns true iff \a e is a virtual edge. - /** - * \pre \a e is an edge in \a M - */ - virtual bool isVirtual (edge e) const=0; - - //! Returns the real edge that corresponds to skeleton edge \a e - /** - * If \a e is virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - virtual edge realEdge (edge e) const=0; - - //! Returns the twin edge of skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - virtual edge twinEdge (edge e) const=0; - - //! Returns the tree node in T containing the twin edge of skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - virtual node twinTreeNode (edge e) const=0; - - OGDF_NEW_DELETE - -protected: - node m_treeNode; //!< corresp. tree node in owner tree - edge m_referenceEdge; //!< reference edge - Graph m_M; //!< actual skeleton graph -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/StaticPlanarSPQRTree.h b/ext/OGDF/ogdf/decomposition/StaticPlanarSPQRTree.h deleted file mode 100644 index 19ce2da37..000000000 --- a/ext/OGDF/ogdf/decomposition/StaticPlanarSPQRTree.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * $Revision: 2535 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 12:19:10 +0200 (Wed, 04 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class StaticPlanarSPQRTree. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once - -// disable wrong warnings (VS compiler bug regarding virtual base classes) -#pragma warning(disable:4250) -#endif - - -#ifndef OGDF_STATIC_PLANAR_SPQR_TREE_H -#define OGDF_STATIC_PLANAR_SPQR_TREE_H - - -#include -#include - - -namespace ogdf { - - -template class Tuple2; - - -//--------------------------------------------------------- -// StaticPlanarSPQRTree -// extension of class StaticSPQRTree for support of embedded graphs -//--------------------------------------------------------- - -//! SPQR-trees of planar graphs. -/** - * The class StaticPlanarSPQRTree maintains the triconnected components of a - * planar biconnected graph G and represents all possible embeddings - * of G. Each skeleton graph is embedded. - * - * The current embeddings of the skeletons define an embedding of G. - * There are two basic operations for obtaining another embedding - * of G: reverse(v), which flips the skeleton of an R-node v - * around its poles, and swap(v,e_1,e_2), which exchanges the - * positions of the edges e_1 and e_2 in the skeleton of a P-node v. - */ - -class OGDF_EXPORT StaticPlanarSPQRTree : public StaticSPQRTree, public PlanarSPQRTree -{ -public: - - // constructors - - //! Creates an SPQR tree \a T for planar graph \a G rooted at the first edge of \a G. - /** - * If \a isEmbedded is set to true, \a G must represent a combinatorial - * embedding, i.e., the counter-clockwise order of the adjacency entries - * around each vertex defines an embedding. - * \pre \a G is planar and biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - StaticPlanarSPQRTree(const Graph &G, bool isEmbedded = false) : - StaticSPQRTree(G) - { - PlanarSPQRTree::init(isEmbedded); - } - - //! Creates an SPQR tree \a T for planar graph \a G rooted at edge \a e. - /** - * If \a isEmbedded is set to true, \a G must represent a combinatorial - * embedding, i.e., the counter-clockwise order of the adjacency entries - * around each vertex defines an embedding. - * \pre \a e is an edge in \a G, and \a G is planar and biconnected and - * contains at least 3 nodes, or \a G has exactly 2 nodes and at least 3 - * edges. - */ - StaticPlanarSPQRTree(const Graph &G, edge e, bool isEmbedded = false) : - StaticSPQRTree(G,e) - { - PlanarSPQRTree::init(isEmbedded); - } -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/StaticSPQRTree.h b/ext/OGDF/ogdf/decomposition/StaticSPQRTree.h deleted file mode 100644 index 78f86015d..000000000 --- a/ext/OGDF/ogdf/decomposition/StaticSPQRTree.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class StaticSPQRTree - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_STATIC_SPQR_TREE_H -#define OGDF_STATIC_SPQR_TREE_H - - -#include -#include - - -namespace ogdf { - - class TricComp; - -//--------------------------------------------------------- -// StaticSPQRTree -// SPQR-tree data structure (static environment) -//--------------------------------------------------------- - -/** - * \brief Linear-time implementation of static SPQR-trees. - * - * The class StaticSPQRTree maintains the arrangement of the triconnected - * components of a biconnected multi-graph \a G [Hopcroft, Tarjan 1973] - * as a so-called SPQR tree \a T [Fi Battista, Tamassia, 1996]. We - * call \a G the original graph of \a T. - * The class StaticSPQRTree supports only the statical construction - * of an SPQR-tree for a given graph \a G, dynamic updates are - * not supported. - * - * Each node of the tree has an associated type (represented by - * SPQRTree::NodeType), which is either SNode, PNode, or - * RNode, and a skeleton (represented by the class StaticSkeleton). - * The skeletons of the nodes of \a T are in one-to-one - * correspondence to the triconnected components of \a G, i.e., - * S-nodes correspond to polygons, P-nodes to bonds, and - * R-nodes to triconnected graphs. - * - * In our representation of SPQR-trees, Q-nodes are omitted. Instead, - * the skeleton S of a node \a v in \a T contains two types of edges: - * real edges, which correspond to edges in \a G, and virtual edges, which - * correspond to edges in \a T having \a v as an endpoint. - * There is a special edge \a er in G at which \a T is rooted, i.e., the - * root node of \a T is the node whose skeleton contains the real edge - * corresponding to \a er. - * - * The reference edge of the skeleton of the root node is \a er, the - * reference edge of the skeleton \a S of a non-root node \a v is the virtual - * edge in \a S that corresponds to the tree edge (parent(\a v),\a v). - */ - -class OGDF_EXPORT StaticSPQRTree : public virtual SPQRTree -{ -public: - - friend class StaticSkeleton; - - - // constructors - - /** - * \brief Creates an SPQR tree \a T for graph \a G rooted at the first edge of \a G. - * \pre \a G is biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - StaticSPQRTree(const Graph &G) : m_skOf(G), m_copyOf(G) { m_pGraph = &G; init(G.firstEdge()); } - - /** - * \brief Creates an SPQR tree \a T for graph \a G rooted at the edge \a e. - * \pre \a e is in \a G, \a G is biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - StaticSPQRTree(const Graph &G, edge e) : m_skOf(G), m_copyOf(G) { m_pGraph = &G; init(e); } - - /** - * \brief Creates an SPQR tree \a T for graph \a G rooted at the first edge of \a G. - * \pre \a G is biconnected and contains at least 3 nodes, - * or \a G has exactly 2 nodes and at least 3 edges. - */ - StaticSPQRTree(const Graph &G, TricComp &tricComp) : m_skOf(G), m_copyOf(G) { m_pGraph = &G; init(G.firstEdge(),tricComp); } - - - // destructor - - ~StaticSPQRTree(); - - - // - // a) Access operations - // - - //! Returns a reference to the original graph \a G. - const Graph &originalGraph() const { return *m_pGraph; } - - //! Returns a reference to the tree \a T. - const Graph &tree() const { return m_tree; } - - //! Returns the edge of \a G at which \a T is rooted. - edge rootEdge() const { return m_rootEdge; } - - //! Returns the root node of \a T. - node rootNode() const { return m_rootNode; } - - //! Returns the number of S-nodes in \a T. - int numberOfSNodes() const { return m_numS; } - - //! Returns the number of P-nodes in \a T. - int numberOfPNodes() const { return m_numP; } - - //! Returns the number of R-nodes in \a T. - int numberOfRNodes() const { return m_numR; } - - /** - * \brief Returns the type of node \a v. - * \pre \a v is a node in \a T - */ - NodeType typeOf(node v) const { return m_type[v]; } - - //! Returns the list of all nodes with type \a t. - List nodesOfType(NodeType t) const; - - /** - * \brief Returns the skeleton of node \a v. - * \pre \a v is a node in \a T - */ - Skeleton &skeleton(node v) const { return *m_sk[v]; } - - /** - * \brief Returns the edge in skeleton of source(\a e) that corresponds to tree edge \a e. - * \pre \a e is an edge in \a T - */ - edge skeletonEdgeSrc(edge e) const { return m_skEdgeSrc[e]; } - - /** - * \brief Returns the edge in skeleton of target(\a e) that corresponds to tree edge \a e. - * \pre \a e is an edge in \a T - */ - edge skeletonEdgeTgt(edge e) const { return m_skEdgeTgt[e]; } - - /** - * \brief Returns the skeleton that contains the real edge \a e. - * \pre \a e is an edge in \a G - */ - const Skeleton &skeletonOfReal(edge e) const { return *m_skOf[e]; } - - /** - * \brief Returns the skeleton edge that corresponds to the real edge \a e. - * \pre \a e is an edge in \a G - */ - edge copyOfReal(edge e) const { return m_copyOf[e]; } - - - // - // b) Update operations - // - - /** - * \brief Roots \a T at edge \a e and returns the new root node of \a T. - * \pre \a e is an edge in \a G - */ - node rootTreeAt(edge e); - - /** - * \brief Roots \a T at node \a v and returns \a v. - * \pre \a v is a node in \a T - */ - node rootTreeAt(node v); - - -protected: - - //! Initialization (called by constructor). - void init(edge e); - - //! Initialization (called by constructor). - void init(edge eRef, TricComp &tricComp); - - //! Recursively performs rooting of tree. - void rootRec(node v, edge ef); - - /** - * \brief Recursively performs the task of adding edges (and nodes) - * to the pertinent graph \a Gp for each involved skeleton graph. - */ - void cpRec(node v, PertinentGraph &Gp) const - { - edge e; - const Skeleton &S = skeleton(v); - - forall_edges(e,S.getGraph()) { - edge eOrig = S.realEdge(e); - if (eOrig != 0) cpAddEdge(eOrig,Gp); - } - - forall_adj_edges(e,v) { - node w = e->target(); - if (w != v) cpRec(w,Gp); - } - } - - - const Graph *m_pGraph; //!< pointer to original graph - Graph m_tree; //!< underlying tree graph - - edge m_rootEdge; //!< edge of \a G at which \a T is rooted - node m_rootNode; //!< root node of \a T - - int m_numS; //!< number of S-nodes - int m_numP; //!< number of P-nodes - int m_numR; //!< number of R-nodes - - NodeArray m_type; //!< type of nodes in \a T - - NodeArray m_sk; //!< pointer to skeleton of a node in \a T - EdgeArray m_skEdgeSrc; //!< corresponding edge in skeleton(source(\a e)) - EdgeArray m_skEdgeTgt; //!< corresponding edge in skeleton(target(\a e)) - - EdgeArray m_skOf; //!< skeleton containing real edge \a e - EdgeArray m_copyOf; //!< skeleton edge corresponding to real edge \a e - -}; // class StaticSPQRTree - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/decomposition/StaticSkeleton.h b/ext/OGDF/ogdf/decomposition/StaticSkeleton.h deleted file mode 100644 index 1e2fec2ba..000000000 --- a/ext/OGDF/ogdf/decomposition/StaticSkeleton.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class StaticSkeleton. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_STATIC_SKELETON_H -#define OGDF_STATIC_SKELETON_H - - -#include - - -namespace ogdf { - - class OGDF_EXPORT StaticSPQRTree; - - -//! %Skeleton graphs of nodes in a static SPQR-tree. -/** - * The class StaticSkeleton maintains the skeleton \a S of a node \a vT in a static SPQR-tree - * \a T. We call \a T the owner tree of \a S and \a vT the corresponding tree node. Let - * \a G be the original graph of \a T. - * - * \a S consists of an undirected multi-graph \a M. If the owner tree of \a S is - * a PlanarSPQRTree, then \a M represents a combinatorial embedding. - * The vertices in \a M correspond to vertices in \a G. The edges in \a M are of - * two types: Real edges correspond to edges in \a G and virtual edges correspond - * to tree-edges in \a T having \a vT as an endpoint. - * - * Let \a e in \a M be a virtual edge and \a eT be the corresponding tree-edge. - * Then there exists exactly one edge \a e' in another skeleton \a S' of \a T that - * corresponds to \a eT as well. We call \a e' the twin edge of \a e. - */ -class OGDF_EXPORT StaticSkeleton : public Skeleton -{ - friend class OGDF_EXPORT StaticSPQRTree; - -public: - - // constructor - - //! Creates a skeleton \a S with owner tree \a T and corresponding node \a vT. - /** - * \pre \a vT is a node in \a T - * - * \remarks Skeletons are created by the constructor of SPQRTree - * and can be accessed with the skeleton() function of SPQRTree. - */ - StaticSkeleton(const StaticSPQRTree *T, node vT); - - - // destructor - ~StaticSkeleton() { } - - - //! Returns the owner tree \a T. - const SPQRTree &owner() const; - - //! Returns the vertex in the original graph \a G that corresponds to \a v. - /** - * \pre \a v is a node in \a M. - */ - node original (node v) const { - return m_orig[v]; - } - - //! Returns true iff \a e is a virtual edge. - /** - * \pre \a e is an edge in \a M - */ - bool isVirtual (edge e) const { - return (m_real[e] == 0); - } - - //! Returns the real edge that corresponds to skeleton edge \a e - /** - * If \a e is virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - edge realEdge (edge e) const { - return m_real[e]; - } - - //! Returns the twin edge of skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - edge twinEdge (edge e) const; - - //! Returns the tree node in T containing the twin edge of skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is returned. - * \pre \a e is an edge in \a M - */ - node twinTreeNode (edge e) const; - - //! Returns the tree edge which is associated with skeleton edge \a e. - /** - * If \a e is not a virtual edge, then 0 is retuned. - * \pre \a e is an edge in \a M - */ - edge treeEdge (edge e) const { - return m_treeEdge[e]; - } - - OGDF_MALLOC_NEW_DELETE - -protected: - const StaticSPQRTree *m_owner; //!< owner tree - NodeArray m_orig; //!< corresp. original node - EdgeArray m_real; //!< corresp. original edge (0 if virtual) - EdgeArray m_treeEdge; //!< corresp. tree edge (0 if real) -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/energybased/CoinTutteLayout.h b/ext/OGDF/ogdf/energybased/CoinTutteLayout.h deleted file mode 100644 index 23f3ebe5d..000000000 --- a/ext/OGDF/ogdf/energybased/CoinTutteLayout.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Revision: 2614 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-16 11:30:08 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Tutte's algorithm - * - * The class CoinTutteLayout represents the layout algorithm by - * Tutte. - * - * \par - * This algorithm draws a planar graph \a G straight-line - * without crossings. It can also draw non-planar graphs. - * - * \par - * The idea of the algorithm is to place every vertex into the - * center of gravity by its neighbours. - * - * \author David Alberts and Andrea Wagner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_TUTTE_LAYOUT_H -#define OGDF_TUTTE_LAYOUT_H - -#include -#include -#include - -#ifdef USE_COIN -#include -#endif - -namespace ogdf { - -class OGDF_EXPORT TutteLayout : public LayoutModule -{ -#ifndef USE_COIN -public: - - void call(GraphAttributes &AG) { THROW_NO_COIN_EXCEPTION; } - void call(GraphAttributes &AG, const List& givenNodes) { THROW_NO_COIN_EXCEPTION; } - -}; - -#else // USE_COIN -public: - - TutteLayout(); - ~TutteLayout() { } - - DRect bbox () const { - return m_bbox; - } - - void bbox (const DRect &bb) { - m_bbox = bb; - } - - void call(GraphAttributes &AG); - void call(GraphAttributes &AG, const List &givenNodes); - - -private: - - void setFixedNodes(const Graph &G, List &nodes, - List &pos, double radius = 1.0); - /*! sets the positions of the nodes in a largest face of $G$ in the - * form of a regular $k$-gon with the prescribed radius. The - * corresponding nodes and their positions are stored in nodes - * and pos, respectively. $G$ does not have to be planar! - */ - - void setFixedNodes(const Graph &G, List &nodes, const List &givenNodes, - List &pos, double radius = 1.0); - /*! the method is overloaded for a given set of nodes. - */ - - bool doCall(GraphAttributes &AG, - const List &fixedNodes, - List &fixedPositions); - - DRect m_bbox; -}; - -#endif // USE_COIN - -} // end namespace ogdf - -#endif // OGDF_TUTTE_LAYOUT_H diff --git a/ext/OGDF/ogdf/energybased/DavidsonHarel.h b/ext/OGDF/ogdf/energybased/DavidsonHarel.h deleted file mode 100644 index 9803bf05d..000000000 --- a/ext/OGDF/ogdf/energybased/DavidsonHarel.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class DavidsonHarel which implements the - * Davidson-Harel approach for drawing graphs. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DAVIDSON_HAREL_H -#define OGDF_DAVIDSON_HAREL_H - - -#include - - -namespace ogdf { - - -//! The Davidson-Harel approach for drawing graphs. -class OGDF_EXPORT DavidsonHarel -{ -public: - - //! Creates an instance of Davidsen-Harel base class. - DavidsonHarel(); - - ~DavidsonHarel() { } - - //! Sets the start temperature to \a startTemp. - void setStartTemperature(int startTemp); - - //! Sets the number of iterations for each temperature step to \a steps. - void setNumberOfIterations(int steps); - - //! Adds an energy function \a F with a certain weight. - void addEnergyFunction(EnergyFunction *F, double weight); - - //! Returns a list of the names of the energy functions. - List returnEnergyFunctionNames(); - - //! Returns a list of the weights of the energy functions. - List returnEnergyFunctionWeights(); - - //! Calls the Davidson-Harel method for graph \a GA. - void call(GraphAttributes &GA); - -private: - //! The default starting temperature. - const static int m_defaultTemp; - //! The default starting radius. - const static double m_defaultRadius; - //! Per default, the number of iterations per temperature are set as a constant multiple of the number of vertices. - const static int m_iterationMultiplier; - //! The fraction by which the temperature is lowered after a temperature step is finished. - const static double m_coolingFactor; - //! the constant by which the radius of the circle around each vertex is shrunk when the temperature is lowered - const static double m_shrinkFactor; - - int m_temperature; //!< The temperature during the annealing process. - double m_shrinkingFactor; //!< The factor for radius. - double m_diskRadius; //!< The radius of the disk around the old position of a vertex where the new position will be. - double m_energy; //!< The current energy of the system. - int m_numberOfIterations; //!< The number of iterations per temperature step. - - List m_energyFunctions; //!< The list of the energy functions. - List m_weightsOfEnergyFunctions; //!< The list of the weights for the energy functions. - - List m_nonIsolatedNodes; //!< The list of nodes with degree greater 0. - - //! Resets the parameters for subsequent runs. - void initParameters(); - - //! Randomly computes a node and a new position for that node. - node computeCandidateLayout(const GraphAttributes &, DPoint &) const; - - //! Tests if new energy value satisfies annealing property (only better if m_fineTune). - bool testEnergyValue(double newVal); - - //! Computes a random number between zero and one - double randNum() const; - - //! Computes the first disk radius as the half the diamter of the enclosing rectangle. - void computeFirstRadius(const GraphAttributes &AG); - - //! Computes the energy of the initial layout and stores it in \a m_energy. - void computeInitialEnergy(); - - //! Computes positions for the vertices of degree zero. - void placeIsolatedNodes(GraphAttributes &AG) const; - - //! Fake assignment operator (dummy to avoid copying) - DavidsonHarel& operator=(const DavidsonHarel &dh); - //! Fake copy constructor (dummy to avoid copying) - DavidsonHarel(const DavidsonHarel &) { } -}; - -} //end namespace -#endif diff --git a/ext/OGDF/ogdf/energybased/DavidsonHarelLayout.h b/ext/OGDF/ogdf/energybased/DavidsonHarelLayout.h deleted file mode 100644 index 99a9d36d8..000000000 --- a/ext/OGDF/ogdf/energybased/DavidsonHarelLayout.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class DavidsonHarelLayout, which is a front-end - * for the fDavidsonHarel class. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DAVIDSON_HAREL_LAYOUT_H -#define OGDF_DAVIDSON_HAREL_LAYOUT_H - - -#include -#include - - -namespace ogdf { - - -//! The Davidson-Harel layout algorithm. -/** - * The implementation used in DavidsonHarelLayout is based on - * the following publication: - * - * Ron Davidson, David Harel: Drawing Graphs Nicely Using Simulated Annealing. - * ACM Transactions on Graphics 15(4), pp. 301-331, 1996. - */ -class OGDF_EXPORT DavidsonHarelLayout : public LayoutModule -{ -public: - //! Easy way to set fixed costs - enum SettingsParameter {spStandard, spRepulse, spPlanar}; //tuning of costs - - //! Easy way to set temperature and iterations - enum SpeedParameter {sppFast, sppMedium, sppHQ}; - - //! Creates an instance of Davidson-Harel layout. - DavidsonHarelLayout(); - - ~DavidsonHarelLayout(){} - - //! Calls the layout algorithm for graph attributes \a GA. - void call(GraphAttributes &GA); - - //! Fixes the cost values to special configurations. - void fixSettings(SettingsParameter sp); - - //! More convenient way of setting the speed of the algorithm. - /** - * Influences number of iterations per temperature step, starting - * temperature, and cooling factor. - */ - void setSpeed(SpeedParameter sp); - - //! Sets the preferred edge length multiplier for attraction. - /** - * This is bad design, cause you dont need to have an attraction function, - * DH is purely modular and independent with its cost functions. - */ - void setPreferredEdgeLengthMultiplier(double multi) {m_multiplier = multi;} - - //! Sets the preferred edge length to \a elen - void setPreferredEdgeLength(double elen) {m_prefEdgeLength = elen;} - - //! Sets the weight for the energy function \a Repulsion. - void setRepulsionWeight(double w); - - //! Returns the weight for the energy function \a Repulsion. - double getRepulsionWeight() const {return m_repulsionWeight;} - - //! Sets the weight for the energy function \a Attraction. - void setAttractionWeight(double); - - //! Returns the weight for the energy function \a Attraction. - double getAttractionWeight() const {return m_attractionWeight;} - - //! Sets the weight for the energy function \a NodeOverlap. - void setNodeOverlapWeight(double); - - //! Returns the weight for the energy function \a NodeOverlap. - double getNodeOverlapWeight() const {return m_nodeOverlapWeight;} - - //! Sets the weight for the energy function \a Planarity. - void setPlanarityWeight(double); - - //! Returns the weight for the energy function \a Planarity. - double getPlanarityWeight() const {return m_planarityWeight;} - - //! Sets the starting temperature to \a t. - void setStartTemperature(int t); - - //! Returns the starting temperature. - int getStartTemperature() const {return m_startTemperature;} - - //! Sets the number of iterations per temperature step to \a steps. - void setNumberOfIterations(int steps); - - //! Returns the number of iterations per temperature step. - int getNumberOfIterations() const {return m_numberOfIterations;} - - //! Switch between using iteration number as fixed number or factor - //! (*number of nodes of graph) - void setIterationNumberAsFactor(bool b) {m_itAsFactor = b;} - -private: - double m_repulsionWeight; //!< The weight for repulsion energy. - double m_attractionWeight; //!< The weight for attraction energy. - double m_nodeOverlapWeight; //!< The weight for node overlap energy. - double m_planarityWeight; //!< The weight for edge crossing energy. - int m_startTemperature; //!< The temperature at the start of the optimization. - int m_numberOfIterations; //!< The number of iterations per temperature step. - SpeedParameter m_speed; //!< You can override this by manually setting iter=0. - double m_multiplier; //!< By default, number of iterations per temperature step is number of vertices multiplied by multiplier. - double m_prefEdgeLength; //!< Preferred edge length (abs value), only used if > 0 - bool m_crossings; //!< Should crossings be computed? - bool m_itAsFactor; //!< Should m_numberOfIterations be factor (true) or fixed number -}; - -} -#endif diff --git a/ext/OGDF/ogdf/energybased/FMMMLayout.h b/ext/OGDF/ogdf/energybased/FMMMLayout.h deleted file mode 100644 index 2b4bd39e2..000000000 --- a/ext/OGDF/ogdf/energybased/FMMMLayout.h +++ /dev/null @@ -1,1388 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Fast Multipole Multilevel Method (FM^3). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FMMMLAYOUT_H -#define OGDF_FMMMLAYOUT_H - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - class Rectangle; - -/** - * \brief The fast multipole multilevel layout algorithm. - * - * The class FMMMLayout implements a force-directed graph drawing - * method suited also for very large graphs. It is based on a - * combination of an efficient multilevel scheme and a strategy for - * approximating the repulsive forces in the system by rapidly - * evaluating potential fields. - * - * The implementation is based on the following publication: - * - * Stefan Hachul, Michael J�nger: Drawing Large Graphs with a - * Potential-Field-Based Multilevel Algorithm. 12th International - * Symposium on %Graph Drawing 1998, New York (GD '04), LNCS 3383, - * pp. 285-295, 2004. - * - *

    Optional parameters

    - * The following options are the most important. You can set - * useHighLevelOptions to true and just need to adjust a few parameters. - * However, you can also adjust all parameters that the implementation - * uses (see below), but this requires good knowledge of the algorithm. - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    useHighLevelOptionsboolfalse - * Whether high-level options are used or not. - *
    pageFormat #PageFormatType #pfSquare - * The desired aspect ratio of the layout. - *
    unitEdgeLengthdouble100.0 - * The unit edge length. - *
    newInitialPlacementboolfalse - * Specifies if initial placement of nodes is varied. - *
    qualityVersusSpeed #QualityVsSpeed #qvsBeautifulAndFast - * Indicates if the algorithm is tuned either for best quality or best speed. - *
    - * - * If you want to do more detailed fine-tuning, you can adjust all parameters - * used by the algorithm. Please refer to the paper cited above for better - * understanding of the algorithm. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    General - *
    randSeedint100 - * The seed of the random number generator. - *
    edgeLengthMeasurement #EdgeLengthMeasurement #elmBoundingCircle - * Indicates how the length of an edge is measured. - *
    allowedPositions #AllowedPositions #apInteger - * Defines which positions for a node are allowed. - *
    maxIntPosExponentint40 - * Defines the exponent used if allowedPositions == apExponent. - *
    Divide et impera step - *
    pageRatiodouble1.0 - * The desired page ratio. - *
    stepsForRotatingComponentsint10 - * The number of rotations per connected component. - *
    tipOverCCs #TipOver #toNoGrowingRow - * Specifies when it is allowed to tip over drawings. - *
    minDistCCdouble100 - * The minimal distance between connected components. - *
    presortCCs #PreSort #psDecreasingHeight - * Defines if the connected components are sorted before - * the packing algorithm is applied. - *
    Multilevel step - *
    minGraphSizeint50 - * Determines the number of nodes of a graph for which - * no more collapsing of galaxies is performed. - *
    galaxyChoice #GalaxyChoice #gcNonUniformProbLowerMass - * Defines how sun nodes of galaxies are selected. - *
    randomTriesint20 - * Defines the number of tries to get a random node with - * minimal star mass. - *
    maxIterChange #MaxIterChange #micLinearlyDecreasing - * Defines how MaxIterations is changed in subsequent multilevels. - *
    maxIterFactorint10 - * Defines the factor used for decreasing MaxIterations. - *
    initialPlacementMult #InitialPlacementMult #ipmAdvanced - * Defines how the initial placement is generated. - *
    Force calculation step - *
    forceModel #ForceModel #fmNew - * The used force model. - *
    springStrengthdouble1.0 - * The strength of the springs. - *
    repForcesStrengthdouble1.0 - * The strength of the repulsive forces. - *
    repulsiveForcesCalculation #RepulsiveForcesMethod #rfcNMM - * Defines how to calculate repulsive forces. - *
    stopCriterion #StopCriterion #scFixedIterationsOrThreshold - * The stop criterion. - *
    thresholddouble0.01 - * The threshold for the stop criterion. - *
    fixedIterationsint30 - * The fixed number of iterations for the stop criterion. - *
    forceScalingFactordouble0.05 - * The scaling factor for the forces. - *
    coolTemperatureboolfalse - * Use coolValue for scaling forces. - *
    coolValuedouble0.99 - * The value by which forces are decreased. - *
    initialPlacementForces #InitialPlacementForces #ipfRandomRandIterNr - * Defines how the initial placement is done. - *
    Force calculation step - *
    resizeDrawingbooltrue - * Specifies if the resulting drawing is resized. - *
    resizingScalardouble1 - * Defines a parameter to scale the drawing if resizeDrawing is true. - *
    fineTuningIterationsint20 - * The number of iterations for fine tuning. - *
    fineTuneScalardouble0.2 - * Defines a parameter for scaling the forces in the fine-tuning iterations. - *
    adjustPostRepStrengthDynamicallybooltrue - * If set to true, the strength of the repulsive force field is calculated. - *
    postSpringStrengthdouble2.0 - * The strength of the springs in the postprocessing step. - *
    postStrengthOfRepForcesdouble0.01 - * The strength of the repulsive forces in the postprocessing step. - *
    Repulsive force approximation methods - *
    frGridQuotientint2 - * The grid quotient. - *
    nmTreeConstruction #ReducedTreeConstruction #rtcSubtreeBySubtree - * Defines how the reduced bucket quadtree is constructed. - *
    nmSmallCell #SmallestCellFinding #scfIteratively - * Defines how the smallest quadratic cell that surrounds - * the particles of a node in the reduced bucket quadtree is calculated. - *
    nmParticlesInLeavesint25 - * The maximal number of particles that are contained in - * a leaf of the reduced bucket quadtree. - *
    nmPrecisionint4 - * The precision \a p for the p-term multipole expansions. - *
    - * - *

    Running time

    - * The running time of the algorithm is - * O(n log n + m) for graphs with \a n nodes - * and \a m edges. The required space is linear in the input size. - */ -class OGDF_EXPORT FMMMLayout : public LayoutModule -{ -public: - //! Possible page formats. - enum PageFormatType { - pfPortrait, //!< A4 portrait page. - pfLandscape, //!< A4 landscape page. - pfSquare //!< Square format. - }; - - //! Trade-off between run-time and quality. - enum QualityVsSpeed { - qvsGorgeousAndEfficient, //!< Best quality. - qvsBeautifulAndFast, //!< Medium quality and speed. - qvsNiceAndIncredibleSpeed //!< Best speed. - }; - - //! Specifies how the length of an edge is measured. - enum EdgeLengthMeasurement { - elmMidpoint, //!< Measure from center point of edge end points. - elmBoundingCircle //!< Measure from border of circle s surrounding edge end points. - }; - - //! Specifies which positions for a node are allowed. - enum AllowedPositions { - apAll, - apInteger, - apExponent - }; - - //! Specifies in which case it is allowed to tip over drawings of connected components. - enum TipOver { - toNone, - toNoGrowingRow, - toAlways - }; - - //! Specifies how connected components are sorted before the packing algorithm is applied. - enum PreSort { - psNone, //!< Do not presort. - psDecreasingHeight, //!< Presort by decreasing height of components. - psDecreasingWidth //!< Presort by decreasing width of components. - }; - - //! Specifies how sun nodes of galaxies are selected. - enum GalaxyChoice { - gcUniformProb, - gcNonUniformProbLowerMass, - gcNonUniformProbHigherMass - }; - - //! Specifies how MaxIterations is changed in subsequent multilevels. - enum MaxIterChange { - micConstant, - micLinearlyDecreasing, - micRapidlyDecreasing - }; - - //! Specifies how the initial placement is generated. - enum InitialPlacementMult { - ipmSimple, - ipmAdvanced - }; - - //! Specifies the force model. - enum ForceModel { - fmFruchtermanReingold, //!< The force-model by Fruchterman, Reingold. - fmEades, //!< The force-model by Eades. - fmNew //!< The new force-model. - }; - - //! Specifies how to calculate repulsive forces. - enum RepulsiveForcesMethod { - rfcExact, //!< Exact calculation. - rfcGridApproximation, //!< Grid approximation. - rfcNMM //!< Calculation as for new multipole method. - }; - - //! Specifies the stop criterion. - enum StopCriterion { - scFixedIterations, //!< Stop if fixedIterations() is reached. - scThreshold, //!< Stop if threshold() is reached. - scFixedIterationsOrThreshold //!< Stop if fixedIterations() or threshold() is reached. - }; - - //! Specifies how the initial placement is done. - enum InitialPlacementForces { - ipfUniformGrid, //!< Uniform placement on a grid. - ipfRandomTime, //!< Random placement (based on current time). - ipfRandomRandIterNr, //!< Random placement (based on randIterNr()). - ipfKeepPositions //!< No change in placement. - }; - - //! Specifies how the reduced bucket quadtree is constructed. - enum ReducedTreeConstruction { - rtcPathByPath, //!< Path-by-path construction. - rtcSubtreeBySubtree //!< Subtree-by-subtree construction. - }; - - //! Specifies how to calculate the smallest quadratic cell surrounding particles of a node in the reduced bucket quadtree. - enum SmallestCellFinding { - scfIteratively, //!< Iteratively (in constant time). - scfAluru //!< According to formula by Aluru et al. (in constant time). - }; - - - //! Creates an instance of the layout algorithm. - FMMMLayout(); - - // destructor - virtual ~FMMMLayout() { } - - - /** - * @name The algorithm call - * @{ - */ - - //! Calls the algorithm for graph \a GA and returns the layout information in \a AG. - void call(GraphAttributes &GA); - - //! Calls the algorithm for clustered graph \a GA and returns the layout information in \a AG. - //! Models cluster by simple edge length adaption based on least common ancestor - //! cluster of end vertices. - void call(ClusterGraphAttributes &GA); - - //! Extended algorithm call: Allows to pass desired lengths of the edges. - /** - * @param GA represents the input graph and is assigned the computed layout. - * @param edgeLength is an edge array of the graph associated with \a GA - * of positive edge length. - */ - void call( - GraphAttributes &GA, //graph and layout - const EdgeArray &edgeLength); //factor for desired edge lengths - - //! Extended algorithm call: Calls the algorithm for graph \a AG. - /** - * Returns layout information in \a AG and a simple drawing is saved in file \a ps_file - * in postscript format (Nodes are drawn as uniformly sized circles). - */ - void call(GraphAttributes &AG, char* ps_file); - - //! Extend algorithm call: Allows to pass desired lengths of the edges. - /** - * The EdgeArray \a edgeLength must be valid for AG.constGraph() and its values must - * be positive. - * A simple drawing is saved in file ps_file in postscript format (Nodes are drawn - * as uniformly sized circles). - */ - void call( - GraphAttributes &AG, //graph and layout - const EdgeArray &edgeLength, //factor for desired edge lengths - char* ps_file); - - /** @} - * @name Further information. - * @{ - */ - - //! Returns the runtime (=CPU-time) of the layout algorithm in seconds. - double getCpuTime() { - return time_total; - } - - - /** @} - * @name High-level options - * Allow to specify the most relevant parameters. - * @{ - */ - - //! Returns the current setting of option useHighLevelOptions. - /** - * If set to true, the high-level options are used to set all low-level options. - * Usually, it is sufficient just to set high-level options; if you want to - * be more specific, set this parameter to false and set the low level options. - */ - bool useHighLevelOptions() const { return m_useHighLevelOptions; } - - //! Sets the option useHighLevelOptions to \a uho. - void useHighLevelOptions(bool uho) { m_useHighLevelOptions = uho; } - - //! Sets single level option, no multilevel hierarchy is created if b == true - void setSingleLevel(bool b) {m_singleLevel = b;} - - //! Returns the current setting of option pageFormat. - /** - * This option defines the desired aspect ratio of the drawing area. - * - \a pfPortrait: A4 page in portrait orientation - * - \a pfLandscape: A4 page in landscape orientation - * - \a pfSquare: square page format - */ - PageFormatType pageFormat() const { return m_pageFormat; } - - //! Sets the option pageRatio to \a t. - void pageFormat(PageFormatType t) { m_pageFormat = t; } - - //! Returns the current setting of option unitEdgeLength. - double unitEdgeLength() const { return m_unitEdgeLength; } - - //! Sets the option unitEdgeLength to \a x. - void unitEdgeLength(double x) {m_unitEdgeLength = (( x > 0.0) ? x : 1);} - - //! Returns the current setting of option newInitialPlacement. - /** - * This option defines if the initial placement of the nodes at the - * coarsest multilevel is varied for each distinct call of FMMMLayout - * or keeps always the same. - */ - bool newInitialPlacement() const { return m_newInitialPlacement; } - - //! Sets the option newInitialPlacement to \a nip. - void newInitialPlacement(bool nip) { m_newInitialPlacement = nip; } - - //! Returns the current setting of option qualityVersusSpeed. - /** - * Indicates if the algorithm is tuned either for best quality or best speed. - * - \a qvsGorgeousAndEfficient: gorgeous quality and efficient speed - * - \a qvsBeautifulAndFast: beautiful quality and fast speed - * - \a qvsNiceAndIncredibleSpeed: nice quality and incredible speed - */ - QualityVsSpeed qualityVersusSpeed() const { return m_qualityVersusSpeed; } - - //! Sets the option qualityVersusSpeed to \a qvs. - void qualityVersusSpeed(QualityVsSpeed qvs) {m_qualityVersusSpeed = qvs; } - - - /** @} - * @name General low-level options - * The low-level options in this and the following sections are meant for - * experts or interested people only. - * @{ - */ - - //! Sets the seed of the random number generator. - void randSeed(int p) { m_randSeed = ((0<=p) ? p : 1);} - - //! Returns the seed of the random number generator. - int randSeed() const {return m_randSeed;} - - //! Returns the current setting of option edgeLengthMeasurement. - /** - * This option indicates how the length of an edge is measured. - * Possible values: - * - \a elmMidpoint: from center to center - * - \a elmBoundingCircle: the distance between the two tight circles bounding the - * graphics of two adjacent nodes - */ - EdgeLengthMeasurement edgeLengthMeasurement() const { - return m_edgeLengthMeasurement; - } - - //! Sets the option edgeLengthMeasurement to \a elm. - void edgeLengthMeasurement(EdgeLengthMeasurement elm) { m_edgeLengthMeasurement = elm; } - - //! Returns the current setting of option allowedPositions. - /** - * This option defines which positions for a node are allowed. - * Possibly values: - * - \a apAll: every position is allowed - * - \a apInteger: only integer positions in the range depending on the number of - * nodes - * - \a apExponent: only integer positions in the range of -2^MaxIntPosExponent to - * 2^MaxIntPosExponent - */ - AllowedPositions allowedPositions() const { return m_allowedPositions; } - - //! Sets the option allowedPositions to \a ap. - void allowedPositions(AllowedPositions ap) { m_allowedPositions = ap; } - - //! Returns the current setting of option maxIntPosExponent. - /** - * This option defines the exponent used if allowedPositions() == \a apExponent. - */ - int maxIntPosExponent() const { return m_maxIntPosExponent; } - - //! Sets the option maxIntPosExponent to \a e. - void maxIntPosExponent(int e) { - m_maxIntPosExponent = (((e >= 31)&&(e<=51))? e : 31); - } - - - /** @} - * @name Options for the divide et impera step - * @{ - */ - - //! Returns the current setting of option pageRatio. - /** - * This option defines the desired aspect ratio of the rectangular drawing area. - */ - double pageRatio() const { return m_pageRatio; } - - //! Sets the option pageRatio to \a r. - void pageRatio(double r) {m_pageRatio = (( r > 0) ? r : 1);} - - //! Returns the current setting of option stepsForRotatingComponents. - /** - * This options determines the number of times each connected component is rotated with - * angles between 0 and 90 degree to obtain a bounding rectangle with small area. - */ - int stepsForRotatingComponents() const { return m_stepsForRotatingComponents; } - - //! Sets the option stepsForRotatingComponents to \a n. - void stepsForRotatingComponents(int n) { - m_stepsForRotatingComponents = ((0<=n) ? n : 0); - } - - //! Returns the current setting of option tipOverCCs. - /** - * Defines in which case it is allowed to tip over drawings of connected components. - * Possible values: - * - \a toNone: not allowed at all - * - \a toNoGrowingRow: only if the height of the packing row does not grow - * - \a toAlways: always allowed - */ - TipOver tipOverCCs() const { return m_tipOverCCs; } - - //! Sets the option tipOverCCs to \a to. - void tipOverCCs(TipOver to) { m_tipOverCCs = to; } - - //! Returns the minimal distance between connected components. - double minDistCC() const { return m_minDistCC; } - - //! Sets the minimal distance between connected components to \a x. - void minDistCC(double x) { m_minDistCC = (( x > 0) ? x : 1);} - - //! Returns the current setting of option presortCCs. - /** - * This option defines if the connected components are sorted before - * the packing algorithm is applied. - * Possible values: - * - \a psNone: no sorting - * - \a psDecreasingHeight: sorted by decreasing height - * - \a psDecreasingWidth: sorted by decreasing width - */ - PreSort presortCCs() const { return m_presortCCs; } - - //! Sets the option presortCCs to \a ps. - void presortCCs(PreSort ps) { m_presortCCs = ps; } - - - /** @} - * @name Options for the multilevel step - * @{ - */ - - //! Returns the current setting of option minGraphSize. - /** - * This option determines the number of nodes of a graph in the - * multilevel representation for which no more collapsing of galaxies - * is performed (i.e. the graph at the highest level). - */ - int minGraphSize() const { return m_minGraphSize; } - - //! Sets the option minGraphSize to \a n. - void minGraphSize(int n) { m_minGraphSize = ((n >= 2)? n : 2);} - - //! Returns the current setting of option galaxyChoice. - /** - * This option defines how sun nodes of galaxies are selected. - * Possible values: - * - \a gcUniformProb: selecting by uniform random probability - * - \a gcNonUniformProbLowerMass: selecting by non-uniform probability depending on - * the star masses (prefering nodes with lower star mass) - * - \a gcNonUniformProbHigherMass: as above but prefering nodes with higher star mass - */ - GalaxyChoice galaxyChoice() const { return m_galaxyChoice; } - - //! Sets the option galaxyChoice to \a gc. - void galaxyChoice(GalaxyChoice gc) { m_galaxyChoice = gc; } - - //! Returns the current setting of option randomTries. - /** - * This option defines the number of tries to get a random node with - * minimal star mass (used in case of galaxyChoice() == gcNonUniformProbLowerMass - * and galaxyChoice() == gcNonUniformProbHigherMass). - */ - int randomTries() const { return m_randomTries; } - - //! Sets the option randomTries to \a n. - void randomTries(int n) {m_randomTries = ((n>=1)? n: 1);} - - //! Returns the current setting of option maxIterChange. - /** - * This option defines how MaxIterations is changed in subsequent multilevels. - * Possible values: - * - \a micConstant: kept constant at the force calculation step at every level - * - \a micLinearlyDecreasing: linearly decreasing from MaxIterFactor*FixedIterations - * to FixedIterations - * - \a micRapidlyDecreasing: rapdily decreasing from MaxIterFactor*FixedIterations - * to FixedIterations - */ - MaxIterChange maxIterChange() const { return m_maxIterChange; } - - //! Sets the option maxIterChange to \a mic. - void maxIterChange(MaxIterChange mic) { m_maxIterChange = mic; } - - //! Returns the current setting of option maxIterFactor. - /** - * This option defines the factor used for decrasing MaxIterations - * (in case of maxIterChange() == micLinearlyDecreasing or maxIterChange() - * == micRapidlyDecreasing). - */ - int maxIterFactor() const { return m_maxIterFactor; } - - //! Sets the option maxIterFactor to \a f. - void maxIterFactor(int f) { m_maxIterFactor = ((f>=1) ? f : 1 ); } - - //! Returns the current setting of option initialPlacementMult. - /** - * This option defines how the initial placement is generated. - * Possible values: - * - \a ipmSimple: only using information about placement of nodes on higher levels - * - \a ipmAdvanced: using additional information about the placement of all inter - * - \a solar system nodes - */ - InitialPlacementMult initialPlacementMult() const { - return m_initialPlacementMult; - } - - //! Sets the option initialPlacementMult to \a ipm. - void initialPlacementMult(InitialPlacementMult ipm) { - m_initialPlacementMult = ipm; - } - - - /** @} - * @name Options for the force calculation step - * @{ - */ - - //! Returns the used force model. - /** - * Possibly values: - * - \a fmFruchtermanReingold: model of Fruchterman and Reingold - * - \a fmEades: model of Eades - * - \a fmNew: new model - */ - ForceModel forceModel() const { return m_forceModel; } - - //! Sets the used force model to \a fm. - void forceModel(ForceModel fm) { m_forceModel = fm; } - - //! Returns the strength of the springs. - double springStrength() const { return m_springStrength; } - - //! Sets the strength of the springs to \a x. - void springStrength(double x) { m_springStrength = ((x > 0)? x : 1);} - - //! Returns the strength of the repulsive forces. - double repForcesStrength() const { return m_repForcesStrength; } - - //! Sets the strength of the repulsive forces to \a x. - void repForcesStrength(double x) { m_repForcesStrength =((x > 0)? x : 1);} - - //! Returns the current setting of option repulsiveForcesCalculation. - /** - * This option defines how to calculate repulsive forces. - * Possible values: - * - \a rfcExact: exact calculation (slow) - * - \a rfcGridApproximation: grid approxiamtion (inaccurate) - * - \a rfcNMM: like in NMM (= New Multipole Method; fast and accurate) - */ - RepulsiveForcesMethod repulsiveForcesCalculation() const { - return m_repulsiveForcesCalculation; - } - - //! Sets the option repulsiveForcesCalculation to \a rfc. - void repulsiveForcesCalculation(RepulsiveForcesMethod rfc) { - m_repulsiveForcesCalculation = rfc; - } - - //! Returns the stop criterion. - /** - * Possible values: - * - \a rscFixedIterations: stop if fixedIterations() is reached - * - \a rscThreshold: stop if threshold() is reached - * - \a rscFixedIterationsOrThreshold: stop if fixedIterations() or threshold() - * is reached - */ - StopCriterion stopCriterion() const { return m_stopCriterion; } - - //! Sets the stop criterion to \a rsc. - void stopCriterion(StopCriterion rsc) { m_stopCriterion = rsc; } - - //! Returns the threshold for the stop criterion. - /** - * (If the average absolute value of all forces in - * an iteration is less then threshold() then stop.) - */ - double threshold() const { return m_threshold; } - - //! Sets the threshold for the stop criterion to \a x. - void threshold(double x) {m_threshold = ((x > 0) ? x : 0.1);} - - //! Returns the fixed number of iterations for the stop criterion. - int fixedIterations() const { return m_fixedIterations; } - - //! Sets the fixed number of iterations for the stop criterion to \a n. - void fixedIterations(int n) { m_fixedIterations = ((n >= 1) ? n : 1);} - - //! Returns the scaling factor for the forces. - double forceScalingFactor() const { return m_forceScalingFactor; } - - //! Sets the scaling factor for the forces to \ f. - void forceScalingFactor(double f) { m_forceScalingFactor = ((f > 0) ? f : 1);} - - //! Returns the current setting of option coolTemperature. - /** - * If set to true, forces are scaled by coolValue()^(actual iteration) * - * forceScalingFactor(); otherwise forces are scaled by forceScalingFactor(). - */ - bool coolTemperature() const { return m_coolTemperature; } - - //! Sets the option coolTemperature to \a b. - void coolTemperature(bool b) { m_coolTemperature = b; } - - //! Returns the current setting of option coolValue. - /** - * This option defines the value by which forces are decreased - * if coolTemperature is true. - */ - double coolValue() const { return m_coolValue; } - - //! Sets the option coolValue to \a x. - void coolValue(double x) { m_coolValue = (((x >0 )&&(x<=1) )? x : 0.99);} - - - //! Returns the current setting of option initialPlacementForces. - /** - * This option defines how the initial placement is done. - * Possible values: - * - \a ipfUniformGrid: uniform on a grid - * - \a ipfRandomTime: random based on actual time - * - \a ipfRandomRandIterNr: random based on randIterNr() - * - \a ipfKeepPositions: no change in placement - */ - InitialPlacementForces initialPlacementForces() const { - return m_initialPlacementForces; - } - - //! Sets the option initialPlacementForces to \a ipf. - void initialPlacementForces(InitialPlacementForces ipf) { - m_initialPlacementForces = ipf; - } - - - /** @} - * @name Options for the postprocessing step - * @{ - */ - - //! Returns the current setting of option resizeDrawing. - /** - * If set to true, the resulting drawing is resized so that the average edge - * length is the desired edge length times resizingScalar(). - */ - bool resizeDrawing() const { return m_resizeDrawing; } - - //! Sets the option resizeDrawing to \a b. - void resizeDrawing(bool b) { m_resizeDrawing = b; } - - //! Returns the current setting of option resizingScalar. - /** - * This option defines a parameter to scale the drawing if - * resizeDrawing() is true. - */ - double resizingScalar() const { return m_resizingScalar; } - - //! Sets the option resizingScalar to \a s. - void resizingScalar(double s) { m_resizingScalar = ((s > 0) ? s : 1);} - - //! Returns the number of iterations for fine tuning. - int fineTuningIterations() const { return m_fineTuningIterations; } - - //! Sets the number of iterations for fine tuning to \a n. - void fineTuningIterations(int n) { m_fineTuningIterations =((n >= 0) ? n : 0);} - - //! Returns the curent setting of option fineTuneScalar. - /** - * This option defines a parameter for scaling the forces in the - * fine-tuning iterations. - */ - double fineTuneScalar() const { return m_fineTuneScalar; } - - //! Sets the option fineTuneScalar to \a s - void fineTuneScalar(double s) { m_fineTuneScalar = ((s >= 0) ? s : 1);} - - //! Returns the current setting of option adjustPostRepStrengthDynamically. - /** - * If set to true, the strength of the repulsive force field is calculated - * dynamically by a formula depending on the number of nodes; otherwise the - * strength are scaled by PostSpringStrength and PostStrengthOfRepForces. - */ - bool adjustPostRepStrengthDynamically() const { - return m_adjustPostRepStrengthDynamically; - } - - //! Sets the option adjustPostRepStrengthDynamically to \a b. - void adjustPostRepStrengthDynamically(bool b) { - m_adjustPostRepStrengthDynamically = b; - } - - //! Returns the strength of the springs in the postprocessing step. - double postSpringStrength() const { return m_postSpringStrength; } - - //! Sets the strength of the springs in the postprocessing step to \a x. - void postSpringStrength(double x) { m_postSpringStrength = ((x > 0)? x : 1);} - - //! Returns the strength of the repulsive forces in the postprocessing step. - double postStrengthOfRepForces() const { return m_postStrengthOfRepForces; } - - //! Sets the strength of the repulsive forces in the postprocessing step to \a x. - void postStrengthOfRepForces(double x) { - m_postStrengthOfRepForces = ((x > 0)? x : 1); - } - - - /** @} - * @name Options for repulsive force approximation methods - * @{ - */ - - //! Returns the current setting of option frGridQuotient. - /** - * The number k of rows and columns of the grid is sqrt(|V|) / frGridQuotient(). - * (Note that in [Fruchterman,Reingold] frGridQuotient is 2.) - */ - int frGridQuotient() const {return m_frGridQuotient;} - - //! Sets the option frGridQuotient to \a p. - void frGridQuotient(int p) { m_frGridQuotient = ((0<=p) ? p : 2);} - - //! Returns the current setting of option nmTreeConstruction. - /** - * This option defines how the reduced bucket quadtree is constructed. - * Possible values: - * - \a rtcPathByPath: path by path construction - * - \a rtcSubtreeBySubtree: subtree by subtree construction - */ - ReducedTreeConstruction nmTreeConstruction() const { return m_NMTreeConstruction; } - - //! Sets the option nmTreeConstruction to \a rtc. - void nmTreeConstruction(ReducedTreeConstruction rtc) { m_NMTreeConstruction = rtc; } - - //! Returns the current setting of option nmSmallCell. - /** - * This option defines how the smallest quadratic cell that surrounds - * the particles of a node in the reduced bucket quadtree is calculated. - * Possible values: - * - \a scfIteratively: iteratively (in constant time) - * - \a scfAluru: by the formula by Aluru et al. (in constant time) - */ - SmallestCellFinding nmSmallCell() const { return m_NMSmallCell; } - - //! Sets the option nmSmallCell to \a scf. - void nmSmallCell(SmallestCellFinding scf) { m_NMSmallCell = scf; } - - //! Returns the current setting of option nmParticlesInLeaves. - /** - * Defines the maximal number of particles that are contained in - * a leaf of the reduced bucket quadtree. - */ - int nmParticlesInLeaves() const { return m_NMParticlesInLeaves; } - - //! Sets the option nmParticlesInLeaves to \a n. - void nmParticlesInLeaves(int n) { m_NMParticlesInLeaves = ((n>= 1)? n : 1);} - - //! Returns the precision \a p for the p-term multipole expansions. - int nmPrecision() const { return m_NMPrecision; } - - //! Sets the precision for the multipole expansions to \ p. - void nmPrecision(int p) { m_NMPrecision = ((p >= 1 ) ? p : 1);} - - //! @} - -private: - - //high level options - bool m_useHighLevelOptions; //!< The option for using high-level options. - PageFormatType m_pageFormat; //!< The option for the page format. - double m_unitEdgeLength; //!< The unit edge length. - bool m_newInitialPlacement; //!< The option for new initial placement. - QualityVsSpeed m_qualityVersusSpeed; //!< The option for quality-vs-speed trade-off. - - //low level options - //general options - int m_randSeed; //!< The random seed. - EdgeLengthMeasurement m_edgeLengthMeasurement; //!< The option for edge length measurement. - AllowedPositions m_allowedPositions; //!< The option for allowed positions. - int m_maxIntPosExponent; //!< The option for the used exponent. - - //options for divide et impera step - double m_pageRatio; //!< The desired page ratio. - int m_stepsForRotatingComponents; //!< The number of rotations. - TipOver m_tipOverCCs; //!< Option for tip-over of connected components. - double m_minDistCC; //!< The separation between connected components. - PreSort m_presortCCs; //!< The option for presorting connected components. - - //options for multilevel step - bool m_singleLevel; //!< Option for pure single level. - int m_minGraphSize; //!< The option for minimal graph size. - GalaxyChoice m_galaxyChoice; //!< The selection of galaxy nodes. - int m_randomTries; //!< The number of random tries. - MaxIterChange m_maxIterChange; //!< The option for how to change MaxIterations. - //!< If maxIterChange != micConstant, the iterations are decreased - //!< depending on the level, starting from - //!< ((maxIterFactor()-1) * fixedIterations()) - int m_maxIterFactor; //!< The factor used for decreasing MaxIterations. - InitialPlacementMult m_initialPlacementMult; //!< The option for creating initial placement. - - //options for force calculation step - ForceModel m_forceModel; //!< The used force model. - double m_springStrength; //!< The strengths of springs. - double m_repForcesStrength; //!< The strength of repulsive forces. - RepulsiveForcesMethod m_repulsiveForcesCalculation; //!< Option for how to calculate repulsive forces. - StopCriterion m_stopCriterion; //!< The stop criterion. - double m_threshold; //!< The threshold for the stop criterion. - int m_fixedIterations; //!< The fixed number of iterations for the stop criterion. - double m_forceScalingFactor; //!< The scaling factor for the forces. - bool m_coolTemperature; //!< The option for how to scale forces. - double m_coolValue; //!< The value by which forces are decreased. - InitialPlacementForces m_initialPlacementForces; //!< The option for how the initial placement is done. - - //options for postprocessing step - bool m_resizeDrawing; //!< The option for resizing the drawing. - double m_resizingScalar; //!< Parameter for resizing the drawing. - int m_fineTuningIterations; //!< The number of iterations for fine tuning. - double m_fineTuneScalar; //!< Parameter for scaling forces during fine tuning. - bool m_adjustPostRepStrengthDynamically; //!< The option adjustPostRepStrengthDynamically. - double m_postSpringStrength; //!< The strength of springs during postprocessing. - double m_postStrengthOfRepForces; //!< The strength of repulsive forces during postprocessing. - - //options for repulsive force approximation methods - int m_frGridQuotient; //!< The grid quotient. - ReducedTreeConstruction m_NMTreeConstruction; //!< The option for how to construct reduced bucket quadtree. - SmallestCellFinding m_NMSmallCell; //!< The option for how to calculate smallest quadtratic cells. - int m_NMParticlesInLeaves; //!< The maximal number of particles in a leaf. - int m_NMPrecision; //!< The precision for multipole expansions. - - //other variables - double max_integer_position; //!< The maximum value for an integer position. - double cool_factor; //!< Needed for scaling the forces if coolTemperature is true. - double average_ideal_edgelength; //!< Measured from center to center. - double boxlength; //!< Holds the length of the quadratic comput. box. - int number_of_components; //!< The number of components of the graph. - DPoint down_left_corner; //!< Holds down left corner of the comput. box. - NodeArray radius; //!< Holds the radius of the surrounding circle for each node. - double time_total; //!< The runtime (=CPU-time) of the algorithm in seconds. - - FruchtermanReingold FR; //!< Class for repulsive force calculation (Fruchterman, Reingold). - NMM NM; //!< Class for repulsive force calculation. - - - //------------------- most important functions ---------------------------- - - //! Calls the divide (decomposition into connected components) and impera (drawing and packing of the componenets) step. - void call_DIVIDE_ET_IMPERA_step( - Graph& G, - NodeArray& A, - EdgeArray& E); - - //! Calls the multilevel step for subGraph \a G. - void call_MULTILEVEL_step_for_subGraph( - Graph& G, - NodeArray& A, - EdgeArray& E, - int comp_index); - - //! Calls the force calculation step for \a G, \a A, \a E. - /** - * If act_level is 0 and resizeDrawing is true the drawing is resized. - * Furthermore, the maximum number of force calc. steps is calculated - * depending on MaxIterChange, act_level, and max_level. - */ - void call_FORCE_CALCULATION_step ( - Graph& G, - NodeArray& A, - EdgeArray& E, - int act_level, - int max_level); - - //! Calls the postprocessing step. - void call_POSTPROCESSING_step( - Graph& G, - NodeArray& A, - EdgeArray& E, - NodeArray& F, - NodeArray& F_attr, - NodeArray& F_rep, - NodeArray& last_node_movement); - - - //---------------- functions for pre/pos-processing ----------------------------- - - //! All parameter options are set to the default values. - void initialize_all_options(); - - //! Updates several low level parameter options due to the settings of the high level parameter options. - void update_low_level_options_due_to_high_level_options_settings(); - - //! Imports for each node \a v of \a G its width, height and position(given from \a GA) in \a A. - void import_NodeAttributes( - const Graph& G, - GraphAttributes& GA, - NodeArray& A); - - //! Imports for each edge e of G its desired length given via edgeLength. - void import_EdgeAttributes ( - const Graph& G, - const EdgeArray& edgeLength, - EdgeArray & E); - - //! Sets the individual ideal edge length for each edge \a e. - void init_ind_ideal_edgelength( - const Graph& G, - NodeArray&A, - EdgeArray & E); - - //! The radii of the surrounding circles of the bounding boxes are computed. - void set_radii(const Graph& G,NodeArray& A); - - //! Exports for each node \a v in \a G_reduced the position of the original_node in \a G. - void export_NodeAttributes( - Graph& G_reduced, - NodeArray& A_reduced, - GraphAttributes& GA); - - //! Creates a simple and loopfree copy of \a G and stores the corresponding node / edge attributes. - /** - * The corresponding node / edge attributes are stored in \a A_reduced and - * \a E_reduced; the links to the copy_node and original node are stored in \a A, - * \a A_reduced, too. - */ - void make_simple_loopfree( - const Graph& G, - NodeArray& A, - EdgeArrayE, - Graph& G_reduced, - NodeArray& A_reduced, - EdgeArray& E_reduced); - - //! Deletes parallel edges of \a G_reduced. - /** - * Saves for each set of parallel edges one representative edge in \a S and - * saves in \a new_edgelength the new edge length of this edge in \a G_reduced. - */ - void delete_parallel_edges( - const Graph& G, - EdgeArray& E, - Graph& G_reduced, - List& S, - EdgeArray& new_edgelength); - - //! Sets for each edge \a e of \a G_reduced in \a S its edgelength to \a new_edgelength[\a e]. - /** - * Also stores this information in \a E_reduced. - */ - void update_edgelength( - List& S, - EdgeArray & new_edgelength, - EdgeArray& E_reduced); - - //! Returns the value for the strength of the repulsive forces. - /** - * Used in the postprocessing step; depending on \a n = G.numberOfNodes(). - */ - double get_post_rep_force_strength(int n) { - return min(0.2,400.0/double(n)); - } - - //! Makes the node positions integers. - /** - * If allowedPositions == apInteger the values are in a range depending on - * G.number_of_nodes() and the average_ideal_edgelength. If allowed_positions - * == apExponent the values are integers in a bounded integer range. - */ - void make_positions_integer(Graph& G, NodeArray& A); - - //! Creates a simple drawing of \a AG in postscript format and saves it in file \a ps_file. - void create_postscript_drawing(GraphAttributes& AG, char* ps_file); - - - //------------------ functions for divide et impera step ----------------------- - - //! Constructs the list of connected components of G. - /** - * Also constructs the corresponding lists with the node / edge attributes - * (containing a pointer to the original node in \a G for each node in a subgraph). - */ - void create_maximum_connected_subGraphs( - Graph& G, - NodeArray&A, - EdgeArray&E, - Graph G_sub[], - NodeArray A_sub[], - EdgeArray E_sub[], - NodeArray& component); - - //! The drawings of the subgraphs are packed. - /** - * This is done such that the subgraphs do not overlap and fit into a small - * box with the desired aspect ratio. - */ - void pack_subGraph_drawings( - NodeArray& A, - Graph G_sub[], - NodeArray A_sub[]); - - //! The bounding rectangles of all connected componenents of \a G are calculated and stored in \a R. - void calculate_bounding_rectangles_of_components( - List& R, - Graph G_sub[], - NodeArray A_sub[]); - - //! The bounding rectangle of the componenet_index-th. component of G is returned. - Rectangle calculate_bounding_rectangle( - Graph& G, - NodeArray& A, - int componenet_index); - - /** - * If number_of_components > 1, the subgraphs \a G_sub are rotated and skipped to - * find bounding rectangles with minimum area. The information is saved in \a R and - * the node positions in \a A_sub are updated. If number_of_components == 1 a rotation - * with minimal aspect ratio is found instead. - */ - void rotate_components_and_calculate_bounding_rectangles( - List&R, - Graph G_sub[], - NodeArray A_sub[]); - - /** - * Returns the area (aspect ratio area) of a rectangle with width w and height h - * if comp_nr > 1 ( comp_nr == 1). - */ - double calculate_area(double width,double height,int comp_nr) { - if (comp_nr == 1) //calculate aspect ratio area of the rectangle - { - double ratio = width/height; - - if(ratio < pageRatio()) //scale width - return ( width * height * (pageRatio()/ratio)); - else //scale height - return (width * height * (ratio/pageRatio())); - } - else //calculate area of the rectangle - return width * height; - } - - /** - * The positions of the nodes in the subgraphs are calculated by using the - * information stored in R and are exported to A. (The coordinates of components - * which surrounding rectangles have been tipped over in the packing step are - * tipped over here,too) - */ - void export_node_positions( - NodeArray& A, - List& R, - Graph G_sub[], - NodeArray A_sub[]); - - //! Frees dynamically allocated memory for the connected component subgraphs. - void delete_all_subGraphs( - Graph G_sub[], - NodeArray A_sub[], - EdgeArray E_sub[]) - { - delete [] G_sub; - delete [] A_sub; - delete [] E_sub; - } - - - - //------------------ functions for multilevel step -------------------------- - - /** - * Returns the maximum number of iterations for the force calc. step depending - * on act_level, max_level, FixedIterations, MaxIterChange, MaxIterFactor, - * and the number of nodes of the Graph in the actual mutilevel. - */ - int get_max_mult_iter(int act_level, int max_level, int node_nr); - - - //------------------ functions for force calculation --------------------------- - - //! The forces are calculated here. - void calculate_forces( - Graph& G, - NodeArray& A, - EdgeArray& E,NodeArray& F, - NodeArray& F_attr, - NodeArray& F_rep, - NodeArray& last_node_movement, - int iter, - int fine_tuning_step); - - //! The length of the computational box in the first iteration is set (down left corner is at (0,0). - void init_boxlength_and_cornercoordinate(Graph& G,NodeArray& A); - - //! The initial placements of the nodes are created by using initialPlacementForces(). - void create_initial_placement (Graph& G,NodeArray& A); - - //! Sets all entries of \a F to (0,0). - void init_F (Graph& G, NodeArray& F); - - - //! Make initializations for the data structures that are used in the choosen class for rep. force calculation. - void make_initialisations_for_rep_calc_classes( - Graph& G/*, - NodeArray &A, - NodeArray& F_rep*/); - - //! Calculates repulsive forces for each node. - void calculate_repulsive_forces( - Graph &G, - NodeArray& A, - NodeArray& F_rep) - { - if(repulsiveForcesCalculation() == rfcExact ) - FR.calculate_exact_repulsive_forces(G,A,F_rep); - else if(repulsiveForcesCalculation() == rfcGridApproximation ) - FR.calculate_approx_repulsive_forces(G,A,F_rep); - else //repulsiveForcesCalculation() == rfcNMM - NM.calculate_repulsive_forces(G,A,F_rep); - } - - - //! Deallocates dynamically allocated memory of the choosen rep. calculation class. - void deallocate_memory_for_rep_calc_classes() - { - if(repulsiveForcesCalculation() == rfcNMM) - NM.deallocate_memory(); - } - - //! Calculates attractive forces for each node. - void calculate_attractive_forces( - Graph& G, - NodeArray & A, - EdgeArray& E, - NodeArray& F_attr); - - //! Returns the attractive force scalar. - double f_attr_scalar (double d,double ind_ideal_edge_length); - - //! Add attractive and repulsive forces for each node. - void add_attr_rep_forces( - Graph& G, - NodeArray& F_attr, - NodeArray& F_rep, - NodeArray& F, - int iter, - int fine_tuning_step); - - //! Move the nodes. - void move_nodes(Graph& G,NodeArray& A,NodeArray& F); - - //! Computes a new tight computational square-box. - /** - * (Guaranteeing, that all midpoints are inside the square.) - */ - void update_boxlength_and_cornercoordinate(Graph& G,NodeArray& A); - - //! Describes the max. radius of a move in one time step, depending on the number of iterations. - double max_radius(int iter) { - return (iter == 1) ? boxlength/1000 : boxlength/5; - } - - //! The average_ideal_edgelength for all edges is computed. - void set_average_ideal_edgelength(Graph& G,EdgeArray& E); - - /** - * Calculates the average force on each node in the actual iteration, which is - * needed if StopCriterion is scThreshold() or scFixedIterationsOrThreshold(). - */ - double get_average_forcevector_length (Graph& G, NodeArray& F); - - /** - * Depending on the direction of \a last_node_movement[\a v], the length of the next - * displacement of node \a v is restricted. - */ - void prevent_oscilations( - Graph& G, - NodeArray& F, - NodeArray& - last_node_movement, - int iter); - - //! Calculates the angle between \a PQ and \a PS in [0,2pi). - double angle(DPoint& P, DPoint& Q, DPoint& R); - - //! \a last_node_movement is initialized to \a F (used after first iteration). - void init_last_node_movement( - Graph& G, - NodeArray& F, - NodeArray& last_node_movement); - - /** - * If resizeDrawing is true, the drawing is adapted to the ideal average - * edge length by shrinking respectively expanding the drawing area. - */ - void adapt_drawing_to_ideal_average_edgelength( - Graph& G, - NodeArray& A, - EdgeArray& E); - - /** - * The force is restricted to have values within the comp. box (needed for - * exception handling, if the force is too large for further calculations). - */ - void restrict_force_to_comp_box(DPoint& force) { - double x_min = down_left_corner.m_x; - double x_max = down_left_corner.m_x+boxlength; - double y_min = down_left_corner.m_y; - double y_max = down_left_corner.m_y+boxlength; - if (force.m_x < x_min ) - force.m_x = x_min; - else if (force.m_x > x_max ) - force.m_x = x_max; - if (force.m_y < y_min ) - force.m_y = y_min; - else if (force.m_y > y_max ) - force.m_y = y_max; - } - - - //------------------- functions for analytic information ------------------------- - - //! Sets time_total to zero. - void init_time() { time_total = 0; } -}; - -} //end namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/energybased/FastMultipoleEmbedder.h b/ext/OGDF/ogdf/energybased/FastMultipoleEmbedder.h deleted file mode 100644 index 8dce27956..000000000 --- a/ext/OGDF/ogdf/energybased/FastMultipoleEmbedder.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Fast-Multipole-Embedder layout algorithm. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FAST_MULTIPOLE_EMBEDDER_H -#define OGDF_FAST_MULTIPOLE_EMBEDDER_H - -#include -#include -#include - -namespace ogdf { - -class ArrayGraph; -class LinearQuadtree; -class LinearQuadtreeExpansion; -class FMEThreadPool; -class FMEThread; -struct FMEGlobalOptions; -class GalaxyMultilevel; - -class OGDF_EXPORT FastMultipoleEmbedder : public LayoutModule -{ -public: - //! constructor - FastMultipoleEmbedder(); - - //! destructor - ~FastMultipoleEmbedder(); - - //! Calls the algorithm for graph \a MLG. - //Does not do anything smart, can be safely removed - //void call(MultilevelGraph &MLG); - - //! Calls the algorithm for graph \a G with the given edgelength and returns the layout information in \a nodeXPosition, nodeYPosition. - void call( - const Graph& G, - NodeArray& nodeXPosition, - NodeArray& nodeYPosition, - const EdgeArray& edgeLength, - const NodeArray& nodeSize); - - //! Calls the algorithm for graph \a GA with the given edgelength and returns the layout information in \a GA. - void call(GraphAttributes &GA, const EdgeArray& edgeLength, const NodeArray& nodeSize); - - //! Calls the algorithm for graph \a GA and returns the layout information in \a GA. - void call(GraphAttributes &GA); - - //! sets the maximum number of iterations - void setNumIterations(__uint32 numIterations) { m_numIterations = numIterations; } - - //! sets the number of coefficients for the expansions. default = 4 - void setMultipolePrec(__uint32 precision) { m_precisionParameter = precision; } - - //! if true, layout algorithm will randomize the layout in the beginning - void setRandomize(bool b) { m_randomize = b; } - - //! - void setDefaultEdgeLength(float edgeLength) { m_defaultEdgeLength = edgeLength; } - - //! - void setDefaultNodeSize(float nodeSize) { m_defaultNodeSize = nodeSize; } - - //! - void setNumberOfThreads(__uint32 numThreads) { m_maxNumberOfThreads = numThreads; } - - //void setEnablePostProcessing(bool b) { m_doPostProcessing = b; } -private: - void initOptions(); - - void runMultipole(); - - void runSingle(); - - //! runs the simulation with the given number of iterations - void run(__uint32 numIterations); - - //! allocates the memory - void allocate(__uint32 numNodes, __uint32 numEdges); - - //! frees the memory - void deallocate(); - - __uint32 m_numIterations; - - ArrayGraph* m_pGraph; - - FMEThreadPool* m_threadPool; - - FMEGlobalOptions* m_pOptions; - - __uint32 m_precisionParameter; - - bool m_randomize; - - float m_defaultEdgeLength; - - float m_defaultNodeSize; - - __uint32 m_numberOfThreads; - - __uint32 m_maxNumberOfThreads; -}; - - -class OGDF_EXPORT FastMultipoleMultilevelEmbedder : public LayoutModule -{ -public: - //! Constructor, just sets number of maximum threads - FastMultipoleMultilevelEmbedder() : m_iMaxNumThreads(1) {} - //! Calls the algorithm for graph \a GA and returns the layout information in \a GA. - void call(GraphAttributes &GA); - - //! sets the bound for the number of nodes for multilevel step - void multilevelUntilNumNodesAreLess(int nodesBound) { m_multiLevelNumNodesBound = nodesBound; } - - void maxNumThreads(int numThreads) { m_iMaxNumThreads = numThreads; } -private: - //! internal function to compute a good edgelength - void computeAutoEdgeLength(const GraphAttributes& GA, EdgeArray& edgeLength, float factor = 1.0f); - - //! internal main function for the multilevel layout - void run(GraphAttributes& GA, const EdgeArray& edgeLength); - - //! creates all multilevels - void createMultiLevelGraphs(Graph* pGraph, GraphAttributes& GA, const EdgeArray& edgeLength); - - //! init the original graphs multilevel - void initFinestLevel(GraphAttributes &GA, const EdgeArray& edgeLength); - - //! calls the fast multipole embedder on current level - void layoutCurrentLevel(); - - //! assigns the nodes in the current level coords by coarser level - void assignPositionsFromPrevLevel(); - - //! writes the current level to graph attributes. used for output - void writeCurrentToGraphAttributes(GraphAttributes& GA); - - //! refine - void nextLevel(); - - //! initialize datastructure by current level - void initCurrentLevel(); - - //! clean up the multilevel graphs - void deleteMultiLevelGraphs(); - - //! for debugging only - void dumpCurrentLevel(const String& filename); - - //! computes the maximum number of iterations by level nr - __uint32 numberOfIterationsByLevelNr(__uint32 levelNr); - - int m_iMaxNumThreads; - int m_iNumLevels; - int m_multiLevelNumNodesBound; - - GalaxyMultilevel* m_pCurrentLevel; - GalaxyMultilevel* m_pFinestLevel; - GalaxyMultilevel* m_pCoarsestLevel; - - Graph* m_pCurrentGraph; - NodeArray* m_pCurrentNodeXPos; - NodeArray* m_pCurrentNodeYPos; - EdgeArray* m_pCurrentEdgeLength; - NodeArray* m_pCurrentNodeSize; - NodeArray m_adjustedNodeSize; - int m_iCurrentLevelNr; - - Graph* m_pLastGraph; - NodeArray* m_pLastNodeXPos; - NodeArray* m_pLastNodeYPos; -}; - -} // end of namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/energybased/GEMLayout.h b/ext/OGDF/ogdf/energybased/GEMLayout.h deleted file mode 100644 index 0023498b1..000000000 --- a/ext/OGDF/ogdf/energybased/GEMLayout.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GEMLayout. - * - * Fast force-directed layout algorithm (GEMLayout) - * based on Frick et al.'s algorithm. - * - * \author Christoph Buchheim - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FAST_LAYOUT_H -#define OGDF_FAST_LAYOUT_H - -#include -#include - - -namespace ogdf { - - class OGDF_EXPORT GraphCopy; - class OGDF_EXPORT GraphCopyAttributes; - -//--------------------------------------------------------- -// GEMLayout -// -// Fast force-directed layout algorithm. See -// - A. Frick, A. Ludwig, H. Mehldau: "A Fast Adaptive -// Layout Algorithm for Undirected Graphs" -// -//--------------------------------------------------------- - -//! The energy-based GEM layout algorithm. -/** - * The implementation used in GEMLayout is based on the following publication: - * - * Arne Frick, Andreas Ludwig, Heiko Mehldau: A Fast Adaptive %Layout - * Algorithm for Undirected Graphs. Proc. %Graph Drawing 1994, - * LNCS 894, pp. 388-403, 1995. - * - *

    Optional parameters

    - * GEM layout provides the following optional parameters. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    numberOfRoundsint20000 - * The maximal number of rounds per node. - *
    minimalTemperaturedouble0.005 - * The minimal temperature. - *
    initialTemperaturedouble10.0 - * The initial temperature. - *
    gravitationalConstantdouble1/16 - * The gravitational constant. - *
    desiredLengthdouble5.0 - * The desired edge length. - *
    maximalDisturbancedouble0 - * The maximal disturbance. - *
    rotationAngledoublepi/3.0 - * The opening angle for rotations. - *
    oscillationAngledoublepi/2.0 - * The opening angle for oscillations. - *
    rotationSensitivitydouble0.01 - * The rotation sensitivity. - *
    oscillationSensitivitydouble0.3 - * The oscillation sensitivity. - *
    attractionFormulaint1 - * The used formula for attraction (1 = Fruchterman / Reingold, 2 = GEM). - *
    minDistCCdouble20 - * The minimal distance between connected components. - *
    pageRatiodouble1.0 - * The page ratio used for the layout of connected components. - *
    -*/ -class OGDF_EXPORT GEMLayout : public LayoutModule -{ - - // algorithm parameters (see below) - - int m_numberOfRounds; //!< The maximal number of rounds per node. - double m_minimalTemperature; //!< The minimal temperature. - double m_initialTemperature; //!< The initial temperature. - double m_gravitationalConstant; //!< The gravitational constant. - double m_desiredLength; //!< The desired edge length. - double m_maximalDisturbance; //!< The maximal disturbance. - double m_rotationAngle; //!< The opening angle for rotations. - double m_oscillationAngle; //!< The opening angle for oscillations. - double m_rotationSensitivity; //!< The rotation sensitivity. - double m_oscillationSensitivity;//!< The oscillation sensitivity. - int m_attractionFormula; //!< The used formula for attraction. - double m_minDistCC; //!< The minimal distance between connected components. - double m_pageRatio; //!< The page ratio used for the layout of connected components. - - // node data used by the algorithm - - NodeArray m_impulseX; //!< x-coordinate of the last impulse of the node - NodeArray m_impulseY; //!< y-coordinate of the last impulse of the node - NodeArray m_localTemperature; //!< local temperature of the node - NodeArray m_skewGauge; //!< skew gauge of the node - - // other data used by the algorithm - - double m_barycenterX; //!< Weighted sum of x-coordinates of all nodes. - double m_barycenterY; //!< Weighted sum of y-coordinates of all nodes. - double m_newImpulseX; //!< x-coordinate of the new impulse of the current node. - double m_newImpulseY; //!< y-coordinate of the new impulse of the current node. - double m_globalTemperature; //!< Average of all node temperatures. - double m_cos; //!< Cosine of m_oscillationAngle / 2. - double m_sin; //!< Sine of (pi + m_rotationAngle) / 2. - -public: - - //! Creates an instance of GEM layout. - GEMLayout(); - - //! Copy constructor. - GEMLayout(const GEMLayout &fl); - - // destructor - ~GEMLayout(); - - //! Assignment operator. - GEMLayout &operator=(const GEMLayout &fl); - - //! Calls the layout algorithm for graph attributes \a GA. - void call(GraphAttributes &GA); - - //! Returns the maximal number of rounds per node. - int numberOfRounds() const { return m_numberOfRounds; } - - //! Sets the maximal number of round per node to \a n. - void numberOfRounds(int n) { - m_numberOfRounds = (n < 0) ? 0 : n; - } - - //! Returns the minimal temperature. - double minimalTemperature() const { return m_minimalTemperature; } - - //! Sets the minimal temperature to \a x. - void minimalTemperature(double x) { - m_minimalTemperature = (x < 0) ? 0 : x; - } - - //! Returns the initial temperature. - double initialTemperature() const { return m_initialTemperature; } - - //! Sets the initial temperature to \a x; must be >= minimalTemperature. - void initialTemperature(double x) { - m_initialTemperature = (x < m_minimalTemperature) ? m_minimalTemperature : x; - } - - //! Returns the gravitational constant. - double gravitationalConstant() const { return m_gravitationalConstant; } - - //! Sets the gravitational constant to \a x; must be >= 0. - //! Attention! Only (very) small values give acceptable results. - void gravitationalConstant(double x) { - m_gravitationalConstant = (x < 0) ? 0 : x; - } - - //! Returns the desired edge length. - double desiredLength() const { return m_desiredLength; } - - //! Sets the desired edge length to \a x; must be >= 0. - void desiredLength(double x) { - m_desiredLength = (x < 0) ? 0 : x; - } - - //! Returns the maximal disturbance. - double maximalDisturbance() const { return m_maximalDisturbance; } - - //! Sets the maximal disturbance to \a x; must be >= 0. - void maximalDisturbance(double x) { - m_maximalDisturbance = (x < 0) ? 0 : x; - } - - //! Returns the opening angle for rotations. - double rotationAngle() const { return m_rotationAngle; } - - //! Sets the opening angle for rotations to \a x (0 <= \a x <= pi / 2). - void rotationAngle(double x) { - if(x < 0) x = 0; - if(x > Math::pi / 2.0) x = Math::pi / 2.0; - m_rotationAngle = x; - } - - //! Returns the opening angle for oscillations. - double oscillationAngle() const { return m_oscillationAngle; } - - //! Sets the opening angle for oscillations to \a x (0 <= \a x <= pi / 2). - void oscillationAngle(double x) { - if(x < 0) x = 0; - if(x > Math::pi / 2.0) x = Math::pi / 2.0; - m_oscillationAngle = x; - } - - //! Returns the rotation sensitivity. - double rotationSensitivity() const { return m_rotationSensitivity; } - - //! Sets the rotation sensitivity to \a x (0 <= \a x <= 1). - void rotationSensitivity(double x) { - if(x < 0) x = 0; - if(x > 1) x = 1; - m_rotationSensitivity = x; - } - - //! Returns the oscillation sensitivity. - double oscillationSensitivity() const { return m_oscillationSensitivity; } - - //! Sets the oscillation sensitivity to \a x (0 <= \a x <= 1). - void oscillationSensitivity(double x) { - if(x < 0) x = 0; - if(x > 1) x = 1; - m_oscillationSensitivity = x; - } - - //! Returns the used formula for attraction (1 = Fruchterman / Reingold, 2 = GEM). - int attractionFormula() const { return m_attractionFormula; } - - //! sets the formula for attraction to \a n (1 = Fruchterman / Reingold, 2 = GEM). - void attractionFormula(int n) { - if(n == 1 || n == 2) m_attractionFormula = n; - } - - //! Returns the minimal distance between connected components. - double minDistCC() const { return m_minDistCC; } - - //! Sets the minimal distance between connected components to \a x. - void minDistCC(double x) { m_minDistCC = x; } - - //! Returns the page ratio used for the layout of connected components. - double pageRatio() const { return m_pageRatio; } - - //! Sets the page ratio used for the layout of connected components to \a x. - void pageRatio(double x) { m_pageRatio = x; } - - -private: - //! Returns the length of the vector (\a x,\a y). - double length(double x,double y = 0) const { - return sqrt(x * x + y * y); - } - - //! Returns the weight of node \a v according to its degree. - double weight(node v) const { - return (double)(v->degree()) / 2.5 + 1.0; - } - - //! Computes the new impulse for node \a v. - void computeImpulse(GraphCopy &GC, GraphCopyAttributes &AGC,node v); - - //! Updates the node data for node \a v. - void updateNode(GraphCopy &GC, GraphCopyAttributes &AGC,node v); - - OGDF_NEW_DELETE -}; - -} // end namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/energybased/MultilevelLayout.h b/ext/OGDF/ogdf/energybased/MultilevelLayout.h deleted file mode 100644 index 83512a6e2..000000000 --- a/ext/OGDF/ogdf/energybased/MultilevelLayout.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MultilevelLayout which realizes a - * wrapper for the multilevel layout computation using the - * Modular Multilevel Mixer. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MULTILEVEL_LAYOUT_H -#define OGDF_MULTILEVEL_LAYOUT_H - - -#include "ogdf/basic/NodeArray.h" -#include "ogdf/basic/GraphAttributes.h" -#include "ogdf/energybased/multilevelmixer/ModularMultilevelMixer.h" -#include "ogdf/energybased/multilevelmixer/InitialPlacer.h" -#include "ogdf/energybased/multilevelmixer/ScalingLayout.h" -#include "ogdf/packing/ComponentSplitterLayout.h" -#include "ogdf/basic/PreprocessorLayout.h" -#include "ogdf/basic/Constraints.h" - -namespace ogdf { - - class OGDF_EXPORT MultilevelLayout : public LayoutModule - { - public: - //! Constructor - MultilevelLayout(); - - //! Destructor - virtual ~MultilevelLayout() {delete m_pp;} - - //! Calculates a drawing for the Graph GA. - void call(GraphAttributes &GA); - - //! Calculates a drawing for the Graph GA and tries to satisfy - //! the constraints in CG if supported. - virtual void call(GraphAttributes &GA, GraphConstraints &GC); - - //Setting of the three main phases' methods - //! Sets the single level layout - void setLayout(LayoutModule* L); - //! Sets the method used for coarsening - void setMultilevelBuilder(MultilevelBuilder* B); - //! Sets the placement method used when refining the levels again. - void setPlacer(InitialPlacer* P); - - - private: - ModularMultilevelMixer* m_mmm; - ScalingLayout* m_sc; - ComponentSplitterLayout* m_cs; - PreprocessorLayout* m_pp; - }; -} //end namespace ogdf -#endif diff --git a/ext/OGDF/ogdf/energybased/SpringEmbedderFR.h b/ext/OGDF/ogdf/energybased/SpringEmbedderFR.h deleted file mode 100644 index fadbceb96..000000000 --- a/ext/OGDF/ogdf/energybased/SpringEmbedderFR.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Spring-Embedder (Fruchterman,Reingold) - * algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SPRING_EMBEDDER_FR_H -#define OGDF_SPRING_EMBEDDER_FR_H - - -#include -#include - - -namespace ogdf { - - - class OGDF_EXPORT GraphCopyAttributes; - class OGDF_EXPORT GraphCopy; - - -//! The spring-embedder layout algorithm by Fruchterman and Reingold. -/** - * The implementation used in SpringEmbedderFR is based on - * the following publication: - * - * Thomas M. J. Fruchterman, Edward M. Reingold: %Graph Drawing by Force-directed - * Placement. Software - Practice and Experience 21(11), pp. 1129-1164, 1991. - * - *

    Optional parameters

    - * Fruchterman/Reingold layout provides the following optional parameters. - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    iterationsint400 - * The number of iterations performed in the optimization. - *
    noisebooltrue - * If set to true, (small) random perturbations are performed. - *
    minDistCCdouble20.0 - * The minimum distance between connected components. - *
    pageRatiodouble1.0 - * The page ratio. - *
    scaling #Scaling #scScaleFunction - * The scaling method for scaling the inital layout. - *
    scaleFunctionFactordouble8.0 - * The scale function factor (used if scaling = scScaleFunction). - *
    userBoundingBoxrectangle(0.0,100.0,0.0,100.0) - * The user bounding box for scaling (used if scaling = scUserBoundingBox). - *
    - */ -class OGDF_EXPORT SpringEmbedderFR : public LayoutModule -{ -public: - //! The scaling method used by the algorithm. - enum Scaling { - scInput, //!< bounding box of input is used. - scUserBoundingBox, //!< bounding box set by userBoundingBox() is used. - scScaleFunction //!< automatic scaling is used with parameter set by scaleFunctionFactor() (larger factor, larger b-box). - }; - - - //! Creates an instance of Fruchterman/Reingold layout. - SpringEmbedderFR(); - - // destructor - ~SpringEmbedderFR() { } - - - //! Calls the layout algorithm for graph attributes \a GA. - void call(GraphAttributes &GA); - - - //! Returns the current setting of iterations. - int iterations() const { - return m_iterations; - } - - //! Sets the number of iterations to \a i. - void iterations(int i) { - if (i>0) - m_iterations = i; - } - - double fineness() const { - return m_fineness; - } - - void fineness(double f) { - m_fineness = f; - } - - //! Returns the current setting of nodes. - bool noise() const { - return m_noise; - } - - //! Sets the parameter noise to \a on. - void noise(bool on) { - m_noise = on; - } - - //! Returns the minimum distance between connected components. - double minDistCC() const { return m_minDistCC; } - - //! Sets the minimum distance between connected components to \a x. - void minDistCC(double x) { m_minDistCC = x; } - - //! Returns the page ratio. - double pageRatio() { return m_pageRatio; } - - //! Sets the page ration to \a x. - void pageRatio(double x) { m_pageRatio = x; } - - //! Returns the current scaling method. - Scaling scaling() const { - return m_scaling; - } - - //! Sets the method for scaling the inital layout to \a sc. - void scaling(Scaling sc) { - m_scaling = sc; - } - - //! Returns the current scale function factor. - double scaleFunctionFactor() const { - return m_scaleFactor; - } - - //! Sets the scale function factor to \a f. - void scaleFunctionFactor(double f) { - m_scaleFactor = f; - } - - //! Sets the user bounding box (used if scaling method is scUserBoundingBox). - void userBoundingBox(double xmin, double ymin, double xmax, double ymax) { - m_bbXmin = xmin; - m_bbYmin = ymin; - m_bbXmax = xmax; - m_bbYmax = ymax; - } - -private: - bool initialize(GraphCopy &G, GraphCopyAttributes &AG); - - void mainStep(GraphCopy &G, GraphCopyAttributes &AG); - void cleanup() { - delete m_A; - m_A = 0; - } - - NodeArray > m_lit; - - int m_cF; - - double m_width; - double m_height; - - double m_txNull; - double m_tyNull; - double m_tx; - double m_ty; - - double m_k; - double m_k2; - double m_kk; - int m_ki; - - int m_xA; - int m_yA; - - Array2D > *m_A; - - - double mylog2(int x) { - double l = 0.0; - while(x > 0) { - l++; - x >>= 1; - } - return l/2; - } - - int m_iterations; //!< The number of iterations. - double m_fineness; //!< The fineness of the grid. - double m_edgeLength; - - double m_xleft; //!< Bounding box (minimal x-coordinate). - double m_xright; //!< Bounding box (maximal x-coordinate). - double m_ysmall; //!< Bounding box (minimal y-coordinate). - double m_ybig; //!< Bounding box (maximal y-coordinate). - - bool m_noise; //!< Perform random perturbations? - - Scaling m_scaling; //!< The scaling method. - double m_scaleFactor; //!< The factor used if scaling type is scScaleFunction. - - double m_bbXmin; //!< User bounding box (minimal x-coordinate). - double m_bbYmin; //!< User bounding box (maximal x-coordinate). - double m_bbXmax; //!< User bounding box (minimal y-coordinate). - double m_bbYmax; //!< User bounding box (maximal y-coordinate). - - double m_minDistCC; //!< The minimal distance between connected components. - double m_pageRatio; //!< The page ratio. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/energybased/SpringEmbedderFRExact.h b/ext/OGDF/ogdf/energybased/SpringEmbedderFRExact.h deleted file mode 100644 index a2270702e..000000000 --- a/ext/OGDF/ogdf/energybased/SpringEmbedderFRExact.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Spring-Embedder (Fruchterman,Reingold) - * algorithm with exact force computations. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SPRING_EMBEDDER_FR_EXACT_H -#define OGDF_SPRING_EMBEDDER_FR_EXACT_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT GraphCopyAttributes; -class OGDF_EXPORT GraphCopy; - - -class OGDF_EXPORT SpringEmbedderFRExact : public ForceLayoutModule -{ -public: - enum CoolingFunction { cfFactor, cfLogarithmic }; - - //! Creates an instance of Fruchterman/Reingold (exact) layout. - SpringEmbedderFRExact(); - - // destructor - ~SpringEmbedderFRExact() { } - - - //! Calls the layout algorithm for graph attributes \a GA. - void call(GraphAttributes &GA); - - - //! Returns the current setting of iterations. - int iterations() const { - return m_iterations; - } - - //! Sets the number of iterations to \a i. - void iterations(int i) { - OGDF_ASSERT(i > 0) - m_iterations = i; - } - - //! Returns the current setting of nodes. - bool noise() const { - return m_noise; - } - - //! Sets the parameter noise to \a on. - void noise(bool on) { - m_noise = on; - } - - //! Switches use of node weights given in GraphAttributtes - void nodeWeights(bool on) { - m_useNodeWeight = on; - } - //! Returns the current setting for the cooling function. - CoolingFunction coolingFunction() const { - return m_coolingFunction; - } - - //! Sets the parameter coolingFunction to \a f. - void coolingFunction(CoolingFunction f) { - m_coolingFunction = f; - } - - //! Returns the ideal edge length. - double idealEdgeLength() const { return m_idealEdgeLength; } - - //! Sets the ideal edge length to \a len. - void idealEdgeLength(double len) { m_idealEdgeLength = len; } - - //! Returns the minimum distance between connected components. - double minDistCC() const { return m_minDistCC; } - - //! Sets the minimum distance between connected components to \a x. - void minDistCC(double x) { m_minDistCC = x; } - - //! Returns the page ratio. - double pageRatio() { return m_pageRatio; } - - //! Sets the page ration to \a x. - void pageRatio(double x) { m_pageRatio = x; } - - void checkConvergence(bool b) {m_checkConvergence = b;} - bool checkConvergence() {return m_checkConvergence;} - void convTolerance(double tol) {m_convTolerance = tol;} - -private: - class ArrayGraph - { - int m_numNodes; - int m_numEdges; - int m_numCC; - - GraphAttributes *m_ga; - node *m_orig; - Array > m_nodesInCC; - NodeArray m_mapNode; - - public: - ArrayGraph(GraphAttributes &ga); - ~ArrayGraph(); - - void initCC(int i); - - int numberOfCCs() const { return m_numCC; } - int numberOfNodes() const { return m_numNodes; } - int numberOfEdges() const { return m_numEdges; } - - node original(int v) const { return m_orig[v]; } - const SList &nodesInCC(int i) const { return m_nodesInCC[i]; } - - int *m_src; - int *m_tgt; - double *m_x; - double *m_y; - double *m_nodeWeight; - //this should be part of a multilevel layout interface class later on - bool m_useNodeWeight; //should given nodeweights be used or all set to 1.0? - }; - - double log2(double x) { return log(x) / log(2.0); } - double mylog2(int x) { - double l = 0.0; - while(x > 0) { - l++; - x >>= 1; - } - return l/2; - } - - void initialize(ArrayGraph &component); - void mainStep(ArrayGraph &component); - void mainStep_sse3(ArrayGraph &component); - - // Fruchterman, Reingold - //double f_att(double d) { return d*d / m_idealEdgeLength; } - //double f_rep(double d) { return m_idealEdgeLength*m_idealEdgeLength / d; } - - // eades - //double f_att(double d) { return 5.0 * d * log2(d/m_idealEdgeLength); } - //double f_rep(double d) { return 20.0 / d; } - - // cooling function - void cool(double &tx, double &ty, int &cF); - - int m_iterations; //!< The number of iterations. - bool m_noise; //!< Perform random perturbations? - CoolingFunction m_coolingFunction; //!< The selected cooling function - - - //double m_tx; - //double m_ty; - - double m_coolFactor_x; - double m_coolFactor_y; - - double m_idealEdgeLength; //!< The ideal edge length. - double m_minDistCC; //!< The minimal distance between connected components. - double m_pageRatio; //!< The page ratio. - - //int m_cF; - double m_txNull; - double m_tyNull; - //see above at ArrayGraph - bool m_useNodeWeight; - bool m_checkConvergence; // - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SPRING_EMBEDDER_KK_H -#define OGDF_SPRING_EMBEDDER_KK_H - - -#include -#include -#include - - -namespace ogdf { - - - class OGDF_EXPORT GraphCopyAttributes; - class OGDF_EXPORT GraphCopy; - - -//! The spring-embedder layout algorithm by Kamada and Kawai. -/** - * The implementation used in SpringEmbedderKK is based on - * the following publication: - * - * Tomihisa Kamada, Satoru Kawai: %An Algorithm for Drawing - * General Undirected Graphs. Information Processing Letters 31, pp. 7-15, 1989. - * - * Precondition: The input graph has to be connected. - *

    Optional parameters

    - * There are some parameters that can be tuned to optimize the - * algorithm's behavior regarding runtime and layout quality. - * First of all note that the algorithm uses all pairs shortest path - * to compute the graph theoretic distance. This can be done either - * with BFS (ignoring node sizes) in quadratic time or by using - * e.g. Floyd's algorithm in cubic time with given edge lengths - * that may reflect the node sizes. Also m_computeMaxIt decides - * if the computation is stopped after a fixed maximum number of - * iterations. The desirable edge length can either be set or computed - * from the graph and the given layout. - * Kamada-Kawai layout provides the following optional parameters. - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    toleranceint0.0001 - * Tolerance for the energy level (below which the main loop stops). - *
    - */ -class OGDF_EXPORT SpringEmbedderKK : public LayoutModule -{ -public: - typedef Tuple2 dpair; - - //! The scaling method used for the desirable length. - //! TODO: Non-functional so far, scScaleFunction is used - enum Scaling { - scInput, //!< bounding box of input is used. - scUserBoundingBox, //!< bounding box set by userBoundingBox() is used. - scScaleFunction, //!< automatic scaling is used, computed using only the node sizes. - scScaleAdaptive //!< automatic scaling is used, adapting the value per iteration. - }; - - //! Constructor: Constructs instance of Kamada Kawai Layout - SpringEmbedderKK() : m_tolerance(0.001), m_ltolerance(0.0001), m_computeMaxIt(true), - m_K(5.0), m_desLength(0.0), m_distFactor(2.0), m_useLayout(true), - m_gItBaseVal(50), m_gItFactor(16) - { - m_maxLocalIt = m_maxGlobalIt = maxVal; - } - - //! Destructor - ~SpringEmbedderKK() {} - - //! Calls the layout algorithm for graph attributes \a GA. - //! Currently, GA.doubleWeight is NOT used to allow simple - //! distinction of BFS/APSS. Precondition: Graph is connected. - void call(GraphAttributes& GA); - //! Calls the layout algorithm for graph attributes \a GA - //! using values in eLength for distance computation. - //! Precondition: Graph is connected. - void call(GraphAttributes& GA, const EdgeArray& eLength); - - //! Sets the value for the stop tolerance, below which the - //! system is regarded stable (balanced) and the optimization stopped - void setStopTolerance(double s) {m_tolerance = s;} - - //! If set to true, the given layout is used for the initial positions - void setUseLayout(bool b) {m_useLayout = b;} - bool useLayout() {return m_useLayout;} - - //! If set != 0, value zerolength is used to determine the - //! desirable edge length by L = zerolength / max distance_ij. - //! Otherwise, zerolength is determined using the node number and sizes. - void setZeroLength(double d) {m_zeroLength = d;} - double zeroLength() {return m_zeroLength;} - - //! Sets desirable edge length directly - void setDesLength(double d) {m_desLength = d;} - - - //! It is possible to limit the number of iterations to a fixed value - //! Returns the current setting of iterations. - //! These values are only used if m_computeMaxIt is set to true. - int maxLocalIterations() const { - return m_maxLocalIt; - } - void setGlobalIterationFactor(int i) {if (i>0) m_gItFactor = i;} - int maxGlobalIterations() const { - return m_maxGlobalIt; - } - //! Sets the number of global iterations to \a i. - void setMaxGlobalIterations(int i) { - if (i>0) - m_maxGlobalIt = i; - } - //! Sets the number of local iterations to \a i. - void setMaxLocalIterations(int i) { - if (i>0) - m_maxLocalIt = i; - } - //! If set to true, number of iterations is computed depending on G - void computeMaxIterations(bool b) - { - m_computeMaxIt = b; - } - //We could add some noise to the computation - // Returns the current setting of nodes. - //bool noise() const { - // return m_noise; - //} - // Sets the parameter noise to \a on. - //void noise(bool on) { - // m_noise = on; - //} - - -protected: - //! Does the actual call - void doCall(GraphAttributes& GA, const EdgeArray& eLength, bool simpleBFS); - //! Checks if main loop is finished because local optimum reached - bool finished(double maxdelta) - { - if (m_prevEnergy == startVal) //first step - { - m_prevEnergy = maxdelta; - return false; - } - - double diff = m_prevEnergy - maxdelta; //energy difference - if (diff < 0.0) diff = -diff; - //#ifdef OGDF_DEBUG - // cout << "Finished(): maxdelta: "<< maxdelta<<" diff/prev: "<& eLengths, - EdgeArray& adaptedLengths); - //! Adapts positions to avoid degeneracy (all nodes on a single point) - void shufflePositions(GraphAttributes& GA); - //! Computes contribution of node u to the first partial - //! derivatives (dE/dx_m, dE/dy_m) (for node m) (eq. 7 and 8 in paper) - dpair computeParDer(node m, - node u, - GraphAttributes& GA, - NodeArray< NodeArray >& ss, - NodeArray< NodeArray >& dist); - //! Compute partial derivative for v - dpair computeParDers(node v, - GraphAttributes& GA, - NodeArray< NodeArray >& ss, - NodeArray< NodeArray >& dist); - //! Does the necessary initialization work for the call functions - void initialize(GraphAttributes& GA, - NodeArray& partialDer, - const EdgeArray& eLength, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& sstrength, - double & maxDist, - bool simpleBFS); - //! Main computation loop, nodes are moved here - void mainStep(GraphAttributes& GA, - NodeArray& partialDer, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& sstrength, - const double maxDist); - //! Does the scaling if no edge lengths are given but node sizes - //! are respected - void scale(GraphAttributes& GA); - -private: - //! The stop criterion when the forces of all strings are - //! considered to be balanced - double m_tolerance; //! 0 - double m_desLength; //!< Desirable edge length, used instead if > 0 - double m_distFactor; //introduces some distance for scaling in case BFS is used - - bool m_useLayout; //!< use positions or allow to shuffle nodes to - //!< avoid degeneration - int m_gItBaseVal; //!< minimum number of global iterations - int m_gItFactor; //!< factor for global iterations: m_gItBaseVal+m_gItFactor*|V| - - static const double startVal; - static const double minVal; - static const double desMinLength; //!< Defines minimum desired edge length. - //! Smaller values are treated as zero - static const int maxVal = INT_MAX; //! defines infinite upper bound for iteration number - - double allpairsspBFS(const Graph& G, NodeArray< NodeArray >& distance); - double allpairssp(const Graph& G, const EdgeArray& eLengths, - NodeArray< NodeArray >& distance, const double threshold = DBL_MAX); -};//SpringEmbedderKK - -//Things that potentially could be added -// //! Returns the page ratio. -// double pageRatio() { return m_pageRatio; } -// -// //! Sets the page ration to \a x. -// void pageRatio(double x) { m_pageRatio = x; } -// -// //! Returns the current scaling method. -// Scaling scaling() const { -// return m_scaling; -// } -// -// //! Sets the method for scaling the inital layout to \a sc. -// void scaling(Scaling sc) { -// m_scaling = sc; -// } -// -// //! Returns the current scale function factor. -// double scaleFunctionFactor() const { -// return m_scaleFactor; -// } -// -// //! Sets the scale function factor to \a f. -// void scaleFunctionFactor(double f) { -// m_scaleFactor = f; -// } -// -// //! Sets the user bounding box (used if scaling method is scUserBoundingBox). -// void userBoundingBox(double xmin, double ymin, double xmax, double ymax) { -// m_bbXmin = xmin; -// m_bbYmin = ymin; -// m_bbXmax = xmax; -// m_bbYmax = ymax; -// } - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/energybased/StressMajorizationSimple.h b/ext/OGDF/ogdf/energybased/StressMajorizationSimple.h deleted file mode 100644 index 02adb8ea4..000000000 --- a/ext/OGDF/ogdf/energybased/StressMajorizationSimple.h +++ /dev/null @@ -1,400 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of simple distance-based layout. Non-final Code (Status: purely experimental). - * - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_STRESS_MAJORIZATION_H -#define OGDF_STRESS_MAJORIZATION_H - - -#include -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT GraphCopyAttributes; -class OGDF_EXPORT GraphCopy; - - -//! Simple stress majorization version that allows radial constraints -//! based on shortest path distances -/** -* The implementation used in StressMajorization is based on -* the following publication: -* -* Brandes, Pich: %More flexible radial layout. Graph Drawing 2009. -* -* Precondition: The input graph has to be connected. -* In order to obtain a radial style layout, the stress majorization -* is applied to the graph plus an additional virtual node at the center. -*

    Optional parameters

    -* There are some parameters that can be tuned to optimize the -* algorithm's behavior regarding runtime and layout quality. -* First of all note that the algorithm uses all pairs shortest path -* to compute the graph theoretic distance. This can be done either -* with BFS (ignoring node sizes) in quadratic time or by using -* e.g. Floyd's algorithm in cubic time with given edge lengths -* that may reflect the node sizes. -* TODO: Fixed number of iterations vs stop criterion -* Radii computation -* The layout provides the following optional parameters. -* -* -* -* -* -*
    OptionTypeDefaultDescription -*
    iterationsint50 -* Number of iterations (determines how often the main loop is executed ). -*
    -*/ -class OGDF_EXPORT StressMajorization : public LayoutModule -{ -public: - typedef Tuple2 dpair; - - //! The scaling method used for the desirable length. - //! TODO: Non-functional so far, scScaleFunction is used - enum Scaling { - scInput, //!< bounding box of input is used. - scUserBoundingBox, //!< bounding box set by userBoundingBox() is used. - scScaleFunction, //!< automatic scaling is used, computed using only the node sizes. - scScaleAdaptive //!< automatic scaling is used, adapting the value per iteration. - }; - - enum Constraints { - cRadial = 0x0001, //radial level depending on some centrality measure - cUpward = 0x0002 //level depending on edge direction - }; - - //! Constructor: Constructs instance of Kamada Kawai Layout - StressMajorization() - : m_tolerance(0.001), - m_ltolerance(0.0001), - m_computeMaxIt(true), - m_K(5.0), - m_desLength(0.0), - m_distFactor(2.0), - m_useLayout(false), - m_constraints(cUpward), - m_radial(false), - m_upward(false), - m_radiiStyle(0), - m_baseRadius(50.0), - m_numSteps(300), - m_itFac(0.0), - m_radiusFactor(1.1), - m_gItBaseVal(50), - m_gItFactor(16) - { - m_maxLocalIt = m_maxGlobalIt = maxVal; - } - - //! Destructor - ~ StressMajorization() {} - - //! Calls the layout algorithm for graph attributes \a GA. - //! Currently, GA.doubleWeight is NOT used to allow simple - //! distinction of BFS/APSS. Precondition: Graph is connected. - void call(GraphAttributes& GA); - - //! Calls the layout algorithm for graph attributes \a GA - //! using values in eLength for distance computation. - //! Precondition: Graph is connected. - void call(GraphAttributes& GA, const EdgeArray& eLength); - - //! Sets a fixed number of iterations for stress majorization in main step - void setIterations(int i) { if (i > 0) m_numSteps = i;} - - //! Number of total iterations is \a m_numSteps + \a m_itFac * number of nodes. - void setGraphSizeIterationFactor(double d) {if (DIsGreaterEqual(d, 0.0)) m_itFac = d; } - - //! Sets the value for the stop tolerance, below which the - //! system is regarded stable (balanced) and the optimization stopped - void setStopTolerance(double s) {m_tolerance = s;} - - //! If set to true, the given layout is used for the initial positions - void setUseLayout(bool b) {m_useLayout = b;} - bool useLayout() {return m_useLayout;} - - //! It is possible to limit the number of iterations to a fixed value - //! Returns the current setting of iterations. - //! These values are only used if m_computeMaxIt is set to true. - int maxLocalIterations() const { - return m_maxLocalIt; - } - void setGlobalIterationFactor(int i) {if (i>0) m_gItFactor = i;} - int maxGlobalIterations() const { - return m_maxGlobalIt; - } - //! Sets the number of global iterations to \a i. - void setMaxGlobalIterations(int i) { - if (i>0) - m_maxGlobalIt = i; - } - //! Sets the number of local iterations to \a i. - void setMaxLocalIterations(int i) { - if (i>0) - m_maxLocalIt = i; - } - //! If set to true, number of iterations is computed depending on G - void computeMaxIterations(bool b) - { - m_computeMaxIt = b; - } - //We could add some noise to the computation - // Returns the current setting of nodes. - //bool noise() const { - // return m_noise; - //} - // Sets the parameter noise to \a on. - //void noise(bool on) { - // m_noise = on; - //} - //! If set to true, radial constraints are added - void radial(bool b) {m_radial = b;} - //! If set to true, radial constraints are added - void upward(bool b) {m_upward = b;} - -protected: - //! Does the actual call - void doCall(GraphAttributes& GA, const EdgeArray& eLength, bool simpleBFS); - - //radius on level \a level, (1 denotes first level) - double radius(int level) - { - if (m_radiiStyle == 0) return m_baseRadius*level; - else - { - double rad = m_baseRadius; - for (int i = 1; i < level; i++) - { - rad*= m_radiusFactor; - } - rad+=m_baseRadius; - return rad; - } - } - - //radius of a specific node, depending on its level - double radius(node v) - { - return m_radii[v]; - } - //computes radii for all nodes based on closeness and saves them in \a m_radii - void computeRadii(const Graph& G, const NodeArray< NodeArray >& distances, double diameter); - - //! Checks if main loop is finished because local optimum reached - bool finished(double maxdelta) - { - if (m_prevEnergy == startVal) //first step - { - m_prevEnergy = maxdelta; - return false; - } - - double diff = m_prevEnergy - maxdelta; //energy difference - if (diff < 0.0) diff = -diff; -#ifdef OGDF_DEBUG - cout << "Finished(): maxdelta: "<< maxdelta<<" diff/prev: "<& eLengths, - EdgeArray& adaptedLengths); - //! Adapts positions to avoid degeneracy (all nodes on a single point) - void shufflePositions(GraphAttributes& GA); - //! Computes contribution of node u to the first partial - //! derivatives (dE/dx_m, dE/dy_m) (for node m) (eq. 7 and 8 in paper) - dpair computeParDer(node m, - node u, - GraphAttributes& GA, - NodeArray< NodeArray >& ss, - NodeArray< NodeArray >& dist); - //! Compute partial derivative for v - dpair computeParDers(node v, - GraphAttributes& GA, - NodeArray< NodeArray >& ss, - NodeArray< NodeArray >& dist); - //! Does the necessary initialization work for the call functions - void initialize(GraphAttributes& GA, - const EdgeArray& eLength, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& weights, - double & maxDist, - bool simpleBFS); - //! Main computation loop, nodes are moved here - void mainStep(GraphAttributes& GA, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& weights, - const double maxDist); - //! Does the scaling if no edge lengths are given but node sizes - //! are respected - void scale(GraphAttributes& GA); - -private: - //! The stop criterion when the forces of all strings are - //! considered to be balanced - double m_tolerance; //! 0 - double m_desLength; //!< Desirable edge length, used instead if > 0 - double m_distFactor; //introduces some distance for scaling in case BFS is used - - bool m_useLayout; //!< use positions or allow to shuffle nodes to - - int m_constraints; //constraints bit pattern - - bool m_radial; //!< if set to true, radial constraints are added - - //!< avoid degeneration - bool m_upward; - int m_radiiStyle; //!< defines how radii are calculated: - //! 0 = fixed distance m_firstRadius - //! 1 = increasing with factor m_radiusFactor - //! 2 = ...functions? - NodeArray m_radii; //!< stores computed radius for each node - double m_baseRadius; //!< radius of first level - int m_numSteps; //!< number of iteration steps - double m_itFac; //!< Factor for additional number of iterations based on graph size - double m_radiusFactor; //!< defines radius transformation from level 1 to k - int m_gItBaseVal; //!< minimum number of global iterations - int m_gItFactor; //!< factor for global iterations: m_gItBaseVal+m_gItFactor*|V| - - - double allpairsspBFS(const Graph& G, NodeArray< NodeArray >& distance, - NodeArray< NodeArray >& weights); - double allpairssp(const Graph& G, const EdgeArray& eLengths, - NodeArray< NodeArray >& distance, NodeArray< NodeArray >& weights, - const double threshold = DBL_MAX); - - static const double startVal; - static const double minVal; - static const double desMinLength; //!< Defines minimum desired edge length. - //! Smaller values are treated as zero - static const int maxVal = INT_MAX; //! defines infinite upper bound for iteration number - -};// StressMajorization - -//Things that potentially could be added -// //! Returns the page ratio. -// double pageRatio() { return m_pageRatio; } -// -// //! Sets the page ration to \a x. -// void pageRatio(double x) { m_pageRatio = x; } -// -// //! Returns the current scaling method. -// Scaling scaling() const { -// return m_scaling; -// } -// -// //! Sets the method for scaling the inital layout to \a sc. -// void scaling(Scaling sc) { -// m_scaling = sc; -// } -// -// //! Returns the current scale function factor. -// double scaleFunctionFactor() const { -// return m_scaleFactor; -// } -// -// //! Sets the scale function factor to \a f. -// void scaleFunctionFactor(double f) { -// m_scaleFactor = f; -// } -// -// //! Sets the user bounding box (used if scaling method is scUserBoundingBox). -// void userBoundingBox(double xmin, double ymin, double xmax, double ymax) { -// m_bbXmin = xmin; -// m_bbYmin = ymin; -// m_bbXmax = xmax; -// m_bbYmax = ymax; -// } - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/BarycenterPlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/BarycenterPlacer.h deleted file mode 100644 index 7a0b27b7f..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/BarycenterPlacer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes at the barycenter of his neighbors. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BARYCENTER_PLACER_H -#define OGDF_BARYCENTER_PLACER_H - -namespace ogdf { - -class OGDF_EXPORT BarycenterPlacer : public InitialPlacer -{ -private: - bool m_weightedPositions; - -public: - BarycenterPlacer(); - - void placeOneLevel(MultilevelGraph &MLG); - void placeOneNode(MultilevelGraph &MLG); - void weightedPositionPriority(bool on); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/CirclePlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/CirclePlacer.h deleted file mode 100644 index 8d61ca0db..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/CirclePlacer.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes on a circle around the barycenter of its neighbors. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CIRCLE_PLACER_H -#define OGDF_CIRCLE_PLACER_H - -namespace ogdf { - -class OGDF_EXPORT CirclePlacer : public InitialPlacer -{ -public: - - enum NodeSelection { - nsNew, - nsOld, - nsAll - }; - - CirclePlacer(); - void setRadiusFixed(bool fixed); - void setCircleSize(float sizeIncrease); - void setNodeSelection(NodeSelection nodeSel); - void placeOneLevel(MultilevelGraph &MLG); - -private: - - float m_circleSize; - bool m_fixedRadius; - NodeSelection m_nodeSelection; -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/EdgeCoverMerger.h b/ext/OGDF/ogdf/energybased/multilevelmixer/EdgeCoverMerger.h deleted file mode 100644 index 8b9aa5d94..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/EdgeCoverMerger.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_COVER_MERGER_H -#define OGDF_EDGE_COVER_MERGER_H - -namespace ogdf { - -class OGDF_EXPORT EdgeCoverMerger : public MultilevelBuilder -{ -private: - double m_levelSizeFactor; - NodeArray m_substituteNodes; - - bool doMerge(MultilevelGraph &MLG, node parent, node mergePartner, int level); - bool buildOneLevel(MultilevelGraph &MLG); - -public: - EdgeCoverMerger(); - void setFactor(double factor); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/IndependentSetMerger.h b/ext/OGDF/ogdf/energybased/multilevelmixer/IndependentSetMerger.h deleted file mode 100644 index dda87e276..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/IndependentSetMerger.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_INDEPENDENT_SET_MERGER_H -#define OGDF_INDEPENDENT_SET_MERGER_H - -namespace ogdf { - -class OGDF_EXPORT IndependentSetMerger : public MultilevelBuilder -{ -private: - float m_base; - - std::vector prebuildLevel(const Graph &G, const std::vector &oldLevelNodes, int level); - bool buildOneLevel(MultilevelGraph &MLG) { return false; } - bool buildOneLevel(MultilevelGraph &MLG, std::vector &levelNodes); - -public: - void buildAllLevels(MultilevelGraph &MLG); - void setSearchDepthBase(float base); - - IndependentSetMerger(); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/InitialPlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/InitialPlacer.h deleted file mode 100644 index b0a1516ae..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/InitialPlacer.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Abstract InitialPlacer places the nodes of the level into the next. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_INITIAL_PLACER_H -#define OGDF_INITIAL_PLACER_H - -#include -#include - -namespace ogdf { - -class OGDF_EXPORT InitialPlacer -{ -protected: - bool m_randomOffset; - -public: - InitialPlacer():m_randomOffset(true) { } - virtual ~InitialPlacer() { } - - virtual void placeOneLevel(MultilevelGraph &MLG) = 0; - - void setRandomOffset(bool on) - { - m_randomOffset = on; - } - -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.h b/ext/OGDF/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.h deleted file mode 100644 index cd588459e..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LOCAL_BICONNECTED_MERGER_H -#define OGDF_LOCAL_BICONNECTED_MERGER_H - -namespace ogdf { - -class OGDF_EXPORT LocalBiconnectedMerger : public MultilevelBuilder -{ -private: - double m_levelSizeFactor; - NodeArray m_substituteNodes; - NodeArray m_isCut; - HashArray m_realNodeMarks; - - void initCuts(Graph &G); - int realNodeMark(int index); - - //! Creates the next level in the hierarchy by merging - //! vertices based on matching, edge cover, and local biconnectivity check. - bool buildOneLevel(MultilevelGraph &MLG); - bool doMerge(MultilevelGraph &MLG, node parent, node mergePartner, int level); - bool doMergeIfPossible(Graph &G, MultilevelGraph &MLG, node parent, node mergePartner, int level); - bool canMerge(Graph &G, node parent, node mergePartner); - bool canMerge(Graph &G, node parent, node mergePartner, int testStrength); - -public: - //! Constructs a LocalBiconnectedMerger multilevel builder. - LocalBiconnectedMerger(); - //! Specifies the ratio between two consecutive level sizes up to which - //! merging is done. - void setFactor(double factor); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleFastLayout.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleFastLayout.h deleted file mode 100644 index 14f4477b5..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleFastLayout.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief useable example of the Modular Multilevel Mixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MMM_EXAMPLE_FAST_LAYOUT_H -#define OGDF_MMM_EXAMPLE_FAST_LAYOUT_H - -#include -#include - -namespace ogdf { - -/** \brief An example Layout using the Modular Mutlievel Mixer - * - * This example is tuned for speed. SolarMerger and SolarPlacer are used as - * merging and placement strategies. The FastMultipoleEmbedder is for force - * calculation. - * - * For an easy variation of the Modular Multilevel Mixer copy the code in call. - */ -class OGDF_EXPORT MMMExampleFastLayout : public LayoutModule -{ -public: - - //! Constructor - MMMExampleFastLayout(); - - //! calculates a drawing for the Graph GA - void call(GraphAttributes &GA); - - //! calculates a drawing for the Graph MLG - void call(MultilevelGraph &MLG); - -private: - -}; - -} // namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNiceLayout.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNiceLayout.h deleted file mode 100644 index 571fefec1..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNiceLayout.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief useable example of the Modular Multilevel Mixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MMM_EXAMPLE_NICE_LAYOUT_H -#define OGDF_MMM_EXAMPLE_NICE_LAYOUT_H - -#include -#include - -namespace ogdf { - -/** \brief An example Layout using the Modular Mutlievel Mixer - * - * This example is tuned for nice drawings for most types of graphs. - * EdgeCoverMerger and BarycenterPlacer are used as merging and placement - * strategies. The FastMultipoleEmbedder is for force calculation. - * - * For an easy variation of the Modular Multilevel Mixer copy the code in call. - */ -class OGDF_EXPORT MMMExampleNiceLayout : public LayoutModule -{ -public: - - //! Constructor - MMMExampleNiceLayout(); - - //! calculates a drawing for the Graph GA - void call(GraphAttributes &GA); - - //! calculates a drawing for the Graph MLG - void call(MultilevelGraph &MLG); - -private: - -}; - -} // namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNoTwistLayout.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNoTwistLayout.h deleted file mode 100644 index fac36466a..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MMMExampleNoTwistLayout.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief useable example of the Modular Multilevel Mixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MMM_EXAMPLE_NO_TWIST_LAYOUT_H -#define OGDF_MMM_EXAMPLE_NO_TWIST_LAYOUT_H - -#include -#include - -namespace ogdf { - -/** \brief An example Layout using the Modular Mutlievel Mixer - * - * This example is tuned to reduce twists in the final drawing. Use this layout - * or a variation of it if many twists occur. LocalBiconnectedMerger and - * BarycenterPlacer are used as merging and placement strategies. The - * FastMultipoleEmbedder is for force calculation. - * - * For an easy variation of the Modular Multilevel Mixer copy the code in call. - */ -class OGDF_EXPORT MMMExampleNoTwistLayout : public LayoutModule -{ -public: - - //! Constructor - MMMExampleNoTwistLayout(); - - //! calculates a drawing for the Graph GA - void call(GraphAttributes &GA); - - //! calculates a drawing for the Graph MLG - void call(MultilevelGraph &MLG); - -private: - -}; - -} // namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MatchingMerger.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MatchingMerger.h deleted file mode 100644 index 2541923a2..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MatchingMerger.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MATCHING_MERGER_H -#define OGDF_MATCHING_MERGER_H - -namespace ogdf { - -class OGDF_EXPORT MatchingMerger : public MultilevelBuilder -{ -private: - NodeArray m_mass; - bool m_selectByMass; - - bool buildOneLevel(MultilevelGraph &MLG); - -public: - MatchingMerger(); - void selectByNodeMass(bool on); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MedianPlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MedianPlacer.h deleted file mode 100644 index e4f514e7d..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MedianPlacer.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes at the position of the merge-partner. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MEDIAN_PLACER_H -#define OGDF_MEDIAN_PLACER_H - -namespace ogdf { - -class OGDF_EXPORT MedianPlacer : public InitialPlacer -{ -public: - void placeOneLevel(MultilevelGraph &MLG); - -private: - void placeOneNode(MultilevelGraph &MLG); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MixedForceLayout.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MixedForceLayout.h deleted file mode 100644 index 132a142b0..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MixedForceLayout.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Uses Fruchtermann Rheingold and Fast Multipole Embedder for faster and better FR results. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIXED_FORCE_LAYOUT_H -#define OGDF_MIXED_FORCE_LAYOUT_H - -#include -#include - -namespace ogdf { - -class OGDF_EXPORT MixedForceLayout : public LayoutModule -{ -public: - - MixedForceLayout(); - - void call(GraphAttributes &GA); - void call(MultilevelGraph &MLG); - -private: - - LayoutModule * m_FR; - LayoutModule * m_FME; - -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/ModularMultilevelMixer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/ModularMultilevelMixer.h deleted file mode 100644 index a175d1423..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/ModularMultilevelMixer.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief MMM is a Multilevel Graph drawing Algorithm that can use different modules. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MODULAR_MULTILEVEL_MIXER_H -#define OGDF_MODULAR_MULTILEVEL_MIXER_H - -#include -#include -#include -#include -#include - - -namespace ogdf { - -/** - * \brief Modular multilevel graph layout. - * - *

    %Module options

    - * The various phases of the algorithm can be exchanged by setting - * module options allowing flexible customization. The algorithm provides - * the following module options: - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    multilevelBuilderMultilevelBuilderSolarMerger - * The multilevel builder module that computes the multilevel graph hierarchy. - *
    initialPlacerInitialPlacerBarycenterPlacer - * The initial placer module that computes the initial positions for nodes inserted into the previous level. - *
    levelLayoutLayoutModuleFastMultipoleEmbedder - * The layout module applied on each level. - *
    finalLayoutLayoutModulenone - * The layout module applied on the last level. - *
    postLayoutLayoutModulenone - * The layout module applied to the final drawing for additional beautification. - *
    - */ -class OGDF_EXPORT ModularMultilevelMixer : public LayoutModule -{ -private: - - //! The layout algorithm applied on each level. - /** - * The one-level layout module should not completely discard the initial Layout - * but do incremental beautification. - * Usually a simple force-directed / energy-based Layout should be chosen. - */ - ModuleOption m_oneLevelLayoutModule; - - //! The layout algorithm applied on the last level (i.e., the largest graph in the multilevel hierarchy). - /** - * The final layout module can be set to speed up the computation if the - * one-level layout ist relatively slow. If not set, the one-level layout - * is also used on the last level. - */ - ModuleOption m_finalLayoutModule; - - //! The multilevel builder module computes the multilevel hierarchy. - ModuleOption m_multilevelBuilder; - - //! The initial placer module computes the initial positions for nodes inserted into the previous level. - ModuleOption m_initialPlacement; - - //! The one-level layout will be called \a m_times to improve quality. - int m_times; - - //! If set to a value > 0, all edge weights will be set to this value. - double m_fixedEdgeLength; - - //! If set to a value > 0, all node sizes will be set to this value. - double m_fixedNodeSize; - - double m_coarseningRatio; //!< Ratio between sizes of previous (p) and current (c) level graphs: c/p - - bool m_levelBound; //!< Determines if computation is stopped when number of levels is too high. - bool m_randomize; //!< Determines if initial random layout is computed. - -public: - - //! Error codes for calls. - enum erc { - ercNone, //!< no error - ercLevelBound //!< level bound exceeded by merger step - }; - - ModularMultilevelMixer(); - - //! Sets the one-level layout module to \a levelLayout. - void setLevelLayoutModule(LayoutModule *levelLayout) { - m_oneLevelLayoutModule.set(levelLayout); - } - - //! Sets the final layout module to \a finalLayout. - void setFinalLayoutModule(LayoutModule *finalLayout) { - m_finalLayoutModule.set(finalLayout); - } - - //! Sets the multilevel builder module to \a levelBuilder. - void setMultilevelBuilder(MultilevelBuilder *levelBuilder) { - m_multilevelBuilder.set(levelBuilder); - } - - //! Sets the initial placer module to \a placement. - void setInitialPlacer(InitialPlacer *placement) { - m_initialPlacement.set(placement); - } - - //! Determines how many times the one-level layout will be called. - void setLayoutRepeats(int times = 1) { m_times = times; } - - //! If \a len > 0, all edge weights will be set to \a len. - void setAllEdgeLengths(double len) { m_fixedEdgeLength = len; } - - //! If \a size > 0, all node sizes will be set to \a size. - void setAllNodeSizes(double size) { m_fixedNodeSize = size; } - - //! Determines if an initial random layout is computed. - void setRandomize(bool b) { m_randomize = b; } - - //! Determines if computation is stopped when number of levels is too high. - void setLevelBound(bool b) { m_levelBound = b; } - - //! Calls the multilevel layout algorithm for graph attributes \a GA. - void call(GraphAttributes &GA); - - /** - * \brief Calls the multilevel layout algorithm for multilevel graph \a MLG. - * - * This method allows the mixer to modify the Graph, saving some memory - * compared to a normal call(GA) in our implementation. - * (because the Graph is already given in the MultiLevelGraph Format - * (or can be converted without creating a copy) AND the layout would need a copy otherwise). - * All Incremental Layouts (especially energy based) CAN be called by ModularMultilevelMixer. - * @param MLG is the input graph and will also be assigned the layout information. - */ - /*virtual void call(MultilevelGraph &MLG) { - GraphAttributes GA(MLG.getGraph()); - MLG.exportAttributesSimple(GA); - call(GA); - MLG.importAttributesSimple(GA); - };*/ - virtual void call(MultilevelGraph &MLG); - - //! Returns the error code of last call. - erc errorCode() { return m_errorCode; } - - //! Returns the ratio c/p between sizes of previous (p) and current (c) level graphs. - double coarseningRatio() { return m_coarseningRatio; } - -private: - erc m_errorCode; //!< The error code of the last call. -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/MultilevelBuilder.h b/ext/OGDF/ogdf/energybased/multilevelmixer/MultilevelBuilder.h deleted file mode 100644 index 144e282d1..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/MultilevelBuilder.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Abstract MultilevelBuilder builds all Levels - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MULTILEVEL_BUILDER_H -#define OGDF_MULTILEVEL_BUILDER_H - -#include -#include - -namespace ogdf { - -class OGDF_EXPORT MultilevelBuilder -{ -private: - /** - * \brief This method constructs one more level on top of an existing MultilevelGraph. - * It must be implemented in any MultilevelBuilder. A level is built by - * adding node-merges to the MultilevelGraph and updating the graph accordingly. - * This is achieved by calling MLG. - * - * @param MLG is the MultilevelGraph for which a new gevel will be built. - * - * @return true if the Graph was changed or false if no Level can be built. - */ - virtual bool buildOneLevel(MultilevelGraph &MLG) = 0; - -protected: - // if set to true the length of the edge between two merged nodes will be added to - // all edges that are moved to the other node in this merge. - int m_adjustEdgeLengths; - int m_numLevels; //!< stores number of levels for statistics purposes - -public: - virtual ~MultilevelBuilder() { } - MultilevelBuilder():m_adjustEdgeLengths(0),m_numLevels(1) { } - - virtual void buildAllLevels(MultilevelGraph &MLG) - { - m_numLevels = 1; - MLG.updateReverseIndizes(); - MLG.updateMergeWeights(); - while (buildOneLevel(MLG)) - { - m_numLevels++; - } - MLG.updateReverseIndizes(); - } - - void setEdgeLengthAdjustment(int factor) { m_adjustEdgeLengths = factor; } - int getNumLevels() {return m_numLevels;} - -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/RandomMerger.h b/ext/OGDF/ogdf/energybased/multilevelmixer/RandomMerger.h deleted file mode 100644 index d0c3d789f..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/RandomMerger.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_RANDOM_MERGER_H -#define OGDF_RANDOM_MERGER_H - -namespace ogdf { - -class OGDF_EXPORT RandomMerger : public MultilevelBuilder -{ -private: - double m_levelSizeFactor; - - bool buildOneLevel(MultilevelGraph &MLG); - -public: - RandomMerger(); - void setFactor(double factor); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/RandomPlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/RandomPlacer.h deleted file mode 100644 index 5bbd4cf37..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/RandomPlacer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes at the position of the merge-partner. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_RANDOM_PLACER_H -#define OGDF_RANDOM_PLACER_H - -namespace ogdf { - -class OGDF_EXPORT RandomPlacer : public InitialPlacer -{ - void placeOneNode(MultilevelGraph &MLG, DPoint center, double radius); - - double m_circleSizeFactor; - -public: - RandomPlacer(); - void placeOneLevel(MultilevelGraph &MLG); - void setCircleSize(double factor); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/ScalingLayout.h b/ext/OGDF/ogdf/energybased/multilevelmixer/ScalingLayout.h deleted file mode 100644 index 3aecd95a4..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/ScalingLayout.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief ScalingLayout scales and calls a secondary layout - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SCALING_LAYOUT_H -#define OGDF_SCALING_LAYOUT_H - -#include -#include -#include -#include - - -namespace ogdf { - -/*!\class ScalingLayout ScalingLayout.h "ogdf/energybased/multilevelmixer/ScalingLayout.h" - * \brief Scales a Graph relative to the ScalingType. - * - * For use with ModularMultilevelMixer. - */ -class OGDF_EXPORT ScalingLayout : public MultilevelLayoutModule -{ -public: - /*! - * \brief To define the relative scale used for a Graph, the ScalingType is applied. - */ - enum ScalingType { - //! Scales by a factor relative to the drawing. - st_relativeToDrawing, - /*! - * Scales by a factor relative to the avg edge weights - * to be used in combination with the fixed edge length - * setting in ModularMultilevelMixer. - */ - st_relativeToAvgLength, - //! Scales by a factor relative to the desired Edgelength m_desEdgeLength. - st_relativeToDesiredLength, - //! Absolute factor, can be used to scale relative to level size change. - st_absolute - }; - - ScalingLayout(); - - /** - * \brief Computes a layout of graph \a GA. - * - * @param GA is the input graph and will also be assigned the layout information. - */ - void call(GraphAttributes &GA); - - /** - * \brief Computes a layout of graph \a MLG. - * - * @param MLG is the input graph and will also be assigned the layout information. - */ - void call(MultilevelGraph &MLG); - - /*! - * \brief Sets the minimum and the maximum scaling factor. - * - * @param min sets the minimum - * @param max sets the maximum - */ - void setScaling(double min, double max); - - /*! - * \brief Sets how often the scaling should be repeated. - * - * @param steps is the number of repeats - */ - void setExtraScalingSteps(unsigned int steps); - - /*! - * \brief Sets a LayoutModule that should be applied after scaling. - * - * @param layout is the secondary LayoutModule - */ - void setSecondaryLayout(LayoutModule* layout); - - /*! - * \brief Is used to compute the scaling relatively to the level size change when ScalingType st_absolute is used. - * - * @param mmm is the ModularMultilevelMixer - */ - void setMMM(ModularMultilevelMixer* mmm); - - /*! - * \brief Sets a ScalingType wich sets the relative scale for the Graph - * - * @param type is the ScalingType - */ - void setScalingType(ScalingType type); - - /*! - * \brief Sets how often the LayoutModule should be applied. - * - * @param repeats is the number of repeats - */ - void setLayoutRepeats(unsigned int repeats); - //TODO: only a workaround, this should be retrieved from the layout module - //when we have a interface class on top of Layoutmodule that allows this - void setDesiredEdgeLength(double eLength); - -private: - - // Usually a simple force-directed / energy-based Layout should be chosen. - ModuleOption m_secondaryLayoutModule; - - double m_minScaling; - double m_maxScaling; - ModularMultilevelMixer* m_mmm;//!< Used to derive level size ratio if st_absolute - double m_desEdgeLength; - - // 0 = scale to maxScaling only - unsigned int m_extraScalingSteps; - - unsigned int m_layoutRepeats; - - ScalingType m_scalingType; -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/SolarMerger.h b/ext/OGDF/ogdf/energybased/multilevelmixer/SolarMerger.h deleted file mode 100644 index 97b44c5be..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/SolarMerger.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with solar system rules. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SOLAR_MERGER_H -#define OGDF_SOLAR_MERGER_H - - -namespace ogdf { - -class OGDF_EXPORT SolarMerger : public MultilevelBuilder -{ - struct PathData { - PathData(int targetSun = 0, double length = 0.0f, int number = 0) - : targetSun(targetSun), length(length), number(number) { } - - int targetSun; - double length; - int number; - }; - - bool m_sunSelectionSimple; - bool m_massAsNodeRadius; - NodeArray m_mass; - NodeArray m_radius; - NodeArray m_celestial; // 0 = unknown, 1 = sun, 2 = planet, 3 = moon - NodeArray m_orbitalCenter; - NodeArray m_distanceToOrbit; - NodeArray< std::vector > m_pathDistances; - std::map< int, std::map > m_interSystemPaths; - - node sunOf(node object); - double distanceToSun(node object, MultilevelGraph &MLG); - void addPath(node sourceSun, node targetSun, double distance); - void findInterSystemPaths(Graph &G, MultilevelGraph &MLG); - int calcSystemMass(node v); - bool collapsSolarSystem(MultilevelGraph &MLG, node sun, int level); - bool buildOneLevel(MultilevelGraph &MLG); - std::vector selectSuns(MultilevelGraph &MLG); - -public: - SolarMerger(bool simple = false, bool massAsNodeRadius = false); - - void buildAllLevels(MultilevelGraph &MLG); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/SolarPlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/SolarPlacer.h deleted file mode 100644 index 5f2bf1ab3..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/SolarPlacer.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places Nodes with solar system rules. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SOLAR_PLACER_H -#define OGDF_SOLAR_PLACER_H - -namespace ogdf { - -class OGDF_EXPORT SolarPlacer : public InitialPlacer -{ -public: - void placeOneLevel(MultilevelGraph &MLG); - -private: - void placeOneNode(MultilevelGraph &MLG); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/energybased/multilevelmixer/ZeroPlacer.h b/ext/OGDF/ogdf/energybased/multilevelmixer/ZeroPlacer.h deleted file mode 100644 index 69a93044f..000000000 --- a/ext/OGDF/ogdf/energybased/multilevelmixer/ZeroPlacer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes at the position of the merge-partner - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ZERO_PLACER_H -#define OGDF_ZERO_PLACER_H - -namespace ogdf { - -class OGDF_EXPORT ZeroPlacer : public InitialPlacer -{ - void placeOneNode(MultilevelGraph &MLG); - - double m_randomRange; - -public: - - void placeOneLevel(MultilevelGraph &MLG); - ZeroPlacer(); - void setRandomRange(double range); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/external/abacus.h b/ext/OGDF/ogdf/external/abacus.h deleted file mode 100644 index ee78dc529..000000000 --- a/ext/OGDF/ogdf/external/abacus.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Handles Abacus Dependencies. - * - * Include this file whenever you want to use Abacus. It does the - * rest for you. Just be sure to structure your code using the - * USE_ABACUS Flag. (See AbacusOptimalCrossingMinimizer for an - * example). - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_ABACUS_H -#define OGDF_ABACUS_H - -#ifdef USE_ABACUS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#else // USE_ABACUS - -#include -#define THROW_NO_ABACUS_EXCEPTION OGDF_THROW_PARAM(LibraryNotSupportedException, lnscAbacus) - - -#endif // USE_ABACUS - -#endif // OGDF_ABACUS_H diff --git a/ext/OGDF/ogdf/external/coin.h b/ext/OGDF/ogdf/external/coin.h deleted file mode 100644 index 6b5c6993c..000000000 --- a/ext/OGDF/ogdf/external/coin.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2614 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-16 11:30:08 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Handles connection to the COIN library, by offering - * helper classes. - * - * If you use Coin, you need to include this file. Please follow - * the example of CoinOptimalCrossingMinimizer for the correct use - * of the USE_COIN precompiler flag. - * - * \todo Currently, there is only a single implementation of the - * CoinCallback-class declared herein (necc. for userdefined cuts). - * This implementation is CPLEX specific. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_COINY_H -#define OGDF_COINY_H - -#include - - -#ifndef USE_COIN - - #define THROW_NO_COIN_EXCEPTION OGDF_THROW_PARAM(LibraryNotSupportedException, lnscCoin) - - namespace ogdf { - class CoinCallbacks {}; - } - -#else // USE_COIN - - #define OGDF_THROW_NO_CALLBACK_EXCEPTION - - #include - #include - - namespace ogdf { - - class OGDF_EXPORT CoinCallbacks { - friend class OGDF_EXPORT CoinManager; - public: - enum CallbackType { CT_Cut = 1, CT_Heuristic = 2, CT_Incumbent = 4, CT_Branch = 8 }; - enum CutReturn { CR_Error, CR_SolutionValid, CR_AddCuts, CR_DontAddCuts, CR_NoCutsFound }; - enum HeuristicReturn { HR_Error, HR_Ignore, HR_Update }; - enum IncumbentReturn { IR_Error, IR_Ignore, IR_Update }; -// enum BranchReturn { BR_Error, ... }; - virtual CutReturn cutCallback(const double /* objValue */, const double* /* fracSolution */, OsiCuts* /* addThese */) { OGDF_THROW_NO_CALLBACK_EXCEPTION; return CR_Error; } - virtual HeuristicReturn heuristicCallback(double& /* objValue */, double* /* solution */) { OGDF_THROW_NO_CALLBACK_EXCEPTION; return HR_Error; } - virtual IncumbentReturn incumbentCallback(const double /* objValue */, const double* /* solution */) { OGDF_THROW_NO_CALLBACK_EXCEPTION; return IR_Error; } -// virtual BranchReturn branchCallback() { OGDF_THROW_NO_CALLBACK_EXCEPTION; return BR_Error; }; - private: - bool registerCallbacks(OsiSolverInterface* _posi, int callbackTypes); - }; - - class OGDF_EXPORT CoinManager { - public: - static OsiSolverInterface* createCorrectOsiSolverInterface(); - static OsiSolverInterface* createCorrectOsiSolverInterface(CoinCallbacks* ccc, int callbackTypes) { - OsiSolverInterface* posi = createCorrectOsiSolverInterface(); - if(ccc->registerCallbacks(posi, callbackTypes)) - return posi; - delete posi; - return NULL; - } - static void logging(OsiSolverInterface* osi, bool logMe); - }; - - } - - -#endif // USE_COIN - -#endif // OGDF_COINY_H - diff --git a/ext/OGDF/ogdf/fileformats/DinoLineBuffer.h b/ext/OGDF/ogdf/fileformats/DinoLineBuffer.h deleted file mode 100644 index ce5d90eee..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoLineBuffer.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the clssses DinoLineBuffer and - * DinoLineBufferPosition - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_LINE_BUFFER_H -#define OGDF_DINO_LINE_BUFFER_H - -#include - - -namespace ogdf { - - //--------------------------------------------------------- - // D i n o L i n e B u f f e r P o s i t i o n - //--------------------------------------------------------- - /** This class characterizes uniquely a position in the line - * buffer. - * - * Note that the element m_lineUpdateCount allows to check - * if a position is obsolete, i.e. its content has already - * been overwritten. - */ - class OGDF_EXPORT DinoLineBufferPosition { - - private: - - /** Contains the lineNumber; Range [0 .. c_maxNoOfLines-1] */ - int m_lineNumber; - - /** Contains the number of times line m_lineNumber has been - * overwritten by new data; Range [0 .. ] - */ - int m_lineUpdateCount; - - /** Contains the position in line m_lineNumber; Range [0 .. c_maxLineLength-1] */ - int m_linePosition; - - public: - - /** Default Constructor */ - DinoLineBufferPosition() : - m_lineNumber(0), - m_lineUpdateCount(0), - m_linePosition(0) - { } - - /** Constructor */ - DinoLineBufferPosition( - int lineNumber, - int lineUpdateCount, - int linePosition); - - /** Copy Constructor */ - DinoLineBufferPosition(const DinoLineBufferPosition &position); - - /** Get the line number */ - inline int getLineNumber() const { - return m_lineNumber; - } - - /** Get the update count of the line */ - inline int getLineUpdateCount() const { - return m_lineUpdateCount; - } - - /** Get the position in the line */ - inline int getLinePosition() const { - return m_linePosition; - } - - /** Set all values */ - void set(int lineNumber, int lineUpdateCount, int linePosition); - - /** Increments the position by 1 */ - void incrementPosition(); - - /** Test if inequal */ - bool operator!=(const DinoLineBufferPosition &position) const; - - /** Assignment */ - const DinoLineBufferPosition &operator=(const DinoLineBufferPosition &position); - - }; // DinoLineBufferPosition - - //--------------------------------------------------------- - // D i n o L i n e B u f f e r - //--------------------------------------------------------- - /** This class maintains the input file and provides a - * convenient interface to handle it. - */ - class OGDF_EXPORT DinoLineBuffer { - - public: - - // Maximal length of a string handled by extractString() - const static int c_maxStringLength; - - // Maximal length of one line - const static int c_maxLineLength; - - // Maximal number of lines - const static int c_maxNoOfLines; - - private: - - // Handle to the input file - istream *m_pIs; - - // Contains for each line of the line buffer its update count - // Range is [0 .. c_maxNoOfLines] - int *m_lineUpdateCountArray; - - // Pointer to the line buffer - char *m_pLinBuf; - - // The current position in m_pLinBuf - DinoLineBufferPosition m_currentPosition; - - // The line which has been read from the file most recently; - // this does not have to be equal to m_currentPosition.m_lineNumber - // because of the lookahead facilities. - // Range is [0 .. c_maxNoOfLines - 1] - int m_numberOfMostRecentlyReadLine; - - // Contains the current line number of the input file; - int m_inputFileLineCounter; - - public: - - // construction - DinoLineBuffer(const char *fileName); - - // destruction - ~DinoLineBuffer(); - - // Returns the current position (as a copy) - DinoLineBufferPosition getCurrentPosition() const{ - return m_currentPosition; - } - - // Returns the character which is currently pointed to - inline char getCurrentCharacter() const { - return m_pLinBuf[(m_currentPosition.getLineNumber() * DinoLineBuffer::c_maxLineLength) + - m_currentPosition.getLinePosition()]; - } - - // Returns line number of the most recently read line of the input file - inline int getInputFileLineCounter() const { - return m_inputFileLineCounter; - } - - // Moves to the next position; - // reading of new lines and handling of eof are done internally. - // If end of file is reached the position will stuck to EOF character. - // The current character after moving is returned - char moveToNextCharacter(); - - // Sets the current position to new positon. - // Takes care if the given newPosition is valid. - // Returns false if given position is invalid - bool setCurrentPosition(const DinoLineBufferPosition &newPosition); - - // Moves to the next character until the currentCharacter is - // no whitespace. - void skipWhitespace(); - - // Copys the characters which have been extracted from the - // line buffer starting from position startPosition (including it) - // to endPosition (excluding it) to targetString (terminated by '\0'). - // The length of strings is limited to c_maxStringLength - // - // Returns false if the startPosition is not valid, i.e. the string - // is too long; targetString will contain the message "String too long!" - bool extractString( - const DinoLineBufferPosition &startPostion, - const DinoLineBufferPosition &endPosition, - char *targetString); - - private: - - // Returns a pointer to the character which is currently pointed to - inline char *getCurrentCharacterPointer() { - return &m_pLinBuf[(m_currentPosition.getLineNumber() * DinoLineBuffer::c_maxLineLength) + - m_currentPosition.getLinePosition()]; - } - - // Sets the given character to the current position - inline void setCurrentCharacter(char c) { - m_pLinBuf[(m_currentPosition.getLineNumber() * DinoLineBuffer::c_maxLineLength) + - m_currentPosition.getLinePosition()] = c; - } - - // Checks wether the given position is valid - bool isValidPosition(const DinoLineBufferPosition &position) const; - - }; // class DinoLineBuffer - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/DinoTools.h b/ext/OGDF/ogdf/fileformats/DinoTools.h deleted file mode 100644 index 670a3077f..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoTools.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class DinoTools - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_TOOLS_H -#define OGDF_DINO_TOOLS_H - -#include -#include - - -namespace ogdf { - - //--------------------------------------------------------- - // D i n o T o o l s - // - // provides some useful tools - //--------------------------------------------------------- - class OGDF_EXPORT DinoTools { - - public: - - // Extracts the single values of string str with format - // "x, y, width, height," and puts them into doubleArray - static void stringToDoubleArray(const String &str, Array &doubleArray); - - // Reports errors to cout - // Value -1 for inputFileLine indicates that this information is - // not available - static void reportError(const char *functionName, - int sourceLine, - const char *errorMessage, - int inputFileLine = -1, - bool abort = true); - - }; // class DinoTools - - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/DinoUmlDiagramGraph.h b/ext/OGDF/ogdf/fileformats/DinoUmlDiagramGraph.h deleted file mode 100644 index 6c96449b6..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoUmlDiagramGraph.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains the class DinoUmlDiagramGraph which represents one - * particular diagram of the complete UML Model. - * - * Each diagram refers to the node and edge information of - * DinoUmlModelGraph. Essentially a diagram contains selected nodes - * and edges of the model provides with additional geometric - * information. - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_UML_DIAGRAM_GRAPH_H -#define OGDF_DINO_UML_DIAGRAM_GRAPH_H - -#include -#include -#include - -namespace ogdf { - - //--------------------------------------------------------- - // D i n o U m l D i a g r a m G r a p h - //--------------------------------------------------------- - /** Contains the class DinoUmlDiagramGraph which represents one - * particular diagram of the complete UML Model. Each diagram refers - * to the node and edge information of DinoUmlModelGraph. Essentially - * a diagram contains selected nodes and edges of the model provides - * with additional geometric information. - */ - class OGDF_EXPORT DinoUmlDiagramGraph { - - friend ostream &operator<<(ostream&, const DinoUmlDiagramGraph &); - - public: - - //--------------------------------------------------------- - // U m l D i a g r a m T y p e - //--------------------------------------------------------- - /** This enum type represents the different diagram types of UML. - */ - enum UmlDiagramType{ - classDiagram, - moduleDiagram, - sequenceDiagram, - collaborationDiagram, - componentDiagram, - unknownDiagram - - }; // enum UmlDiagramType - - private: - - /** Reference to the model graph. */ - const DinoUmlModelGraph &m_modelGraph; - - /** The name of the diagram. */ - String m_diagramName; - - /** The type of diagram. */ - UmlDiagramType m_diagramType; - - /** This list holds pointer to the nodes contained in - * the represented diagram. - */ - SList m_containedNodes; - - /** This list holds pointer to the edges contained in - * the represented diagram. - */ - SList m_containedEdges; - - /** This list contains the x-coordinates of the nodes - * contained in the represented diagram. - */ - SList m_x; - - /** This list contains the y-coordinates of the nodes - * contained in the represented diagram. - */ - SList m_y; - - /** This list contains the width of the nodes - * contained in the represented diagram. - */ - SList m_w; - - /** This list contains the height of the nodes - * contained in the represented diagram. - */ - SList m_h; - - public: - - /** Constructor. */ - DinoUmlDiagramGraph(const DinoUmlModelGraph ¨ModelGraph, - UmlDiagramType diagramType, - String diagramName); - - /** Destructor. */ - ~DinoUmlDiagramGraph(); - - /** Adds a node with the given coordinates. */ - void addNodeWithGeometry(NodeElement* node, - double x, double y, double w, double h); - - /** Adds an edge. */ - void addEdge(EdgeElement* edge); - - /** Returns the name of the diagram. */ - String getDiagramName() const{ - return m_diagramName; - } - - /** Returns the type of the diagram as string. */ - String getDiagramTypeString() const; - - /** Access to contained nodes. */ - const SList &getNodes() const{ - return m_containedNodes; - } - - /** Access to contained edges. */ - const SList &getEdges() const{ - return m_containedEdges; - } - - /** Access to x-coordinates. */ - const SList &getX() const{ - return m_x; - } - - /** Access to y-coordinates. */ - const SList &getY() const{ - return m_y; - } - - /** Access to width. */ - const SList &getWidth() const{ - return m_w; - } - - /** Access to height. */ - const SList &getHeight() const{ - return m_h; - } - - }; // class DinoUmlDiagramGraph - - /** Output operator for DinoUmlDiagramGraph. */ - ostream &operator<<(ostream &os, const DinoUmlDiagramGraph &diagramGraph); - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/DinoUmlModelGraph.h b/ext/OGDF/ogdf/fileformats/DinoUmlModelGraph.h deleted file mode 100644 index 50a3db949..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoUmlModelGraph.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains the class DinoUmlModelGraph which represents the - * complete UML Model in a graph like data structure. - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_UML_MODEL_GRAPH_H -#define OGDF_DINO_UML_MODEL_GRAPH_H - -#include -#include -#include - -namespace ogdf { - - //--------------------------------------------------------- - // D i n o U m l M o d e l G r a p h - //--------------------------------------------------------- - /** This class represents the complete UML Model in a graph- - * like data structure. - */ - class OGDF_EXPORT DinoUmlModelGraph : public Graph { - - private: - - /** The name of the model. */ - String m_modelName; - - /** The label of the contained nodes. */ - NodeArray m_nodeLabel; - - /** The types of the contained edges. - * Types are association or generalization. - */ - EdgeArray m_eType; - - /** The types of the contained nodes. - * Types are vertex, dummy, generalizationMerger - */ - NodeArray m_vType; - - public: - - /** Constructor. */ - DinoUmlModelGraph(); - - /** Destructor. */ - ~DinoUmlModelGraph(); - - /** Sets the name of the model. */ - void setModelName(const String &name) { m_modelName = name; } - - /** Returns a const reference to the label of the given node. */ - const String &getNodeLabel(node v) const { return m_nodeLabel[v]; } - - /** Returns a reference to the label of the given node. */ - String &labelNode(node v) { return m_nodeLabel[v]; } - - /** Returns a const reference to the type of the given edge. */ - const Graph::EdgeType &type(edge e) const { return m_eType[e]; } - - /** Returns a reference to the type of the given edge. */ - Graph::EdgeType &type(edge e) { return m_eType[e]; } - - /** Returns a const reference to the type of the given node. */ - const Graph::NodeType &type(node v) const { return m_vType[v]; } - - /** Returns a reference to the type of the given node. */ - Graph::NodeType &type(node v) { return m_vType[v]; } - - }; // class DinoUmlModelGraph - - /** Output operator for DinoUmlModelGraph. */ - ostream &operator<<(ostream &os, const DinoUmlModelGraph &modelGraph); - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/DinoUmlToGraphConverter.h b/ext/OGDF/ogdf/fileformats/DinoUmlToGraphConverter.h deleted file mode 100644 index 302e08881..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoUmlToGraphConverter.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains the class DinoUmlToGraphConverter... - * - * ...which performs all necessary steps to obtain a model graph - * and a set of diagram graphs from the input file. - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_UML_TO_GRAPH_CONVERTER_H -#define OGDF_DINO_UML_TO_GRAPH_CONVERTER_H - -#include -#include -#include -#include - -namespace ogdf { - - //--------------------------------------------------------- - // D i n o U m l T o G r a p h C o n v e r t e r - //--------------------------------------------------------- - /** This class performs all necessary steps to obtain a model - * graph and diagram graphs from the input file which contains - * an UML model in XML format. - * In particular the following is done: - * - Given the input file a class DinoXmlParser is created which - * accomplishes the parsing of the XML file; as result of the - * parsing procedure a parse tree representing the xml document - * is accessible. - * - The parse tree is used to extract the model graph of the contained - * uml model as well as a set of diagram graphs which are part of the - * uml model. - * - * The graphs can be accessed via the functions getModelGraph() and - * getDiagramGraphs(). - * - * In debug mode warnings and the content of the model graph and the diagram - * graphs are written into the log file named \e umlToGraphConversionLog.txt. - */ - class OGDF_EXPORT DinoUmlToGraphConverter { - - private: - - /** The parser used for parsing the input file. */ - DinoXmlParser *m_xmlParser; - - /** The graph which represents the complete UML model. */ - DinoUmlModelGraph *m_modelGraph; - - /** The set of graphs which represent special diagrams - * contained in the model. - */ - SList m_diagramGraphs; - - /** This list contains the set of graphs of the list #m_diagramGraphs - * in UMLGraph format. The transformation is performed in the constructor - * #DinoUmlToGraphConverter(). - */ - SList m_diagramGraphsInUMLGraphFormat; - - /** Predefined info indices for known tag and attribute names. */ - enum PredefinedInfoIndex { - xmi = 0, - xmiContent, - xmiId, - umlModel, - umlNamespaceOwnedElement, - umlClass, - name, - umlGeneralization, - child, - parent, - umlAssociation, - umlAssociationConnection, - umlAssociationEnd, - type, - umlDiagram, - rootUmlDiagramElement, - umlDiagramElement, - geometry, - subject, - umlPackage, - umlInterface, - umlDependency, - client, - supplier, - diagramType, - classDiagram, - moduleDiagram, - - nextPredefinedInfoIndex - }; - - /** Maps string info to node. - * We need this hash table for fast access to nodes corresponding - * to UML elements. For each UML Element in XMI format we have an - * unique identifier via the xmi.id attribute. The xmi.id attribute - * is saved as string in the hash table of the parser, hence we can - * use the info index of it. While scanning for relations between nodes - * we encounter the xmi.id attribute values of the involved elements referenced - * as type attribute in the relation. Now we can use the hash table to - * access the corresponding node. - */ - Hashing m_idToNode; - - /** Maps string info to edge. - * The functionality is the same as for #m_idToNode. - */ - Hashing m_idToEdge; - - /** The log file. - * The log file is named \e umlToGraphConversionLog.txt and contains - * warnings and errors ocurred during the conversion process. Furthermore - * it contains the content of the model graph #m_modelGraph and of the - * diagram graphs #m_diagramGraphs. - */ - ofstream *m_logFile; - - public: - - /** Constructor. - * The constructor performs the following: - * - A parser object of class DinoXmlParser is created and - * the parse process is started via DinoXmlParser::createParseTree(). - * - The variable #m_modelGraph is initialized with an empty object - * of type DinoUmlModelGraph. Then the model graph is build up with - * createModelGraph(). - * - The list of diagram graphs #m_diagramGraphs is given to - * createDiagramGraphs() to build them up. - * - * @param fileName The file name of the xml file which contains the data - * of the uml model to be converted into the graph format. - */ - DinoUmlToGraphConverter(const char *fileName); - - /** Destructor. - * The destructor destroys: - * - the diagram graphs contained in #m_diagramGraphs, - * - the model graph contained in #m_modelGraph, - * - the parser contained in #m_xmlParser. - */ - ~DinoUmlToGraphConverter(); - - /** Access to model graph. - * @return A const reference to the model graph. - */ - const DinoUmlModelGraph &getModelGraph() const { - return *m_modelGraph; - } - - /** Access to diagram graphs. - * @return A const reference to the list of diagram graphs. - */ - const SList & getDiagramGraphs () const { - return m_diagramGraphs; - } - - /** Access to the diagrams graphs in UMLGraph format. - * @return A const reference to a list of diagram graphs in UMLGraph format. - */ - const SList & getDiagramGraphsInUMLGraphFormat () const { - return m_diagramGraphsInUMLGraphFormat; - } - - /** Prints the content of each diagram to \a os. - * @param os The output stream where to direct the output to. - */ - void printDiagramsInUMLGraphFormat(ofstream &os); - - /** Print hash table which maps the ids to the NodeElements. - * @param os The output stream where to direct the output to. - */ - void printIdToNodeMappingTable(ofstream &os); - - private: - - /** Inserts known strings for tags and attributes into the hashtable - * of the parser. The info elements for the hashtable are taken from - * enum #PredefinedInfoIndex. - */ - void initializePredefinedInfoIndices(); - - /** Converts the relevant information contained in the parse tree - * into the data structure of DinoUmlModelGraph. Error messages are - * reported in #m_logFile. - * @param modelGraph The model graph into which the nodes and edges - * corresponding to uml elements and uml relations should be inserted. - * @return Returns true if conversion was succesful, false otherwise. - */ - bool createModelGraph(DinoUmlModelGraph &modelGraph); - - /** Traverses the package structure and identifies classifiers inside - * the parse tree (starting at \a currentRootTag) and inserts a new node - * for each classifier. This function will call itself recursively while - * traversing nested packages. - * - * Valid classifiers are currently: \c class and \c interface. - * @param currentRootTag The tag where to start the search for classifiers. - * @param currentPackageName This string should contain the name of the package - * path corresponding to \a currentRootTag. - * @param modelGraph The model graph into which nodes are inserted. - * @return False if something went wrong, true otherwise. - */ - bool traversePackagesAndInsertClassifierNodes( - const XmlTagObject ¤tRootTag, - String currentPackageName, - DinoUmlModelGraph &modelGraph); - - /** Tries to find all classifiers of type \a desiredClassifier inside the parse - * tree (starting at \a currentRootTag). Inserts a new node into \a modelGraph - * for each classifier found. - * @param currentRootTag The tag where to start the search for the desired - * classifier. - * @param currentPackageName This string should contain the name of the package - * path corresponding to \a currentRootTag. - * @param desiredClassifier The info index of the desired class - * (see enum #PredefinedInfoIndex). - * @param modelGraph The model graph into which nodes are inserted. - * @return False if something went wrong, true otherwise. - */ - bool insertSpecificClassifierNodes( - const XmlTagObject ¤tRootTag, - String currentPackageName, - int desiredClassifier, - DinoUmlModelGraph &modelGraph); - - /** Traverses the package structure and identifies associations inside - * the parse tree and inserts a new edge between the corresponding - * nodes of the involved classifiers. - * - * Note that it is not possible to include this function into - * traversePackagesAndInsertClassifierNodes(). The reason is that it - * is possible that edges are specified prior to that one or both nodes - * have been created. - * @param currentRootTag The tag where to start the search for associations. - * @param modelGraph The model graph into which edges are inserted. - * @return False if something went wrong, true otherwise. - */ - bool traversePackagesAndInsertAssociationEdges( - const XmlTagObject ¤tRootTag, - DinoUmlModelGraph &modelGraph); - - /** Traverses the package structure and identifies generalization inside - * the parse tree and inserts a new edge between the corresponding - * nodes of the involved classifiers. - * - * It does not make sense to put this function and - * traversePackagesAndInsertAssociationEdges() together since the generalization - * tags are inside the class tags, so first the classes have to be identified - * again in contrast to traversePackagesAndInsertAssociationEdges(). - * @param currentRootTag The tag where to start the search for generalizations. - * @param modelGraph The model graph into which edges are inserted. - * @return False if something went wrong, true otherwise. - */ - bool traversePackagesAndInsertGeneralizationEdges( - const XmlTagObject ¤tRootTag, - DinoUmlModelGraph &modelGraph); - - - /** Identifies dependency tags inside the parse tree and inserts a - * new edge between the corresponding nodes of the involved elements. - * @param currentRootTag The tag where to start the search for dependencies. - * @param modelGraph The model graph into which edges are inserted. - * @return False if something went wrong, true otherwise. - */ - bool insertDependencyEdges( - const XmlTagObject ¤tRootTag, - DinoUmlModelGraph &modelGraph); - - /** For each diagram converts the relevant information contained in the parse tree - * into the data structure of DinoUmlDiagramGraph. Error messages are - * reported in #m_logFile. - * @return Returns true if conversion was succesful, false otherwise. - * \todo Currently only class diagrams are handled. Must be extended to handle - * other kinds of uml diagrams. - */ - bool createDiagramGraphs(); - - /** Transforms each diagram graph contained in #m_diagramGraphs into an equivalent - * Error messages are reported in #m_logFile. - * @param diagramGraphsInUMLGraphFormat The list of diagram graphs in UMLGraph - * format which have been obtained from the diagram graphs. - * @return Returns true if conversion was successful, false otherwise. - */ - bool createDiagramGraphsInUMLGraphFormat(SList &diagramGraphsInUMLGraphFormat); - - - }; // class DinoUmlToGraphConverter - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/DinoXmlParser.h b/ext/OGDF/ogdf/fileformats/DinoXmlParser.h deleted file mode 100644 index 9f211fd37..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoXmlParser.h +++ /dev/null @@ -1,461 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains the struct declarations XmlAttributeObject, XmlTagObject - * and the class DinoXmlParser. - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_XML_PARSER_H -#define OGDF_DINO_XML_PARSER_H - -#include -#include -#include -#include -#include - - - -namespace ogdf { - - //--------------------------------------------------------- - // H a s h e d S t r i n g - //--------------------------------------------------------- - - typedef HashElement HashedString; - - //--------------------------------------------------------- - // X m l A t t r i b u t e O b j e c t - //--------------------------------------------------------- - /** This struct represents an attribute associated to a tag. - */ - struct OGDF_EXPORT XmlAttributeObject { - - /** Contains the name of the attribute, i.e. - * for ... it contains "attr1" - */ - HashedString *m_pAttributeName; - - /** Contains the value assigned to this attribute without qoutes, i.e. - * for ... it contains "value1" and not "\"value1\"". - */ - HashedString *m_pAttributeValue; - - /** Pointer to the next attribute and 0 if this is the only attribute. */ - XmlAttributeObject *m_pNextAttribute; - - /** Constructor */ - XmlAttributeObject(HashedString *name, HashedString *value) : - m_pAttributeName(name), - m_pAttributeValue(value), - m_pNextAttribute(0) - {}; - - /** Destructor; will be performed in destroyParseTree(). */ - ~XmlAttributeObject(){}; - - /** Flag denotes whether attribute is valid or not. */ - bool m_valid; - - /** Getter. */ - const String& getName() const { - return m_pAttributeName->key(); - } - - const String& getValue() const { - return m_pAttributeValue->key(); - } - - const bool& valid() const { - return m_valid; - } - - /** Setter. */ - void setValid() { - m_valid = true; - } - - void setInvalid() { - m_valid = false; - } - - // Overloaded new and delete operators - OGDF_NEW_DELETE - - }; // struct XmlAttributeObject - - //--------------------------------------------------------- - // X m l T a g O b j e c t - //--------------------------------------------------------- - /** This struct represents a node in the XML parse tree. - */ - struct OGDF_EXPORT XmlTagObject { - - /** The identifier of the tag, - *i.e. for the identifier is "A" - */ - HashedString *m_pTagName; - - /** Pointer to the first attribute; - * if there is more than one attribute these are linked by - * m_pNextAttribute in struct XmlAttributeObject - */ - XmlAttributeObject *m_pFirstAttribute; - - /** Contains the characters inbetween the start tag and the end tag, - * i.e. for lala it contains " lala " - */ - HashedString *m_pTagValue; - - /** Contains the pointer to the first son tag object, - * i.e. for ... ... it contains a pointer - * to the object representing B - * The other children of A are reachable via m_pBrother of the first son, - * i.e. the variable m_pBrother of the object representing B contains a - * pointer to the object representing C - */ - XmlTagObject *m_pFirstSon; - - /** Contains the pointer to a brother tag object or 0 if this - * object is the only child - */ - XmlTagObject *m_pBrother; - - /** Constructor */ - XmlTagObject(HashedString *name) : - m_pTagName(name), - m_pFirstAttribute(0), - m_pTagValue(0), - m_pFirstSon(0), - m_pBrother(0), - m_valid(0) - {}; - - /** Destructor; will be performed in destroyParseTree(). */ - ~XmlTagObject(){}; - - /** Flag denotes whether attribute is valid or not. */ - mutable bool m_valid; - - /** integer value for the depth in the xml parse tree */ - int m_depth; - - /** integer value that stores the line number - * of the tag in the parsed xml document */ - int m_line; - - public: - - /**Checks if currentNode is leaf in the parse tree. - * Returns true if list of sons is empty. - * Returns false otherwise. - * - * NEW - */ - bool isLeaf() const; - - /**Searches for a son with tag name sonsName. - * Returns the son via the referenced pointer son. - * Returns true if son is found. - * Returns false, otherwise, son is set to NULL. - * - * NEW - */ - bool findSonXmlTagObjectByName( const String sonsName, - XmlTagObject *&son) const; - - /**Searches for sons with tag name sonsName. - * Returns the sons via a list with pointers to the sons. - * Returns true if at least one son was found. - * Returns false otherwise, sons is set to NULL. - * - * NEW - */ - bool findSonXmlTagObjectByName( const String sonsName, - List &sons) const; - - /**Searches for sons of father which names are inequal to those - * in list sonsNames. - * Returns true if at least one son of father is found whose name - * doesn't match one in sonsNames. - * Returns false otherwise. - * - * NEW - */ - bool hasMoreSonXmlTagObject(const List &sonNamesToIgnore) const; - - /**Searches for an attribute with name name. - * - * NEW - */ - bool findXmlAttributeObjectByName( - const String attName, - XmlAttributeObject*& attribute) const; - - /**Checks if currentTag owns at least one attribute. - * Returns true if list of attributes isn't empty. - * Returns false otherwise. - * - * NEW - */ - bool isAttributeLess() const; - - /** Getter. */ - const bool& valid() const { - return m_valid; - } - - const String& getName() const { - return m_pTagName->key(); - } - - const String& getValue() const { - return m_pTagValue->key(); - } - - /** Setter. */ - void setValid() const { - m_valid = true; - } - - void setInvalid() { - m_valid = false; - } - - /* get for depth of xml-tag-object */ - const int& getDepth() const { - return m_depth; - } - - /* setter for new depth */ - void setDepth(int newDepth){ - m_depth = newDepth; - } - - - /* get for line of xml-tag-object */ - const int& getLine() const { - return m_line; - } - - /* setter for line */ - void setLine(int line) { - m_line = line; - } - - // Overloaded new and delete operators - OGDF_NEW_DELETE - - }; // struct XmlTagObject - - //--------------------------------------------------------- - // D i n o X m l P a r s e r - //--------------------------------------------------------- - /** This class parses the XML input file and builds up a - * parse tree with linked elements XMLTagObject and - * XMLAttributeObject. The class DinoXmlScanner is used to - * get the token for the parse process. - */ - class OGDF_EXPORT DinoXmlParser { - - friend ostream &operator<<(ostream&, const DinoXmlParser &); - - private: - - /** Pointer to the root element of the parse tree. */ - XmlTagObject *m_pRootTag; - - /** Pointer to the scanner. */ - DinoXmlScanner *m_pScanner; - - /** Hash table for storing names of TagObjects and - * AttributeObjects in an efficient manner. - * The key element is String. - * The info element is int. - */ - Hashing m_hashTable; - - /** The info element of the hash table is simply an integer - * number which is incremented for each new element (starting at 0). - * The value m_hashTableInfoIndex - 1 is the last used index. - */ - int m_hashTableInfoIndex; - - /** Recursion depth of parse(). */ - int m_recursionDepth; - /** stack for checking correctness of correspondent closing tags */ - Stack m_tagObserver; - - - public: - - /** Constructor. - * Inside the constructor the scanner is generated. - */ - DinoXmlParser(const char *fileName); - - /** Destructor; destroys the parse tree. */ - ~DinoXmlParser(); - - /** Creates a new hash element and inserts it into the hash table. - */ - void addNewHashElement(const String &key, int info){ - OGDF_ASSERT(info >= m_hashTableInfoIndex) - m_hashTable.fastInsert(key, info); - m_hashTableInfoIndex = info + 1; - } - - /** Creates the parse tree and anchors it in m_pRootTag. - * TODO: Should return a value to indicate if success. - */ - void createParseTree(); - - /** Allows (non modifying) access to the parse tree. */ - const XmlTagObject &getRootTag() const { - return *m_pRootTag; - } - - /** Traverses the parseTree starting at startTag using the path - * description in path, which contains the infoIndices of the tags - * which have to be traversed. - * If the XmlTagObject associated to the last infoIndex in the path is - * found, it is returned via targetTag and the return value is true - * If the XmlTagObject is not found the return value is false. - */ - bool traversePath( - const XmlTagObject &startTag, - const Array &infoIndexPath, - const XmlTagObject *&targetTag) const; - - /** Searches for a specific son (identified by sonInfoIndex) - * of father. - * Returns the son via the referenced pointer son. - * Returns true if son is found. - * Returns false otherwise, son is set to NULL. - */ - bool findSonXmlTagObject( - const XmlTagObject &father, - int sonInfoIndex, - const XmlTagObject *&son) const; - - /** Searches for a specific brother (identified by brotherInfoIndex) - * of current. - * Returns the brother via the referenced pointer brother. - * Returns true if brother is found. - * Returns false otherwise, brother is set to NULL. - */ - bool findBrotherXmlTagObject( - const XmlTagObject ¤tTag, - int brotherInfoIndex, - const XmlTagObject *&brother) const; - - /** Searches for a specific attribute (identified by attributeInfoIndex) - * of current. - * Returns the attribute via the referenced pointer attribute. - * Returns true if attribute is found. - * Returns false otherwise, attribute is set to NULL. - */ - bool findXmlAttributeObject( - const XmlTagObject ¤tTag, - int attributeInfoIndex, - const XmlAttributeObject *&attribute) const; - - /** Returns line number of the most recently read line of - * the input file. - */ - inline int getInputFileLineCounter() const { - return m_pScanner->getInputFileLineCounter(); - } - - /** Prints the content of the hash table to os. */ - void printHashTable(ostream &os); - - private: - - /** Destroys the parse tree appended to root. */ - void destroyParseTree(XmlTagObject *root); - - /** Parses the token stream provided by the scanner until a complete - * XmlTagObject is identified which will be returned. - * This function is likely to be called recursively - * due to the recursive structure of XML documents. - */ - XmlTagObject* parse(); - - /** Append attributeObject to list of attributes of tagObject. */ - void appendAttributeObject( - XmlTagObject *tagObject, - XmlAttributeObject *attributeObject); - - /** Appends sonTagObject to the list of sons of currentTagObject. */ - void appendSonTagObject( - XmlTagObject *currentTagObject, - XmlTagObject *sonTagObject); - - /** Returns the hash element for the given string. - * If the key str is not contained in the table yet, it is - * inserted together with a new info index and the new - * hash element is returned. - * If the key str exists, the associated hash element is returned. - */ - HashedString *hashString(const String &str); - - /** Prints the given XmlTagObject and its children recursively. - * The parameter indent is used as indentation value. - */ - void printXmlTagObjectTree( - ostream &os, - const XmlTagObject &rootObject, - int indent = 0) const; - - /** Little helper that prints nOfSpaces space characters. */ - void printSpaces(ostream &os, int nOfSpaces) const; - - }; // class DinoXmlParser - - /** Output operator for DinoXmlParser. */ - ostream &operator<<(ostream &os, const DinoXmlParser &parser); - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/DinoXmlScanner.h b/ext/OGDF/ogdf/fileformats/DinoXmlScanner.h deleted file mode 100644 index 75dd206aa..000000000 --- a/ext/OGDF/ogdf/fileformats/DinoXmlScanner.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains the enum XmlToken and the class DinoXmlScanner. - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DINO_XML_SCANNER_H -#define OGDF_DINO_XML_SCANNER_H - -#include - -namespace ogdf { - - //--------------------------------------------------------- - // X m l T o k e n - //--------------------------------------------------------- - /** This enum type represents the values, which are returned by - * the function DinoXmlScanner::getNextToken(). - * @see DinoXmlScanner::getNextToken() - */ - enum XmlToken { - openingBracket, ///< < - closingBracket, ///< > - questionMark, ///< ? - exclamationMark, ///< ! - minus, ///< - - slash, ///< / - equalSign, ///< = - identifier, ///< (a..z|A..Z){(a..z|A..Z|0..9|.|_|:)} - attributeValue, ///< a sequence of characters, digits, minus - and dot . - quotedValue, ///< all quoted content " ... " or ' ... ' - endOfFile, ///< End of file detected - invalidToken, ///< No token identified - noToken ///< Used for the m_lookAheadToken to indicate that there - ///< is no lookahead token - }; // enum XmlToken - - - //--------------------------------------------------------- - // D i n o X m l S c a n n e r - //--------------------------------------------------------- - /** This class scans the characters of the input file and - * provides the detected token. - */ - class OGDF_EXPORT DinoXmlScanner { - - private: - - // Pointer to the line buffer - DinoLineBuffer *m_pLineBuffer; - - // String which contains the characters of the current token - // Its size is limited to DinoLineBuffer::c_maxStringLength - char *m_pCurrentTokenString; - - public: - // construction - DinoXmlScanner(const char *fileName); - - // destruction: destroys the parse tree - ~DinoXmlScanner(); - - // This function represents the core of the scanner. It scans the input - // and returns the identified token. After performing getNextToken() the - // token is "consumed", i.e. the line buffer pointer already points to the - // next token. - // The scanned string is deposited in m_pCurrentTokenString, hence it is - // available via getCurrentTokenString() - XmlToken getNextToken(); - - // Returns the current token string - inline const char *getCurrentTokenString(){ - return m_pCurrentTokenString; - } - - // This function provides a lookahead to the next token; - // the token is NOT consumed like it is the case for getNextToken() - XmlToken testNextToken(); - - // This function provides a lookahead to the nextnext token; - // the tokens are NOT consumed like it is the case for getNextToken() - XmlToken testNextNextToken(); - - // Skips until the searchCharacter is found; - // - // If skipOverSearchCharacter is set true the currentPosition will be set - // BEHIND the search character - // otherwise the pointer currentPosition points TO the searchCharacter - // - // Returns true if the searchCharacter is found - // Returns false if file ends before the searchCharacter is found - bool skipUntil(char searchCharacter, bool skipOverSearchCharacter = true); - - // Skips until '>' is found (> is consumed) - // Nested brackets are taken into account - // Returns true if matching bracket has been found; false otherwise - bool skipUntilMatchingClosingBracket(); - - // Reads until the searchCharacter is found; the string starting at the current - // position and ending at the position where the search character is found - // is deposited in m_pCurrentTokenString. - // If includeSearchCharacter is false (default) the search character is - // not contained; otherwise it is contained - // - // Returns true if the searchCharacter is found - // Returns false if file ends before the searchCharacter is found - bool readStringUntil(char searchCharacter, bool includeSearchCharacter = false); - - // Returns line number of the most recently read line of the input file - inline int getInputFileLineCounter() const { - return m_pLineBuffer->getInputFileLineCounter(); - } - - // This function tests the scanner by reading the complete - // input file and printing the identified token to stdout - void test(); - - }; // class DinoXmlScanner - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/GmlParser.h b/ext/OGDF/ogdf/fileformats/GmlParser.h deleted file mode 100644 index 337c5bb48..000000000 --- a/ext/OGDF/ogdf/fileformats/GmlParser.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of classes GmlObject and GmlParser. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GML_PARSER_H -#define OGDF_GML_PARSER_H - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -typedef HashElement *GmlKey; -enum GmlObjectType { gmlIntValue, gmlDoubleValue, gmlStringValue, gmlListBegin, - gmlListEnd, gmlKey, gmlEOF, gmlError }; - - -//--------------------------------------------------------- -// GmlObject -// represents node in GML parse tree -//--------------------------------------------------------- -struct OGDF_EXPORT GmlObject { - GmlObject *m_pBrother; // brother of node in tree - GmlKey m_key; // tag of node - GmlObjectType m_valueType; // type of node - - // the entry in the union is selected according to m_valueType: - // gmlIntValue -> m_intValue - // gmlDoubleValue -> m_doubleValue - // gmlStringValue -> m_stringValue - // gmlListBegin -> m_pFirstSon (in case of a list, m_pFirstSon is pointer - // to first son and the sons are chained by m_pBrother) - union { - int m_intValue; - double m_doubleValue; - const char *m_stringValue; - GmlObject *m_pFirstSon; - }; - - // construction - GmlObject(GmlKey key, int intValue) : m_pBrother(0), m_key(key), - m_valueType(gmlIntValue), m_intValue(intValue) { } - - GmlObject(GmlKey key, double doubleValue) : m_pBrother(0), m_key(key), - m_valueType(gmlDoubleValue), m_doubleValue(doubleValue) { } - - GmlObject(GmlKey key, const char *stringValue) : m_pBrother(0), m_key(key), - m_valueType(gmlStringValue), m_stringValue(stringValue) { } - - GmlObject(GmlKey key) : m_pBrother(0), m_key(key), - m_valueType(gmlListBegin), m_pFirstSon(0) { } - - OGDF_NEW_DELETE -}; - - -//--------------------------------------------------------- -// GmlParser -// reads GML file and constructs GML parse tree -//--------------------------------------------------------- -class OGDF_EXPORT GmlParser { - Hashing m_hashTable; // hash table for tags - int m_num; - - istream *m_is; - bool m_error; - String m_errorString; - - char *m_rLineBuffer, *m_lineBuffer, *m_pCurrent, *m_pStore, m_cStore; - - int m_intSymbol; - double m_doubleSymbol; - const char *m_stringSymbol; - GmlKey m_keySymbol; - String m_longString; - - GmlObject *m_objectTree; // root node of GML parse tree - - bool m_doCheck; - Array m_mapToNode; - GmlObject *m_graphObject; - -public: - // predefined id constants for all used keys - enum PredefinedKey { idPredefKey = 0, labelPredefKey, CreatorPredefKey, - namePredefKey, graphPredefKey, versionPredefKey, directedPredefKey, - nodePredefKey, edgePredefKey, graphicsPredefKey, xPredefKey, - yPredefKey, wPredefKey, hPredefKey, typePredefKey, widthPredefKey, - sourcePredefKey, targetPredefKey, arrowPredefKey, LinePredefKey, - pointPredefKey, generalizationPredefKey, subGraphPredefKey, fillPredefKey, clusterPredefKey, - rootClusterPredefKey, vertexPredefKey, colorPredefKey, - heightPredefKey, stipplePredefKey, patternPredefKey, - linePredefKey, lineWidthPredefKey, templatePredefKey, - edgeWeightPredefKey, NEXTPREDEFKEY }; - - // construction: creates object tree - // sets m_error flag if an error occured - GmlParser(const char *fileName, bool doCheck = false); - GmlParser(istream &is, bool doCheck = false); - - // destruction: destroys object tree - ~GmlParser(); - - // returns id of object - int id(GmlObject *object) const { return object->m_key->info(); } - - // true <=> an error in GML files has been detected - bool error() const { return m_error; } - // returns error message - const String &errorString() const { return m_errorString; } - - // creates graph from GML parse tree - bool read(Graph &G); - // creates attributed graph from GML parse tree - bool read(Graph &G, GraphAttributes &AG); - //creates clustergraph from GML parse tree - //bool read(Graph &G, ClusterGraph & CG); - //read only cluster part of object tree and create cluster graph structure - bool readCluster(Graph &G, ClusterGraph& CG); - //the same with attributes - bool readAttributedCluster( - Graph &G, - ClusterGraph& CG, - ClusterGraphAttributes& ACG); - -protected: - - //read all cluster tree information - bool clusterRead( - GmlObject* rootCluster, - ClusterGraph& CG); - - //with attributes - bool attributedClusterRead( - GmlObject* rootCluster, - ClusterGraph& CG, - ClusterGraphAttributes& ACG); - - //recursively read cluster subtree information - bool recursiveClusterRead( - GmlObject* clusterObject, - ClusterGraph& CG, - cluster c); - - bool recursiveAttributedClusterRead( - GmlObject* clusterObject, - ClusterGraph& CG, - ClusterGraphAttributes& ACG, - cluster c); - - bool readClusterAttributes( - GmlObject* cGraphics, - cluster c, - ClusterGraphAttributes& ACG); - -private: - void doInit(istream &is, bool doCheck); - void createObjectTree(istream &is, bool doCheck); - void initPredefinedKeys(); - void setError(const char *errorString); - - GmlObject *parseList(GmlObjectType closingKey, GmlObjectType errorKey); - GmlObjectType getNextSymbol(); - bool getLine(); - - GmlKey hashString(const String &str); - - GmlObject *getNodeIdRange(int &minId,int &maxId); - void readLineAttribute(GmlObject *object, DPolyline &dpl); - - void destroyObjectList(GmlObject *object); - - void indent(ostream &os, int d); - void output(ostream &os, GmlObject *object, int d); - -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/Ogml.h b/ext/OGDF/ogdf/fileformats/Ogml.h deleted file mode 100644 index b0506b523..000000000 --- a/ext/OGDF/ogdf/fileformats/Ogml.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains diverse enumerations and string constants. - * See comments for further information. - * - * \author Christian Wolf - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_OGML_H -#define OGDF_OGML_H - -#include - - -namespace ogdf -{ - -class Ogml -{ -public: - - //! Max count of ogml tags (used for setting maxOccurs). - static const int MAX_TAG_COUNT = 4000; - - - //! This enumeration is used for identifying OGML tags. - enum TagId - { - t_none = -1, - t_bool, - t_composed, - t_constraint, - t_constraints, - t_content, - t_data, - t_default, - t_edge, - t_edgeRef, - t_edgeStyle, - t_edgeStyleTemplate, - t_edgeStyleTemplateRef, //!< tag template within tag edgeStyle/-Template - t_endpoint, - t_fill, - t_font, - t_graph, - t_graphStyle, - t_int, - t_label, - t_labelRef, - t_labelStyle, - t_labelStyleTemplate, - t_labelStyleTemplateRef, //!< tag template within tag labelStyle/-Template - t_layout, - t_line, - t_location, - t_node, - t_nodeRef, - t_nodeStyle, - t_nodeStyleTemplate, - t_nodeStyleTemplateRef, //!< tag template within tag nodeStyle/-Template - t_num, - t_ogml, - t_point, - t_port, - t_segment, - t_shape, - t_source, - t_sourceStyle, - t_string, - t_structure, - t_styles, - t_styleTemplates, - t_target, - t_targetStyle, - t_text, - t_image, - - TAG_NUM //!< number of tags - }; - - - //! Stores the names of all OGML tags. - static const String s_tagNames[TAG_NUM]; - - - //! This enumeration is used for identifying OGML attributes. - enum AttributeId - { - a_none = -1, - a_alignment, - a_angle, - a_color, - a_decoration, - a_defaultEdgeTemplate, - a_defaultLabelTemplate, - a_defaultNodeTemplate, - a_family, - a_height, - a_id, //!< id attribute - a_nodeIdRef, //!< attribute idRef of elements source, target, nodeRef, nodeStyle - a_edgeIdRef, //!< attribute idRef of elements edgeRef, edgeStyle - a_labelIdRef, //!< attribute idRef of elements edgeRef, edgeStyle - a_sourceIdRef, //!< attribute idRef of element endpoint - a_targetIdRef, //!< attribute idRef of element endpoint - a_nodeStyleTemplateIdRef, //!< attribute idRef of subelement template of element nodeStyle - a_edgeStyleTemplateIdRef, //!< attribute idRef of subelement template of element edgeStyle - a_labelStyleTemplateIdRef, //!< attribute idRef of subelement template of element labelStyle - a_endpointIdRef, //!< attribute idRef of subelement endpoint of element segment - a_name, - a_nLineType, //!< attribute type of subelement line of tag nodeStyleTemplate - a_nShapeType, //!< attribute type of subelement shape of tag nodeStyleTemplate - a_pattern, - a_patternColor, - a_rotation, - a_size, - a_stretch, - a_style, - a_transform, - a_type, //!< attribute type of subelements source-/targetStyle of tag edgeStyleTemplate - a_uri, - a_intValue, - a_boolValue, - a_numValue, - a_variant, - a_weight, - a_width, - a_x, - a_y, - a_z, - a_imageUri, - a_imageStyle, - a_imageAlignment, - a_imageDrawLine, - a_imageWidth, - a_imageHeight, - a_constraintType, - a_disabled, - - ATT_NUM //!< number of attributes - }; - - - //! Stores the names of all OGML attributes. - static const String s_attributeNames[ATT_NUM]; - - - //! This enumeration is used for identifying OGML attributes. - enum AttributeValueId - { - av_any = 0, //!< for any attributeValue - av_blink, - av_bold, - av_bolder, - av_bool, - av_box, - av_capitalize, - av_center, - av_checked, - av_circle, - av_condensed, - av_cursive, - av_dashed, - av_esNoPen, //!< values for line style - av_esSolid, - av_esDash, - av_esDot, - av_esDashdot, - av_esDashdotdot, - av_diamond, - av_dotted, - av_double, - av_doubleSlash, - av_ellipse, - av_expanded, - av_extraCondensed, - av_extraExpanded, - av_fantasy, - av_filledBox, - av_filledCircle, - av_filledDiamond, - av_filledHalfBox, - av_filledHalfCircle, - av_filledHalfDiamond, - av_filledHalfRhomb, - av_filledRhomb, - av_smurf, - av_arrow, - av_groove, - av_halfBox, - av_halfCircle, - av_halfDiamond, - av_halfRhomb, - av_hexagon, - av_hex, //!< hexadecimal value - av_id, - av_nodeIdRef, //!< attribute idRef of elements source, target, nodeRef, nodeStyle - av_edgeIdRef, //!< attribute idRef of elements edgeRef, edgeStyle - av_labelIdRef, //!< attribute idRef of elements edgeRef, edgeStyle - av_sourceIdRef, //!< attribute idRef of element endpoint - av_targetIdRef, //!< attribute idRef of element endpoint - av_nodeStyleTemplateIdRef, //!< attribute idRef of subelement template of element nodeStyle - av_edgeStyleTemplateIdRef, //!< attribute idRef of subelement template of element edgeStyle - av_labelStyleTemplateIdRef, //!< attribute idRef of subelement template of element labelStyle - av_pointIdRef, //!< attribute idRef of subelement endpoint of element segment - av_image, - av_inset, - av_int, //!< integer value - av_italic, - av_justify, - av_left, - av_lighter, - av_line, - av_lineThrough, - av_lowercase, - av_lParallelogram, - av_monospace, - av_narrower, - av_none, - av_normal, - av_num, //!< real value - av_oblique, - av_oct, - av_octagon, - av_outset, - av_overline, - av_pentagon, - av_rect, - av_rectSimple, - av_rhomb, - av_ridge, - av_right, - av_rParallelogram, - av_sansSerif, - av_semiCondensed, - av_semiExpanded, - av_serif, - av_slash, - av_smallCaps, - av_solid, - av_bpNone, //!< values for node patterns - av_bpSolid, - av_bpDense1, - av_bpDense2, - av_bpDense3, - av_bpDense4, - av_bpDense5, - av_bpDense6, - av_bpDense7, - av_bpHorizontal, - av_bpVertical, - av_bpCross, - av_bpBackwardDiagonal, - av_bpForwardDiagonal, - av_bpDiagonalCross, - av_string, - av_striped, - av_trapeze, - av_triangle, - av_triple, - av_ultraCondensed, - av_ultraExpanded, - av_umlClass, - av_underline, - av_uppercase, - av_upTrapeze, - av_uri, - av_wider, - av_freeScale, //!< image-style - av_fixScale, //!< image-style - av_topLeft, //!< image-alignemnt - av_topCenter, //!< image-alignemnt - av_topRight, //!< image-alignemnt - av_centerLeft, //!< image-alignemnt - // av_center, // just defined // image-alignemnt - av_centerRight, //!< image-alignemnt - av_bottomLeft, //!< image-alignemnt - av_bottomCenter, //!< image-alignemnt - av_bottomRight, //!< image-alignemnt - // Constraint-Types: - av_constraintAlignment, - av_constraintAnchor, - av_constraintSequence, - - ATT_VAL_NUM //!< number of attribute values - }; - - - //! Stores the names of all OGML values of attributes. - static const String s_attributeValueNames[ATT_VAL_NUM]; - - - //! This enumeration is used for encoding diverse validity stati of tags and attributes after parsing and validating a Xml file. - enum ValidityState - { - vs_tagEmptIncl = -10, //!< empty tag inclusion - vs_idNotUnique = -9, //!< id already exhausted - vs_idRefErr = -8, //!< referenced id wasn't found or wrong type of referenced tag - vs_unexpTag = -7, //!< tag unexpected - vs_unexpAtt = -6, //!< attribute unexpected - vs_expTagNotFound = -5, //!< expected tag not found - vs_expAttNotFound = -4, //!< expected attribute not found - vs_attValueErr = -3, //!< attribute-value error - vs_cardErr = -2, //!< tag/attribute cardinality error - vs_invalid = -1, //!< tag/attribute is invalid (no detailled information) - vs_valid = 1 //!< tag/attribute is valid - }; - - - //! This enumeration is used for indentifying graph types. - enum GraphType - { - graph, - clusterGraph, - compoundGraph, - corruptCompoundGraph - }; - - - //! Stores the names of graph types. - static const String s_graphTypeS[]; -}; - -}; //namspace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/OgmlParser.h b/ext/OGDF/ogdf/fileformats/OgmlParser.h deleted file mode 100644 index 05f47af74..000000000 --- a/ext/OGDF/ogdf/fileformats/OgmlParser.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of auxiliary classes OgmlAttributeValue, - * OgmlAttribute and OgmlTag. - * - * \author Christian Wolf and Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -//KK: Commented out the constraint stuff using //o -//CG: compound graph stuff has been removed with commit 2465 - -#ifndef OGDF_OGML_PARSER_H -#define OGDF_OGML_PARSER_H - -#include -#include -#include -#include -#include -#include - -// constraints -//o#include - - -namespace ogdf { - -// -// ---------- O g m l P a r s e r ------------------------ -// - -/**Objects of this class represent a validating parser for files in Ogml. -*/ -class OgmlParser -{ -private: - - // struct definitions for mapping of templates - struct OgmlNodeTemplate; - struct OgmlEdgeTemplate; - //struct OgmlLabelTemplate; - - struct OgmlSegment; - - class OgmlAttributeValue; - class OgmlAttribute; - class OgmlTag; - - friend ostream& operator<<(ostream& os, const OgmlParser::OgmlAttribute& oa); - friend ostream& operator<<(ostream& os, const OgmlParser::OgmlTag& ot); - - static Hashing *s_tags; //!< Hashtable for saving all ogml tags. - static Hashing *s_attributes; //!< Hashtable for saving all ogml attributes. - static Hashing *s_attValues; //!< Hashtable for saving all values of ogml attributes. - - - //! Builds hashtables for tags and attributes. - static void buildHashTables(); - - mutable Ogml::GraphType m_graphType; //!< Saves a graph type. Is set by checkGraphType. - - Hashing m_ids; //!< Saves all ids of an ogml-file. - - /** - * Checks if all tags (XmlTagObject), their attributes (XmlAttributeObject) and - * their values are valid (are tags expected, do they own the rigth attributes...) - * and sets a valid flag to these. Furthermore it checks if ids of tags are - * unique and if id references are valid. - * See OgmlTag.h for semantics of the encodings. - * Returns the validity state of the current processed tag. - */ - int validate(const XmlTagObject *xmlTag, int ogmlTag); - - /** - * Wrapper method for validate method above. - * Returns true when validation is successfull, false otherwise. - */ - //bool validate(const char* fileName); - - //! Prints some useful information about un-/successful validation. - void printValidityInfo(const OgmlTag &ot, - const XmlTagObject &xto, - int valStatus, - int line); - - /** - * Finds the OGML-tag in the parse tree with the specified id, - * stores the tag in xmlTag - * recTag is the tag for recursive calls - * returns false if something goes wrong - */ - //bool getXmlTagObjectById(XmlTagObject *recTag, String id, XmlTagObject *&xmlTag); - - /** - * Checks the graph type and stores it in the member variable m_graphType - * xmlTag has to be the root or the graph or the structure Ogml-tag - * returns false if something goes wrong - */ - bool checkGraphType(const XmlTagObject *xmlTag) const; - - //! Returns true iff subgraph is an hierarchical graph. - bool isGraphHierarchical(const XmlTagObject *xmlTag) const; - - //! Returns true iff node contains other nodes. - bool isNodeHierarchical(const XmlTagObject *xmlTag) const; - - Ogml::GraphType getGraphType() { return m_graphType; }; - - - // id hash tables - // required variables for building - // hash table with id from file and node - Hashing m_nodes; - Hashing m_edges; - Hashing m_clusters; - // hash table for bend-points - Hashing m_points; - - // hash table for checking uniqueness of ids - // (key:) int = id in the created graph - // (info:) String = id in the ogml file - Hashing m_nodeIds; - Hashing m_edgeIds; - Hashing m_clusterIds; - - // build methods - - //! Builds a graph; ignores nodes which have hierarchical structure. - bool buildGraph(Graph &G); - - //! Builds a cluster graph. - bool buildCluster( - const XmlTagObject *rootTag, - Graph &G, - ClusterGraph &CG); - - //! Recursive part of buildCluster. - bool buildClusterRecursive( - const XmlTagObject *xmlTag, - cluster parent, - Graph &G, - ClusterGraph &CG); - - //! Build a cluster graph with style/layout attributes. - bool buildAttributedClusterGraph( - Graph &G, - ClusterGraphAttributes &CGA, - const XmlTagObject *root); - - //! Method for setting labels of clusters. - bool setLabelsRecursive( - Graph &G, - ClusterGraphAttributes &CGA, - XmlTagObject *root); - - // helping pointer for constraints-loading - // this pointer is set in the building methods - // so we don't have to traverse the tree in buildConstraints - XmlTagObject* m_constraintsTag; - - // hashing lists for templates - // string = id - Hashing m_ogmlNodeTemplates; - Hashing m_ogmlEdgeTemplates; - //Hashing m_ogmlLabelTemplates; - - // auxiliary methods for mapping graph attributes - - //! Returns int value for the pattern. - int getBrushPatternAsInt(String s); - - //! Returns the shape as an integer value. - int getShapeAsInt(String s); - - //! Maps the OGML attribute values to corresponding GDE values. - String getNodeTemplateFromOgmlValue(String s); - - //! Returns the line type as an integer value. - int getLineTypeAsInt(String s); - - //! Returns the image style as an integer value. - int getImageStyleAsInt(String s); - - //! Returns the alignment of image as an integer value. - int getImageAlignmentAsInt(String s); - - // arrow style, actually a "boolean" function - // because it returns only 0 or 1 according to GDE - // sot <=> source or target - int getArrowStyleAsInt(String s, String sot); - - // the matching method to getArrowStyleAsInt - GraphAttributes::EdgeArrow getArrowStyle(int i); - - // function that operates on a string - // the input string contains "<" instead of "<" - // and ">" instead of ">" - // to disable interpreting the string as xml-tags (by DinoXmlParser) - // so this function substitutes "<" for "<" - String getLabelCaptionFromString(String str); - - //! Returns the integer value of the id at the end of the string (if it exists). - bool getIdFromString(String str, int &id); - - //! Validiation method. - void validate(const char* fileName); - -public: - - //! Constructs an OGML parser. - OgmlParser() { } - - ~OgmlParser() { } - - - //! Reads a cluster graph \a CG from file \a fileName in OGML format. - /** - * @param fileName is the name of the file to be parsed as OGML file. - * @param G is the graph to be build from the OGML file; must be the graph associated with \a CG. - * @param CG is the cluster graph to be build from the OGML file. - * @return true if succesfull, false otherwise. - */ - bool read( - const char* fileName, - Graph &G, - ClusterGraph &CG); - - //! Reads a cluster graph \a CG with attributes \a CGA from file \a fileName in OGML format. - /** - * @param fileName is the name of the file to be parsed as OGML file. - * @param G is the graph to be build from the OGML file; must be the graph associated with \a CG. - * @param CG is the cluster graph to be build from the OGML file. - * @param CGA are the cluster graph attributes (associated with CG) in which layout and style information are stored. - * @return true if succesfull, false otherwise. - */ - bool read( - const char* fileName, - Graph &G, - ClusterGraph &CG, - ClusterGraphAttributes &CGA); - -};//end class OGMLParser - -}//end namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/fileformats/SteinLibParser.h b/ext/OGDF/ogdf/fileformats/SteinLibParser.h deleted file mode 100644 index dcc3e9402..000000000 --- a/ext/OGDF/ogdf/fileformats/SteinLibParser.h +++ /dev/null @@ -1,223 +0,0 @@ -/** \file - * \brief Implementation of a parser for SteinLib instances. - * - * \author Matthias Woste - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_STEIN_LIB_PARSER_H_ -#define OGDF_STEIN_LIB_PARSER_H_ - -#include -#include -#include - -namespace ogdf { - -/*! - * \brief Reads a SteinLib file and converts it into a weighted graph and a set of terminal nodes. - * - * Attention: The coordinate section is not read! - */ -template -class SteinLibParser { -public: - /*! - * \brief Reads a SteinLib file and converts it into a weighted graph and a set of terminal nodes - * @param fileName Name of the SteinLib file - * @param wG Graph structure that will represent the graph stored in the SteinLib file - * @param terminals List of terminals specified in the SteinLib file - * @param isTerminal Incidence vector for the terminal nodes in the graph - * @return True, if the parsing was successful, false otherwise - */ - bool readSteinLibInstance(const char *fileName, EdgeWeightedGraph &wG, List &terminals, - NodeArray &isTerminal) const { - - std::ifstream is(fileName); - if (!is && !is.good()) { - return false; - } - - char buffer[1024]; - int section = 0; - int nextSection = 1; - char value[1024]; - char key[1024]; - int scannedElements; - int n; - int v1, v2, v3; - Array indexToNode; - //node root; // root terminal (directed case) - - std::string name, date, creator, remark; - - // 1. line = identifier - is.getline(buffer, 1024); - if (strcasecmp(buffer, "33D32945 STP File, STP Format Version 1.0") - && strcasecmp(buffer, "33d32945 STP File, STP Format Version 1.00")) { - return false; - } - - while (!is.eof()) { - is.getline(buffer, 1024); - - if (buffer[0] == '#' || strlen(buffer) == 0 || buffer[0] == '\n') { - continue; - } - - switch (section) { - case 0: - if (!strcasecmp(buffer, "SECTION Comment") - && nextSection == 1) { - section = 1; - } else if (!strcasecmp(buffer, "SECTION Graph") - && nextSection == 2) { - section = 2; - } else if (!strcasecmp(buffer, "SECTION Terminals") - && nextSection == 3) { - section = 3; - } else if (!strcasecmp(buffer, "SECTION Coordinates") - && nextSection == 4) { - section = 4; - } else if (!strcasecmp(buffer, "EOF") && nextSection >= 4) { - return true; - } - break; - case 1: // comment section - sscanf(buffer, "%s %s", key, value); - if (strcmp(key, "Name") == 0) { - name = value; - } else if (!strcasecmp(key, "Date")) { - date = value; - } else if (!strcasecmp(key, "Creator")) { - creator = value; - } else if (!strcasecmp(key, "Remark")) { - remark = value; - } else if (!strcasecmp(key, "END")) { - nextSection = 2; - section = 0; - } else { - return false; - } - break; - case 2: // graph section - scannedElements = sscanf(buffer, "%s %d %d %d", key, &v1, &v2, &v3); - switch (scannedElements) { - case 1: // END - if (!strcasecmp(key, "END")) { - nextSection = 3; - section = 0; - } else { - return false; - } - break; - case 2: //Number of nodes, edges or arcs - if (!strcasecmp(key, "Nodes")) { - n = v1; - indexToNode = Array(1, n, 0); - for (int i = 1; i <= n; i++) { - indexToNode[i] = wG.newNode(); - isTerminal[indexToNode[i]] = false; - } - } -#if 0 - else if (!strcasecmp(key, "Edges")) { - m = v1; - wG.directed(false); - } else if (!strcasecmp(key, "Arcs")) { - m = v1; - wG.directed(true); - } -#endif - break; - case 4: // specific edge or arc - switch (buffer[0]) { - case 'E': - case 'A': - if (v1 > n || v2 > n) { - return false; - } - wG.newEdge(indexToNode[v1], indexToNode[v2], v3); - break; - default: - return false; - } - ; - break; - default: - return false; - } - break; - case 3: // terminals section - sscanf(buffer, "%s %d", key, &v1); -#if 0 - if (!strcasecmp(key, "Terminals")) { - t = v1; // set number of terminals - } else if (!strcasecmp(key, "Root")) { - if (v1 > n) { - return false; - } - root = indexToNode[v1]; - } else -#endif - if (!strcasecmp(key, "T")) { - if (v1 > n) { - return false; - } - terminals.pushBack(indexToNode[v1]); - isTerminal[indexToNode[v1]] = true; - } else if (!strcasecmp(key, "END")) { - nextSection = 4; - section = 0; - } - // no else: ignore unused keys - break; - case 4: // coordinates section (omitted) - sscanf(buffer, "%s", key); - if (!strcasecmp(key, "END")) { - nextSection = 5; - section = 0; - } - break; - default: - return false; - } - } - return false; - } -}; - -} - -#endif /* OGDF_STEIN_LIB_PARSER_H_ */ diff --git a/ext/OGDF/ogdf/fileformats/XmlObject.h b/ext/OGDF/ogdf/fileformats/XmlObject.h deleted file mode 100644 index 8257aa0cd..000000000 --- a/ext/OGDF/ogdf/fileformats/XmlObject.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class XmlObject. - * - * \author Sebastian Leipert and Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_XML_OBJECT_H -#define OGDF_XML_OBJECT_H - - - -namespace ogdf { - - -typedef HashElement *XmlKey; -enum XmlObjectType { xmlIntValue, xmlDoubleValue, xmlStringValue, xmlListBegin, - xmlListEnd, xmlKey, xmlEOF, xmlError }; - - -//--------------------------------------------------------- -// XmlObject -// represents node in XML parse tree -//--------------------------------------------------------- -struct OGDF_EXPORT XmlObject { - - XmlObject *m_pBrother; // brother of node in tree - XmlKey m_key; // tag of node - XmlObjectType m_valueType; // type of node - - // the entry in the union is selected according to m_valueType: - // xmlIntValue -> m_intValue - // xmlDoubleValue -> m_doubleValue - // xmlStringValue -> m_stringValue - // xmlListBegin -> m_pFirstSon (in case of a list, m_pFirstSon is pointer - // to first son and the sons are chained by m_pBrother) - union { - int m_intValue; - double m_doubleValue; - const char *m_stringValue; - XmlObject *m_pFirstSon; - }; - - // construction - - // Some Reference on the XML notation: - // XML consists of one or more elements. - // An element is marked with the following form: - // - // elementinformation - // - // The opening and the closing are the tags - // of the element. The text between the two tags is considered - // part of the element. - // Elemets can have attributes applied, e.g. - // blablabla - // The attribute is specified inside the opening tag - // and is called "style". It is given a value "bold" which is expressed - // inside quotation marks. - - - - // Stores the "tag" of an XML element - XmlObject(XmlKey key) : m_pBrother(0), m_key(key), - m_valueType(xmlListBegin), m_pFirstSon(0) { } - - // Stores an integer "attribute" of an XML element - XmlObject(XmlKey key, int intValue) : m_pBrother(0), m_key(key), - m_valueType(xmlIntValue), m_intValue(intValue) { } - - // Stores a double "attribute" of an XML element - XmlObject(XmlKey key, double doubleValue) : m_pBrother(0), m_key(key), - m_valueType(xmlDoubleValue), m_doubleValue(doubleValue) { } - - // Stores a string "attribute" of an XML element - XmlObject(XmlKey key, const char *stringValue) : m_pBrother(0), m_key(key), - m_valueType(xmlStringValue), m_stringValue(stringValue) { } - - // Stores the body of the element - XmlObject(const char *stringValue) : m_pBrother(0), m_key(0), - m_valueType(xmlStringValue), m_stringValue(stringValue) { } - - - OGDF_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/XmlParser.h b/ext/OGDF/ogdf/fileformats/XmlParser.h deleted file mode 100644 index 322b83325..000000000 --- a/ext/OGDF/ogdf/fileformats/XmlParser.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class XmlParser. - * - * \author Sebastian Leipert and Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_XML_PARSER_H -#define OGDF_XML_PARSER_H - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - - -//--------------------------------------------------------- -// XmlParser -// reads XML file and constructs XML parse tree -//--------------------------------------------------------- -class OGDF_EXPORT XmlParser { - Hashing m_hashTable; // hash table for tags - int m_num; - - istream *m_is; - bool m_error; - String m_errorString; - - char *m_rLineBuffer, *m_lineBuffer, *m_pCurrent, *m_pStore, m_cStore; - - int m_intSymbol; // integer attribute - double m_doubleSymbol; // double attribute - const char *m_stringSymbol; // string attribute - char *m_keyName; // Tag name - XmlKey m_keySymbol; // Tag name and Attribute Name in Hash Table - String m_longString; - bool m_eoTag; // end of Tag recognized - - XmlObject *m_objectTree; // root node of XML parse tree - - bool m_doCheck; - - SList m_objectBody; - -public: - // predefined id constants for all used keys - enum PredefinedKey { idPredefKey = 0, labelPredefKey, CreatorPredefKey, - namePredefKey, graphPredefKey, versionPredefKey, directedPredefKey, - nodePredefKey, edgePredefKey, graphicsPredefKey, xPredefKey, - yPredefKey, wPredefKey, hPredefKey, nodetypePredefKey, edgetypePredefKey, - typePredefKey, widthPredefKey, heightPredefKey, sizePredefKey, - positionPredefKey, pathPredefKey, - sourcePredefKey, targetPredefKey, sensePredefKey, arrowPredefKey, LinePredefKey, - pointPredefKey, NEXTPREDEFKEY }; - - // construction: creates object tree - // sets m_error flag if an error occured - XmlParser(const char *fileName, bool doCheck = false); - XmlParser(istream &is, bool doCheck = false); - - // destruction: destroys object tree - ~XmlParser(); - - // returns root object - XmlObject *root() { return m_objectTree; } - - // id of a string in hash table; -1 if not contained - int getId(const String &tag) const { - HashElement *it = m_hashTable.lookup(tag); - return (it != 0) ? it->info() : -1; - } - - // returns id of object - int id(XmlObject *object) const { return object->m_key->info(); } - - // true <=> an error in XML files has been detected - bool error() const { return m_error; } - // returns error message - const String &errorString() const { return m_errorString; } - - // creates graph from XML parse tree - bool read(Graph &G); - // creates attributed graph from XML parse tree - bool read(Graph &G, GraphAttributes &AG); - -private: - void createObjectTree(istream &is, bool doCheck); - void initPredefinedKeys(); - void setError(const char *errorString); - - XmlObject *parseList(XmlObjectType closingKey, XmlObjectType errorKey, const char *objectBodyName); - XmlObjectType getNextSymbol(); - bool getLine(); - - XmlKey hashString(const String &str); - - XmlObject *getNodeIdRange( - int &minId, - int &maxId, - int &nodetypeCount, - XmlObject *graphObject); - - bool makeIdMap( - int maxId, - Array &idMap, - int nodetypeCount, - Array & typeName, - Array &typeWidth, - Array &typeHeight, - XmlObject *graphObject); - - void closeLabels(Array idMap, Array typeName); - - void readLineAttribute(XmlObject *object, DPolyline &dpl); - - void destroyObjectList(XmlObject *object); - - void indent(ostream &os, int d); - void output(ostream &os, XmlObject *object, int d); - -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/fileformats/simple_graph_load.h b/ext/OGDF/ogdf/fileformats/simple_graph_load.h deleted file mode 100644 index d0a5d446a..000000000 --- a/ext/OGDF/ogdf/fileformats/simple_graph_load.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of simple graph loaders. - * - * \author Markus Chimani, Carsten Gutwenger, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SIMPLE_GRAPH_LOAD_H -#define OGDF_SIMPLE_GRAPH_LOAD_H - -#include -#include - - -namespace ogdf { - -/** @name Simple graph formats (without layout) - * These functions load graphs stored in some common, simple text-based file formats. They just read - * the graph structure and not any layout specific data. - */ -///@{ - -//! Loads a graph \a G stored in the Rome-Graph-format from an input stream \a is. -/** - * The Rome format contains (in this order) n "node-lines", 1 "separator-line", m "edge-lines". - * These lines are as follows (whereby all IDs are integer numbers): - * - node-line: NodeId 0 - * - separator-line: starts with a #-sign - * - edge-line: EdgeId 0 SourceNodeId TargetNodeId - * - * @param G is assigned the loaded graph. - * @param is is the input stream from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - * - * \warning - * This is a very simple implementation only usable for very properly formatted files! - */ -OGDF_EXPORT bool loadRomeGraph(Graph &G, istream &is); - -//! Loads a graph \a G stored in the Rome-Graph-format from a file \a fileName. -/** - * @param G is assigned the loaded graph. - * @param fileName is the name of the file from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - * - * \see loadRomeGraph(Graph &, istream&) - */ -OGDF_EXPORT bool loadRomeGraph(Graph &G, const char *fileName); - -/** \brief Loads a graph \a G stored in the chaco file format from an input stream \a is. - * - * Graphs stored in the chaco file format are typically used in graph partitioning and - * use the file extension .graph. - * - * The first line contains two integers separated by spacing: \#nodes \#edges - * A third entry indicates node and edge weights (not supported here yet). - * Each of the following \#nodes lines from 1 to \#nodes contains the space - * separated index list of the adjacent nodes for the node associated with - * that line (where node indices are from 1 to n). - * Macro SIMPLE_LOAD_BUFFER_SIZE defines the length of the line read buffer - * and should be adjusted according to the maximum read size. - * - * @param G is assigned the loaded graph. - * @param is is the input stream from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - */ -OGDF_EXPORT bool loadChacoGraph(Graph &G, istream &is); - -//! Loads a graph \a G stored in the chaco file format from a file \a fileName. -/** - * @param G is assigned the loaded graph. - * @param fileName is the name of the file from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - * - * \see loadChacoGraph(Graph &, istream&) - */ -OGDF_EXPORT bool loadChacoGraph(Graph &G, const char *fileName); - -//! Loads a graph \a G stored in a simple format from an input stream \a is. -/** - * Simple format has a leading line stating the name of the graph - * and a following line stating the size of the graph. - * - *
    - * *BEGIN unknown_name.numN.numE
    - * *GRAPH numN numE UNDIRECTED UNWEIGHTED
    - * 
    - * - * @param G is assigned the loaded graph. - * @param is is the input stream from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - * */ -OGDF_EXPORT bool loadSimpleGraph(Graph &G, istream &is); - -//! Loads a graph \a G stored in a simple format from a file \a fileName. -/** - * This format is used e.g. for the graphs from Petra Mutzel's Ph.D. Thesis. - * - * @param G is assigned the loaded graph. - * @param fileName is the name of the file from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - * - * \see loadSimpleGraph(Graph &G, istream &is) - */ -OGDF_EXPORT bool loadSimpleGraph(Graph &G, const char *fileName); - -//! Loads a graph \a G stored in the Y-graph-format from file stream (one line) \a lineStream. -/** - * This format is e.g. produced by NAUTY (http://www.cs.sunysb.edu/~algorith/implement/nauty/implement.shtml) - * - * Details on the format, as given in NAUTYs graph generator (see above link): - * "[A] graph occupies one line with a terminating newline. - * Except for the newline, each byte has the format 01xxxxxx, where - * each "x" represents one bit of data. - * - * First byte: xxxxxx is the number of vertices n - * - * Other ceiling(n(n-1)/12) bytes: These contain the upper triangle of - * the adjacency matrix in column major order. That is, the entries - * appear in the order (0,1),(0,2),(1,2),(0,3),(1,3),(2,3),(0,4),... . - * The bits are used in left to right order within each byte. - * Any unused bits on the end are set to zero. - */ -OGDF_EXPORT bool loadYGraph(Graph &G, FILE *lineStream); - -///@} - -/** @name Simple graph formats (with layout) - * These functions load and save graphs in some common, simple text-based file formats, - * which also store layout specific data in some limited way. - */ -///@{ - -//! Loads a graph \a G with layout \a gl stored in GD-Challenge-format from stream \a is. -/** - * @param G is assigned the loaded graph. - * @param gl is assigned the grid layout. - * @param is is the input stream from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - */ -OGDF_EXPORT bool loadChallengeGraph(Graph &G, GridLayout &gl, istream &is); - -//! Loads a graph \a G with layout \a gl stored in GD-Challenge-format from file \a fileName. -/** - * @param G is assigned the loaded graph. - * @param gl is assigned the grid layout. - * @param fileName is the name of the file from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - */ -OGDF_EXPORT bool loadChallengeGraph(Graph &G, GridLayout &gl, const char *fileName); - -//! Writes graph \a G with layout \a gl in GD-Challenge-format to stream \a os. -/** - * @param G is the graph to be stored. - * @param gl is the grid layout to be stored. - * @param os is the output stream to which the graph is written. - * \return true if the graph was stored successfully, false otherwise. - */ -OGDF_EXPORT bool saveChallengeGraph(const Graph &G, const GridLayout &gl, ostream &os); - -//! Writes graph \a G with layout \a gl in GD-Challenge-format to file \a fileName. -/** - * @param G is the graph to be stored. - * @param gl is the grid layout to be stored. - * @param fileName is the name of the file to which the graph is written. - * \return true if the graph was stored successfully, false otherwise. - */ -OGDF_EXPORT bool saveChallengeGraph(const Graph &G, const GridLayout &gl, const char *fileName); - -///@} - -/** @name Simple graph formats (with subgraph) - * These functions load and store graphs in a simple text-based file format that also specifies - * a subgraph (given as a list of edges). - */ -///@{ - -//! Loads graph \a G with subgraph defined by \a delEdges from stream \a is. -/** - * @param G is assigned the loaded graph. - * @param delEdges is assigned the edges of the subgraph. - * @param is is the input stream from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - */ -OGDF_EXPORT bool loadEdgeListSubgraph(Graph &G, List &delEdges, istream &is); - -//! Loads graph \a G with subgraph defined by \a delEdges from file \a fileName. -/** - * @param G is assigned the loaded graph. - * @param delEdges is assigned the edges of the subgraph. - * @param fileName is the name of the file from which the graph is read. - * \return true if the graph was loaded successfully, false otherwise. - */ -OGDF_EXPORT bool loadEdgeListSubgraph(Graph &G, List &delEdges, const char *fileName); - -//! Writes graph \a G with subgraph defined by \a delEdges to stream \a os. -/** - * @param G is the graph to be stored. - * @param delEdges specifies the edges of the subgraph to be stored. - * @param os is the output stream to which the graph is written. - * \return true if the graph was stored successfully, false otherwise. - */ -OGDF_EXPORT bool saveEdgeListSubgraph(const Graph &G, const List &delEdges, ostream &os); - -//! Writes graph \a G with subgraph defined by \a delEdges to file \a fileName. -/** - * @param G is the graph to be stored. - * @param delEdges specifies the edges of the subgraph to be stored. - * @param fileName is the name of the file to which the graph is written. - * \return true if the graph was stored successfully, false otherwise. - */ -OGDF_EXPORT bool saveEdgeListSubgraph(const Graph &G, const List &delEdges, const char *fileName); - -///@} - -/** @name Hypergraphs - * These functions load hypergraphs stored in file formats used for electrical circuits. - * The hypergraphs are directly transformed into their point-based expansions (and hence stored - * in a usual Graph and not a Hypergraph). - */ -///@{ - -//! Loads a hypergraph in the BENCH-format from input stream \a is. -/** - * A hypergraph in OGDF is represented by its point-based expansion, i.e., for each - * hyperedge h we have a corresponding hypernode n. All nodes originally - * incident to h are incident to n, i.e., have regular edges to n. - * - * @param G is assigned the graph (point-based expansion of the hypergraph). - * @param hypernodes is assigned the list of nodes which have to be interpreted as hypernodes. - * @param shell if 0 only the BENCH-hypergraph is loaded. Otherwise we extend the loaded graph - * by a simple edge e=(i,o) and two hyperedges: one hyperedges groups all input nodes and - * i together, the other hyperedge groups all output edges and o. - * These additional edges are then also collocated in shell. - * @param is is the input stream from which the hypergraph is read. - * - * \warning - * This is a very simple implementation only usable for very properly formatted files! - */ -OGDF_EXPORT bool loadBenchHypergraph(Graph &G, List& hypernodes, List *shell, istream &is); - -//! Loads a hypergraph in the BENCH-format from the specified file. -/** - * @param G is assigned the graph (point-based expansion of the hypergraph). - * @param hypernodes is assigned the list of nodes which have to be interpreted as hypernodes. - * @param shell if 0 only the BENCH-hypergraph is loaded. Otherwise we extend the loaded graph - * by a simple edge e=(i,o) and two hyperedges: one hyperedges groups all input nodes and - * i together, the other hyperedge groups all output edges and o. - * These additional edges are then also collocated in shell. - * @param fileName is the name of the file from which the hypergraph is read. - * - * \see loadBenchHypergraph(Graph &G, List& hypernodes, List* shell, istream &is) - */ -OGDF_EXPORT bool loadBenchHypergraph(Graph &G, List& hypernodes, List *shell, const char *fileName); - -//! Loads a hypergraph in the PLA-format from input stream \a is. -/** - * A hypergraph in OGDF is represented by its point-based expansion, i.e., for each - * hyperedge h we have a corresponding hypernode n. All nodes originally - * incident to h are incident to n, i.e., have regular edges to n. - * - * @param G is assigned the graph (point-based expansion of the hypergraph). - * @param hypernodes is assigned the list of nodes which have to be interpreted as hypernodes. - * @param shell if 0 only the PLA-hypergraph is loaded. Otherwise we extend the loaded graph - * by a simple edge e=(i,o) and two hyperedges: one hyperedges groups all input nodes and - * i together, the other hyperedge groups all output edges and o. - * These additional edges are then also collocated in shell. - * @param is is the input stream from which the hypergraph is read. - * - * \warning - * This is a very simple implementation only usable for very properly formatted files! - */ -OGDF_EXPORT bool loadPlaHypergraph(Graph &G, List& hypernodes, List *shell, istream &is); - -//! Loads a hypergraph in the PLA-format from file \a fileName. -/** - * @param G is assigned the graph (point-based expansion of the hypergraph). - * @param hypernodes is assigned the list of nodes which have to be interpreted as hypernodes. - * @param shell if 0 only the PLA-hypergraph is loaded. Otherwise we extend the loaded graph - * by a simple edge e=(i,o) and two hyperedges: one hyperedges groups all input nodes and - * i together, the other hyperedge groups all output edges and o. - * These additional edges are then also collocated in shell. - * @param fileName is the name of the file from which the hypergraph is read. - * - * \see loadPlaHypergraph(Graph &G, List& hypernodes, List *shell, istream &is) - */ -OGDF_EXPORT bool loadPlaHypergraph(Graph &G, List& hypernodes, List* shell, const char *fileName); - -///@} - - -} - -#endif //OGDF_SIMPLE_GRAPH_LOAD_H diff --git a/ext/OGDF/ogdf/graphalg/CliqueFinder.h b/ext/OGDF/ogdf/graphalg/CliqueFinder.h deleted file mode 100644 index 872656701..000000000 --- a/ext/OGDF/ogdf/graphalg/CliqueFinder.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares CliqueFinder class. - * CliqueFinder searches for complete (dense) subgraphs. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLIQUEFINDER_H -#define OGDF_CLIQUEFINDER_H - - -#include -#include -#include -#include - -namespace ogdf{ - - -//! Finds cliques and dense subgraphs. -/** - * The class CliqueFinder can be called on a graph - * to retrieve (disjoint) cliques or dense subgraphs - * respectively. Uses SPQR trees to find 3-connected - * components. - * - * In the following, clique always stands for a subgraph - * with properties that can be defined by the user to change - * the standard definition of a complete subgraph, e.g. a - * minimum size/degree etc. - * We search for cliques in graph G by first dividing G into - * its triconnnected components and then using a greedy - * heuristics within each component - */ -class OGDF_EXPORT CliqueFinder { - -public: - //constructor - CliqueFinder(const Graph &G); - ~CliqueFinder(); - - //Calls - //We first make G biconnected, this keeps the triconnected - //components. then the triconnected components are computed - //within these components, we search for cliques - - //!Searches for cliques and returns the clique index number for each node - /** - * Each clique will be assigned a different number, each node gets the - * number of the clique it is contained in, -1 if not a clique member - */ - void call(NodeArray &cliqueNumber); - //!Searches for cliques and returns the list of cliques - /** - * Each clique on return is represented by a list of member nodes - * in the list of cliques cliqueLists - */ - void call(List< List > &cliqueLists); - - //! the minimum degree of the nodes within the clique/subgraph - void setMinSize(int i) { m_minDegree = max(2, i-1);} - enum postProcess {ppNone, ppSimple}; - - //! Sets the abstract measure of density needed for subgraphs to be detected. - /** - * Does not have an effect for graphs with less than 4 nodes. - */ - void setDensity(int density) - { - if (density < 0) m_density = 0; - else if (density > 100) m_density = 100; - else m_density = density; - } - -protected: - /** - * doing the real work, find subgraphs in graph G, skip - * all nodes with degree < minDegree - * value 2: all triangles are cliques - */ - void doCall(int minDegree = 2); - - //------------------------------------------------------ - //sets the results of doCall depending on call signature - - //clique nodes get numbers from >=0, all other nodes -1 - void setResults(NodeArray &cliqueNumber); - void setResults(List< List > &cliqueLists); - void setResults(List< List* > &cliqueLists); - - //work on the result of the first phase (heuristic), e.g. - //by dropping, splitting or joining some of the found subgraphs - void postProcessCliques(List< List* > &cliqueList, - EdgeArray &usableEdge); - - //check if node v is adjacent to all nodes in node list - bool allAdjacent(node v, List* vList); - void writeGraph(Graph &G, NodeArray &cliqueNumber, - const String &fileName); - - //does a heuristic evaluation of node v (in m_pCopy) - //concerning its qualification as a cluster start node - //the higher the return value, the better the node - //uses only edges with usableEdge == true - int evaluate(node v, EdgeArray &usableEdge); - void checkCliques(List< List* > &cliqueList, bool sizeCheck = true); - bool cliqueOK(List *clique); - void findClique(node v, List &neighbours, - int numRandom = 0); - -private: - const Graph* m_pGraph; - GraphCopy* m_pCopy; - NodeArray m_copyCliqueNumber; - NodeArray m_usedNode; //node is assigned to clique - //List< List* > m_cliqueList; - int m_minDegree; - int m_numberOfCliques; //stores the number of found cliques - postProcess m_postProcess; - bool m_callByList; //stores information on type of call for result setting - List< List > *m_pList; //stores pointer on list given as call parameter - - int m_density; //an abstract value from 0..100 definin how dense the - //subgraphs need to be, is not directly related to any - //measure (degree, ...) but translated into a constraint - //based on the heuristical search of the subgraphs -};//CliqueFinder - -}//end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/graphalg/Clusterer.h b/ext/OGDF/ogdf/graphalg/Clusterer.h deleted file mode 100644 index 29ff50d16..000000000 --- a/ext/OGDF/ogdf/graphalg/Clusterer.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Clusterer class that computes a clustering - * for a given graph based on the local neighborhood - * structure of each edge. Uses the criteria by - * Auber, Chiricota, Melancon for small-world graphs to - * compute clustering index and edge strength. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTERER_H -#define OGDF_CLUSTERER_H - -#include - -namespace ogdf { - - - /** - * Clustering is determined based on the threshold values (connectivity - * thresholds determine edges to be deleted) and stopped if average - * clustering index drops below m_stopIndex. - * - * \pre Input graph has to be connected - */ - class OGDF_EXPORT Clusterer : public ClustererModule - { - public: - //Constructor taking a graph G to be clustered - Clusterer(const Graph &G); - //Default constructor allowing to cluster multiple - //graphs with the same instance of the Clusterer - //Clusterer(); - virtual ~Clusterer() {} - - //The clustering can be done recursively (use single threshold - //on component to delete weak edges (recompute strengths)) or - //by applying a set of thresholds, set the behaviour in - //function setRecursive - virtual void computeClustering(SList &sl); - //set the thresholds defining the hierarchy assignment decision - //should be dependent on the used metrics - void setClusteringThresholds(const List &threshs); - //thresholds are computed from edge strengths to split off - //at least some edges as long as there is a difference between - //min and max strength (progressive clustering) - //set this value to 0 to use your own or the default values - void setAutomaticThresholds(int numValues) - {m_autoThreshNum = numValues;} - //for recursive clustering, only the first threshold is used - void setRecursive(bool b) {m_recursive = b;} - //preliminary - void computeEdgeStrengths(EdgeArray & strength); - void computeEdgeStrengths(const Graph &G, EdgeArray & strength); - - void createClusterGraph(ClusterGraph &C); - - void setStopIndex(double stop) {m_stopIndex = stop;} - - //compute a clustering index for node v - //number of connections in neighborhood compared to clique - virtual double computeCIndex(node v) - { - return computeCIndex(*m_pGraph, v); - } - virtual double computeCIndex(const Graph &G, node v) - { - OGDF_ASSERT(v->graphOf() == &G); - if (v->degree()<2) return 1.0; - int conns = 0; //connections, without v - NodeArray neighbor(G, false); - adjEntry adjE; - forall_adj(adjE, v) - { - neighbor[adjE->twinNode()] = true; - } - forall_adj(adjE, v) - { - adjEntry adjEE; - forall_adj(adjEE, adjE->twinNode()) - { - if (neighbor[adjEE->twinNode()]) - conns++; - } - } - //connections were counted twice - double index = conns / 2.0; - return index / (v->degree()*(v->degree()-1)); - } - - protected: - EdgeArray m_edgeValue; //strength value for edge clustering index - NodeArray m_vertexValue; //clustering index for vertices - List m_thresholds; //clustering level thresholds - List m_autoThresholds; //automatically generated values (dep. on graph instance) - List m_defaultThresholds; //some default values - double m_stopIndex; //average clustering index when recursive clustering stops - //between 0 and 1 - bool m_recursive; //recursive clustering or list of tresholds - //bool m_autoThresholds; //compute thresholds according to edge strengths - int m_autoThreshNum; //number of thresholds to be computed - - };//class Clusterer - -} //end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/graphalg/ConvexHull.h b/ext/OGDF/ogdf/graphalg/ConvexHull.h deleted file mode 100644 index f50616744..000000000 --- a/ext/OGDF/ogdf/graphalg/ConvexHull.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of doubly linked lists and iterators - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CONVEX_HULL_H -#define OGDF_CONVEX_HULL_H - -#include -#include -#include -#include - -namespace ogdf { - -// all returned Polygons are clockwise (cw) -class OGDF_EXPORT ConvexHull { -private: - bool sameDirection(const DPoint &start, const DPoint &end, const DPoint &s, const DPoint &e) const; - - // calculates a convex hull very quickly but only works with cross-free Polygons! - DPolygon conv(const DPolygon &poly) const; - - // Calculates the Part of the convex hull that is left of line start-end - // /a points should only contain points that really are left of the line. - void leftHull(std::vector points, DPoint &start, DPoint &end, DPolygon &hullPoly) const; - - -public: - ConvexHull(); - ~ConvexHull(); - - DPoint calcNormal(const DPoint &start, const DPoint &end) const; - double leftOfLine(const DPoint &normal, const DPoint &point, const DPoint &pointOnLine) const; - - DPolygon call(std::vector points) const; - DPolygon call(GraphAttributes &GA) const; - DPolygon call(MultilevelGraph &MLG) const; - -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/graphalg/Dijkstra.h b/ext/OGDF/ogdf/graphalg/Dijkstra.h deleted file mode 100644 index 7f689a3cd..000000000 --- a/ext/OGDF/ogdf/graphalg/Dijkstra.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Dijkstra's single source shortest path algorithm - * - * \author Matthias Woste - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DIJKSTRA_H_ -#define OGDF_DIJKSTRA_H_ - -#include -#include -#include - -namespace ogdf { - -/*! - * \brief Dijkstra's single source shortest path algorithm. - * - * This class implements Dijkstra's algorithm for computing single source shortest path. - * It requires a graph with proper, positive edge weights and returns a predecessor array - * as well as the shortest distances from the source node to all others. - */ -template -class Dijkstra { -public: - - /*! - * \brief Calculates, based on the graph G with corresponding edge costs and a source node s, - * the shortest paths and distances to all other nodes by Dijkstra's algorithm. - * @param G The original input graph - * @param weight The edge weights - * @param s The source node - * @param predecessor The resulting predecessor relation - * @param distance The resulting distances to all other nodes - */ - void call(const Graph &G, const EdgeArray &weight, node s, NodeArray &predecessor, - NodeArray &distance) { - BinaryHeap2 queue(G.numberOfNodes()); - int* qpos = new int[G.numberOfNodes()]; - NodeArray vIndex(G); - T maxEdgeWeight = 0; - int i = 0; - node v; - edge e; - - // determining maximum edge weight - forall_edges(e, G) - { - if (maxEdgeWeight < weight[e]) { - maxEdgeWeight = weight[e]; - } - } - - // setting distances to "infinity" - forall_nodes(v, G) - { - vIndex[v] = i; - distance[v] = std::numeric_limits::max() - maxEdgeWeight - 1; - predecessor[v] = 0; - queue.insert(v, distance[v], &qpos[i++]); - } - - distance[s] = 0; - queue.decreaseKey(qpos[vIndex[s]], 0); - - while (!queue.empty()) { - v = queue.extractMin(); - forall_adj_edges(e, v) - { - node w = e->opposite(v); - if (distance[w] > distance[v] + weight[e]) { - distance[w] = distance[v] + weight[e]; - queue.decreaseKey(qpos[vIndex[w]], distance[w]); - predecessor[w] = e; - } - } - } - delete[] qpos; - } - -}; - -} // end namespace ogdf - -#endif /* OGDF_DIJKSTRA_H_ */ diff --git a/ext/OGDF/ogdf/graphalg/GraphReduction.h b/ext/OGDF/ogdf/graphalg/GraphReduction.h deleted file mode 100644 index 9cac32b06..000000000 --- a/ext/OGDF/ogdf/graphalg/GraphReduction.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of GraphReduction class - * reduces by Leaves & Chains. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_GRAPH_REDUCTION_H -#define OGDF_GRAPH_REDUCTION_H - - -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// GraphReduction -// kick leaves & chains -// GraphReduction is read-only !!! -//--------------------------------------------------------- -class OGDF_EXPORT GraphReduction : public Graph { -protected: - - const Graph *m_pGraph; // original graph - NodeArray m_vOrig; // corresponding node in original graph - EdgeArray > m_eOrig; // corresponding edge in original graph - - NodeArray m_vReduction; // corresponding node in graph copy - EdgeArray m_eReduction; // corresponding chain of edges in graph copy - - GraphReduction() : m_vOrig(), m_eOrig(), m_vReduction(), m_eReduction() {} - -public: - // construction - GraphReduction(const Graph& G); - virtual ~GraphReduction() { } - - // returns original graph - const Graph &original() const { return *m_pGraph; } - - // returns original node - node original(node v) const { return m_vOrig[v]; } - // returns original edges - const List &original(edge e) const { return m_eOrig[e]; } - - // returns reduction of node v (0 if none) - node reduction(node v) const { return m_vReduction[v]; } - // returns reduction of edge e - edge reduction(edge e) const { return m_eReduction[e]; } - -}; // class GraphCopy - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/graphalg/MinCostFlowReinelt.h b/ext/OGDF/ogdf/graphalg/MinCostFlowReinelt.h deleted file mode 100644 index 1c6ddf491..000000000 --- a/ext/OGDF/ogdf/graphalg/MinCostFlowReinelt.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of min-cost-flow algorithm (class - * MinCostFlowReinelt) - * - * \author Carsten Gutwenger and Gerhard Reinelt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIN_COST_FLOW_REINELT_H -#define OGDF_MIN_COST_FLOW_REINELT_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT MinCostFlowReinelt : public MinCostFlowModule -{ -public: - MinCostFlowReinelt() { } - - // computes min-cost flow - // Precond.: graph must be connected, lowerBound[e] <= upperBound[e] - // for all edges e, sum over all supply[v] equals 0 - // returns true iff a feasible min-cost flow exists - bool call( - const Graph &G, // directed graph - const EdgeArray &lowerBound, // lower bound for flow - const EdgeArray &upperBound, // upper bound for flow - const EdgeArray &cost, // cost of an edge - const NodeArray &supply, // supply (if neg. demand) of a node - EdgeArray &flow); // computed flow - - bool call( - const Graph &G, // directed graph - const EdgeArray &lowerBound, // lower bound for flow - const EdgeArray &upperBound, // upper bound for flow - const EdgeArray &cost, // cost of an edge - const NodeArray &supply, // supply (if neg. demand) of a node - EdgeArray &flow, // computed flow - NodeArray &dual); // computed dual variables - - int infinity() const { return INT_MAX; } - -private: - - struct arctype; - - struct nodetype { - nodetype *father; /* ->father in basis tree */ - nodetype *successor; /* ->successor in preorder */ - arctype *arc_id; /* ->arc (node,father) */ - bool orientation; /* false<=>basic arc=(father->node)*/ - int dual; /* value of dual variable */ - int flow; /* flow in basic arc (node,father) */ - int name; /* identification of node = node-nr*/ - nodetype *last; /* last node in subtree */ - int nr_of_nodes; /* number of nodes in subtree */ - }; - - struct arctype { - arctype *next_arc; /* -> next arc in list */ - nodetype *tail; /* -> tail of arc */ - nodetype *head; /* -> head of arc */ - int cost; /* cost of unit flow */ - int upper_bound; /* capacity of arc */ - int arcnum; /* number of arc in input */ - - OGDF_NEW_DELETE - }; - - - int mcf( - int mcfNrNodes, - int mcfNrArcs, - Array &mcfSupply, - Array &mcfTail, - Array &mcfHead, - Array &mcfLb, - Array &mcfUb, - Array &mcfCost, - Array &mcfFlow, - Array &mcfDual, - int *mcfObj - ); - - void start(Array &supply); - - void beacircle(arctype **eplus, arctype **pre, bool *from_ub); - void beadouble(arctype **eplus, arctype **pre, bool *from_ub); - - - Array nodes; /* node space */ - Array arcs; /* arc space */ - //Array p; /*used for starting procedure*/ - - nodetype *root; /*->root of basis tree*/ - nodetype rootStruct; - - arctype *last_n1; /*->start for search for entering arc in N' */ - arctype *last_n2; /*->start for search for entering arc in N''*/ - arctype *start_arc; /* -> initial arc list*/ - arctype *start_b; /* -> first basic arc*/ - arctype *start_n1; /* -> first nonbasic arc in n'*/ - arctype *start_n2; /* -> first nonbasic arc in n''*/ - arctype *startsearch; /* ->start of search for basis entering arc */ - arctype *searchend; /* ->end of search for entering arc in bea */ - arctype *searchend_n1; /*->end of search for entering arc in N' */ - arctype *searchend_n2; /*->end of search for entering arc in N''*/ - - //int artvalue; /*cost and upper_bound of artificial arc */ - int m_maxCost; // maximum of the cost of all input arcs - - int nn; /*number of original nodes*/ - int mm; /*number of original arcs*/ - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/graphalg/MinimumCut.h b/ext/OGDF/ogdf/graphalg/MinimumCut.h deleted file mode 100644 index 1217f4228..000000000 --- a/ext/OGDF/ogdf/graphalg/MinimumCut.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares & implements a minimum-cut algorithm according - * to an approach of Stoer and Wagner 1997. However, no Priority Queues - * are used as suggested in the approach. Should be adapted to improve - * performance. - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MINIMUM_CUT_H -#define OGDF_MINIMUM_CUT_H - -#include -#include -#include -#include - -namespace ogdf { - - -class OGDF_EXPORT MinCut { - -public: - //Todo: Shift parameters to the call! - //m_minCut is only initialized once!!! - MinCut(Graph &G, EdgeArray &w); - ~MinCut(); - - // implements the main loop that computes the minimum cut by invoking function - // minimumCutPhase() in each iteration. Returns the mincut value. - double minimumCut(); - - // returns the edges defining the computed mincut in list \a edges. - void cutEdges(List &edges, Graph &G); - - // returns list of nodes belonging to one side of the bipartition in list \a nodes. - void partition(List &nodes); - - double minCutValue() const {return m_minCut;} - -private: - - // stores the value of the minimum cut - double m_minCut; - - // GraphCopy of the corresponding Graph. Used for the computation in order not - // to destroy the original Graph. - GraphCopy m_GC; - - // an EdgeArray containing the corresponding edge weights. - EdgeArray m_w; - - // the two node lists corresponding to the node contraction - List m_contraction1, m_contraction2; - - // store one side of the computed bipartition. - List m_partition; - - // the list of edges defining the cut - List m_cutEdges; - - // each node has a list containing the nodes with which it has been contracted. - // Because the GraphCopy \a m_GC is destroyed during the algorithm, this is - // necessary to be able to determine the original nodes in the end. - NodeArray > m_contractedNodes; - - // computes and returns the value of the minimum cut of the current phase (itertion). - double minimumCutPhase(); - - // Contracts the nodes \a s and \a t, i.e \a s is collapsed to \a t. - // The edge (if existing) between \a s and \t s is deleted. Edges incident to \a s are redirected to \t. - // If parallel edges occur, one of them is deleted and its weight is added to the other one. - void contraction(node t, node s); - -}; - -}// end namespace - -#endif diff --git a/ext/OGDF/ogdf/graphalg/PageRank.h b/ext/OGDF/ogdf/graphalg/PageRank.h deleted file mode 100644 index 4b98b1511..000000000 --- a/ext/OGDF/ogdf/graphalg/PageRank.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * $Revision: 2597 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 19:26:11 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of basic page rank. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_PAGE_RANK_H_ -#define OGDF_PAGE_RANK_H_ - -#include -#include - -namespace ogdf { - -//! Basic page rank calculation -class BasicPageRank -{ -public: - BasicPageRank() - { - initDefaultOptions(); - } - - //! main algorithm call - void call( - const Graph& graph, - const EdgeArray& edgeWeight, - NodeArray& pageRankResult); - - //! sets the default options. - void initDefaultOptions() - { - m_dampingFactor = 0.85; - m_maxNumIterations = 1000; - m_threshold = 0.0; - } - - //! returns the damping factor for each iteration (default is 0.85) - double dampingFactor() const - { - return m_dampingFactor; - } - - //! sets the damping factor for each iteration (default is 0.85) - void setDampingFactor(double dampingFactor) - { - m_dampingFactor = dampingFactor; - } - - //! the maximum number of iterations (default is 1000) - int maxNumIterations() const - { - return m_maxNumIterations; - } - - //! sets the maximum number of iterations (default is 1000) - void setMaxNumIterations(int maxNumIterations) - { - m_maxNumIterations = maxNumIterations; - } - - /*! returns the threshold/epsilon. After each iteration the result is compared to - * to the old one and in case all changes are smaller than threshold the algorithm - * stops. Note that the default value is 0.0 resulting in maxNumIterations usually. - */ - double threshold() const - { - return m_threshold; - } - - - //! sets the threshold to t. See threshold for more information - void setThreshold(double t) - { - m_threshold = t; - } - -private: - //! the damping factor - double m_dampingFactor; - - //! maximum number of iterations - int m_maxNumIterations; - - //! the threshold - double m_threshold; -}; - -} // end of namespace ogdf - -#endif // OGDF_PAGE_RANK_H_ - diff --git a/ext/OGDF/ogdf/graphalg/ShortestPathWithBFM.h b/ext/OGDF/ogdf/graphalg/ShortestPathWithBFM.h deleted file mode 100644 index 083ac26dd..000000000 --- a/ext/OGDF/ogdf/graphalg/ShortestPathWithBFM.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class ShortestPathWithBFM which computes - * shortest paths via Bellman-Ford-Moore. - * - * \author Gunnar W. Klau - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SHORTEST_PATH_BFM_H -#define OGDF_SHORTEST_PATH_BFM_H - - -#include - - -namespace ogdf { - -class OGDF_EXPORT ShortestPathWithBFM : public ShortestPathModule -{ -public: - ShortestPathWithBFM() { } - - // computes shortest paths - // Precond.: - // - // returns false iff the graph contains a negative cycle - bool call( - const Graph &G, // directed graph - const node s, // source node - const EdgeArray &length, // length of an edge - NodeArray &d, // contains shortest path distances after call - NodeArray &pi - ); - - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/internal/augmentation/PALabel.h b/ext/OGDF/ogdf/internal/augmentation/PALabel.h deleted file mode 100644 index 9587c0b0f..000000000 --- a/ext/OGDF/ogdf/internal/augmentation/PALabel.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * $Revision: 2597 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 19:26:11 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares auxiliary structure of planar augmentation algorithms. - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PA_LABEL_H -#define OGDF_PA_LABEL_H - - -#include - - -namespace ogdf { - - enum paStopCause { paPlanarity, paCDegree, paBDegree, paRoot }; - -/** - * \brief auxiliary class for the planar augmentation algorithm - * - * A label contains several pendants, a parent- and a head- node. - * The head node is a cutvertex in the correspondign BC-Tree. - * The pendants can be connected by edges so planarity is maintained. - */ -class PALabel -{ - friend class PlanarAugmentation; - friend class PlanarAugmentationFix; - -private: - - /** - * \brief the "parent" of the pendants in the BC-Tree, m_parent is a b-vertex or a c-vertex - * if it is a b-vertex m_parent != 0 - * otherwise m_parent == 0 and the parent is the head node - * m_head is always != 0 - */ - node m_parent; - - node m_head; //!< the cutvertex and perhaps (see m_parent) the parent node - - List m_pendants; //!< list with all pendants of the label - - paStopCause m_stopCause; //!< the stop cause that occurs when traversing from the pendants to the bc-tree-root computed in PlanarAugmentation::followPath() - -public: - PALabel(node parent, node cutvertex, paStopCause sc = paBDegree) { - m_parent = parent; - m_head = cutvertex; - m_stopCause = sc; - } - - bool isBLabel() { - return (m_parent != 0); - } - - bool isCLabel() { - return (m_parent == 0); - } - - //! return pendant with number nr, starts counting at 0 - node getPendant(int nr) { - return (nr < m_pendants.size()) ? (*(m_pendants.get(nr))) : 0; - } - - node getFirstPendant() { - return (m_pendants.size() > 0) ? m_pendants.front() : 0; - } - - node getLastPendant() { - return (m_pendants.size() > 0) ? m_pendants.back() : 0; - } - - //! return number of pendants - int size() { - return m_pendants.size(); - } - - void removePendant(node pendant); - - void removePendant(ListIterator it){ - m_pendants.del(it); - } - - void removeFirstPendant() { - if (m_pendants.size() > 0){ - m_pendants.popFront(); - } - } - - void addPendant(node pendant) { - m_pendants.pushBack(pendant); - } - - void deleteAllPendants() { - m_pendants.clear(); - } - - //! return the parent node. If the label is a c-label it returns m_head - node parent() { - return (m_parent != 0) ? m_parent : m_head; - } - - //! returns the head node - node head() { - return m_head; - } - - void setParent(node newParent){ - m_parent = newParent; - } - - void setHead(node newHead){ - m_head = newHead; - } - - paStopCause stopCause(){ - return m_stopCause; - } - - void stopCause(paStopCause sc){ - m_stopCause = sc; - } - - OGDF_NEW_DELETE -}; // class PALabel - - -typedef PALabel* pa_label; - - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/basic/MallocMemoryAllocator.h b/ext/OGDF/ogdf/internal/basic/MallocMemoryAllocator.h deleted file mode 100644 index 5bb3d6332..000000000 --- a/ext/OGDF/ogdf/internal/basic/MallocMemoryAllocator.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of memory manager for allocating small - * pieces of memory - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MALLOC_MEMORY_ALLOCATOR_H -#define OGDF_MALLOC_MEMORY_ALLOCATOR_H - - -namespace ogdf { - -//! Implements a simple memory manager using \c malloc() and \c free(). -class OGDF_EXPORT MallocMemoryAllocator -{ - struct MemElem { MemElem *m_next; }; - typedef MemElem *MemElemPtr; - -public: - - MallocMemoryAllocator() { } - ~MallocMemoryAllocator() { } - - - static void init() { } - static void initThread() { } - static void cleanup() { } - - static bool checkSize(size_t /* nBytes */) { return true; } - - //! Allocates memory of size \a nBytes. - static void *allocate(size_t nBytes, const char *, int) { return allocate(nBytes); } - - //! Allocates memory of size \a nBytes. - static void *allocate(size_t nBytes) - { - void *p = malloc(nBytes); - if (OGDF_UNLIKELY(p == 0)) OGDF_THROW(ogdf::InsufficientMemoryException); - return p; - } - - - //! Deallocates memory at address \a p which is of size \a nBytes. - static void deallocate(size_t /* nBytes */, void *p) { free(p); } - - //! Deallocate a complete list starting at \a pHead and ending at \a pTail. - /** - * The elements are assumed to be chained using the first word of each element and - * elements are of size \a nBytes. - */ - static void deallocateList(size_t /* nBytes */, void *pHead, void *pTail) - { - MemElemPtr q, pStop = MemElemPtr(pTail)->m_next; - while (pHead != pStop) { - q = MemElemPtr(pHead)->m_next; - free(pHead); - pHead = q; - } - } - - static void flushPool() { } - static void flushPool(__uint16 /* nBytes */) { } - - //! Always returns 0, since no blocks are allocated. - static size_t memoryAllocatedInBlocks() { return 0; } - - //! Always returns 0, since no blocks are allocated. - static size_t memoryInFreelist() { return 0; } -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/basic/PoolMemoryAllocator.h b/ext/OGDF/ogdf/internal/basic/PoolMemoryAllocator.h deleted file mode 100644 index bd74656d6..000000000 --- a/ext/OGDF/ogdf/internal/basic/PoolMemoryAllocator.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of memory manager for allocating small - * pieces of memory - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_POOL_MEMORY_ALLOCATOR_H -#define OGDF_POOL_MEMORY_ALLOCATOR_H - -#ifndef OGDF_MEMORY_POOL_NTS -#include -#else -#include -#endif - - -namespace ogdf { - - -//! The class \a PoolAllocator represents ogdf's pool memory allocator. -/** - *

    Usage:

    - * - * Adding the macro \c #OGDF_NEW_DELETE in a class declaration overloads - * new and delete operators of that class such that they use this - * memory allocator. This is useful if the size of a class is less than - * \c PoolAllocator::eTableSize bytes. - * - * Another benefit from the OGDF memory-manager is that it throws an - * InsufficientMemoryException if no more memory is available. Hence - * it is legal to omit checking if new returned 0 as long as stack- - * unwinding frees all memory allocated so far. - * It is also possible to make the usual \c new operator behave the same - * way (throwing an InsufficientMemoryException) by defining the - * macro \c #OGDF_MALLOC_NEW_DELETE in a class declaration. - */ - -class PoolMemoryAllocator -{ - struct MemElem { - MemElem *m_next; - }; - struct MemElemEx { - MemElemEx *m_next; - MemElemEx *m_down; - }; - - typedef MemElem *MemElemPtr; - typedef MemElemEx *MemElemExPtr; - - struct PoolVector; - struct PoolElement; - struct BlockChain; - typedef BlockChain *BlockChainPtr; - -public: - enum { - eMinBytes = sizeof(MemElemPtr), - eTableSize = 256, - eBlockSize = 8192, - ePoolVectorLength = 15 - }; - - PoolMemoryAllocator() { } - ~PoolMemoryAllocator() { } - - //! Initializes the memory manager. - static OGDF_EXPORT void init(); - - static OGDF_EXPORT void initThread(); - - //! Frees all memory blocks allocated by the memory manager. - static OGDF_EXPORT void cleanup(); - - static OGDF_EXPORT bool checkSize(size_t nBytes); - - //! Allocates memory of size \a nBytes. - static OGDF_EXPORT void *allocate(size_t nBytes); - - //! Deallocates memory at address \a p which is of size \a nBytes. - static OGDF_EXPORT void deallocate(size_t nBytes, void *p); - - //! Deallocate a complete list starting at \a pHead and ending at \a pTail. - /** - * The elements are assumed to be chained using the first word of each element and - * elements are of size \a nBytes. This is much more efficient the deallocating - * each element separately, since the whole chain can be concatenated with the - * free list, requiring only constant effort. - */ - static OGDF_EXPORT void deallocateList(size_t nBytes, void *pHead, void *pTail); - - static OGDF_EXPORT void flushPool(); - static OGDF_EXPORT void flushPool(__uint16 nBytes); - - //! Returns the total amount of memory (in bytes) allocated from the system. - static OGDF_EXPORT size_t memoryAllocatedInBlocks(); - - //! Returns the total amount of memory (in bytes) available in the global free lists. - static OGDF_EXPORT size_t memoryInGlobalFreeList(); - - //! Returns the total amount of memory (in bytes) available in the thread's free lists. - static OGDF_EXPORT size_t memoryInThreadFreeList(); - -private: - static int slicesPerBlock(__uint16 nBytes) { - int nWords; - return slicesPerBlock(nBytes,nWords); - } - - static int slicesPerBlock(__uint16 nBytes, int &nWords) { - nWords = (nBytes+sizeof(MemElemPtr)-1)/sizeof(MemElemPtr); - return (eBlockSize-sizeof(MemElemPtr))/(nWords*sizeof(MemElemPtr)); - } - - static void incVectorSlot(PoolElement &pe); - - static void flushPoolSmall(__uint16 nBytes); - static MemElemExPtr collectGroups( - __uint16 nBytes, - MemElemPtr &pRestHead, - MemElemPtr &pRestTail, - int &nRest); - - static void *fillPool(MemElemPtr &pFreeBytes, __uint16 nBytes); - - static MemElemPtr allocateBlock(__uint16 nBytes); - - static PoolElement s_pool[eTableSize]; - static MemElemPtr s_freeVectors; - static BlockChainPtr s_blocks; - -#ifdef OGDF_MEMORY_POOL_NTS - static MemElemPtr s_tp[eTableSize]; -#elif defined(OGDF_NO_COMPILER_TLS) - static CriticalSection *s_criticalSection; - static pthread_key_t s_tpKey; -#else - static CriticalSection *s_criticalSection; - static OGDF_DECL_THREAD MemElemPtr s_tp[eTableSize]; -#endif -}; - - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/basic/intrinsics.h b/ext/OGDF/ogdf/internal/basic/intrinsics.h deleted file mode 100644 index 0e5e7c1e6..000000000 --- a/ext/OGDF/ogdf/internal/basic/intrinsics.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Include of header files for SSE-intrinsics - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_INTRINSICS_H -#define OGDF_INTRINSICS_H - -#include - - -#ifdef OGDF_SYSTEM_WINDOWS -#include - -#if (defined(_M_IX86) || defined(_M_IA64)) && !defined(_M_CEE_PURE) -#define OGDF_SSE2_EXTENSIONS -#define OGDF_SSE3_EXTENSIONS -#endif - -#elif defined(OGDF_SYSTEM_UNIX) && (defined(__x86_64__) || defined(__i386__)) -#include - -#if (defined(__x86_64__) || defined(__i386__)) && !(defined(__GNUC__) && !defined(__SSE2__)) -#define OGDF_SSE2_EXTENSIONS -#endif - -#if (defined(__x86_64__) || defined(__i386__)) && !(defined(__GNUC__) && !defined(__SSE3__)) -#define OGDF_SSE3_EXTENSIONS -#endif - - -#endif - - -#endif diff --git a/ext/OGDF/ogdf/internal/basic/list_templates.h b/ext/OGDF/ogdf/internal/basic/list_templates.h deleted file mode 100644 index 833e492ef..000000000 --- a/ext/OGDF/ogdf/internal/basic/list_templates.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of algorithms as templates working with - * different list types - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LIST_TEMPLATES_H -#define OGDF_LIST_TEMPLATES_H - - -#include - - -namespace ogdf { - -// sorts list L using quicksort -template -void quicksortTemplate(LIST &L) -{ - const int n = L.size(); - Array A(n); - - int i = 0; - typename LIST::iterator it; - for (it = L.begin(); it.valid(); ++it) - A[i++] = *it; - - A.quicksort(); - - for (i = 0, it = L.begin(); i < n; i++) - *it++ = A[i]; -} - - -// sorts list L using quicksort and compare element comp -template -void quicksortTemplate(LIST &L, COMPARER &comp) -{ - const int n = L.size(); - Array A(n); - - int i = 0; - typename LIST::iterator it; - for (it = L.begin(); it.valid(); ++it) - A[i++] = *it; - - A.quicksort(comp); - - for (i = 0, it = L.begin(); i < n; i++) - *it++ = A[i]; -} - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/CPlanarSubClusteredST.h b/ext/OGDF/ogdf/internal/cluster/CPlanarSubClusteredST.h deleted file mode 100644 index 811aaafe4..000000000 --- a/ext/OGDF/ogdf/internal/cluster/CPlanarSubClusteredST.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of CPlanarSubClusteredST class. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CPLANAR_SUBCLUSTERED_ST_H -#define OGDF_CPLANAR_SUBCLUSTERED_ST_H - - -#include -#include -#include - -namespace ogdf { - -//! Constructs a c-planar subclustered spanning tree of the input by setting edgearray values -class CPlanarSubClusteredST -{ - -public: - - CPlanarSubClusteredST() { } - - //! sets values in inST according to membership in c-planar STGraph - virtual void call(const ClusterGraph& CG, EdgeArray& inST); - //! sets values in inST according to membership in c-planar STGraph, - //! computes minimum spanning tree according to weight in \a weight - virtual void call(const ClusterGraph& CG, - EdgeArray& inST, - EdgeArray& weight); - -private: - - //! builds spanning tree on original graph out of repgraphs STs - void dfsBuildOriginalST(/*ClusterGraph& CG,*/ - node v, - ClusterArray< EdgeArray > &treeEdges, //edges in repgraph - EdgeArray& inST, //original edges - NodeArray &visited); - //builds spanning tree on graph of node v in treeEdges - void dfsBuildSpanningTree(node v, - EdgeArray &treeEdges, - NodeArray &visited); - - //! constructs for every cluster a graph representing its - //! main structure (children & their connections) - //! only insert nodes here - void constructRepresentationGraphNodes(const ClusterGraph& CG, - Graph& g, - cluster c - ) - { - - //insert nodes for all child clusters - ListConstIterator it; - for (it = c->cBegin(); it.valid(); it++) - { - node v = g.newNode(); - m_cRepNode[*it] = v; - }//for - //insert nodes for all node entries in c - ListConstIterator itn; - for (itn = c->nBegin(); itn.valid(); itn++) - { - node v = g.newNode(); - m_vRepNode[*itn] = v; - }//for - }//constructRepresentationGraphNodes - - //! insert rep edges for all edges in clustergraph - void constructRepresentationGraphEdges(const ClusterGraph& CG, - ClusterArray& RepGraph) - { - edge e; - forall_edges(e, CG.getGraph()) - { - //insert representation in RepGraph[allocation cluster] - //defined by lowest common ancestor of end points - node u = e->source(); - node v = e->target(); - cluster uAncestor, vAncestor; - cluster allocCluster = - CG.commonClusterLastAncestors(u,v, uAncestor, vAncestor); - m_allocCluster[e] = allocCluster; - //now derive the real ancestors (maybe the nodes themselves from - //the supplied clusters - - //Case1: both nodes in same cluster => connect the nodes in the - //cluster representation graph - if (uAncestor == vAncestor) - { - m_repEdge[e] = RepGraph[uAncestor]->newEdge( - m_vRepNode[u], m_vRepNode[v]); - }//if - else - { - OGDF_ASSERT(!((uAncestor == CG.rootCluster())&& - (vAncestor == CG.rootCluster()))) - //now only one node can be directly in rootcluster - //this case now seems to fall together with else else... - if (uAncestor == CG.rootCluster()) - { - m_repEdge[e] = RepGraph[uAncestor]->newEdge( - m_vRepNode[u], m_cRepNode[vAncestor]); - }//if u in rootcluster - else if (vAncestor == CG.rootCluster()) - { - m_repEdge[e] = RepGraph[vAncestor]->newEdge( - m_cRepNode[uAncestor], m_vRepNode[v]); - }//if v in rootcluster - else - { - OGDF_ASSERT(allocCluster != 0) - //now create edge in lowest common cluster - node v1, v2; - v1 = ( (uAncestor == 0) ? m_vRepNode[u] : - m_cRepNode[uAncestor]); - v2 = ( (vAncestor == 0) ? m_vRepNode[v] : - m_cRepNode[vAncestor]); - m_repEdge[e] = RepGraph[allocCluster]->newEdge(v1, v2); - } - }//else - - }//foralledges - //m_repEdge - }//constructRepresentationGraphEdges - - //! Computes representation graphs used for spanning tree computation - void computeRepresentationGraphs(const ClusterGraph& CG, - ClusterArray& RepGraph) - { - cluster c; - forall_clusters(c, CG) - { - RepGraph[c] = new Graph; - constructRepresentationGraphNodes(CG, *RepGraph[c], c); - }//forallclusters - constructRepresentationGraphEdges(CG, RepGraph); - }//computeRepresentationGraphs - - void deleteRepresentationGraphs(const ClusterGraph& CG, - ClusterArray& RepGraph) - { - cluster c; - forall_clusters(c, CG) - { - if (RepGraph[c]) - delete RepGraph[c]; - }//forallclusters - - }//deleteRepresentationGraphs - - //! Initializes some internally used members on CG - void initialize(const ClusterGraph& CG); - - //**************************************************** - //data fields - - // store status of original edge: in subclustered graph? also used to check spanning tree - //EdgeArray m_edgeStatus; - - //! store the allocation cluster to avoid multiple computation - EdgeArray m_allocCluster; - //! store the representation edge - EdgeArray m_repEdge; - //! store the representation nodes for nodes and clusters - ClusterArray m_cRepNode; - NodeArray m_vRepNode; - //pointer to input ClusterPlanRep - //set in call, not to be used anywhere else - //m_pCPR; - //int m_genDebug; //only for debugging - -};//cplanarsubclusteredST - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/ClusterPQContainer.h b/ext/OGDF/ogdf/internal/cluster/ClusterPQContainer.h deleted file mode 100644 index 40403458e..000000000 --- a/ext/OGDF/ogdf/internal/cluster/ClusterPQContainer.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of ClusterPQContainer. - * - * Stores information for a biconnected component - * of a cluster for embedding the cluster in the - * top down traversal - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CLUSTER_PQ_CONTAINER_H -#define OGDF_CLUSTER_PQ_CONTAINER_H - -#include -#include -#include -#include - - -namespace ogdf { - -class ClusterPQContainer { - - friend class CconnectClusterPlanarEmbed; - - - // Definition - // incoming edge of v: an edge e = (v,w) with number(v) < number(w) - - - // Stores for every node v the keys corresponding to the incoming edges of v - NodeArray* > >* m_inLeaves; - - // Stores for every node v the keys corresponding to the outgoing edges of v - NodeArray* > >* m_outLeaves; - - // Stores for every node v the sequence of incoming edges of v according - // to the embedding - NodeArray >* m_frontier; - - // Stores for every node v the nodes corresponding to the - // opposed sink indicators found in the frontier of v. - NodeArray >* m_opposed; - - // Stores for every node v the nodes corresponding to the - // non opposed sink indicators found in the frontier of v. - NodeArray >* m_nonOpposed; - - // Table to acces for every edge its corresponding key in the PQTree - EdgeArray*>* m_edge2Key; - - // Stores for every node its st-number - NodeArray *m_numbering; - - // Stores for every st-number the node - Array *m_tableNumber2Node; - - node m_superSink; - - // the subgraph that contains the biconnected component - // NOT THE COPY OF THE BICONNECTED COMPONENT THAT WAS CONSTRUCTED - // DURING PLANARITY TESTING. THIS HAS BEEN DELETED. - Graph *m_subGraph; - // corresponding PQTree - EmbedPQTree *m_T; - // The leaf correpsonding to the edge (s,t). - PlanarLeafKey *m_stEdgeLeaf; - -public: - - ClusterPQContainer(): - m_inLeaves(0),m_outLeaves(0),m_frontier(0), - m_opposed(0),m_nonOpposed(0),m_edge2Key(0), - m_numbering(0),m_tableNumber2Node(0), - m_superSink(0),m_subGraph(0),m_T(0), m_stEdgeLeaf(0) { } - - ~ClusterPQContainer() { } - - void init(Graph *subGraph){ - m_subGraph = subGraph; - m_inLeaves - = OGDF_NEW NodeArray* > >(*subGraph); - - m_outLeaves - = OGDF_NEW NodeArray* > >(*subGraph); - - m_frontier - = OGDF_NEW NodeArray >(*subGraph); - - m_opposed - = OGDF_NEW NodeArray >(*subGraph); - - m_nonOpposed - = OGDF_NEW NodeArray >(*subGraph); - - m_edge2Key - = OGDF_NEW EdgeArray*>(*subGraph); - - m_numbering - = OGDF_NEW NodeArray(*subGraph); - - m_tableNumber2Node - = OGDF_NEW Array(subGraph->numberOfNodes()+1); - } - - - void Cleanup() { - if (m_inLeaves) - delete m_inLeaves; - if (m_outLeaves) - { - node v; - forall_nodes(v,*m_subGraph) - { - while (!(*m_outLeaves)[v].empty()) - { - PlanarLeafKey* L = (*m_outLeaves)[v].popFrontRet(); - delete L; - } - } - delete m_outLeaves; - } - if (m_frontier) - delete m_frontier; - if (m_opposed) - delete m_opposed; - if (m_nonOpposed) - delete m_nonOpposed; - if (m_edge2Key) - delete m_edge2Key; - if (m_T) - { - m_T->emptyAllPertinentNodes(); - delete m_T; - } - if (m_numbering) - delete m_numbering; - if (m_tableNumber2Node) - delete m_tableNumber2Node; - - } -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/Cluster_ChunkConnection.h b/ext/OGDF/ogdf/internal/cluster/Cluster_ChunkConnection.h deleted file mode 100644 index 1fc716e56..000000000 --- a/ext/OGDF/ogdf/internal/cluster/Cluster_ChunkConnection.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of initial cut-constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * A feasible ILP solution has to imply a completely connected, planar Sub-Clustergraph. - * For each cluster that is not connected, additional connection edges have to be inserted - * between the chunks of the cluster, to obtain c-connectivity. - * Thus, initial constraints are added that guarantee initial c-connectivity, if the number of chunks - * is at most 3. If some cluster consists of more than 3 chunks, additional constraints - * have to be separated during the optimization. - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_CLUSTER_CHUNK_CONNECTION_H -#define OGDF_CLUSTER_CHUNK_CONNECTION_H - -#include -#include -#include -#include -#include - -#include - -namespace ogdf { - - -class ChunkConnection : public BaseConstraint { -#ifdef OGDF_DEBUG - //Mainly for debugging output purposes - friend class Master; - friend class Sub; - friend class CPlanarMaster; - friend class CPlanarSub; -#endif -public: - - ChunkConnection(ABA_MASTER *master, const ArrayBuffer& chunk, const ArrayBuffer& cochunk); - - virtual ~ChunkConnection(); - - // Computes and returns the coefficient for the given variable - virtual double coeff(ABA_VARIABLE *v) { - EdgeVar *ev = (EdgeVar *)v; - //Safe for both clustered planarity testing and maximum c-planar subgraph - return (ev->theEdgeType() != EdgeVar::CONNECT) ? 0.0 : (double)coeff(ev->sourceNode(), ev->targetNode()); - } - inline int coeff(const nodePair& n) { return coeff(n.v1,n.v2); } - int coeff(node v1, node v2); - - void printMe(ostream& out) const { - out << "[ChunkCon: ("; - int j; - forall_arrayindices(j,m_chunk) { - Logger::slout() << m_chunk[j] << ","; - } - out << "|"; - forall_arrayindices(j,m_cochunk) { - Logger::slout() << m_cochunk[j] << ","; - } - out << ")]"; - } - -private: - - // The nodePairs corresponding to the constraint - Array m_chunk; - Array m_cochunk; -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/Cluster_CutConstraint.h b/ext/OGDF/ogdf/internal/cluster/Cluster_CutConstraint.h deleted file mode 100644 index 6fbada050..000000000 --- a/ext/OGDF/ogdf/internal/cluster/Cluster_CutConstraint.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * This class represents the cut-constraints belonging to the ILP formulation. - * Cut-constraints are dynamically separated be means of cutting plane methods. - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_CLUSTER_CUT_CONSTRAINT_H -#define OGDF_CLUSTER_CUT_CONSTRAINT_H - -#include -#include - -#include - -namespace ogdf { - -class CutConstraint : public BaseConstraint { - -public: - - CutConstraint(ABA_MASTER *master, ABA_SUB *sub, List &edges); - - virtual ~CutConstraint(); - - // Computes and returns the coefficient for the given variable - virtual double coeff(ABA_VARIABLE *v) { EdgeVar *ev = (EdgeVar *)v; return (double)coeff(ev->sourceNode(), ev->targetNode()); } - inline int coeff(const nodePair& n) { return coeff(n.v1,n.v2); } - int coeff(node n1, node n2); - - void printMe(ostream& out) const { - out << "[CutCon: "; - forall_listiterators(nodePair, it, m_cutEdges) { - (*it).printMe(out); - out << ","; - } - out << "]"; - } - -private: - - // The list containing the node pairs corresponding to the cut edges - List m_cutEdges; - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/Cluster_EdgeVar.h b/ext/OGDF/ogdf/internal/cluster/Cluster_EdgeVar.h deleted file mode 100644 index 7919a97e1..000000000 --- a/ext/OGDF/ogdf/internal/cluster/Cluster_EdgeVar.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the variable class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_MAX_CPLANAR_EDGE_H -#define OGDF_MAX_CPLANAR_EDGE_H - -#include -#include - -#include - -namespace ogdf { - - -class EdgeVar : public ABA_VARIABLE { - friend class Sub; -public: -enum edgeType {ORIGINAL, CONNECT}; - - EdgeVar(ABA_MASTER *master, double obj, edgeType eType, node source, node target); - //! Simple version for cplanarity testing (only connect edges allowed) - EdgeVar(ABA_MASTER *master, double obj, node source, node target); - //! Simple version for cplanarity testing (only connect edges allowed, lower bound given) - EdgeVar(ABA_MASTER *master, double obj, double lbound, node source, node target); - - virtual ~EdgeVar(); - - edge theEdge() const {return m_edge;} - node sourceNode() const {return m_source;} - node targetNode() const {return m_target;} - edgeType theEdgeType() const {return m_eType;} - //double objCoeff() const {return m_objCoeff;} - - virtual void printMe(ostream& out) { - out << "[Var: " << sourceNode() << "->" << targetNode() << " (" << ((theEdgeType()==EdgeVar::ORIGINAL)?"original":"connect") << ") ZF=" << obj() << "]"; - } - -private: - - // The edge type of the variable - edgeType m_eType; - - // The corresponding nodes and edge - node m_source; - node m_target; - edge m_edge; - -}; - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/cluster/Cluster_MaxPlanarEdges.h b/ext/OGDF/ogdf/internal/cluster/Cluster_MaxPlanarEdges.h deleted file mode 100644 index 3ff561ee5..000000000 --- a/ext/OGDF/ogdf/internal/cluster/Cluster_MaxPlanarEdges.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * These constraint do not necessarily belong to the ILP formulation, but - * have the purpose to strengthen the LP-relaxations in the case of very dense - * Graphs, by restricting the maximum number of edges that can occur in any optimal - * solution according to Euler's formula for planar Graphs: |E| <= 3|V|-6 - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_CLUSTER_MAX_PLANAR_EDGES_H -#define OGDF_CLUSTER_MAX_PLANAR_EDGES_H - -#include -#include - -#include - -namespace ogdf { - - -class MaxPlanarEdgesConstraint : public ABA_CONSTRAINT { -#ifdef OGDF_DEBUG - friend class Sub; - friend class CPlanarSub; -#endif - public: - //construction - MaxPlanarEdgesConstraint(ABA_MASTER *master, int edgeBound, List &edges); - MaxPlanarEdgesConstraint(ABA_MASTER *master, int edgeBound); - - //destruction - virtual ~MaxPlanarEdgesConstraint(); - - //computes and returns the coefficient for the given variable - virtual double coeff(ABA_VARIABLE *v); - - private: - List m_edges; - bool m_graphCons; -}; - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/cluster/KuratowskiConstraint.h b/ext/OGDF/ogdf/internal/cluster/KuratowskiConstraint.h deleted file mode 100644 index 07cb0e8f7..000000000 --- a/ext/OGDF/ogdf/internal/cluster/KuratowskiConstraint.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * These constraints represent the planarity-constraints belonging to the - * ILP formulation. These constraints are dynamically separated. - * For the separation the planarity test algorithm by Boyer and Myrvold is used. - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_KURATOWSKI_CONSTRAINT_H -#define OGDF_KURATOWSKI_CONSTRAINT_H - -#include -#include -#include -//#include -//#include - -#include - -namespace ogdf { - - -class KuratowskiConstraint : public ABA_CONSTRAINT { - -public: - - KuratowskiConstraint(ABA_MASTER *master, int nEdges, SListPure &ks); - - virtual ~KuratowskiConstraint(); - - // Computes and returns the coefficient for the given variable - virtual double coeff(ABA_VARIABLE *v); - - void printMe(ostream& out) { - out << "[KuraCon: "; - forall_listiterators(nodePair, it, m_subdivision) { - (*it).printMe(out); - out << ","; - } - out << "]"; - } - -private: - - // The subdivision containing edges forming a SubGraph that is not planar - List m_subdivision; - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Master.h b/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Master.h deleted file mode 100644 index 64489fe09..000000000 --- a/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Master.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the master class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * This class is managing the optimization. - * Variables and initial constraints are generated and pools are initialized. - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_MAX_CPLANAR_MASTER_H -#define OGDF_MAX_CPLANAR_MASTER_H - -//#include -#include -#include -#include -#include -#include - -#include - -namespace ogdf { - - - -class Master : public ABA_MASTER { - - friend class Sub; - - // Pointers to the given Clustergraph and underlying Graph are stored. - const ClusterGraph *m_C; - const Graph *m_G; - - - // Each time the primal bound is improved, the integer solution induced Graph is built. - // \a m_solutionGraph is a pointer to the currently best solution induced Graph. - GraphCopy *m_solutionGraph; - - List m_allOneEdges; // m_originalOneEdges; // m_connectionOneEdges; // m_deletedOriginalEdges; // &original, List &connection, List &deleted); - - // Returns the optimal solution induced Clustergraph - Graph *solutionInducedGraph() {return (Graph*)m_solutionGraph;} - - // Returns nodePairs of original, connection, deleted or all optimal solution edges in list \a edges. - void getAllOptimalSolutionEdges(List &edges) const; - void getOriginalOptimalSolutionEdges(List &edges) const; - void getConnectionOptimalSolutionEdges(List &egdes) const; - void getDeletedEdges(List &edges) const; - - // Get parameters - const int getKIterations() const {return m_nKuratowskiIterations;} - const int getNSubdivisions() const {return m_nSubdivisions;} - const int getNKuratowskiSupportGraphs() const {return m_nKuratowskiSupportGraphs;} - const int getHeuristicLevel() const {return m_heuristicLevel;} - const int getHeuristicRuns() const {return m_nHeuristicRuns;} - const double getKBoundHigh() const {return m_kuratowskiBoundHigh;} - const double getKBoundLow() const {return m_kuratowskiBoundLow;} - const bool perturbation() const {return m_usePerturbation;} - const double branchingOEdgeSelectGap() const {return m_branchingGap;} - const double getHeuristicFractionalBound() const {return m_heuristicFractionalBound;} - const int numberOfHeuristicPermutationLists() const {return m_nHeuristicPermutationLists;} - const bool getMPHeuristic() const {return m_mpHeuristic;} - const bool getCheckCPlanar() const {return m_checkCPlanar;} - const int getNumAddVariables() const {return m_numAddVariables;} - const double getStrongConstraintViolation() const {return m_strongConstraintViolation;} - const double getStrongVariableViolation() const {return m_strongVariableViolation;} - - // Read global constraint counter, i.e. the number of added constraints of specific type. - const int addedKConstraints() const {return m_nKConsAdded;} - const int addedCConstraints() const {return m_nCConsAdded;} - - - // Set parameters - void setKIterations(int n) {m_nKuratowskiIterations = n;} - void setNSubdivisions(int n) {m_nSubdivisions = n;} - void setNKuratowskiSupportGraphs(int n) {m_nKuratowskiSupportGraphs = n;} - void setNHeuristicRuns(int n) {m_nHeuristicRuns = n;} - void setKBoundHigh(double n) {m_kuratowskiBoundHigh = ((n>0.0 && n<1.0) ? n : 0.8);} - void setKBoundLow(double n) {m_kuratowskiBoundLow = ((n>0.0 && n<1.0) ? n : 0.2);} - void heuristicLevel(int level) {m_heuristicLevel = level;} - void setHeuristicRuns(int n) {m_nHeuristicRuns = n;} - void setPertubation(bool b) {m_usePerturbation = b;} - void setHeuristicFractionalBound(double b) {m_heuristicFractionalBound = b;} - void setHeuristicPermutationLists(int n) {m_nHeuristicPermutationLists = n;} - void setMPHeuristic(bool b) {m_mpHeuristic = b;}//!< Switches use of lower bound heuristic - void setNumAddVariables(int i) {m_numAddVariables=i;} - void setStrongConstraintViolation(double d) { m_strongConstraintViolation=d;} - void setStrongVariableViolation(double d) { m_strongVariableViolation=d;} - - //! If set to true, PORTA output is written in a file - void setPortaFile(bool b) {m_porta = b;} - - // Updating global constraint counter - void updateAddedCCons(int n) {m_nCConsAdded += n;} - void updateAddedKCons(int n) {m_nKConsAdded += n;} - - // Returns global primal and dual bounds. - double getPrimalBound() {return globalPrimalBound;} - double getDualBound() {return globalDualBound;} - - // Cut pools for connectivity and planarity - //! Returns cut pool for connectivity - ABA_STANDARDPOOL *getCutConnPool() {return m_cutConnPool;} - //! Returns cut pool for planarity - ABA_STANDARDPOOL *getCutKuraPool() {return m_cutKuraPool;} - - //! Returns true if default cut pool is used. Otherwise, separate - //! connectivity and Kuratowski pools are generated and used. - bool &useDefaultCutPool() { return m_useDefaultCutPool;} - -#ifdef OGDF_DEBUG - bool m_solByHeuristic; //solution computed by heuristic or ILP - // Simple output function to print the given graph to the console. - // Used for debugging only. - void printGraph(const Graph &G); -#endif - - //! The name of the file that contains the standard, i.e., non-cut, - //! constraints (may be deleted by ABACUS and shouldn't be stored twice) - const char* getStdConstraintsFileName() - { - return "StdConstraints.txt"; - } - - int getNumInactiveVars() { return m_inactiveVariables.size();} - -protected: - - // Initializes constraints and variables and an initial dual bound. - virtual void initializeOptimization(); - - // Function that is invoked at the end of the optimization - virtual void terminateOptimization(); - - double heuristicInitialLowerBound(); - -private: - - // Computes a dual bound for the optimal solution. - // Tries to find as many edge-disjoint Kuratowski subdivisions as possible. - // If k edge-disjoint groups of subdivisions are found, the upper bound can be - // initialized with number of edges in underlying graph minus k. - double heuristicInitialUpperBound(); - - // Is invoked by heuristicInitialUpperBound() - void clusterConnection(cluster c, GraphCopy &GC, double &upperBound); - - // Computes the graphtheoretical distances of edges incident to node \a u. - void nodeDistances(node u, NodeArray > &dist); - - - // Parameters - int m_nKuratowskiSupportGraphs; // Maximal number of times the Kuratowski support graph is computed - int m_nKuratowskiIterations; // Maximal number of times BoyerMyrvold is invoked - int m_nSubdivisions; // Maximal number of extracted Kuratowski subdivisions - int m_nMaxVars; // Max Number of variables - int m_heuristicLevel; // Indicates if primal heuristic shall be used or not - int m_nHeuristicRuns; // Counts how often the primal heuristic has been called - - bool m_usePerturbation; // Indicates whether C-variables should be perturbated or not - double m_branchingGap; // Modifies the branching behaviour - double m_heuristicFractionalBound; - int m_nHeuristicPermutationLists; // The number of permutation lists used in the primal heuristic - bool m_mpHeuristic; //!< Indicates if simple max planar subgraph heuristic - // should be used to derive lower bound if only root cluster exists - - double m_kuratowskiBoundHigh; // Upper bound for deterministic edge addition in computation of the Supportgraph - double m_kuratowskiBoundLow; // Lower bound for deterministic edge deletion in computation of the Supportgraph - - int m_numAddVariables; // how many variables should i add maximally per pricing round? - double m_strongConstraintViolation; // when do i consider a constraint strongly violated -> separate in first stage - double m_strongVariableViolation; // when do i consider a variable strongly violated (red.cost) -> separate in first stage - - ABA_MASTER::OUTLEVEL m_out; // Determines the output level of ABACUS - ABA_STRING *m_maxCpuTime; // Time threshold for optimization - - - // The basic objective function coefficient for connection edges. - double m_epsilon; - // If pertubation is used, this variable stores the largest occuring coeff, - // i.e. the one closest to 0. Otherwise it corresponds to \a m_epsilon - double m_largestConnectionCoeff; - - // Counters for the number of added constraints - int m_nCConsAdded; - int m_nKConsAdded; - int m_solvesLP; - int m_varsInit; - int m_varsAdded; - int m_varsPotential; - int m_varsMax; - int m_varsCut; - int m_varsKura; - int m_varsPrice; - int m_varsBranch; - int m_activeRepairs; - ArrayBuffer m_repairStat; - inline void clearActiveRepairs() { - if(m_activeRepairs) { - m_repairStat.push(m_activeRepairs); - m_activeRepairs = 0; - } - } - - double globalPrimalBound; - double globalDualBound; - - inline double getDoubleTime(const ABA_TIMER* act) { - long tempo = act->centiSeconds()+100*act->seconds()+6000*act->minutes()+360000*act->hours(); - return ((double) tempo)/ 100.0; - } - - //number of calls of the fast max planar subgraph heuristic - const int m_fastHeuristicRuns; - - //! Cut pools for connectivity and Kuratowski constraints - ABA_STANDARDPOOL< ABA_CONSTRAINT, ABA_VARIABLE > *m_cutConnPool; //!< Connectivity Cuts - ABA_STANDARDPOOL< ABA_CONSTRAINT, ABA_VARIABLE > *m_cutKuraPool; //!< Kuratowski Cuts - - //! Defines if the ABACUS default cut pool or the separate Connectivity - //! and Kuratowski constraint pools are used - bool m_useDefaultCutPool; - - //! Defines if only clustered planarity is checked, i.e., - //! all edges of the original graph need to be fixed to be - //! part of the solution - bool m_checkCPlanar; - - //! - double m_delta; - double m_deltaCount; - double nextConnectCoeff() { return (m_checkCPlanar ? -1 : -m_epsilon) + m_deltaCount--*m_delta; } // TODO-TESTING - EdgeVar* createVariable(ListIterator& it) { - ++m_varsAdded; - EdgeVar* v = new EdgeVar(this, nextConnectCoeff(), EdgeVar::CONNECT, (*it).v1, (*it).v2); - v->printMe(Logger::slout()); - m_inactiveVariables.del(it); - return v; - } - List m_inactiveVariables; - void generateVariablesForFeasibility(const List& ccons, List& connectVars); - - bool goodVar(node a, node b); - - //! If set to true, PORTA output is written in a file - bool m_porta; - //! writes coefficients of all orig and connect variables in constraint con into - //! emptied list coeffs - void getCoefficients(ABA_CONSTRAINT* con, const List & orig, - const List & connect, List & coeffs); -}; - -}//end namespace - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_MinimalClusterConnection.h b/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_MinimalClusterConnection.h deleted file mode 100644 index ba47fdda6..000000000 --- a/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_MinimalClusterConnection.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of an initial constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * If some cluster has no connection to some other cluster, - * the optimal solution might insert a new connection-edge between theese two clusters, - * to obtain connectivity. Since the objective function minimizes the number - * of new connection-edges, at most one new egde will be inserted between - * two clusters that are not connected. - * This behaviour of the LP-solution is guaranteed from the beginning, by creating - * an initial constraint for each pair of non-connected clusters, - * which is implemented by this constraint class. - * - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_MAX_CPLANAR_MINIMAL_CLUSTER_CONNECTION_H -#define OGDF_MAX_CPLANAR_MINIMAL_CLUSTER_CONNECTION_H - -#include -#include - -#include - -namespace ogdf { - - -class MinimalClusterConnection : public ABA_CONSTRAINT { - -public: - - MinimalClusterConnection(ABA_MASTER *master, List &edges); - - virtual ~MinimalClusterConnection(); - - // Computes and returns the coefficient for the given variable - virtual double coeff(ABA_VARIABLE *v); - -private: - - // The node pairs corresponding to the constraint - List m_edges; - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Sub.h b/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Sub.h deleted file mode 100644 index 2d4bb1e64..000000000 --- a/ext/OGDF/ogdf/internal/cluster/MaxCPlanar_Sub.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the sub-problem class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem - * Contains separation algorithms as well as primal heuristics. - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_MAX_CPLANAR_SUB_H -#define OGDF_MAX_CPLANAR_SUB_H - -#include -#include -#include - -#include - -namespace ogdf { - -class Sub : public ABA_SUB { - -public: - - Sub(ABA_MASTER *master); - Sub(ABA_MASTER *master, ABA_SUB *father, ABA_BRANCHRULE *branchRule, List& criticalConstraints); - - virtual ~Sub(); - - // Creation of a child-node in the Branch&Bound tree according to the - // branching rule \a rule - virtual ABA_SUB *generateSon(ABA_BRANCHRULE *rule); - - -protected: - - - // Checks if the current solution of the LP relaxation is also a feasible solution to the ILP, - // i.e. Integer-feasible + satisfying all Kuratowski- and Cut-constraints. - virtual bool feasible(); - - virtual int makeFeasible() { return 0; } // to trick ABA_SUB::solveLp... -// virtual int removeNonLiftableCons() { return 0; } // to trick ABA_SUB::solveLp into returning 2 - int repair(); - - virtual int optimize() { - Logger::slout() << "OPTIMIZE BEGIN\tNode=" << this->id() << "\n"; - int ret = ABA_SUB::optimize(); - Logger::slout() << "OPTIMIZE END\tNode=" << this->id() << " db=" << dualBound() << "\tReturn=" << (ret?"(error)":"(ok)") << "\n"; - return ret; - } - - //functions for testing properties of the clustered graph - - //! Checks if the cluster induced graphs and their complement - //! are connected in the current solution. - bool checkCConnectivity(const GraphCopy& support); - bool checkCConnectivityOld(const GraphCopy& support); - - //! run through the pointer list parent and return the representative - //! i.e. the node with parent[v] == v - inline node getRepresentative(node v, NodeArray &parent) - { - while (v != parent[v]) - v = parent[v]; - return v; - } - - // Todo: Think about putting this into extended_graph_alg.h to make it - // publically available - int clusterBags(ClusterGraph &CG, cluster c); - -// using the below two functions iunstead (and instead of solveLp) we would get a more traditional situation -// virtual int separate() { -// return separateRealO(0.001); -// } -// virtual int pricing() { -// return pricingRealO(0.001); -// } - - /** these functions are mainly reporting to let abacus think everthing is normal. the actual work is done - * by separateReal() and pricingReal(). - * The steering of this process is performed in solveLp() - */ - - int separateReal(double minViolate); - int pricingReal(double minViolate); - - inline int separateRealO(double minViolate) { - Logger::slout() << "\tSeparate (minViolate=" << minViolate << ").."; - int r = separateReal(minViolate); - Logger::slout() << "..done: " << r << "\n"; - return r; - } - inline int pricingRealO(double minViolate) { - Logger::slout() << "\tPricing (minViolate=" << minViolate << ").."; - int r = pricingReal(minViolate); - master()->m_varsPrice += r; - Logger::slout() << "..done: " << r << "\n"; - return r; - } - - virtual int separate() { - Logger::slout() << "\tReporting Separation: "<<((m_reportCreation>0)?m_reportCreation:0)<<"\n"; - return (m_reportCreation>0)?m_reportCreation:0; - } - virtual int pricing() { - if(inOrigSolveLp) return 1; - Logger::slout() << "\tReporting Prizing: "<<((m_reportCreation<0)?-m_reportCreation:0)<<"\n"; - return (m_reportCreation<0)?-m_reportCreation:0; - } - - virtual int solveLp(); - - // Implementation of virtual function improve() inherited from ABA::SUB. - // Invokes the function heuristicImprovePrimalBound(). - // Tthis function belongs to the ABACUS framework. It is invoked after each separation-step. - // Since the heuristic is rather time consuming and because it is not very advantageous - // to run the heuristic even if additional constraints have been found, the heuristic - // is run "by hand" each time no further constraints coud be found, i.e. after having solved - // the LP-relaxation optimally. - virtual int improve(double &primalValue); - - // Two functions inherited from ABACUS and overritten to manipulate the branching behaviour. - virtual int selectBranchingVariableCandidates(ABA_BUFFER &candidates); - virtual int selectBranchingVariable(int &variable); - - //! Adds the given constraints to the given pool - inline int addPoolCons(ABA_BUFFER &cons, ABA_STANDARDPOOL *pool) - { - return (master()->useDefaultCutPool()) ? addCons(cons) : addCons(cons, pool); - }//addPoolCons - inline int separateCutPool(ABA_STANDARDPOOL *pool, double minViolation) - { - return (master()->useDefaultCutPool()) ? 0 : constraintPoolSeparation(0, pool, minViolation); - }//separateCutPool - -private: - - Master* master() { return (Master*)master_; } - - // A flag indicating if constraints have been found in the current separation step. - // Is used to check, if the primal heuristic should be run or not. - bool m_constraintsFound; - bool detectedInfeasibility; - bool inOrigSolveLp; - double realDualBound; - - // used for the steering in solveLp - int m_reportCreation; - bool m_sepFirst; - List< ABA_CONSTRAINT* > criticalSinceBranching; - ArrayBuffer bufferedForCreation; - int createVariablesForBufferedConstraints(); - - void myAddVars(ABA_BUFFER& b) { - int num = b.number(); - ABA_BUFFER keep(master(),num); - for(int i=num; i-->0;) - keep.push(true); - int r = addVars(b,0,&keep); - OGDF_ASSERT( r==num ) - } - - - // Computes the support graph for Kuratowski- constraints according to the current LP-solution. - // Parameter \a low defines a lower threshold, i.e all edges having value at most \a low - // are not added to the support graph. - // Parameter \a high defines an upper threshold, i.e all edges having value at least \a high, - // are added to the support graph. - // Edges having LP-value k that lies between \a low and \a high are added to the support graph - // randomly with a probability of k. - void kuratowskiSupportGraph( - GraphCopy &support, - double low, - double high); - - // Computes the support graph for Connectivity- constraints according to the current LP-solution. - void connectivitySupportGraph( - GraphCopy &support, - EdgeArray &weight); - - // Computes the integer solution induced Graph. - void intSolutionInducedGraph(GraphCopy &support); - - // Computes and returns the value of the lefthand side of the Kuratowski constraint - // induced by \a it and given support graph \a gc. - double subdivisionLefthandSide( - SListConstIterator it, - GraphCopy *gc); - - // Updates the best known solution according to integer solution of this subproblem. - void updateSolution(); - - - // The following four functions are used by the primal heuristic. - - int getArrayIndex(double lpValue); - - void childClusterSpanningTree( - GraphCopy &GC, - List &clusterEdges, - List &MSTEdges); - - void clusterSpanningTree( - ClusterGraph &C, - cluster c, - ClusterArray > &treeEdges, - ClusterArray > &clusterEdges); - - // Tries to improve the best primal solution by means of the current fractional LP-solution. - double heuristicImprovePrimalBound( - List &originalEdges, - List &connectionEdges, - List &deletedEdges); - - //! Adds the given constraints to the connectivity cut pool - inline int addCutCons(ABA_BUFFER cons) - { - return addPoolCons(cons, ((Master*)master_)->getCutConnPool()); - } - //! Adds the given constraints to the planarity cut pool - inline int addKuraCons(ABA_BUFFER cons) - { - return addPoolCons(cons, ((Master*)master_)->getCutKuraPool()); - } - - //tries to regenerate connectivity cuts - inline int separateConnPool(double minViolation) - { - return separateCutPool(((Master*)master_)->getCutConnPool(),minViolation); - } - //tries to regenerate kuratowski cuts - inline int separateKuraPool(double minViolation) - { - return separateCutPool(((Master*)master_)->getCutKuraPool(),minViolation); - } - /* - void minimumSpanningTree( - GraphCopy &GC, - List &clusterEdges, - List &MSTEdges); - - void recursiveMinimumSpanningTree( - ClusterGraph &C, - cluster c, - ClusterArray > &treeEdges, - List &edgesByIncLPValue, - List &clusterNodes); - - double heuristicImprovePrimalBoundDet( - List &origEdges, - List &conEdges, - List &delEdges); - */ - -}; - -}//end namespace - -#endif diff --git a/ext/OGDF/ogdf/internal/cluster/basics.h b/ext/OGDF/ogdf/internal/cluster/basics.h deleted file mode 100644 index f03f613c9..000000000 --- a/ext/OGDF/ogdf/internal/cluster/basics.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * $Revision: 2555 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 12:12:10 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the master class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * Basic classes for c-planarity computation. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_CPLANAR_BASICS_H -#define OGDF_CPLANAR_BASICS_H - -#include -#include -#include -#include - -namespace ogdf { -class ChunkConnection; - -//! Struct for storing the two corresponding nodes of an edge. -struct nodePair { - node v1; - node v2; - nodePair() {} - nodePair(node u1, node u2) : v1(u1), v2(u2) {} - void printMe(ostream& out) const { out << "("< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ADJACENCY_ORACLE_H -#define OGDF_ADJACENCY_ORACLE_H - - -#include -#include - - -namespace ogdf { - -//! Tells you in linear time if two nodes are adjacent -/** - * AdjacencyOracle is intialized with a Graph and returns for - * any pair of nodes in constant time if they are adajcent. - */ -class AdjacencyOracle { -public: - //! The one and only constrcutor for the class - AdjacencyOracle(const Graph &G); - //! This is the destructor - ~AdjacencyOracle() {delete m_adjacencyMatrix;} - //! This returns true if the two nodes are adjacent in G, false otherwise - bool adjacent(const node, const node) const; -private: - NodeArray m_nodeNum; //!< The internal number given to each node - Array2D *m_adjacencyMatrix; //!< A 2D-array where the entry is true if the nodes with the corresponding number are adjacent -}; - -} -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/Attraction.h b/ext/OGDF/ogdf/internal/energybased/Attraction.h deleted file mode 100644 index 06af82adb..000000000 --- a/ext/OGDF/ogdf/internal/energybased/Attraction.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class Attraction. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ATTRACTION_H -#define OGDF_ATTRACTION_H - - -#include - -namespace ogdf { - - -//! Energy function for attraction between two adjacent vertices. -/** - * Implements an energy function that simulates - * attraction between two adjacent vertices. There is an optimum - * distance where the energy is zero. The energy grows quadratic - * with the difference to the optimum distance. The optimum - * distance between two adjacent vertices depends on the size of - * the two vertices. - */ -class Attraction: public NodePairEnergy { -public: - //Initializes data structures to speed up later computations - Attraction(GraphAttributes &AG); - ~Attraction() {} - //! set the preferred edge length to the absolute value l - void setPreferredEdgelength(double l) {m_preferredEdgeLength = l;} - //! set multiplier for the edge length with repspect to node size to multi - void reinitializeEdgeLength(double multi); -#ifdef OGDF_DEBUG - void printInternalData() const; -#endif -private: - //! Average length and height of nodes is multiplied by this factor to get preferred edge length - static const double MULTIPLIER; - //! the length that that all edges should ideally have - double m_preferredEdgeLength; - //! computes the energy contributed by the two nodes if they are placed at the two given positions - double computeCoordEnergy(node,node, const DPoint&, const DPoint &) const; -}; - -}// namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/EdgeAttributes.h b/ext/OGDF/ogdf/internal/energybased/EdgeAttributes.h deleted file mode 100644 index 421050f3d..000000000 --- a/ext/OGDF/ogdf/internal/energybased/EdgeAttributes.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class EdgeAttributes. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_ATTRIBUTES_H -#define OGDF_EDGE_ATTRIBUTES_H - -#include -#include - -namespace ogdf { - - -class OGDF_EXPORT EdgeAttributes -{ - //helping data structure that stores the graphical attributes of an edge - //that are needed for the force-directed algorithms. - - //outputstream for EdgeAttributes - friend ostream &operator<< (ostream &,const EdgeAttributes &); - - //inputstream for EdgeAttributes - friend istream &operator>> (istream &,EdgeAttributes &); - -public: - - EdgeAttributes(); //constructor - ~EdgeAttributes() { } //destructor - - void set_EdgeAttributes(double l, edge e_orig, edge e_sub) - { - length = l; - e_original = e_orig; - e_subgraph = e_sub; - } - - void set_length(double l) { length = l; } - double get_length() const { return length; } - - - //needed for the divide et impera step in FMMM - - void set_original_edge (edge e) { e_original = e; } - void set_subgraph_edge (edge e) { e_subgraph = e; } - edge get_original_edge() const { return e_original; } - edge get_subgraph_edge() const { return e_subgraph; } - - //needed for the preprocessing step in FMMM (set/get_original_edge are needed, too) - - void set_copy_edge (edge e) {e_subgraph = e;} - edge get_copy_edge() const {return e_subgraph;} - - //needed for multilevel step - - void set_higher_level_edge (edge e) { e_subgraph = e; } - edge get_higher_level_edge() const { return e_subgraph; } - bool is_moon_edge() const { return moon_edge; } - void make_moon_edge() { moon_edge = true; } - bool is_extra_edge() const { return extra_edge; } - void make_extra_edge() { extra_edge = true; } - void mark_as_normal_edge() { extra_edge = false; } - void init_mult_values() { e_subgraph = NULL; moon_edge = false; } - -private: - double length; - edge e_original; - edge e_subgraph; - bool moon_edge; //indicates if this edge is associasted with a moon node - bool extra_edge;//indicates if this edge is an extra edge that is added to - //enforce few edge crossings -}; - -}//namespace ogdf -#endif - diff --git a/ext/OGDF/ogdf/internal/energybased/EnergyFunction.h b/ext/OGDF/ogdf/internal/energybased/EnergyFunction.h deleted file mode 100644 index 996002d1e..000000000 --- a/ext/OGDF/ogdf/internal/energybased/EnergyFunction.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class EnergyFunction... - * - * ...which specifies an interface for energy functions for - * the Davidson Harel graph drawing method. It is used in the - * class DavidsonHarel. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ENERGY_FUNCTION_H -#define OGDF_ENERGY_FUNCTION_H - - -#include - - -namespace ogdf { - -//! The interface for energy functions for the Davidson Harel graph drawing method. -/** - * It is used in the class DavidsonHarel. - */ -class EnergyFunction { -public: - //! Initializes data dtructures to speed up later computations - EnergyFunction(const String &funcname, GraphAttributes &AG); - virtual ~EnergyFunction() { } - - //! computes energy for the layout at the beginning of the optimization process - virtual void computeEnergy()=0; - //! sets m_testNode, m_testX and m_testY and computes the energy for the new configuration (vertex v moves to newPos) - double computeCandidateEnergy( - const node v, - const DPoint &newPos); - //! prints the name of the energy function - String getName() const {return m_name;} - //! Changes m_currentX and m_currentY by setting the position of m_testNode to m_testX and m_testY. Sets m_energy to m_candidateEnergy. Computes the energy of the layout stored in AG. - void candidateTaken(); -#ifdef OGDF_DEBUG - //! prints status information for debugging - void printStatus() const; -#endif - double energy() const {return m_energy;} -protected: - const Graph &m_G;//!< the graph that should be drawn - const String m_name;//!< name of the energy function - double m_candidateEnergy;//!< the energy of the layout if the candidate layout is chosen - double m_energy;//!< energy of the current layout - //! returns candidate position for the node to be moved - DPoint testPos() {return m_testPos;} - //! returns the current position of vertex v - DPoint currentPos(const node v) const {return DPoint(m_AG.x(v),m_AG.y(v));} - //! returns the vertex that is under consideration in the current step - node testNode() const {return m_testNode;} - //! changes the data of a specific energy function if the candidate was taken - virtual void internalCandidateTaken() = 0; - //! computes the energy if m_testNode changes position to m_testX and m_testY, sets the value of m_candidateEnergy. - virtual void compCandEnergy()=0; -#ifdef OGDF_DEBUG - virtual void printInternalData() const = 0; -#endif -private: - //! the copy constructor is fake and can not be used. - EnergyFunction(const EnergyFunction &e):m_G(e.m_G),m_name(e.m_name),m_AG(e.m_AG) { } - //! the assignment operator is fake and can not be used. - EnergyFunction& operator=(const EnergyFunction &e); - GraphAttributes& m_AG; //!< This stores the graph with its graphical attributes and the current positions for the vertices - node m_testNode;//!< The node that changed position in the candidate - DPoint m_testPos;//!< New candidate positions for m_testNode -}; - -}// end namespace -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/FruchtermanReingold.h b/ext/OGDF/ogdf/internal/energybased/FruchtermanReingold.h deleted file mode 100644 index 01338d5a1..000000000 --- a/ext/OGDF/ogdf/internal/energybased/FruchtermanReingold.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class FruchtermanReingold (computation of forces). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FRUCHTERMAN_REINGOLD_H -#define OGDF_FRUCHTERMAN_REINGOLD_H - -#include -#include -#include -#include -#include - -namespace ogdf { - -class OGDF_EXPORT FruchtermanReingold -{ -public: - FruchtermanReingold(); //constructor - ~FruchtermanReingold() { } //destructor - - //Calculate exact rep. forces for each node. - void calculate_exact_repulsive_forces( - const Graph &G, - NodeArray& A, - NodeArray& F_rep); - - //Grid approximation of rep.forces for each node. - void calculate_approx_repulsive_forces( - const Graph &G, - NodeArray& A, - NodeArray& F_rep); - - //Make all initialisations that are needed for FruchtermanReingold. - void make_initialisations ( - double boxlength, - DPoint down_left_corner, - int grid_quotient); - - //Import updated information of the drawing area. - void update_boxlength_and_cornercoordinate(double b_l, DPoint d_l_c) { - boxlength = b_l; down_left_corner = d_l_c; - } - -private: - int _grid_quotient;//for coarsening the FrRe-grid - int max_gridindex; //maximum index of a grid row/column - double boxlength; //length of drawing box - DPoint down_left_corner;//down left corner of drawing box - - //Returns the repulsing force_function_value of scalar d. - double f_rep_scalar (double d); - - //The number k of rows and colums of the grid is sqrt(|V|) / frGridQuotient() - //(Note that in [FrRe] frGridQuotient() is 2.) - void grid_quotient(int p) { _grid_quotient = ((0<=p) ? p : 2);} - int grid_quotient() const {return _grid_quotient;} -}; - -}//namespace ogdf -#endif - diff --git a/ext/OGDF/ogdf/internal/energybased/IntersectionRectangle.h b/ext/OGDF/ogdf/internal/energybased/IntersectionRectangle.h deleted file mode 100644 index 312379170..000000000 --- a/ext/OGDF/ogdf/internal/energybased/IntersectionRectangle.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class IntersectionRectangle which realizes axis - * parallel rectangles. - * - * The class can compute the rectangle that - * is created by the intersection of two rectangles and it can - * compute the area of a rectangle. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_INTERSECTION_RECTANGLE_H -#define OGDF_INTERSECTION_RECTANGLE_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT IntersectionRectangle { - -private: - - DPoint m_p1; // lower left Point - DPoint m_p2; // upper right Point - double m_area; - DPoint m_center; - -public: - - // constructs zero area rectangle - IntersectionRectangle() : m_p1(), m_p2(), m_area(0.0), m_center() { } - - //constructs rectangle with diagonal from p1 to p2 - IntersectionRectangle(const DPoint &p1, const DPoint &p2) : m_p1(p1), m_p2(p2) { init(); } - - //copy constructor - IntersectionRectangle(const IntersectionRectangle &dr) : - m_p1(dr.m_p1), m_p2(dr.m_p2), m_area(dr.m_area), m_center(dr.m_center) { } - - //constructs rectangle with diagonal from (x1,y1) to (x2,y2) - IntersectionRectangle(double x1, double y1, double x2, double y2) { - m_p1.m_x = x1; m_p1.m_y = y1; m_p2.m_x = x2; m_p2.m_y = y2; - init(); - } - - //constructs rectangle with diagonal dl - IntersectionRectangle(const DLine &dl) : m_p1(dl.start()), m_p2(dl.end()) - { init(); } - - // constructs a rectangle from the center point, width and height - IntersectionRectangle(const DPoint &, double , double); - - // returns true if two rectangles have the same coordinates - bool operator==(const IntersectionRectangle &dr) const { - return m_p1 == dr.m_p1 && m_p2 == dr.m_p2; - } - - // returns true if two rectangles have different coordinates - bool operator!=(const IntersectionRectangle &dr) const { - return !(*this == dr); - } - - // assignment - IntersectionRectangle &operator= (const IntersectionRectangle &dr) { - if (this != &dr) { // don't assign myself - m_p1 = dr.m_p1; - m_p2 = dr.m_p2; - m_center = dr.m_center; - m_area = dr.m_area; - } - return *this; - } - - // returns the width of the rectangle - double width() const { - return m_p2.m_x - m_p1.m_x; - } - - //returns the height of the rectangle - double height() const { - return m_p2.m_y - m_p1.m_y; - } - - //returns the center of the rectangle - DPoint center() const { return m_center; } - - //returns the area of the rectangle - double area() const { return m_area; } - - - // returns rect-defining vertices - const DPoint &p1() const { return m_p1; } - const DPoint &p2() const { return m_p2; } - - // tests if p is inside the rectangle modulo the comparison epsilon - bool inside(const DPoint &p) const { - if ((p.m_x + OGDF_GEOM_EPS) < m_p1.m_x || - (p.m_x - OGDF_GEOM_EPS) > m_p2.m_x || - (p.m_y + OGDF_GEOM_EPS) < m_p1.m_y || - (p.m_y - OGDF_GEOM_EPS) > m_p2.m_y) - return false; - return true; - } - - // tests if *this and the argument rectangle intersect - bool intersects(const IntersectionRectangle &) const; - - // returns the rectangle resulting from intersection of this and argument. - // Returns a rectangle with zero width and height and center (0,0) if intersection - // is empty. - IntersectionRectangle intersection(const IntersectionRectangle &) const; - - // computes distance between two rectangles - double distance(const IntersectionRectangle &) const; - - //moves the rectangle such that its center is at the given point - void move(const DPoint &); - -private: - // makes sure, that m_p1 <= m_p2, default after construction, sets area and center - void init(); - - // swaps the two y-coordinates - void yInvert() { swap(m_p1.m_y, m_p2.m_y); } - - // swaps the two x-coordinates - void xInvert() { swap(m_p1.m_x, m_p2.m_x); } - - // functions for computing bounding lines - DLine bottom() const { return DLine(m_p1.m_x,m_p1.m_y,m_p2.m_x,m_p1.m_y); } - DLine top() const { return DLine(m_p1.m_x, m_p2.m_y, m_p2.m_x,m_p2.m_y); } - DLine left() const { return DLine(m_p1.m_x, m_p1.m_y, m_p1.m_x, m_p2.m_y); } - DLine right() const { return DLine(m_p2.m_x, m_p1.m_y, m_p2.m_x, m_p2.m_y); } - - // computes distance between parallel line segments - double parallelDist(const DLine &, const DLine &) const; - - // computes distance between two points - double pointDist(const DPoint &p1, const DPoint &p2) const { - return sqrt((p1.m_y - p2.m_y) * (p1.m_y - p2.m_y) + (p1.m_x - p2.m_x) * (p1.m_x - p2.m_x)); - } - - friend ostream& operator<<(ostream &,const IntersectionRectangle &); -}; - -/* -//the point comparer is needed for sorting points and storing them in -//sorted sequences -class PointComparer { -public: - static int compare(const DPoint &p1, const DPoint &p2) { - if(p1.m_x > p2.m_x) return 1; - if(p1.m_x < p2.m_x) return -1; - if(p1.m_y > p2.m_y) return 1; - if(p1.m_y < p2.m_y) return -1; - return 0; - } - OGDF_AUGMENT_STATICCOMPARER(DPoint) -}; -*/ - -} -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/MultilevelGraph.h b/ext/OGDF/ogdf/internal/energybased/MultilevelGraph.h deleted file mode 100644 index 27acd6e4c..000000000 --- a/ext/OGDF/ogdf/internal/energybased/MultilevelGraph.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief MLG is the main data structure for ModularMultilevelMixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MULTILEVEL_GRAPH_H -#define OGDF_MULTILEVEL_GRAPH_H - -#include -#include -#include -#include - -namespace ogdf { - -//Stores info on merging for a refinement level -struct NodeMerge -{ - // Node/Edge IDs instead of pointers as the nodes themselves may be nonexistent. - std::vector m_deletedEdges; - std::vector m_changedEdges; - std::map m_doubleWeight; // for changed and deleted edges - std::map m_source; - std::map m_target; - - int m_mergedNode; - std::vector< std::pair > m_position; // optional information . mergedNode will be placed at average of relative distances to target. - - std::vector m_changedNodes; // there may be placement strategies that use more than one reference-node. - std::map m_radius; // for changed nodes and the merged node - - int m_level; - - - NodeMerge(int level) : m_level(level) { } - ~NodeMerge() { } -}; - - -class OGDF_EXPORT MultilevelGraph -{ -private: - bool m_createdGraph; //used in destructor, TODO: check if it is needed - Graph * m_G; - GraphAttributes * m_GA; // m_changes; - NodeArray m_radius; - double m_avgRadius; //stores average node radius for scaling and random layout purposes - - EdgeArray m_weight; - - // Associations to index only as the node/edge may be nonexistent - NodeArray m_nodeAssociations; - EdgeArray m_edgeAssociations; - - std::vector m_reverseNodeIndex; - std::vector m_reverseNodeMergeWeight;// m_reverseEdgeIndex; - - MultilevelGraph * removeOneCC(std::vector &componentSubArray); - void copyFromGraph(const Graph &G, NodeArray &nodeAssociations, EdgeArray &edgeAssociations); - void prepareGraphAttributes(GraphAttributes &GA) const; - - void initReverseIndizes(); - void initInternal(); - -public: - ~MultilevelGraph(); - MultilevelGraph(); - MultilevelGraph(Graph &G); - MultilevelGraph(GraphAttributes &GA); - // if the Graph is available without const, no copy needs to be created. - MultilevelGraph(GraphAttributes &GA, Graph &G); - - // creates MultilevelGraph directly from GML file. - MultilevelGraph(istream &is); - MultilevelGraph(const String &filename); - - NodeArray &getRArray() { return m_radius; } - EdgeArray &getWArray() { return m_weight; } - - edge getEdge(unsigned int index); - node getNode(unsigned int index); - - double radius(node v) { return m_radius[v]; } - void radius(node v, double r) { m_radius[v] = r; } - double averageRadius() const { return m_avgRadius;} - - double x(node v) { return m_GA->x(v); } - double y(node v) { return m_GA->y(v); } - void x(node v, double x) { m_GA->x(v) = x;} - void y(node v, double y) { m_GA->y(v) = y;} - - void weight(edge e, double weight) { m_weight[e] = weight; } - double weight(edge e) { return m_weight[e]; } - - //returns the merge weight, i.e. the number of nodes represented by v on the current level - int mergeWeight(node v) {return m_reverseNodeMergeWeight[v->index()];} - - void moveToZero(); - - int getLevel(); - Graph & getGraph() { return *m_G; } - //! Returns attributes of current level graph as GraphAttributes - GraphAttributes & getGraphAttributes() const { return *m_GA; } - void exportAttributes(GraphAttributes &GA) const; - void exportAttributesSimple(GraphAttributes &GA) const; - void importAttributes(const GraphAttributes &GA); - void importAttributesSimple(const GraphAttributes &GA); - void reInsertGraph(MultilevelGraph &MLG); - void reInsertAll(std::vector components); - void copyNodeTo(node v, MultilevelGraph &MLG, std::map &tempNodeAssociations, bool associate, int index = -1); - void copyEdgeTo(edge e, MultilevelGraph &MLG, std::map &tempNodeAssociations, bool associate, int index = -1); - void writeGML(ostream &os); - void writeGML(const String &fileName); - - // the original graph will be cleared to save Memory - std::vector splitIntoComponents(); - - bool postMerge(NodeMerge * NM, node merged); - //\a merged is the node now represented by \a theNode - bool changeNode(NodeMerge * NM, node theNode, double newRadius, node merged); - bool changeEdge(NodeMerge * NM, edge theEdge, double newWeight, node newSource, node newTarget); - bool deleteEdge(NodeMerge * NM, edge theEdge); - std::vector moveEdgesToParent(NodeMerge * NM, node theNode, node parent, bool deleteDoubleEndges, int adjustEdgeLengths); - NodeMerge * getLastMerge(); - node undoLastMerge(); - - void updateReverseIndizes(); - //sets the merge weights back to initial values - void updateMergeWeights(); -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/NMM.h b/ext/OGDF/ogdf/internal/energybased/NMM.h deleted file mode 100644 index 972864ff7..000000000 --- a/ext/OGDF/ogdf/internal/energybased/NMM.h +++ /dev/null @@ -1,513 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class NMM (New Multipole Method). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NMM_H -#define OGDF_NMM_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT NMM -{ -public: - NMM(); //constructor - ~NMM() { } //destructor - - //Calculate rep. forces for each node. - void calculate_repulsive_forces(const Graph &G, - NodeArray& A, - NodeArray& F_rep); - - //Make all initialisations that are needed for New Multipole Method (NMM) - void make_initialisations (const Graph &G, - double boxlength, - DPoint down_left_corner, - int particles_in_leaves, - int precision, - int tree_construction_way, - int find_small_cell); - - //Dynamically allocated memory is freed here. - void deallocate_memory(); - - //Import updated information of the drawing area. - void update_boxlength_and_cornercoordinate(double b_l,DPoint d_l_c); - -private: - int MIN_NODE_NUMBER; //The minimum number of nodes for which the forces are - //calculated using NMM (for lower values the exact - //calculation is used). - bool using_NMM; //Indicates whether the exact method or NMM is used for force - //calculation (value depends on MIN_NODE_NUMBER) - FruchtermanReingold ExactMethod; //needed in case that using_NMM == false - - int _tree_construction_way;//1 = pathwise;2 = subtreewise - int _find_small_cell;//0 = iterative; 1= Aluru - int _particles_in_leaves;//max. number of particles for leaves of the quadtree - int _precision; //precision for p-term multipole expansion - - double boxlength;//length of drawing box - DPoint down_left_corner;//down left corner of drawing box - - int* power_of_2; //holds the powers of 2 (for speed reasons to calculate the - //maximal boxindex (index is from 0 to max_power_of_2_index) - int max_power_of_2_index;//holds max. index for power_of_2 (= 30) - double ** BK; //holds the binomial coefficients - List rep_forces; //stores the rep. forces of the last iteration - //(needed for error calculation) - - //private helping functions - - //The array power_of_2 is calculated for values from 0 to max_power_of_2_index - //which is set here to 30. - void init_power_of_2_array(); - - //The space of power_of_2 is freed. - void free_power_of_2_array(); - - //Returns power_of_2[i] for values <= max_power_of_2_index else it returns - //pow(2,i). - int power_of_two(int i); - - //Returns the maximal index of a box in level i. - int maxboxindex (int level); - - //Use NMM for force calculation (used for large Graphs (|V| > MIN_NODE_NUMBER)). - void calculate_repulsive_forces_by_NMM(const Graph &G, NodeArray - & A, NodeArray& F_rep); - - //Use the exact method for force calculation (used for small Graphs (|V| <= - //MIN_NODE_NUMBER) for speed reasons). - void calculate_repulsive_forces_by_exact_method(const Graph &G, - NodeArray& A, - NodeArray& F_rep); - - // *********Functions needed for path by path tree construction*********** - - //The reduced quadtree is build up path by path (the Lists LE,ME, the - //centers, D1, D2, M, and quad_tree_leaves are not calculated here. - void build_up_red_quad_tree_path_by_path(const Graph& G, - NodeArray& A, - QuadTreeNM& T); - - //Makes L_x(y)_copy a copy of L_x(y)_orig and sets p.copy_item for each element in - //L_x(y)_orig to the ListIterator of the corresponding element in L_x(y)_copy; - //Furthermore, the p.cross_ref_items in L_x(y)_copy are set and p.subList_ptr and - //p.tmp_cross_ref_item is reset to NULL in both lists. - void make_copy_and_init_Lists(List& L_x_orig, - List& L_x_copy, - List& L_y_orig, - List& L_y_copy); - - //The root node of T is constructed. - void build_up_root_node(const Graph& G,NodeArray& A, QuadTreeNM& T); - - //The sorted and linked Lists L_x and L_y for the root node are created. - void create_sorted_coordinate_Lists(const Graph& G,NodeArray& A, - List& L_x, List& L_y); - - //T is extended by a subtree T1 rooted at the T.get_act_node(). - //The boxlength and down_left_corner of the actual node is reduced if it is - //not the minimal subquad that contains all the particles in the represented area. - void decompose_subtreenode(QuadTreeNM& T, - List& act_x_List_copy, - List& act_y_List_copy, - List& new_leaf_List); - - //The extreme coordinates of the particles contained in *act_ptr are calculated. - void calculate_boundaries_of_act_node(QuadTreeNodeNM* act_ptr, - double& x_min, - double& x_max, - double& y_min, - double& y_max); - - //Returns true if the rectangle defined by x_min,...,y_max lies within the - //left(right)_top(bottom) quad of the small cell of *act_ptr. - bool in_lt_quad(QuadTreeNodeNM* act_ptr, double x_min,double x_max, double y_min, double y_max); - bool in_rt_quad(QuadTreeNodeNM* act_ptr, double x_min,double x_max, double y_min, double y_max); - bool in_lb_quad(QuadTreeNodeNM* act_ptr, double x_min,double x_max, double y_min, double y_max); - bool in_rb_quad(QuadTreeNodeNM* act_ptr, double x_min,double x_max, double y_min, double y_max); - - //The Lists *act_ptr->get_x(y)_List_ptr() are split into two sublists containing - //the particles in the left and right half of the actual quad. The list that is - //larger is constructed from *act_ptr->get_x(y)_List_ptr() by deleting the other - //elements; The smaller List stays empty at this point, but the corresponding - //elements in L_x(y)_copy contain a pointer to the x(y) List, where they belong to. - void split_in_x_direction( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List*& L_y_left_ptr, - List*& L_x_right_ptr, - List *& L_y_right_ptr); - - //The Lists *act_ptr->get_x(y)_List_ptr() are split into two subLists containing - //the particles in the top /bottom half ... - void split_in_y_direction( - QuadTreeNodeNM* act_ptr, - List*& L_x_bottom_ptr, - List*& L_y_bottom_ptr, - List*& L_x_top_ptr, - List*& L_y_top_ptr); - - - //The Lists *L_x(y)_left_ptr are constructed from *act_ptr->get_x(y)_List_ptr() - //by deleting all elements right from last_left_item in *act_ptr->get_x_List_ptr() - //the corresponding values in *act_ptr->get_y_List_ptr() are deleted as well. - //The corresponding List-elements of the deleted elements in the Lists L_x(y)_copy - //hold the information, that they belong to the Lists *L_x(y)_left_ptr. - void x_delete_right_subLists( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List *& L_y_left_ptr, - List*& L_x_right_ptr, - List *& L_y_right_ptr, - ListIterator last_left_item); - - //Analogue as above. - void x_delete_left_subLists( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List *& L_y_left_ptr, - List*& L_x_right_ptr, - List *& L_y_right_ptr, - ListIterator last_left_item); - - //The Lists *L_x(y)_left_ptr are constructed from *act_ptr->get_x(y)_List_ptr() - //by deleting all elements right from last_left_item in *act_ptr->get_y_List_ptr() - //the ... - void y_delete_right_subLists( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List*& L_y_left_ptr, - List*& L_x_right_ptr, - List *& L_y_right_ptr, - ListIterator last_left_item); - - //Analogue as above. - void y_delete_left_subLists( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List*& L_y_left_ptr, - List*& L_x_right_ptr, - List *& L_y_right_ptr, - ListIterator last_left_item); - - - //The Lists *L_x(y)_b_ptr and *L_x(y)_t_ptr are constructed from the Lists - // *L_x(y)_ptr. - void split_in_y_direction( - QuadTreeNodeNM* act_ptr, - List*& L_x_ptr, - List*& L_x_b_ptr, - List*& L_x_t_ptr, - List*& L_y_ptr, - List*& L_y_b_ptr, - List*& L_y_t_ptr); - - //The Lists *L_x(y)_b(t)_ptr are constructed from the Lists *L_x(y)_ptr by - //moving all List elements from *L_x(y)_ptr that belong to *L_x(y)_l_ptr - //to this List. the L_x(y)_right_ptr point to the reduced Lists L_x(y)_ptr - //afterwards. - void y_move_left_subLists(List*& L_x_ptr, - List*& L_x_b_ptr, - List*& L_x_t_ptr, - List*& L_y_ptr, - List *& L_y_b_ptr, - List*& L_y_t_ptr, - ListIterator last_left_item); - - //Same as above but the elements that belong to *&L_x(y)_right_ptr are moved. - void y_move_right_subLists(List*& L_x_ptr, - List*& L_x_b_ptr, - List*& L_x_t_ptr, - List*&L_y_ptr, - List *& L_y_b_ptr, - List*& L_y_t_ptr, - ListIterator last_left_item); - - //The sorted subLists, that can be accesssed by the entries in L_x(y)_copy-> - //get_subList_ptr() are constructed. - void build_up_sorted_subLists(List& L_x_copy, - List& act_y_List_copy); - - // ************functions needed for subtree by subtree tree construction ********** - - //The reduced quadtree is build up subtree by subtree (the lists LE, ME the - //centers, D1, D2, M, quad_tree_leaves are not calculated here. - void build_up_red_quad_tree_subtree_by_subtree(const Graph& G, - NodeArray& A, - QuadTreeNM& T); - - //The root node of T is constructed and contained_nodes is set to the list of - //all nodes of G. - void build_up_root_vertex(const Graph&G, QuadTreeNM& T); - - //The reduced subtree of T rooted at *subtree_root_ptr containing all the particles - //of subtree_root_ptr->get_contained_nodes() is constructed; Pointers to leaves - //of the subtree that contain more than particles_in_leaves() particles in their - //contained_nodes() lists are added to new_subtree_root_List_ptr; The lists - //contained_nodes() are nonempty only for the (actual) leaves of T. - void construct_subtree(NodeArray& A, - QuadTreeNM& T, - QuadTreeNodeNM* subtree_root_ptr, - List& new_subtree_root_List); - - //A complete subtree of T and of depth subtree_depth, rooted at *T.get_act_ptr() is - //constructed. Furthermore leaf_ptr[i][j] points to a leaf node of the subtree - //that represents the quadratic subregion of *T.get_act_ptr() at subtree_depth - //and position [i][j] i,j in 0,...,maxindex;act_depth(x_index,y_index) are - //helping variables for recursive calls. - void construct_complete_subtree(QuadTreeNM& T, - int subtree_depth, - Array2D& leaf_ptr, - int act_depth, - int act_x_index, - int act_y_index); - - //The particles in subtree_root_ptr->get_contained_nodes() are assigned to - //the the contained_nodes lists of the leaves of the subtree by using the - //information of A,leaf_ptr and maxindex. Afterwards contained_nodes of - // *subtree_root_ptr is empty. - void set_contained_nodes_for_leaves(NodeArray& A, - QuadTreeNodeNM* subtree_root_ptr, - Array2D& leaf_ptr, - int maxindex); - - //The subtree of T rooted at *T.get_act_ptr() is traversed bottom up, such that - //the subtreeparticlenumber of every node in this subtree is set correctly. - void set_particlenumber_in_subtree_entries(QuadTreeNM& T); - - //The reduced subtree rooted at *T.get_act_ptr() is calculated ; A pointer to - //every leaf of this subtree that contains more then particles_in_leaves() - //particles is added to new_subtree_root_List; The lists contained_nodes are - //empty for all but the leaves. - void construct_reduced_subtree(NodeArray& A, - QuadTreeNM& T, - List& new_subtree_root_List); - - //All subtrees of *T.get_act_ptr() that have a child c of *T.get_act_ptr() as root - //and c.get_particlenumber_in_subtree() == 0 are deleted. - void delete_empty_subtrees(QuadTreeNM& T); - - //If *T.get_act_ptr() is a degenerated node (has only one child c) *T.get_act_ptr() - //is deleted from T and the child c is linked with the father of *T.get_act_ptr() - //if *T.get_act_ptr() is the root of T than c is set to the new root of T - //T.get_act_ptr() points to c afterwards; Furthermore true is returned if - // *T.get_act_ptr() has been degenerated, else false is returned. - bool check_and_delete_degenerated_node(QuadTreeNM& T); - - //The subtree rooted at new_leaf_ptr is deleted, *new_leaf_ptr is a leaf - //of T and new_leaf_ptr->get_contained_nodes() contains all the particles - //contained in the leaves of the deleted subtree; Precondition: T.get_act_ptr() is - //new_leaf_ptr. - void delete_sparse_subtree(QuadTreeNM& T, QuadTreeNodeNM* new_leaf_ptr); - - //new_leaf_ptr->get_contained_nodes() contains all the particles contained in - //the leaves of its subtree afterwards; Precondition: T.get_act_ptr() is - //new_leaf_ptr - void collect_contained_nodes(QuadTreeNM& T, QuadTreeNodeNM* new_leaf_ptr); - - //If all nodes in T.get_act_ptr()->get_contained_nodes() have the same position - //false is returned. Else true is returned and - //the boxlength, down_left_corner and level of *T.get_act_ptr() is updated - //such that this values are minimal (i.e. the smallest quad that contains all - //the particles of T.get_act_ptr()->get_contained_nodes(); If all this particles - //are placed at a point nothing is done. - bool find_smallest_quad(NodeArray& A, QuadTreeNM& T); - - // *********functions needed for subtree by subtree tree construction(end) ******** - - //Finds the small cell of the actual Node of T iteratively,and updates - //Sm_downleftcorner, Sm_boxlength, and level of *act_ptr. - void find_small_cell_iteratively(QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max); - - //Finds the small cell of the actual Node of T by Aluru's Formula, and updates - //Sm_downleftcorner, Sm_boxlength, and level of *act_ptr. - void find_small_cell_by_formula(QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max); - - //The reduced quad tree is deleted; Furthermore the treenode_number is calculated. - void delete_red_quad_tree_and_count_treenodes(QuadTreeNM& T); - - //The multipole expansion terms ME are calculated for all nodes of T ( centers are - //initialized for each cell and quad_tree_leaves stores pointers to leaves of T). - void form_multipole_expansions(NodeArray& A, - QuadTreeNM& T, - List& quad_tree_leaves); - - //The multipole expansion List ME for the tree rooted at T.get_act_ptr() is - //recursively calculated. - void form_multipole_expansion_of_subtree(NodeArray& A, - QuadTreeNM& T, - List& quad_tree_leaves); - - //The Lists ME and LE are both initialized to zero entries for *act_ptr. - void init_expansion_Lists(QuadTreeNodeNM* act_ptr); - - //The center of the box of *act_ptr is initialized. - void set_center(QuadTreeNodeNM* act_ptr); - - //Calculate List ME for *act_ptr Precondition: *act_ptr is a leaf. - void form_multipole_expansion_of_leaf_node(NodeArray& A, - QuadTreeNodeNM* act_ptr); - - //Add the shifted ME Lists of *act_ptr to act_ptr->get_father_ptr() ; precondition - // *act_ptr has a father_node. - void add_shifted_expansion_to_father_expansion(QuadTreeNodeNM* act_ptr); - - //According to NMM T is traversed recursively top-down starting from act_node_ptr - //== T.get_root_ptr() and thereby the lists D1, D2, M and LE are calculated for all - //treenodes. - void calculate_local_expansions_and_WSPRLS(NodeArray&A, - QuadTreeNodeNM* act_node_ptr); - - //If the small cell of ptr_1 and ptr_2 are well separated true is returned (else - //false). - bool well_separated(QuadTreeNodeNM* ptr_1, QuadTreeNodeNM* ptr_2); - - //If ptr_1 and ptr_2 are nonequal and bordering true is returned; else false. - bool bordering(QuadTreeNodeNM* ptr_1, QuadTreeNodeNM* ptr_2); - - //The shifted local expansion of the father of node_ptr is added to the local - //expansion of node_ptr;precondition: node_ptr is not the root of T. - void add_shifted_local_exp_of_parent(QuadTreeNodeNM* node_ptr); - - //The multipole expansion of *ptr_1 is transformed into a local expansion around - //the center of *ptr_2 and added to *ptr_2 s local expansion list. - void add_local_expansion(QuadTreeNodeNM* ptr_1, QuadTreeNodeNM* ptr_2); - - //The multipole expansion for every particle of leaf_ptr->contained_nodes - //(1,0,...) is transformed into a local expansion around the center of *ptr_2 and - //added to *ptr_2 s local expansion List;precondition: *leaf_ptr is a leaf. - void add_local_expansion_of_leaf(NodeArray&A, - QuadTreeNodeNM* leaf_ptr, - QuadTreeNodeNM* act_ptr); - - //For each leaf v in quad_tree_leaves the force contribution defined by - //v.get_local_exp() is calculated and stored in F_local_exp. - void transform_local_exp_to_forces(NodeArray &A, - List& quad_tree_leaves, - NodeArray& F_local_exp); - - //For each leaf v in quad_tree_leaves the force contribution defined by all nodes - //in v.get_M() is calculated and stored in F_multipole_exp. - void transform_multipole_exp_to_forces(NodeArray& A, - List& quad_tree_leaves, - NodeArray& F_multipole_exp); - - //For each leaf v in quad_tree_leaves the force contributions from all leaves in - //v.get_D1() and v.get_D2() are calculated. - void calculate_neighbourcell_forces(NodeArray& A, - List& quad_tree_leaves, - NodeArray& F_direct); - - //Add repulsive force contributions for each node. - void add_rep_forces(const Graph& G, - NodeArray& F_direct, - NodeArray& F_multipole_exp, - NodeArray& F_local_exp, - NodeArray& F_rep); - - //Returns the repulsing force_function_value of scalar d. - double f_rep_scalar (double d); - - //Init BK -matrix for values n, k in 0 to t. - void init_binko(int t); - - //Free space for BK. - void free_binko(); - - //Returns n over k. - double binko(int n, int k); - - //The way to construct the reduced tree (0) = level by level (1) path by path - //(2) subtree by subtree - int tree_construction_way() const { return _tree_construction_way; } - - void tree_construction_way(int a) { - _tree_construction_way = (((0<=a)&&(a<=2)) ? a : 0); - } - - //(0) means that the smallest quadratic cell that surrounds a node of the - //quadtree is calculated iteratively in constant time (1) means that it is - //calculated by the formula of Aluru et al. in constant time - int find_sm_cell() const { return _find_small_cell; } - - void find_sm_cell(int a) { - _find_small_cell = (((0<=a)&&(a<=1)) ? a : 0); - } - - //Max. number of particles that are contained in a leaf of the red. quadtree. - void particles_in_leaves (int b) { _particles_in_leaves = ((b>= 1)? b : 1); } - int particles_in_leaves () const { return _particles_in_leaves; } - - //The precision p for the p-term multipole expansions. - void precision (int p) { _precision = ((p >= 1 ) ? p : 1); } - int precision () const { return _precision; } -}; - -}//namespace ogdf -#endif - diff --git a/ext/OGDF/ogdf/internal/energybased/NodeAttributes.h b/ext/OGDF/ogdf/internal/energybased/NodeAttributes.h deleted file mode 100644 index 7f478eb38..000000000 --- a/ext/OGDF/ogdf/internal/energybased/NodeAttributes.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * $Revision: 2555 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 12:12:10 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class NodeAttributes. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_ATTRIBUTES_H -#define OGDF_NODE_ATTRIBUTES_H - -#include -#include -#include - -namespace ogdf { - -class OGDF_EXPORT NodeAttributes -{ - //helping data structure that stores the graphical attributes of a node - //that are needed for the force-directed algorithms. - - - //outputstream for NodeAttributes - friend ostream &operator<< (ostream &,const NodeAttributes &); - - //inputstream for NodeAttributes - friend istream &operator>> (istream &,NodeAttributes &); - -public: - - NodeAttributes(); //constructor - ~NodeAttributes() { } //destructor - - void set_NodeAttributes(double w, double h, DPoint pos,node v_low,node - v_high) - { - width = w; - height = h; - position = pos; - v_lower_level = v_low; - v_higher_level = v_high; - } - - void set_position(DPoint pos) {position = pos;} - void set_width(double w) {width = w;} - void set_height(double h) {height = h;} - void set_x(double x) {position.m_x = x;} - void set_y(double y) {position.m_y = y;} - - DPoint get_position() const { return position; } - double get_x() const {return position.m_x;} - double get_y() const {return position.m_y;} - double get_width() const {return width;} - double get_height() const {return height;} - - - //for preprocessing step in FMMM - - void set_original_node (node v) {v_lower_level = v;} - void set_copy_node (node v) {v_higher_level = v;} - node get_original_node() const {return v_lower_level;} - node get_copy_node() const {return v_higher_level;} - - //for divide et impera step in FMMM (set/get_original_node() are needed, too) - - void set_subgraph_node (node v) {v_higher_level = v;} - node get_subgraph_node() const {return v_higher_level;} - - //for the multilevel step in FMMM - - void set_lower_level_node (node v) {v_lower_level = v;} - void set_higher_level_node (node v) {v_higher_level = v;} - node get_lower_level_node() const {return v_lower_level;} - node get_higher_level_node() const {return v_higher_level;} - void set_mass(int m) {mass = m;} - void set_type(int t) {type = t;} - void set_dedicated_sun_node(node v){dedicated_sun_node = v;} - void set_dedicated_sun_distance(double d) {dedicated_sun_distance = d;} - void set_dedicated_pm_node(node v) {dedicated_pm_node = v;} - void place(){placed = true;} - void set_angle_1(double a) {angle_1 = a;} - void set_angle_2(double a) {angle_2 = a;} - - int get_mass() const {return mass;} - int get_type() const {return type;} - node get_dedicated_sun_node() const {return dedicated_sun_node;} - double get_dedicated_sun_distance() const {return dedicated_sun_distance;} - node get_dedicated_pm_node() const {return dedicated_pm_node;} - bool is_placed() const {return placed;} - double get_angle_1() const {return angle_1;} - double get_angle_2() const {return angle_2;} - - - List* get_lambda_List_ptr() {return lambda_List_ptr;} - List* get_neighbour_sun_node_List_ptr() {return neighbour_s_node_List_ptr;} - List* get_dedicated_moon_node_List_ptr() {return moon_List_ptr;} - - - //initialzes all values needed for multilevel representations - void init_mult_values(); - -private: - - DPoint position; - double width; - double height; - - //for the multilevel and divide et impera and preprocessing step - - node v_lower_level; //the corresponding node in the lower level graph - node v_higher_level;//the corresponding node in the higher level graph - //for divide et impera v_lower_level is the original graph and - //v_higher_level is the copy of the copy of this node in the - //maximum connected subraph - - //for the multilevel step - - int mass; //the mass (= number of previously collapsed nodes) of this node - int type; //1 = sun node (s_node); 2 = planet node (p_node) without a dedicate moon - //3 = planet node with dedicated moons (pm_node);4 = moon node (m_node) - node dedicated_sun_node; //the dedicates s_node of the solar system of this node - double dedicated_sun_distance;//the distance to the dedicated sun node of the galaxy - //of this node - node dedicated_pm_node;//if type == 4 the dedicated_pm_node is saved here - List lambda; //the factors lambda for scaling the length of this edge - //relative to the pass between v's sun and the sun of a - //neighbour solar system - List neighbour_s_node;//this is the list of the neighbour solar systems suns - //lambda[i] corresponds to neighbour_s_node[i] - List* lambda_List_ptr; //a pointer to the lambda list - List* neighbour_s_node_List_ptr; //a pointer to to the neighbour_s_node list - List moon_List;//the list of all dedicated moon nodes (!= nil if type == 3) - List* moon_List_ptr;//a pointer to the moon_List - bool placed; //indicates weather an initial position has been assigned to this - //node or not - double angle_1;//describes the sector where nodes that are not adjacent to other - double angle_2;//solar systems have to be placed -}; - -}//namespace ogdf -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/NodePairEnergy.h b/ext/OGDF/ogdf/internal/energybased/NodePairEnergy.h deleted file mode 100644 index 0f9dce3c9..000000000 --- a/ext/OGDF/ogdf/internal/energybased/NodePairEnergy.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class NodePairEnergy which implements an energy - * function where the energy of a layout depends on the - * each pair of nodes. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_PAIR_ENERGY_H -#define OGDF_NODE_PAIR_ENERGY_H - - -#include -#include -#include - - -namespace ogdf { - -class NodePairEnergy: public EnergyFunction { -public: - //Initializes data dtructures to speed up later computations - NodePairEnergy(const String energyname, GraphAttributes &AG); - virtual ~NodePairEnergy() {delete m_nodeNums; delete m_pairEnergy;} - //computes the energy of the initial layout - void computeEnergy(); -protected: - //computes the energy stored by a pair of vertices at the given positions - virtual double computeCoordEnergy(node, node, const DPoint&, const DPoint&) const = 0; - //returns the internal number given to each vertex - int nodeNum(node v) const { return (*m_nodeNums)[v]; } - //returns true in constant time if two vertices are adjacent - bool adjacent(const node v, const node w) const {return m_adjacentOracle.adjacent(v,w);} - //returns the shape of a vertex as an IntersectionRectangle - const IntersectionRectangle& shape(const node v) const {return m_shape[v];} - -#ifdef OGDF_DEBUG - virtual void printInternalData() const; -#endif - -private: - NodeArray *m_nodeNums;//stores internal number of each vertex - Array2D *m_pairEnergy;//stores for each pair of vertices its energy - NodeArray m_candPairEnergy;//stores for each vertex its pair energy with - //respect to the vertex to be moved if its new position is chosen - NodeArray m_shape;//stores the shape of each vertex as - //an IntersectionRectangle - List m_nonIsolated;//list of vertices with degree greater zero - const AdjacencyOracle m_adjacentOracle;//structure for constant time adjacency queries - //function computes energy stored in a certain pair of vertices - double computePairEnergy(const node v, const node w) const; - //computes energy of whole layout if new position of the candidate vertex is chosen - void compCandEnergy(); - //If a candidate change is chosen as the new position, this function sets the - //internal data accordingly - void internalCandidateTaken(); - }; - - -}// namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/Overlap.h b/ext/OGDF/ogdf/internal/energybased/Overlap.h deleted file mode 100644 index b05d83415..000000000 --- a/ext/OGDF/ogdf/internal/energybased/Overlap.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Overlap which implements an energy - * function that gives a penalty for each pair of overlapping - * vertices. - * - * The penalty for each pair is the area of the overlap. It only - * works if the shape of the vertices is a rectangle. It uses the - * class IntersectionRectangle. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_OVERLAP_H -#define OGDF_OVERLAP_H - - -#include - - -namespace ogdf { - - -class Overlap: public NodePairEnergy { -public: - //Initializes private data structures - Overlap(GraphAttributes &AG); - ~Overlap() { } -private: - //computes for two vertices at the given position the overlap energy - double computeCoordEnergy(node,node, const DPoint&, const DPoint &) const; -}; - - -}// namespace ogdf -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/ParticleInfo.h b/ext/OGDF/ogdf/internal/energybased/ParticleInfo.h deleted file mode 100644 index c4963b566..000000000 --- a/ext/OGDF/ogdf/internal/energybased/ParticleInfo.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class ParticleInfo. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PARTICLE_INFO_H -#define OGDF_PARTICLE_INFO_H - -#include -#include - -namespace ogdf { - -class OGDF_EXPORT ParticleInfo -{ - //Helping data structure for building up the reduced quad tree by NMM. - - //Outputstream for ParticleInfo. - friend ostream &operator<< (ostream & output, const ParticleInfo & A) - { - output <<" node_index "<index()<<" x_y_coord "<> (istream & input, ParticleInfo & A) - { - input >> A; - return input; - } - -public: - - ParticleInfo() //constructor - { - vertex = NULL; - x_y_coord = 0; - cross_ref_item = NULL; - copy_item = NULL; - subList_ptr = NULL; - marked = false; - tmp_item = NULL; - } - - ~ParticleInfo() { } //destructor - - void set_vertex(node v) { vertex = v; } - void set_x_y_coord(double c) { x_y_coord = c; } - void set_cross_ref_item (ListIterator it) { cross_ref_item = it; } - void set_subList_ptr(List* ptr) { subList_ptr = ptr; } - void set_copy_item (ListIterator it) { copy_item = it; } - void mark() { marked = true; } - void unmark() { marked = false; } - void set_tmp_cross_ref_item(ListIterator it) { tmp_item = it; } - - node get_vertex() const { return vertex; } - double get_x_y_coord() const { return x_y_coord; } - ListIterator get_cross_ref_item() const { return cross_ref_item; } - List* get_subList_ptr() const { return subList_ptr; } - ListIterator get_copy_item() const{return copy_item;} - bool is_marked() const { return marked; } - ListIterator get_tmp_cross_ref_item() const { return tmp_item; } - -private: - node vertex; //the vertex of G that is associated with this attributes - double x_y_coord; //the x (resp. y) coordinate of the actual position of the vertex - ListIterator cross_ref_item; //the Listiterator of the - //ParticleInfo-Element that - //containes the vertex in the List storing the other - //coordinates (a cross reference) - List* subList_ptr; //points to the subList of L_x(L_y) where the - //actual entry of ParticleInfo has to be stored - ListIterator copy_item; //the item of this entry in the copy List - bool marked; //indicates if this ParticleInfo object is marked or not - ListIterator tmp_item; //a temporily item that is used to construct - //the cross references for the copy_Lists - //and the subLists -}; - - -//Needed for sorting algorithms in ogdf/List and ogdf/Array. -class ParticleInfoComparer { -public: - //Returns -1(1) if height of a <(>) height of b. If they are equal 0 is - //returned. - static int compare(const ParticleInfo& a,const ParticleInfo & b) - { - double p = a.get_x_y_coord(); - double q = b.get_x_y_coord(); - if(p < q ) return -1; - else if(p > q ) return 1; - else return 0; - } - OGDF_AUGMENT_STATICCOMPARER(ParticleInfo) -}; - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/Planarity.h b/ext/OGDF/ogdf/internal/energybased/Planarity.h deleted file mode 100644 index c64c1f2e1..000000000 --- a/ext/OGDF/ogdf/internal/energybased/Planarity.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Planarity which implements an - * energy function where the energy of a layout depends - * on the number of crossings. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANARITY_H -#define OGDF_PLANARITY_H - - -#include -#include - - -namespace ogdf { - - -class Planarity: public EnergyFunction { -public: - //! Initializes data structures to speed up later computations. - Planarity(GraphAttributes &AG); - - ~Planarity(); - - //! Computes energy of initial layout and stores it in \a m_energy. - void computeEnergy(); - -private: - struct ChangedCrossing { - int edgeNum1; - int edgeNum2; - bool cross; - }; - - //! Returns 1 if edges cross else 0. - bool intersect(const edge, const edge) const; - - //! Computes energy of candidate. - void compCandEnergy(); - - //! Changes internal data if candidate is taken. - void internalCandidateTaken(); - - //! Releases memory allocated for \a m_candidateCrossings. - void clearCandidateCrossings(); - - //! Tests if two lines given by four points intersect. - bool lowLevelIntersect( const DPoint&, const DPoint&, const DPoint&, - const DPoint&) const; - -#ifdef OGDF_DEBUG - virtual void printInternalData() const; -#endif - - EdgeArray *m_edgeNums; //!< numbers of edges - Array2D *m_crossingMatrix; //!< stores for each pair of edges if they cross - - /** - * stores for all edges incident to the test node - * an array with the crossings that change if the candidate position is chosen - */ - List m_crossingChanges; - - List m_nonSelfLoops; //!< list of edges that are not slef loops -}; // class Planarity - - -}// namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/PlanarityGrid.h b/ext/OGDF/ogdf/internal/energybased/PlanarityGrid.h deleted file mode 100644 index 459b330e9..000000000 --- a/ext/OGDF/ogdf/internal/energybased/PlanarityGrid.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarityGrid which implements an - * energy function where the energy of a layout depends - * on the number of crossings. - * - * Uses the UniformGris Class to compute the number of crossings. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANARITYGRID_H -#define OGDF_PLANARITYGRID_H - - -#include -#include - - -namespace ogdf { - - -class PlanarityGrid: public EnergyFunction { -public: - //initializes data structures to speed up later computations - PlanarityGrid(GraphAttributes &AG); - ~PlanarityGrid(); - // computes energy of initial layout and stores it in m_energy - void computeEnergy(); -private: - // computes energy of candidate - void compCandEnergy(); - // changes internal data if candidate is taken - void internalCandidateTaken(); -#ifdef OGDF_DEBUG - virtual void printInternalData() const; -#endif - const GraphAttributes &m_layout; //The current layout - UniformGrid *m_currentGrid; //stores grid for current layout - UniformGrid *m_candidateGrid; //stores grid for candidate layout -}; // class Planarity - - -}// namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/QuadTreeNM.h b/ext/OGDF/ogdf/internal/energybased/QuadTreeNM.h deleted file mode 100644 index 7e7294dd0..000000000 --- a/ext/OGDF/ogdf/internal/energybased/QuadTreeNM.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class QuadTreeNM. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_QUAD_TREE_NM_H -#define OGDF_QUAD_TREE_NM_H - -#include -#include "ParticleInfo.h" - - -namespace ogdf { - -class QuadTreeNM -{ - //Helping data structure that stores the information needed to represent - //the modified quadtree in the New Multipole Merthod (NMM) - -public: - QuadTreeNM(); //constructor - ~QuadTreeNM() { } //destructor - - //Deletes the tree starting at node_ptr. - void delete_tree(QuadTreeNodeNM* node_ptr); - - //Deletes the tree starting at node_ptr and counts the nodes of the subtree. - void delete_tree_and_count_nodes(QuadTreeNodeNM* node_ptr,int& nodecounter); - - //Pre_order traversal of the tree rooted at node_ptr (with or without - //output of the M,L-lists from 0 to precision). - void cout_preorder(QuadTreeNodeNM* node_ptr); - void cout_preorder(QuadTreeNodeNM* node_ptr,int precision); - - //Creates the root node and lets act_ptr and root_ptr point to the root node. - void init_tree() { - root_ptr = new QuadTreeNodeNM(); - act_ptr = root_ptr; - } - - //Sets act_ptr to the root_ptr. - void start_at_root() - { - act_ptr = root_ptr; - } - - //Sets act_ptr to the father_ptr. - void go_to_father() - { - if (act_ptr->get_father_ptr() != NULL) - act_ptr = act_ptr->get_father_ptr(); - else - cout<<"Error QuadTreeNM: No father Node exists"; - } - - //Sets act_ptr to the left_top_child_ptr. - void go_to_lt_child() - { - act_ptr = act_ptr->get_child_lt_ptr(); - } - - //Sets act_ptr to the right_top_child_ptr. - void go_to_rt_child() - { - act_ptr = act_ptr->get_child_rt_ptr(); - } - - //Sets act_ptr to the left_bottom_child_ptr. - void go_to_lb_child() - { - act_ptr = act_ptr->get_child_lb_ptr(); - } - - //Sets act_ptr to the right_bottom_child_ptr. - void go_to_rb_child() - { - act_ptr = act_ptr->get_child_rb_ptr(); - } - - //Creates a new left_top_child of the actual node (importing L_x(y)_ptr). - void create_new_lt_child(List* L_x_ptr, List* L_y_ptr); - void create_new_lt_child(); - - //Creates a new right_top_child of the actual node (importing L_x(y)_ptr). - void create_new_rt_child(List* L_x_ptr, List* L_y_ptr); - void create_new_rt_child(); - - //Creates a new left_bottom_child of the actual node (importing L_x(y)_ptr). - void create_new_lb_child(List* L_x_ptr, List* L_y_ptr); - void create_new_lb_child(); - - //Creates a new right_bottom_child of the actual node(importing L_x(y)_ptr). - void create_new_rb_child(List* L_x_ptr, List* L_y_ptr); - void create_new_rb_child(); - - //Returns the actual/root node pointer of the tree. - QuadTreeNodeNM* get_act_ptr() { return act_ptr; } - QuadTreeNodeNM* get_root_ptr() { return root_ptr; } - - //Sets root_ptr to r_ptr. - void set_root_ptr(QuadTreeNodeNM* r_ptr) { root_ptr = r_ptr; } - - //Sets act_ptr to a_ptr. - void set_act_ptr(QuadTreeNodeNM* a_ptr) { act_ptr = a_ptr; } - - //Sets the content of *root_ptr to r. - void set_root_node(QuadTreeNodeNM& r) { *root_ptr = r; } - -private: - QuadTreeNodeNM* root_ptr; //points to the root node - QuadTreeNodeNM* act_ptr; //points to the actual node - -}; - -}//namespace ogdf -#endif - diff --git a/ext/OGDF/ogdf/internal/energybased/QuadTreeNodeNM.h b/ext/OGDF/ogdf/internal/energybased/QuadTreeNodeNM.h deleted file mode 100644 index b2f20530f..000000000 --- a/ext/OGDF/ogdf/internal/energybased/QuadTreeNodeNM.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class QuadTreeNodeNM. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_QUAD_TREE_NODE_NM_H -#define OGDF_QUAD_TREE_NODE_NM_H - - -#include -#include -#include -#include -#include - - -using std::complex; - -namespace ogdf { - -class QuadTreeNodeNM -{ - //Helping data structure that stores the information needed to represent - //a node of the reduced quad tree in the New Multipole Method (NMM). - - //Outputstream for QuadTreeNodeNM. - friend ostream &operator<< (ostream &,const QuadTreeNodeNM &); - - //Inputstream for QuadTreeNodeNM. - friend istream &operator>> (istream &,QuadTreeNodeNM &); - -public: - - QuadTreeNodeNM(); //constructor - ~QuadTreeNodeNM(); //destructor - - void set_Sm_level(int l) { Sm_level = l;} - void set_Sm_downleftcorner(DPoint dlc) {Sm_downleftcorner = dlc;} - void set_Sm_boxlength(double l) {Sm_boxlength = l;} - void set_x_List_ptr(List* x_ptr) {L_x_ptr = x_ptr;} - void set_y_List_ptr(List* y_ptr) {L_y_ptr = y_ptr;} - void set_particlenumber_in_subtree(int p){ subtreeparticlenumber = p;} - void set_Sm_center(complex c) {Sm_center = c;} - void set_contained_nodes(List& L) {contained_nodes = L;} - void pushBack_contained_nodes(node v) {contained_nodes.pushBack(v);} - node pop_contained_nodes() {return contained_nodes.popFrontRet();} - bool contained_nodes_empty() {return contained_nodes.empty();} - - void set_I(List& l) {I = l;} - void set_D1(List& l) {D1 = l;} - void set_D2(List& l) {D2 = l;} - void set_M(List& l) {M = l;} - - //LE[i] is set to local[i] for i = 0 to precision and space for LE is reserved. - void set_locale_exp(Array > &local,int precision) - { - int i; - LE = new complex [precision+1]; - for (i = 0 ; i<= precision; i++) - LE[i] = local[i]; - } - - //ME[i] is set to multi[i] for i = 0 to precision and space for LE is reserved. - void set_multipole_exp(Array > &multi,int precision) - { - int i; - ME = new complex [precision+1]; - for (i = 0 ; i<= precision; i++) - ME[i] = multi[i]; - } - - //ME[i] is set to multi[i] for i = 0 to precision and no space for LE is reserved. - void replace_multipole_exp(Array > &multi,int precision) - { - int i; - for (i = 0 ; i<= precision; i++) - ME[i] = multi[i]; - } - - void set_father_ptr (QuadTreeNodeNM* f) { father_ptr = f;} - void set_child_lt_ptr(QuadTreeNodeNM* c) {child_lt_ptr = c;} - void set_child_rt_ptr(QuadTreeNodeNM* c) {child_rt_ptr = c;} - void set_child_lb_ptr(QuadTreeNodeNM* c) {child_lb_ptr = c;} - void set_child_rb_ptr(QuadTreeNodeNM* c) {child_rb_ptr = c;} - - bool is_root() {if(father_ptr == NULL) return true; else return false;} - bool is_leaf(){if ((child_lt_ptr == NULL) &&(child_rt_ptr == NULL) &&(child_lb_ptr - == NULL) && (child_rb_ptr == NULL)) - return true; else return false;} - bool child_lt_exists() { if (child_lt_ptr != NULL) return true; else return false;} - bool child_rt_exists() { if (child_rt_ptr != NULL) return true; else return false;} - bool child_lb_exists() { if (child_lb_ptr != NULL) return true; else return false;} - bool child_rb_exists() { if (child_rb_ptr != NULL) return true; else return false;} - - int get_Sm_level () const {return Sm_level;} - DPoint get_Sm_downleftcorner () const {return Sm_downleftcorner;} - double get_Sm_boxlength () const {return Sm_boxlength; } - List* get_x_List_ptr() {return L_x_ptr;} - List* get_y_List_ptr() {return L_y_ptr;} - int get_particlenumber_in_subtree()const { return subtreeparticlenumber;} - complex get_Sm_center() const {return Sm_center;} - complex* get_local_exp () const {return LE;} - complex* get_multipole_exp () const {return ME;} - void get_contained_nodes(List& L) const {L = contained_nodes;} - void get_I (List & l){l = I;} - void get_D1 (List & l){l = D1;} - void get_D2 (List & l){l = D2;} - void get_M (List & l){l = M;} - - QuadTreeNodeNM* get_father_ptr () const {return father_ptr;} - QuadTreeNodeNM* get_child_lt_ptr () const {return child_lt_ptr;} - QuadTreeNodeNM* get_child_rt_ptr () const {return child_rt_ptr;} - QuadTreeNodeNM* get_child_lb_ptr () const {return child_lb_ptr;} - QuadTreeNodeNM* get_child_rb_ptr () const {return child_rb_ptr;} - -private: - - int Sm_level; //level of the small cell - DPoint Sm_downleftcorner; //coords of the down left corner of the small cell - double Sm_boxlength; //length of small cell - List* L_x_ptr; //points to the lists that contain each Particle - //of G with its x(y)coordinate in increasing order - List* L_y_ptr; //and a cross reference to the list_item in the - //list with the other coordinate - int subtreeparticlenumber; //the number of particles in the subtree rooted - //at this node - complex Sm_center; //center of the small cell - complex* ME; //Multipole Expansion terms - complex* LE; //Locale Expansion terms - List contained_nodes; //list of nodes of G that are contained in this - //QuadTreeNode (emty if it is not a leave of - //the ModQuadTree - List I; //the list of min. ill sep. nodes in DIM2 - List D1,D2; //list of neighbouring(=D1) and not adjacent(=D2) - //leaves for direct force calculation in DIM2 - List M; //list of nodes with multipole force contribution - //like in DIM2 - QuadTreeNodeNM* father_ptr; //points to the father node - QuadTreeNodeNM* child_lt_ptr; //points to left top child - QuadTreeNodeNM* child_rt_ptr; //points to right bottom child - QuadTreeNodeNM* child_lb_ptr; //points to left bottom child - QuadTreeNodeNM* child_rb_ptr; //points to right bottom child -}; - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/Repulsion.h b/ext/OGDF/ogdf/internal/energybased/Repulsion.h deleted file mode 100644 index c014f66f1..000000000 --- a/ext/OGDF/ogdf/internal/energybased/Repulsion.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Repulsion which implements an enrgy - * function, where the energy of the layout grows with the - * proximity of the vertices. - * - * Thus, a layout has lower energy if all vertices are far appart. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_REPULSION_H -#define OGDF_REPULSION_H - - -#include - - -namespace ogdf { - -class Repulsion: public NodePairEnergy { -public: - //Initializes data structures to speed up later computations - Repulsion(GraphAttributes &AG); -private: - //computes for two vertices an the given positions the repulsive energy - double computeCoordEnergy(node, node, const DPoint&, const DPoint&) const; -}; - - -}// namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/energybased/UniformGrid.h b/ext/OGDF/ogdf/internal/energybased/UniformGrid.h deleted file mode 100644 index 6b12df1c1..000000000 --- a/ext/OGDF/ogdf/internal/energybased/UniformGrid.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class UniformGrid. - * - * This is a class implementing a 2-dimensional Hash array. - * It uses templates for the keys and the data of the objects - * stored in it. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UNIFORMGRID_H -#define OGDF_UNIFORMGRID_H - -#include -#include -#include -#include -#include -#include -#include - -namespace ogdf { - - - class UniformGrid{ - public: - UniformGrid(const GraphAttributes &); - //This constructor takes an GraphAttributes and computes a grid for the given - //layout. - UniformGrid(const GraphAttributes &,const node, const DPoint&); - //This constructor gets the current layout, the node that may be - //moved and its new position and computes the data for the - //modified layout. - UniformGrid(const UniformGrid &, const node, const DPoint&); - //Takes a UniformGrid and produces a new grid for the updated layout - int numberOfCrossings() const {return m_crossNum;} - bool newGridNecessary(const node v, const DPoint& p) { - bool resize = false; - IntersectionRectangle ir; - computeGridGeometry(v,p,ir); - double l = max(ir.width(),ir.height()); - l/=m_edgeMultiplier*(m_graph).numberOfEdges(); - if(l <= m_CellSize/2.0 || l >= m_CellSize*2.0) resize = true; - return resize; - } - - private: - void ModifiedBresenham(const IPoint &, const IPoint &, SList &) const; - //This takes two DPoints with and computes a list of points - //that are the lower left corners of the cells that may possibly contain points - //of the straight line segment connecting the two points - void DoubleModifiedBresenham(const DPoint &, const DPoint &, SList &) const; - //this function computes the grid coordinate of a point that depends on the - //coordiantes of the point, the lower left corner of the bounding rectangle - //and the size of a cell - IPoint computeGridPoint(const DPoint &dp) const { - double x = floor(dp.m_x/m_CellSize); - OGDF_ASSERT(isInt(x)); - double y = floor(dp.m_y/m_CellSize); - OGDF_ASSERT(isInt(y)); - return IPoint(int(x),int(y)); - } - //computes for a grid point the corresponding DPoint - DPoint computeRealPoint(const IPoint &ip) const { - DPoint p; - p.m_x = ip.m_x*m_CellSize; - p.m_y = ip.m_y*m_CellSize; - return p; - } - //checks if a double number is an integer - bool isInt(double d) const { - if(d - floor(d) > 0) return false; - if(d < INT_MIN || d > INT_MAX) return false; - return true; - } - //computes the crossings of the given edges for the given layout - //with the node moved to the position given as argument - void computeCrossings(const List&, const node, const DPoint&); - //computes the geometry of the grid if the node is moved - //to the position given by the point - void computeGridGeometry(const node, const DPoint&, IntersectionRectangle&) const; - //Checks if two edges cross inside the given cell. - //The node and the point are the moved node and its - //new position - bool crossingTest( - const edge, - const edge, - const node, - const DPoint&, - const IPoint&); - -#ifdef OGDF_DEBUG - void markCells(SList &, Array2D &) const; - bool crossesCell(IPoint, IPoint, const IPoint &) const; - bool crossesCell(DPoint, DPoint, const IPoint &) const; - void checkBresenham(DPoint, DPoint) const; - void checkBresenham(IPoint, IPoint) const; - bool intervalIntersect(double,double,double,double) const; - friend ostream& operator<<(ostream &,const UniformGrid&); - int m_crossingTests; - int m_maxEdgesPerCell; - double m_time; -#endif - const GraphAttributes &m_layout; //the layout - const Graph &m_graph; - HashArray2D > m_grid; //stores for each grid cell - //the Array of edges that cross that cell - EdgeArray > m_crossings; //stores for each edge the edges - //its crossings in the current layout - EdgeArray > m_cells; //Contains for each edge the - //list of cells it crosses - double m_CellSize; //Sidelength of one cell - const static double m_epsilon; //tolerance fo double computation - const static double m_edgeMultiplier; //this controls the gridsize - int m_crossNum; //number of crossings - - UniformGrid& operator=(const UniformGrid& ug); - }; -#ifdef OGDF_DEBUG -ostream &operator<<(ostream &, const IPoint &); -#endif -} //namespace -#endif diff --git a/ext/OGDF/ogdf/internal/lpsolver/LPSolver_coin.h b/ext/OGDF/ogdf/internal/lpsolver/LPSolver_coin.h deleted file mode 100644 index 5aef03e6e..000000000 --- a/ext/OGDF/ogdf/internal/lpsolver/LPSolver_coin.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Coin implementation of class LPSolver - * - * \author - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_LPSOLVER_COIN_H -#define OGDF_LPSOLVER_COIN_H - -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT LPSolver -{ -public: - enum OptimizationGoal { lpMinimize, lpMaximize }; - enum Status { lpOptimal, lpInfeasible, lpUnbounded }; - - // Constructor - LPSolver(); - ~LPSolver() { delete osi; } - - double infinity() const; - - // Call of LP solver - // - // Input is an optimization goal, an objective function, a matrix in sparse format, an - // equation-sense, and a right-hand side. - // The arrays have to be allocated as follows: - // - // double obj [numCols] - // int matrixBegin [numCols] - // int matrixCount [numCols] - // int matrixIndex [numNonzeroes] - // double matrixValue [numNonzeroes] - // double rightHandSide [numRows] - // char equationSense [numRows] - // double lowerBound [numCols] - // double upperBound [numCols] - // double x [numCols] - // - // The return value indicates the status of the solution. If an optimum solitions has - // been found, the result is lpOptimal - - Status optimize( - OptimizationGoal goal, // goal of optimization (minimize or maximize) - Array &obj, // objective function vector - Array &matrixBegin, // matrixBegin[i] = begin of column i - Array &matrixCount, // matrixCount[i] = number of nonzeroes in column i - Array &matrixIndex, // matrixIndex[n] = index of matrixValue[n] in its column - Array &matrixValue, // matrixValue[n] = non-zero value in matrix - Array &rightHandSide, // right-hand side of LP constraints - Array &equationSense, // 'E' == 'G' >= 'L' <= - Array &lowerBound, // lower bound of x[i] - Array &upperBound, // upper bound of x[i] - double &optimum, // optimum value of objective function (if result is lpOptimal) - Array &x // x-vector of optimal solution (if result is lpOptimal) - ); - - bool checkFeasibility( - const Array &matrixBegin, // matrixBegin[i] = begin of column i - const Array &matrixCount, // matrixCount[i] = number of nonzeroes in column i - const Array &matrixIndex, // matrixIndex[n] = index of matrixValue[n] in its column - const Array &matrixValue, // matrixValue[n] = non-zero value in matrix - const Array &rightHandSide, // right-hand side of LP constraints - const Array &equationSense, // 'E' == 'G' >= 'L' <= - const Array &lowerBound, // lower bound of x[i] - const Array &upperBound, // upper bound of x[i] - const Array &x // x-vector of optimal solution (if result is lpOptimal) - ); - -private: - OsiSolverInterface* osi; -}; - - -} - - -#endif diff --git a/ext/OGDF/ogdf/internal/orthogonal/NodeInfo.h b/ext/OGDF/ogdf/internal/orthogonal/NodeInfo.h deleted file mode 100644 index 04e39a9de..000000000 --- a/ext/OGDF/ogdf/internal/orthogonal/NodeInfo.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class NodeInfo. - * - * The class NodeInfo holds the information that is necessary for - * the rerouting of the edges after the constructive compaction step - * the rerouting works on a PlanRep and derives the info in member - * get_data. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODEINFO_H -#define OGDF_NODEINFO_H - -#include -#include -#include -#include -#include -#include - -namespace ogdf { - -class OGDF_EXPORT NodeInfo -{ -public: - //standard constr. - NodeInfo() { init(); } - - void init() - { - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - m_nbe[i][j] = 0; - m_delta[i][j] = 0; - m_eps[i][j] = 0; - m_routable[i][j] = 0; - m_flips[i][j] = 0; - } - num_s_edges[i] = 0; - m_gen_pos[i] = -1; - m_nbf[i] = 0; - m_coord[i] = 0; - m_ccoord[i] = 0; - } - lu = ll = ru = rl = tl = tr = bl = br = 0; - }//init - - //Constructor, adj holds entry for inner face edge - NodeInfo( - OrthoRep& H, - GridLayout& L, - node v, - adjEntry adj, - RoutingChannel& rc, - NodeArray& nw, - NodeArray& nh) : m_adj(adj) - { - init(); - get_data(H, L, v, rc, nw, nh); - } - - virtual ~NodeInfo() { } - - adjEntry cage_entry() { return m_adj; } - - //get - int coord(OrthoDir bs) const { return m_coord[bs]; }//nodeboxside coordinates (real size) - int cage_coord(OrthoDir bs) const { return m_ccoord[bs]; }//nodecageside coordinates (expanded size) - int cageCoord(OrthoDir bs) const { return m_ccoord[bs]; }//nodecageside coordinates (expanded size) - - //return distance between Node and Cage coord - int coordDistance(OrthoDir bs) - { - int result; - switch (bs) - { - case odSouth: - case odEast: - result = m_ccoord[bs] - m_coord[bs]; - break; - case odNorth: - case odWest: - result = m_coord[bs] - m_ccoord[bs]; - break; - default: cout<<"unknown direction in coordDistance"<= 0); - return result; - }//coordDistance - - //returns side coord respecting already flipped edges - int free_coord(OrthoDir s_main, OrthoDir s_to); - - int node_xsize() const { return box_x_size; }//original box sizes, fake - int node_ysize() const { return box_y_size; } - - int nodeSize(OrthoDir od) const { return ((od % 2 == 0) ? box_y_size : box_x_size); } - int cageSize(OrthoDir od) const { return ((od % 2 == 0) ? cage_y_size : cage_x_size); } - int rc(OrthoDir od) const { return m_rc[od]; } //routing channel size - - List& inList(OrthoDir bs) { return in_edges[bs]; } - List& inPoint(OrthoDir bs) { return point_in[bs]; } - - //these values are computed dependant on the nodes placement - int l_upper_unbend() { return lu; } //position of first and last unbend edge on every side - int l_lower_unbend() { return ll; } - int r_upper_unbend() { return ru; } - int r_lower_unbend() { return rl; } - int t_left_unbend() { return tl; } - int t_right_unbend() { return tr; } - int b_left_unbend() { return bl; } - int b_right_unbend() { return br; } - - //object separation distances - //if (no) generalization enters..., side/gener. dependant paper delta values - //distance at side mainside, left/right from existing generalization to side neighbour - int delta(OrthoDir mainside, OrthoDir neighbour) const { return m_delta[mainside][neighbour]; } - - //paper epsilon - int eps(OrthoDir mainside, OrthoDir neighbour) const { return m_eps[mainside][neighbour]; } - - //cardinality of the set of edges that will bend, bside side to the side bneighbour - int num_bend_edges(OrthoDir s1, OrthoDir sneighbour) { return m_nbe[s1][sneighbour]; } - int num_E_hook(OrthoDir s1, OrthoDir sneighbour) { return m_routable[s1][sneighbour]; } - //number of edges flipped from s1 to s2 to save one bend - int& flips(OrthoDir s1, OrthoDir s2) { return m_flips[s1][s2]; } - - int num_bend_free(OrthoDir s) const { return m_nbf[s]; } //number of edges routed bendfree - int& nbf(OrthoDir s) { return m_nbf[s]; } - - int num_edges(OrthoDir od) const { - return num_s_edges[od]; //return number of edges at side od - } - - //position of gen. edges in edge lists for every side, starting with 1 - int gen_pos(OrthoDir od) const { return m_gen_pos[od]; } - bool has_gen(OrthoDir od) { return m_gen_pos[od] > -1; } - - bool is_in_edge(OrthoDir od, int pos) { - ListConstIterator b_it = point_in[od].get(pos); - return *b_it; - } - - //set - void reclassify(OrthoDir) { }//set m_nbf, nb, m_routable based on bend_type values on s, - //erst mal nur zum vergleichen benutzen ist soll - void set_coord(OrthoDir bs, int co) { m_coord[bs] = co; } - void set_cage_coord(OrthoDir bs, int co) { m_ccoord[bs] = co; } - void setCageCoord(OrthoDir bs, int co) { m_ccoord[bs] = co; } - - //delta values, due to placement problems, cut to box_size / 2 - void set_delta(OrthoDir bside, OrthoDir bneighbour, int dval) { - switch (bside) - { - case odNorth: - case odSouth: - if (dval > box_y_size) { - dval = int(floor(((double)box_y_size / 2))) - m_eps[bside][bneighbour]; - } break; - case odEast: - case odWest: - if (dval > box_x_size) { - dval = int(floor(((double)box_x_size / 2))) - m_eps[bside][bneighbour]; - } break; - OGDF_NODEFAULT - }//switch - m_delta[bside][bneighbour] = dval; - } - - void set_eps(OrthoDir mainside, OrthoDir neighbour, int dval) { m_eps[mainside][neighbour] = dval; } - - //number of bending edges on one side at corner to second side - //void set_num_bend_edges(box_side bs1, box_side bs2, int num) {nbe[bs1][bs2] = num;} - //set position of generalization on each side - void set_gen_pos(OrthoDir od, int pos) { - m_gen_pos[od] = pos; //odir: N 0, E 1 - } - void set_num_edges(OrthoDir od, int num) { - num_s_edges[od] = num; //odir: N 0, E 1, check correct od parameter? - } - - - //computes the size of the cage face and the node box - void compute_cage_size() { - cage_x_size = m_ccoord[odSouth]-m_ccoord[odNorth]; - cage_y_size = m_ccoord[odEast] - m_ccoord[odWest]; - } - // int compute_rc(box_side b) {cout<<"rc not yet implemented\n";exit(1);} - - //set the unbend edges after (in) placement step - void set_l_upper(int d) { lu = d; } - void set_l_lower(int d) { ll = d; } - void set_r_upper(int d) { ru = d; } - void set_r_lower(int d) { rl = d; } - void set_t_left(int d) { tl = d; } - void set_t_right(int d) { tr = d; } - void set_b_left(int d) { bl = d; } - void set_b_right(int d) { br = d; } - - //paper set E_s1_s2 - void inc_E_hook(OrthoDir s_from, OrthoDir s_to, int num = 1) { - m_routable[s_from][s_to] += num; m_nbe[s_from][s_to] += num; - } - void inc_E(OrthoDir s_from, OrthoDir s_to, int num = 1) { - m_nbe[s_from][s_to] += num; - } - - //read the information for node v from attributed graph/planrep - //(needs positions ...) - void get_data( - OrthoRep& O, - GridLayout& L, - node v, - RoutingChannel& rc, - NodeArray& nw, - NodeArray& nh); //check input parameter - void get_OR_data(node v, OrthoRep& O); - // - int num_routable(OrthoDir s_from, OrthoDir s_to) const { return m_routable[s_from][s_to]; } //card. of paper E^_s1,s2 - int& numr(OrthoDir s_from, OrthoDir s_to) { return m_routable[s_from][s_to]; } - int vDegree() { return m_vdegree; } - adjEntry& firstAdj() { return m_firstAdj; } - - friend ostream& operator<<(ostream& O, const NodeInfo& inf); - -private: - int m_rc[4]; - int m_coord[4]; //coordinates of box segments, x for ls_left/right, y for s_top/bottom - int m_ccoord[4]; //coordinates of expanded cage segments, -"- - int cage_x_size, cage_y_size, //cage size - box_x_size, box_y_size; //box size - int lu,ll,ru,rl,tl,tr,bl,br; //first/last unbend edge on all sides - //most of the following are only [4][2] but use 44 for users conv - int m_delta[4][4]; //sepa. distance (paper delta) - int m_eps[4][4]; //corner separation distance (paper epsilon) - int m_gen_pos[4]; //pos num of generaliz. edge in adj lists - int num_s_edges[4]; //number of edges at sides 0..3=N..W - int m_routable[4][4]; //number of reroutable edges, paper E^_s1,s2, got to be initialized after box placement - int m_flips[4][4]; //real number of flipped edges - int m_nbe[4][4]; //paper E_s1,s2 - int m_nbf[4]; //number of bendfree edges per side - adjEntry m_firstAdj; //adjEntry of first encountered outgoing edge, note: this is a copy - - List in_edges[4]; //inedges on each side will be replaced by dynamic ops - //preliminary bugfix of in/out dilemma - List point_in[4]; //save in/out info - adjEntry m_adj; //entry of inner cage face - //degree of expanded vertex - int m_vdegree; -}; - - -ostream& operator<<(ostream& O, const NodeInfo& inf); - -} //end namespace - -#endif diff --git a/ext/OGDF/ogdf/internal/orthogonal/RoutingChannel.h b/ext/OGDF/ogdf/internal/orthogonal/RoutingChannel.h deleted file mode 100644 index bbec1be0b..000000000 --- a/ext/OGDF/ogdf/internal/orthogonal/RoutingChannel.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class RoutingChannel which maintains - * required size of routing channels and separation, cOverhang. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_ROUTING_CHANNEL_H -#define OGDF_ROUTING_CHANNEL_H - - -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// RoutingChannel -// maintains input sizes for constructive compaction (size -// of routing channels, separation, cOverhang) -//--------------------------------------------------------- -template -class RoutingChannel -{ -public: - // constructor - RoutingChannel(const Graph &G, ATYPE sep, double cOver) : - m_channel(G), m_separation(sep), m_cOverhang(cOver) { } - - // size of routing channel of side dir of node v - const ATYPE &operator()(node v, OrthoDir dir) const { - return m_channel[v].rc[dir]; - } - - ATYPE &operator()(node v, OrthoDir dir) { - return m_channel[v].rc[dir]; - } - - // returns separation (minimum distance between vertices/edges) - ATYPE separation() const { - return m_separation; - } - - // returns cOverhang (such that overhang = separation * cOverhang) - double cOverhang() const { - return m_cOverhang; - } - - // returns overhang (distance between vertex corners and edges) - ATYPE overhang() const { - return ATYPE(m_cOverhang * m_separation); - } - - void computeRoutingChannels(const OrthoRep &OR, bool align = false) - { - const Graph &G = OR; - - node v; - forall_nodes(v,G) - { - const OrthoRep::VertexInfoUML *pInfo = OR.cageInfo(v); - - if (pInfo) { - const OrthoRep::SideInfoUML &sNorth = pInfo->m_side[odNorth]; - const OrthoRep::SideInfoUML &sSouth = pInfo->m_side[odSouth]; - const OrthoRep::SideInfoUML &sWest = pInfo->m_side[odWest]; - const OrthoRep::SideInfoUML &sEast = pInfo->m_side[odEast]; - - (*this)(v,odNorth) = computeRoutingChannel(sNorth,sSouth,align); - (*this)(v,odSouth) = computeRoutingChannel(sSouth,sNorth,align); - (*this)(v,odWest ) = computeRoutingChannel(sWest ,sEast ,align); - (*this)(v,odEast ) = computeRoutingChannel(sEast ,sWest ,align); - } - } - } - -private: - // computes required size of routing channel at side si with opposite side siOpp - int computeRoutingChannel( - const OrthoRep::SideInfoUML &si, - const OrthoRep::SideInfoUML &siOpp, - bool align = false) - { - if (si.m_adjGen == 0) - { - int k = si.m_nAttached[0]; - if (k == 0 || - ((k == 1 && siOpp.totalAttached() == 0) && !align) ) - return 0; - else - return (k+1)*m_separation; - - } else { - int m = max(si.m_nAttached[0],si.m_nAttached[1]); - if (m == 0) - return 0; - else - return (m+1)*m_separation; - } - } - - struct vInfo { - ATYPE rc[4]; - vInfo() { - rc[0] = rc[1] = rc[2] = rc[3]; - } - }; - - NodeArray m_channel; - ATYPE m_separation; - double m_cOverhang; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldInit.h b/ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldInit.h deleted file mode 100644 index 658ccf57d..000000000 --- a/ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldInit.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the classes BoyerMyrvoldInit and BucketLowPoint - * - * \author Jens Schmidt - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BOYER_MYRVOLD_INIT_H -#define OGDF_BOYER_MYRVOLD_INIT_H - - -#include -#include - - -namespace ogdf { - -//! This class is used in the Boyer-Myrvold planarity test for preprocessing purposes. -/** -* Among these is the computation of lowpoints, highestSubtreeDFIs, -* separatedDFSChildList and of course building the DFS-tree. -*/ -class BoyerMyrvoldInit { - public: - //! Constructor, the parameter BoyerMyrvoldPlanar is needed - BoyerMyrvoldInit(BoyerMyrvoldPlanar* pBM); - - //! Destructor - ~BoyerMyrvoldInit() { } - - //! Creates the DFSTree - void computeDFS(); - - //! Computes lowpoint, highestSubtreeDFI and links virtual to nonvirtual vertices - void computeLowPoints(); - - //! Computes the list of separated DFS children for all nodes - void computeDFSChildLists(); - - // avoid automatic creation of assignment operator - //! Assignment operator is undefined! - BoyerMyrvoldInit &operator=(const BoyerMyrvoldInit &); - - private: - //! The input graph - Graph& m_g; - - //! Some parameters... see BoyerMyrvold.h for further instructions - const int& m_embeddingGrade; - const bool& m_randomDFSTree; - - //! Link to non-virtual vertex of a virtual Vertex. - /** A virtual vertex has negative DFI of the DFS-Child of related non-virtual Vertex - */ - NodeArray& m_realVertex; - - //! The one and only DFI-Array - NodeArray& m_dfi; - - //! Returns appropriate node from given DFI - Array& m_nodeFromDFI; - - //! Links to opposite adjacency entries on external face in clockwise resp. ccw order - /** m_link[0]=CCW, m_link[1]=CW - */ - NodeArray (&m_link)[2]; - - //! The adjEntry which goes from DFS-parent to current vertex - NodeArray& m_adjParent; - - //! The DFI of the least ancestor node over all backedges - /** If no backedge exists, the least ancestor is the DFI of that node itself - */ - NodeArray& m_leastAncestor; - - //! Contains the type of each \a edge - /** @param 0 = EDGE_UNDEFINED - * @param 1 = EDGE_SELFLOOP - * @param 2 = EDGE_BACK - * @param 3 = EDGE_DFS - * @param 4 = EDGE_DFS_PARALLEL - * @param 5 = EDGE_BACK_DELETED - */ - EdgeArray& m_edgeType; - - //! The lowpoint of each \a node - NodeArray& m_lowPoint; - - //! The highest DFI in a subtree with \a node as root - NodeArray& m_highestSubtreeDFI; - - //! A list to all separated DFS-children of \a node - /** The list is sorted by lowpoint values (in linear time) - */ - NodeArray >& m_separatedDFSChildList; - - //! Pointer to \a node contained in the DFSChildList of his parent, if exists. - /** If node isn't in list or list doesn't exist, the pointer is set to NULL. - */ - NodeArray >& m_pNodeInParent; - - //! Creates and links a virtual vertex of the node belonging to \a father - void createVirtualVertex(const adjEntry father); -}; - -//! BucketFunction for lowPoint buckets -/** Parameter lowPoint may not be deleted til destruction of this class. -*/ -class BucketLowPoint : public BucketFunc { - public: - BucketLowPoint(const NodeArray& lowPoint) :m_pLow(&lowPoint) { } - - //! This function has to be derived from BucketFunc, it gets the buckets from lowPoint-Array - int getBucket(const node& v) { - return (*m_pLow)[v]; - } - private: - //! Stored to be able to get the buckets - const NodeArray* m_pLow; -}; - -} - - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldPlanar.h b/ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldPlanar.h deleted file mode 100644 index 6ae1c4071..000000000 --- a/ext/OGDF/ogdf/internal/planarity/BoyerMyrvoldPlanar.h +++ /dev/null @@ -1,470 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class BoyerMyrvoldPlanar - * - * \author Jens Schmidt - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BOYER_MYRVOLD_PLANAR_H -#define OGDF_BOYER_MYRVOLD_PLANAR_H - -#include -#include -#include -#include -#include - - -namespace ogdf { - -//! Directions for clockwise and counterclockwise traversal -enum enumDirection { - CCW=0, - CW=1 -}; - -//! Type of edge -/** @param 0 undefined - * @param 1 selfloop - * @param 2 backedge - * @param 3 DFS-edge - * @param 4 parallel DFS-edge - * @param 5 deleted backedge - */ -enum enumEdgeType { - EDGE_UNDEFINED=0, - EDGE_SELFLOOP=1, - EDGE_BACK=2, - EDGE_DFS=3, - EDGE_DFS_PARALLEL=4, - EDGE_BACK_DELETED=5 -}; - -class KuratowskiStructure; -class FindKuratowskis; - -//! This class implements the extended BoyerMyrvold planarity embedding algorithm -class BoyerMyrvoldPlanar -{ - friend class BoyerMyrvold; - friend class BoyerMyrvoldInit; - friend class FindKuratowskis; - friend class ExtractKuratowskis; - -public: - //! Constructor, for parameters see BoyerMyrvold - BoyerMyrvoldPlanar( - Graph& g, - bool bundles, - int m_embeddingGrade, - bool limitStructures, - SListPure& output, - bool randomDFSTree, - bool avoidE2Minors); - - //! Destructor - ~BoyerMyrvoldPlanar() { } - - //! Starts the embedding algorithm - bool start(); - - //! Denotes the different embedding options - enum enumEmbeddingGrade { - doNotEmbed=-3, // and not find any kuratowski subdivisions - doNotFind=-2, // but embed - doFindUnlimited=-1, // and embed - doFindZero=0 // and embed - }; - - //! Flips all nodes of the bicomp with unique, real, rootchild c as necessary - /** @param c is the unique rootchild of the bicomp - * @param marker is the value which marks nodes as visited - * @param visited is the array containing visiting information - * @param wholeGraph Iff true, all bicomps of all connected components will be traversed - * @param deleteFlipFlags Iff true, the flipping flags will be deleted after flipping - */ - void flipBicomp( - int c, - int marker, - NodeArray& visited, - bool wholeGraph, - bool deleteFlipFlags); - - // avoid automatic creation of assignment operator - //! Assignment operator is undefined! - BoyerMyrvoldPlanar &operator=(const BoyerMyrvoldPlanar &); - -protected: - /***** Methods for Walkup and Walkdown ******/ - - //! Checks whether node \a w is pertinent. \a w has to be non-virtual. - inline bool pertinent(node w) { - OGDF_ASSERT(w!=NULL); - if (m_dfi[w] <= 0) return false; - return (!m_backedgeFlags[w].empty() || !m_pertinentRoots[w].empty()); - } - - //! Checks whether real node \a w is internally active while embedding node with DFI \a v - inline bool internallyActive(node w, int v) { - OGDF_ASSERT(w!=NULL); - if (m_dfi[w] <= 0) return false; - return (pertinent(w) && !externallyActive(w,v)); - } - - //! Checks whether real node \a w is externally active while embedding node with DFI \a v - inline bool externallyActive(node w, int v) { - OGDF_ASSERT(w!=NULL); - if (m_dfi[w] <= 0) return false; - if (m_leastAncestor[w] < v) return true; - if (m_separatedDFSChildList[w].empty()) return false; - return (m_lowPoint[m_separatedDFSChildList[w].front()] < v); - } - - //! Checks whether real node \a w is inactive while embedding node with DFI \a v - inline bool inactive(node w, int v) { - OGDF_ASSERT(w!=NULL); - if (m_dfi[w] <= 0) return true; - if (!m_backedgeFlags[w].empty() || !m_pertinentRoots[w].empty() - || m_leastAncestor[w] < v) return false; - if (m_separatedDFSChildList[w].empty()) return true; - return (m_lowPoint[m_separatedDFSChildList[w].front()] >= v); - } - - //! Checks all dynamic information about a node \a w while embedding node with DFI \a v - /** - * @return This method returns the following values: - * - 0 = inactive - * - 1 = internallyActive - * - 2 = pertinent and externallyActive - * - 3 = externallyActive and not pertinent - */ - inline int infoAboutNode(node w, int v) { - OGDF_ASSERT(w!=NULL); - if (m_dfi[w] <= 0) return 0; - if (!m_pertinentRoots[w].empty() || !m_backedgeFlags[w].empty()) { - // pertinent - if (m_leastAncestor[w] < v) return 2; - if (m_separatedDFSChildList[w].empty()) return 1; - return (m_lowPoint[m_separatedDFSChildList[w].front()] < v - ? 2 : 1); - } else { - // not pertinent - if (m_leastAncestor[w] < v) return 3; - if (m_separatedDFSChildList[w].empty()) return 0; - return (m_lowPoint[m_separatedDFSChildList[w].front()] < v - ? 3 : 0); - } - } - - //! Walks upon external face in the given \a direction starting at \a w - /** If none of the bicomps has been flipped then CW = clockwise and - * CCW = counterclockwise holds. In general, the traversaldirection could have - * been changed due to flipped components. If this occurs, the - * traversaldirection is flipped. - */ - inline node successorOnExternalFace(node w, int& direction) { - OGDF_ASSERT(w!=NULL); - OGDF_ASSERT(w->degree()>0); - OGDF_ASSERT(m_link[CW][w]!=NULL && m_link[CCW][w]!=NULL); - adjEntry adj = m_link[direction][w]; - OGDF_ASSERT(adj->theNode()!=NULL); - - if (w->degree() > 1) direction = - adj==beforeShortCircuitEdge(adj->theNode(),CCW)->twin(); - OGDF_ASSERT(direction || adj==beforeShortCircuitEdge(adj->theNode(),CW)->twin()); - return adj->theNode(); - } - - //! Walks upon external face in given \a direction avoiding short circuit edges - inline node successorWithoutShortCircuit(node w, int& direction) { - OGDF_ASSERT(w!=NULL); - OGDF_ASSERT(w->degree()>0); - OGDF_ASSERT(m_link[CW][w]!=NULL && m_link[CCW][w]!=NULL); - adjEntry adj = beforeShortCircuitEdge(w,direction); - OGDF_ASSERT(adj->theNode()!=NULL); - - if (w->degree() > 1) direction = - adj==beforeShortCircuitEdge(adj->theNode(),CCW)->twin(); - OGDF_ASSERT(direction || adj==beforeShortCircuitEdge(adj->theNode(),CW)->twin()); - return adj->theNode(); - } - - //! Returns the successornode on the external face in given \a direction - /** \a direction is not changed. - */ - inline node constSuccessorOnExternalFace(node v, int direction) { - OGDF_ASSERT(v!=NULL); - OGDF_ASSERT(v->degree()>0); - return m_link[direction][v]->theNode(); - } - - //! Walks upon external face in \a direction avoiding short circuit edges - /** \a direction is not changed. - */ - inline node constSuccessorWithoutShortCircuit(node v, int direction) { - OGDF_ASSERT(v!=NULL); - OGDF_ASSERT(v->degree()>0); - return beforeShortCircuitEdge(v,direction)->theNode(); - } - - //! Returns underlying former adjEntry, if a short circuit edge in \a direction of \a v exists - /** Otherwise the common edge is returned. In every case the returned adjEntry - * points to the targetnode. - */ - inline adjEntry beforeShortCircuitEdge(node v, int direction) { - OGDF_ASSERT(v!=NULL); - return (m_beforeSCE[direction][v]==NULL) ? m_link[direction][v] : m_beforeSCE[direction][v]; - } - - //! Walks upon external face in the given \a direction starting at \a w until an active vertex is reached - /** Returns dynamical typeinformation \a info of that endvertex. - */ - node activeSuccessor(node w, int& direction, int v, int& info); - - //! Walks upon external face in the given \a direction (without changing it) until an active vertex is reached - /** Returns dynamical typeinformation \a info of that endvertex. But does not change the \a direction. - */ - inline node constActiveSuccessor(node w, int direction, int v, int& info) { - return activeSuccessor(w,direction,v,info); - } - - //! Checks, if one ore more wNodes exist between the two stopping vertices \a stopx and \a stopy - /** The node \a root is root of the bicomp containing the stopping vertices - */ - inline bool wNodesExist(node root, node stopx, node stopy) { - OGDF_ASSERT(root != stopx && root != stopy && stopx != stopy); - int dir = CCW; - bool between = false; - while (root != NULL) { - root = successorOnExternalFace(root,dir); - if (between && pertinent(root)) { - return true; - } - if (root == stopx || root == stopy) { - if (between) { - return false; - } - between = true; - } - } - return false; - } - - //! Prints informations about node \a v - inline void printNodeInfo(node v) { - cout << "\nprintNodeInfo(" << m_dfi[v] << "): "; - cout << "CCW=" << m_dfi[constSuccessorOnExternalFace(v,CCW)]; - cout << ",CW=" << m_dfi[constSuccessorOnExternalFace(v,CW)]; - cout << "\tCCWBefore=" << m_dfi[constSuccessorWithoutShortCircuit(v,CCW)]; - cout << ",CWBefore=" << m_dfi[constSuccessorWithoutShortCircuit(v,CW)]; - cout << "\tadjList: "; - adjEntry adj; - for (adj = v->firstAdj(); adj; adj = adj->succ()) { - cout << adj->twinNode() << " "; - } - } - - //! Merges the last two biconnected components saved in \a stack while embedding them - /** \a j is the outgoing traversal direction of the current node to embed - */ - void mergeBiconnectedComponent(StackPure& stack, const int j); - - //! Merges the last two biconnected components saved in \a stack without embedding them - /** \a j is the outgoing traversal direction of the current node to embed - */ - void mergeBiconnectedComponentOnlyPlanar(StackPure& stack, const int j); - - //! Embeds backedges from node \a v with direction \a v_dir to node \a w with direction \a w_dir - /** \a i is the DFI of current embedded node. - */ - void embedBackedges(const node v, const int v_dir, - const node w, const int w_dir, const int i); - - //! Links (not embed) backedges from node \a v with direction \a v_dir to node \a w with direction \a w_dir - /** \a i is the DFI of current embedded node. - */ - void embedBackedgesOnlyPlanar(const node v, const int v_dir, - const node w, const int w_dir, const int i); - - //! Creates a short circuit edge from node \a v with direction \a v_dir to node \a w with direction \a w_dir - void createShortCircuitEdge(const node v, const int v_dir, - const node w, const int w_dir); - - //! Walkup: Builds the pertinent subgraph for the backedge \a back. - /** \a back is the backedge between nodes \a v and \a w. \a v is the current node to embed. - * All visited nodes are marked with value \a marker. The Function returns the last traversed node. - */ - node walkup(const node v, const node w, const int marker, const edge back); - - //! Walkdown: Embeds all backedges with DFI \a i as targetnode to node \a v - /** - * @param i is the DFI of the current vertex to embed - * @param v is the virtual node being the root of the bicomp attached to \a i - * @param findKuratowskis collects information in order to extract Kuratowski Subdivisions later - * @return 1, iff the embedding process found a stopping configuration - */ - int walkdown(const int i, const node v, FindKuratowskis* findKuratowskis); - - //! Merges unprocessed virtual nodes such as the dfs-roots with their real counterpart - void mergeUnprocessedNodes(); - - //! Postprocessing of the graph, so that all virtual vertices are embedded and all bicomps are flipped - /** In addition, embedding steps for parallel edges and self-loops are implemented. - */ - void postProcessEmbedding(); - - //! Starts the embedding phase, which embeds \a m_g node by node in descending DFI-order. - /** Returns true, if graph is planar, false otherwise. - */ - bool embed(); - - - /***** Members ******/ - //! Input graph, which can be altered - Graph& m_g; - - //! Some parameters... see BoyerMyrvold for further options - const bool m_bundles; - const int m_embeddingGrade; - const bool m_limitStructures; - const bool m_randomDFSTree; - const bool m_avoidE2Minors; - - //! The whole number of bicomps, which have to be flipped - int m_flippedNodes; - - /***** Members from Boyer Myrvold-Init ******/ - //! Link to non-virtual vertex of a virtual Vertex. - /** A virtual vertex has negative DFI of the DFS-Child of related non-virtual Vertex - */ - NodeArray m_realVertex; - - //! The one and only DFI-NodeArray - NodeArray m_dfi; - - //! Returns appropriate node from given DFI - Array m_nodeFromDFI; - - //! Links to opposite adjacency entries on external face in clockwise resp. ccw order - /** m_link[0]=CCW, m_link[1]=CW - */ - NodeArray m_link[2]; - - //! Links for short circuit edges. - /** If short circuit edges are introduced, the former adjEntries to the neighbors - * have to be saved here for embedding and merging purposes. If there is no - * short circuit edge, this adjEntry is NULL. - */ - NodeArray m_beforeSCE[2]; - - //! The adjEntry which goes from DFS-parent to current vertex - NodeArray m_adjParent; - - //! The DFI of the least ancestor node over all backedges - /** If no backedge exists, the least ancestor is the DFI of that node itself - */ - NodeArray m_leastAncestor; - - //! Contains the type of each \a edge - /** @param 0 = EDGE_UNDEFINED - * @param 1 = EDGE_SELFLOOP - * @param 2 = EDGE_BACK - * @param 3 = EDGE_DFS - * @param 4 = EDGE_DFS_PARALLEL - * @param 5 = EDGE_BACK_DELETED - */ - EdgeArray m_edgeType; - - //! The lowpoint of each \a node - NodeArray m_lowPoint; - - //! The highest DFI in a subtree with \a node as root - NodeArray m_highestSubtreeDFI; - - //! A list to all separated DFS-children of \a node - /** The list is sorted by lowpoint values (in linear time) - */ - NodeArray > m_separatedDFSChildList; - - //! Pointer to \a node contained in the DFSChildList of his parent, if exists. - /** If node isn't in list or list doesn't exist, the pointer is set to NULL. - */ - NodeArray > m_pNodeInParent; - - /***** Members for Walkup and Walkdown ******/ - //! This Array keeps track of all vertices that are visited by current walkup - NodeArray m_visited; - - //! Identifies the rootnode of the child bicomp the given backedge points to - EdgeArray m_pointsToRoot; - - //! Keeps track of all vertices that are visited by the walkup through a specific backedge - /** This is done in order to refer to the unique child-bicomp of v. - */ - NodeArray m_visitedWithBackedge; - - //! Iff true, the node is the root of a bicomp which has to be flipped. - /** The DFS-child of every bicomp root vertex is unique. if a bicomp - * is flipped, this DFS-child is marked to check whether the bicomp - * has to be flipped or not. - */ - NodeArray m_flipped; - - //! Holds information, if node is the source of a backedge. - /** This information refers to the adjEntries on the targetnode - * and is used during the walkdown - */ - NodeArray > m_backedgeFlags; - - //! List of virtual bicomp roots, that are pertinent to the current embedded node - NodeArray > m_pertinentRoots; - - //! Data structure for the kuratowski subdivisions, which will be returned - SListPure& m_output; -}; - - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/ConnectedSubgraph.h b/ext/OGDF/ogdf/internal/planarity/ConnectedSubgraph.h deleted file mode 100644 index 23a714ea6..000000000 --- a/ext/OGDF/ogdf/internal/planarity/ConnectedSubgraph.h +++ /dev/null @@ -1,424 +0,0 @@ -/* - * $Revision: 2589 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 23:31:45 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes a connected subgraph G' of G containing node n. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CONNECTED_SUBGRAPH_h -#define OGDF_CONNECTED_SUBGRAPH_h - -#include -#include - -namespace ogdf { - -template -class ConnectedSubgraph -{ -public: - //constructor - ConnectedSubgraph() { } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nSG is assigned the corresponding node of nG in SG. - * \param nodeLengthG stores for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - node& nSG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG) - { - EdgeArray edgeLengthG(G, 1); - EdgeArray edgeLengthSG; - call(G, SG, nG, nSG, nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG); - } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nodeLengthG stores for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - * \param nG_to_nSG is assigned a mapping of nodes in G to nodes in SG. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - NodeArray& nG_to_nSG) - { - node nSG; - NodeArray nSG_to_nG; - EdgeArray eSG_to_eG; - EdgeArray eG_to_eSG; - EdgeArray edgeLengthG(G, 1); - EdgeArray edgeLengthSG; - call(G, SG, nG, nSG, nSG_to_nG, eSG_to_eG, nG_to_nSG, eG_to_eSG, - nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG); - } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nSG is assigned the corresponding node of nG in SG. - * \param nodeLengthG is saving for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - * \param edgeLengthG is saving for each edge of G its length. - * \param edgeLengthSG is assigned for each edge of SG its length. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - node& nSG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG) - { - NodeArray nSG_to_nG(SG); - EdgeArray eSG_to_eG(SG); - call(G, SG, nG, nSG, nSG_to_nG, eSG_to_eG, nodeLengthG, - nodeLengthSG, edgeLengthG, edgeLengthSG); - } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nodeLengthG stores for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG) - { - node nSG; - call(G, SG, nG, nSG, nodeLengthG, nodeLengthSG); - } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nodeLengthG stores for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - * \param edgeLengthG stores for each edge of G its length. - * \param edgeLengthSG is assigned for each edge of SG its length. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG) - { - node nSG = 0; - call(G, SG, nG, nSG, nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG); - } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nSG - * \param nSG_to_nG is mapping nodes in SG to nodes in G - * \param eSG_to_eG is mapping edges in SG to edges in G - * \param nodeLengthG is saving for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - * \param edgeLengthG stores for each edge of G its length. - * \param edgeLengthSG is assigned for each edge of SG its length. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - node& nSG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG) - { - NodeArray nG_to_nSG; - EdgeArray eG_to_eSG; - call(G, SG, nG, nSG, nSG_to_nG, eSG_to_eG, nG_to_nSG, eG_to_eSG, nodeLengthG, - nodeLengthSG, edgeLengthG, edgeLengthSG); - } - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nSG - * \param nSG_to_nG is mapping nodes in SG to nodes in G - * \param eSG_to_eG is mapping edges in SG to edges in G - * \param nG_to_nSG is mapping nodes in G to nodes in SG - * \param eG_to_eSG is mapping edges in G to edges in SG - * \param nodeLengthG stores for each node of G its length. - * \param nodeLengthSG is assigned for each node of SG its length. - * \param edgeLengthG stores for each edge of G its length. - * \param edgeLengthSG is assigned for each edge of SG its length. - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - node& nSG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - NodeArray& nG_to_nSG, - EdgeArray& eG_to_eSG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG); - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nSG_to_nG is mapping nodes in SG to nodes in G - * \param eSG_to_eG is mapping edges in SG to edges in G - * \param nG_to_nSG is mapping nodes in G to nodes in SG - * \param eG_to_eSG is mapping edges in G to edges in SG - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - NodeArray& nG_to_nSG, - EdgeArray& eG_to_eSG); - - /** - * \brief Computes a connected subgraph SG of G containing node nG. - * \param G is the original graph. - * \param SG is assigned the connected subgraph containing nG. - * \param nG is a node in G. - * \param nSG_to_nG is mapping nodes in SG to nodes in G - */ - static void call(const Graph& G, - Graph& SG, - const node& nG, - NodeArray& nSG_to_nG) - { - NodeArray nodeLengthG(G, 0); - NodeArray nodeLengthSG(SG); - EdgeArray edgeLengthG(G, 0); - EdgeArray edgeLengthSG(SG); - node nSG; - EdgeArray eSG_to_eG; - call(G, SG, nG, nSG, nSG_to_nG, eSG_to_eG, nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG); - } - -private: - /** - * \brief Copies to SG node nG and recursively all adjacent edges - * and nodes. - * - * \param SG is the connected subgraph. - * \param nodeVisited saves for all nodes in G, if they were already - * treated. - * \param edgeVisited saves for all edges in G, if they were already - * treated. - * \param nG is a node in G. - * \param nodeLengthG is saving for each node of G its length. - * \param nodeLengthSG is saving for each node of SG its length. - * \param edgeLengthG is saving for each edge of G its length. - * \param edgeLengthSG is saving for each edge of SG its length. - * \param nSG_to_nG is mapping nodes in SG to nodes in G - * \param eSG_to_eG is mapping edges in SG to edges in G - * \param nG_to_nSG is mapping nodes in G to nodes in SG - * \param eG_to_eSG is mapping edges in G to edges in SG - */ - static void recursion(Graph& SG, - bool* nodeVisited, - bool* edgeVisited, - const node& nG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - NodeArray& nG_to_nSG, - EdgeArray& eG_to_eSG); -}; - - -template -void ConnectedSubgraph::recursion(Graph& SG, - bool* nodeVisited, - bool* edgeVisited, - const node& nG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - NodeArray& nG_to_nSG, - EdgeArray& eG_to_eSG) -{ - node nSG = SG.newNode(); - nodeLengthSG[nSG] = nodeLengthG[nG]; - nG_to_nSG[nG] = nSG; - nSG_to_nG[nSG] = nG; - nodeVisited[nG->index()] = true; - - edge eG; - forall_adj_edges(eG, nG) - { - if (!nodeVisited[eG->source()->index()]) - recursion(SG, nodeVisited, edgeVisited, eG->source(), - nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG, - nSG_to_nG, eSG_to_eG, nG_to_nSG, eG_to_eSG); - else if (!nodeVisited[eG->target()->index()]) - recursion(SG, nodeVisited, edgeVisited, eG->target(), - nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG, - nSG_to_nG, eSG_to_eG, nG_to_nSG, eG_to_eSG); - if (!edgeVisited[eG->index()]) - { - edge eSG = SG.newEdge(nG_to_nSG[eG->source()], nG_to_nSG[eG->target()]); - edgeLengthSG[eSG] = edgeLengthG[eG]; - eG_to_eSG[eG] = eSG; - eSG_to_eG[eSG] = eG; - edgeVisited[eG->index()] = true; - } - } -} - - -template -void ConnectedSubgraph::call(const Graph& G, - Graph& SG, - const node& nG, - node& nSG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - NodeArray& nG_to_nSG, - EdgeArray& eG_to_eSG, - const NodeArray& nodeLengthG, - NodeArray& nodeLengthSG, - const EdgeArray& edgeLengthG, - EdgeArray& edgeLengthSG) -{ - SG.clear(); - bool* nodeVisited = new bool[G.numberOfNodes()]; - bool* edgeVisited = new bool[G.numberOfEdges()]; - for (int i = 0; i < G.numberOfNodes(); i++) - nodeVisited[i] = false; - for (int i = 0; i < G.numberOfEdges(); i++) - edgeVisited[i] = false; - nSG_to_nG.init(SG); - eSG_to_eG.init(SG); - nodeLengthSG.init(SG); - edgeLengthSG.init(SG); - nG_to_nSG.init(G); - eG_to_eSG.init(G); - - recursion(SG, nodeVisited, edgeVisited, nG, - nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG, - nSG_to_nG, eSG_to_eG, nG_to_nSG, eG_to_eSG); - nSG = nG_to_nSG[nG]; - - delete nodeVisited; - delete edgeVisited; -} - - -template -void ConnectedSubgraph::call(const Graph& G, - Graph& SG, - const node& nG, - NodeArray& nSG_to_nG, - EdgeArray& eSG_to_eG, - NodeArray& nG_to_nSG, - EdgeArray& eG_to_eSG) -{ - SG.clear(); - bool* nodeVisited = new bool[G.numberOfNodes()]; - bool* edgeVisited = new bool[G.numberOfEdges()]; - for (int i = 0; i < G.numberOfNodes(); i++) - nodeVisited[i] = false; - for (int i = 0; i < G.numberOfEdges(); i++) - edgeVisited[i] = false; - nSG_to_nG.init(SG); - eSG_to_eG.init(SG); - NodeArray nodeLengthG(G, 0); - NodeArray nodeLengthSG(SG); - EdgeArray edgeLengthG(G, 1); - EdgeArray edgeLengthSG(SG); - nG_to_nSG.init(G); - eG_to_eSG.init(G); - - recursion(SG, nodeVisited, edgeVisited, nG, - nodeLengthG, nodeLengthSG, edgeLengthG, edgeLengthSG, - nSG_to_nG, eSG_to_eG, nG_to_nSG, eG_to_eSG); - - delete nodeVisited; - delete edgeVisited; -} - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/EmbedIndicator.h b/ext/OGDF/ogdf/internal/planarity/EmbedIndicator.h deleted file mode 100644 index 10623d112..000000000 --- a/ext/OGDF/ogdf/internal/planarity/EmbedIndicator.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class EmbedIndicator. - * - * Implements the direction Indicator. Used by class EmbedPQTree. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - - -#ifndef OGDF_EMBED_INDICATOR_H -#define OGDF_EMBED_INDICATOR_H - - - -#include -#include -#include -#include - -namespace ogdf{ - - -class EmbedIndicator : public PQNode -{ -public: - - EmbedIndicator(int count, PQNodeKey* infoPtr) - : PQNode(count,infoPtr) { } - - virtual ~EmbedIndicator() { - delete getNodeInfo()->userStructInfo(); - delete getNodeInfo(); - } - - PQNodeType type() const { return leaf; } - - void type(PQNodeType) { } - - PQNodeStatus status() const { return PQNodeRoot::INDICATOR; } - - void status(PQNodeStatus) { } - - PQNodeMark mark() const { return UNMARKED; } - - void mark(PQNodeMark) { } - - PQLeafKey* getKey() const { return 0; } - - bool setKey(PQLeafKey* pointerToKey) { - return (pointerToKey == 0); - } - - PQInternalKey* getInternal() const { return 0; } - - bool setInternal(PQInternalKey* pointerToInternal) { - return (pointerToInternal == 0); - } -}; - - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/planarity/EmbedPQTree.h b/ext/OGDF/ogdf/internal/planarity/EmbedPQTree.h deleted file mode 100644 index 0968817a2..000000000 --- a/ext/OGDF/ogdf/internal/planarity/EmbedPQTree.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class EmbedPQTree. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - - -#ifndef OGDF_EMBED_PQTREE_H -#define OGDF_EMBED_PQTREE_H - -#include -#include -#include -#include -#include - -namespace ogdf { - -typedef PQBasicKey *PtrPQBasicKeyEIB; - -template<> -inline bool doDestruction(const PtrPQBasicKeyEIB*) { return false; } - - -typedef PlanarLeafKey *PtrPlanarLeafKeyI; - -template<> -inline bool doDestruction(const PtrPlanarLeafKeyI*) { return false; } - - -class EmbedPQTree: public PQTree -{ -public: - - EmbedPQTree() : PQTree() { } - - virtual ~EmbedPQTree() { } - - virtual void emptyAllPertinentNodes(); - - virtual void clientDefinedEmptyNode(PQNode* nodePtr); - - virtual int Initialize(SListPure*> &leafKeys); - - void ReplaceRoot( - SListPure*> &leafKeys, - SListPure &frontier, - SListPure &opposed, - SListPure &nonOpposed, - node v); - - virtual bool Reduction(SListPure*> &leafKeys); - - PQNode* scanSibLeft(PQNode *nodePtr) const { - return clientSibLeft(nodePtr); - } - - PQNode* scanSibRight(PQNode *nodePtr) const { - return clientSibRight(nodePtr); - } - - PQNode* scanLeftEndmost(PQNode *nodePtr) const { - return clientLeftEndmost(nodePtr); - } - - PQNode* scanRightEndmost(PQNode *nodePtr) const { - return clientRightEndmost(nodePtr); - } - - PQNode* scanNextSib( - PQNode *nodePtr, - PQNode *other) { - return clientNextSib(nodePtr,other); - } - - virtual void getFront( - PQNode* nodePtr, - SListPure*> &leafKeys); - -protected: - - virtual PQNode* - clientSibLeft(PQNode *nodePtr) const; - - virtual PQNode* - clientSibRight(PQNode *nodePtr) const; - - virtual PQNode* - clientLeftEndmost(PQNode *nodePtr) const; - - virtual PQNode* - clientRightEndmost(PQNode *nodePtr) const; - - virtual PQNode* - clientNextSib(PQNode *nodePtr, - PQNode *other) const; - virtual const char* - clientPrintStatus(PQNode *nodePtr); - - virtual void front( - PQNode* nodePtr, - SListPure*> &leafKeys); - -private: - - void ReplaceFullRoot( - SListPure*> &leafKeys, - SListPure*> &frontier, - node v, - bool addIndicator = false, - PQNode *opposite = 0); - - void ReplacePartialRoot( - SListPure*> &leafKeys, - SListPure*> &frontier, - node v); -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphs.h b/ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphs.h deleted file mode 100644 index e43c4d4cb..000000000 --- a/ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphs.h +++ /dev/null @@ -1,1906 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a biconnected graph with maximum - * external face. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MAX_FACE_BICONNECTED_GRAPHS_H -#define OGDF_EMBEDDER_MAX_FACE_BICONNECTED_GRAPHS_H - -#include -#include -#include - - -namespace ogdf { - -//! Computes an embedding of a biconnected graph with maximum external face. -/** - * See the paper "Graph Embedding with Minimum Depth and - * Maximum External Face" by C. Gutwenger and P. Mutzel (2004) for - * details. - */ -template -class EmbedderMaxFaceBiconnectedGraphs -{ -public: - //! Creates an embedder. - EmbedderMaxFaceBiconnectedGraphs() { } - - /** - * \brief Embeds \a G by computing and extending a maximum face in \a G - * containing \a n. - * \param G is the original graph. - * \param adjExternal is assigned an adjacency entry of the external face. - * \param nodeLength stores for each vertex in \a G its length. - * \param edgeLength stores for each edge in \a G its length. - * \param n is a vertex of the original graph. If n is given, a maximum face - * containing n is computed, otherwise any maximum face. - */ - static void embed( - Graph& G, - adjEntry& adjExternal, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - const node& n = 0); - - /** - * \brief Computes the component lengths of all virtual edges in spqrTree. - * \param G is the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of \a G. - * \param edgeLengthSkel is saving for each skeleton graph of the SPQR-tree - * all edge lengths. - */ - static void compute( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel); - - /** - * \brief Returns the size of a maximum external face in \a G containing the node \a n. - * \param G is the original graph. - * \param n is a node of the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \return The size of a maximum external face in \a G containing the node \a n. - */ - static T computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength); - - /** - * \brief Returns the size of a maximum external face in \a G containing - * the node \a n. - * - * \param G is the original graph. - * \param n is a node of the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of G. - * \return The size of a maximum external face in \a G containing the node \a n. - */ - static T computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree); - - /** - * \brief Returns the size of a maximum external face in \a G containing - * the node \a n. - * - * \param G is the original graph. - * \param n is a node of the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of G. - * \param edgeLengthSkel is saving for each skeleton graph the length - * of each edge. - * \return The size of a maximum external face in \a G containing the node \a n. - */ - static T computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - const NodeArray< EdgeArray >& edgeLengthSkel); - - /** - * \brief Returns the size of a maximum external face in \a G. - * \param G is the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \return The size of a maximum external face in \a G. - */ - static T computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength); - - /** - * \brief Returns the size of a maximum external face in \a G. - * The SPQR-tree is given. The computed component lengths are - * computed and returned. - * - * \param G is the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of G. - * \param edgeLengthSkel is saving for each skeleton graph the length - * of each edge. - * \return The size of a maximum external face in \a G. - */ - static T computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel); - -private: - /** - * \brief Bottom up traversal of SPQR-tree computing the component length of - * all non-reference edges. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static void bottomUpTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength); - - /** - * \brief Top down traversal of SPQR-tree computing the component length of - * all reference edges. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static void topDownTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength); - - /** - * \brief Computes the size of a maximum face in the skeleton graph of \a mu - * containing \a n. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param n is a node of the original graph \a G. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static T largestFaceContainingNode( - const StaticSPQRTree& spqrTree, - const node& mu, - const node& n, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength); - - /** - * \brief Computes the size of a maximum face in the skeleton graph of \a mu. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static T largestFaceInSkeleton( - const StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength); - - /* \brief ExpandEdge embeds all edges in the skeleton graph \a S into an - * existing embedding and calls recursively itself for all virtual edges - * in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjExternal is an adjacency entry in the external face. - * \param n is only set, if ExpandEdge is called for the first time, because - * then there is no virtual edge which has to be expanded, but the max face - * has to contain a certain node \a n. - */ - static void expandEdge( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal, - const node& n = 0); - - /* \brief Embeds all edges in the skeleton graph \a S of an S-node of the - * SPQR-tree into an existing embedding and calls recursively itself for - * all virtual edges in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjExternal is an adjacency entry in the external face. - */ - static void expandEdgeSNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal); - - /* \brief Embeds all edges in the skeleton graph \a S of an P-node of the - * SPQR-tree into an existing embedding and calls recursively itself for - * all virtual edges in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjExternal is an adjacency entry in the external face. - */ - static void expandEdgePNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal); - - /* \brief Embeds all edges in the skeleton graph \a S of an R-node of the - * SPQR-tree into an existing embedding and calls recursively itself for - * all virtual edges in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjExternal is an adjacency entry in the external face. - * \param n is only set, if ExpandEdge is called for the first time, because - * then there is no virtual edge which has to be expanded, but the max face - * has to contain a certain node \a n. - */ - static void expandEdgeRNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal, - const node& n); - - /* \brief Writes a given adjacency entry into the newOrder. If the edge - * belonging to ae is a virtual edge, it is expanded. - * - * \param ae is the adjacency entry which has to be expanded. - * \param before is the adjacency entry of the node in \a G, before - * which ae has to be inserted. - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjExternal is an adjacency entry in the external face. - */ - static void adjEntryForNode( - adjEntry& ae, - ListIterator& before, - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal); -}; - - -template -void EmbedderMaxFaceBiconnectedGraphs::embed( - Graph& G, - adjEntry& adjExternal, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - const node& n /* = 0*/) -{ - //Base cases (SPQR-Tree implementation would crash with these inputs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() <= 2) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //**************************************************************************** - //First step: calculate maximum face and edge lengths for virtual edges - //**************************************************************************** - StaticSPQRTree spqrTree(G); - NodeArray< EdgeArray > edgeLengthSkel; - compute(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); - - //**************************************************************************** - //Second step: Embed G - //**************************************************************************** - T biggestFace = -1; - node bigFaceMu; - if (n == 0) - { - node mu; - forall_nodes(mu, spqrTree.tree()) - { - //Expand all faces in skeleton(mu) and get size of the largest of them: - T sizeMu = largestFaceInSkeleton(spqrTree, mu, nodeLength, edgeLengthSkel); - if (sizeMu > biggestFace) - { - biggestFace = sizeMu; - bigFaceMu = mu; - } - } - } - else - { - edge nAdjEdge; - node* mus = new node[n->degree()]; - int i = 0; - forall_adj_edges(nAdjEdge, n) - { - mus[i] = spqrTree.skeletonOfReal(nAdjEdge).treeNode(); - bool alreadySeenMu = false; - for (int j = 0; j < i && !alreadySeenMu; j++) - { - if (mus[i] == mus[j]) - alreadySeenMu = true; - } - if (alreadySeenMu) - { - i++; - continue; - } - else - { - //Expand all faces in skeleton(mu) containing n and get size of - //the largest of them: - T sizeInMu = largestFaceContainingNode(spqrTree, mus[i], n, - nodeLength, edgeLengthSkel); - if (sizeInMu > biggestFace) - { - biggestFace = sizeInMu; - bigFaceMu = mus[i]; - } - - i++; - } - } - delete mus; - } - - bigFaceMu = spqrTree.rootTreeAt(bigFaceMu); - - NodeArray< List > newOrder(G); - NodeArray treeNodeTreated(spqrTree.tree(), false); - ListIterator it; - adjExternal = 0; - NodeArray< ListIterator > adjBeforeNodeArraySource(spqrTree.tree()); - NodeArray< ListIterator > adjBeforeNodeArrayTarget(spqrTree.tree()); - expandEdge(spqrTree, treeNodeTreated, bigFaceMu, 0, nodeLength, - edgeLengthSkel, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, adjExternal, n); - - node v; - forall_nodes(v, G) - G.sort(v, newOrder[v]); -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::adjEntryForNode( - adjEntry& ae, - ListIterator& before, - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal) -{ - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - if (S.isVirtual(ae->theEdge())) - { - edge twinE = S.twinEdge(ae->theEdge()); - node twinNT = S.twinTreeNode(ae->theEdge()); - //Skeleton& twinS = spqrTree.skeleton(twinNT); - - if (!treeNodeTreated[twinNT]) - { - node m_leftNode; - if (ae->theEdge()->source() == leftNode) - m_leftNode = twinE->source(); - else - m_leftNode = twinE->target(); - - if (ae->theEdge()->source() == ae->theNode()) - adjBeforeNodeArraySource[twinNT] = before; - else - adjBeforeNodeArrayTarget[twinNT] = before; - - //recursion call: - expandEdge(spqrTree, treeNodeTreated, twinNT, m_leftNode, - nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - } //if (!treeNodeTreated[twinNT]) - - if (ae->theEdge() == referenceEdge) - { - if (ae->theNode() == ae->theEdge()->source()) - { - ListIterator tmpBefore = adjBeforeNodeArraySource[mu]; - adjBeforeNodeArraySource[mu] = before; - before = tmpBefore; - } - else - { - ListIterator tmpBefore = adjBeforeNodeArrayTarget[mu]; - adjBeforeNodeArrayTarget[mu] = before; - before = tmpBefore; - } - } - else //!(ae->theEdge() == referenceEdge) - { - if (ae->theNode() == ae->theEdge()->source()) - before = adjBeforeNodeArraySource[twinNT]; - else - before = adjBeforeNodeArrayTarget[twinNT]; - } - } - else //!(S.isVirtual(ae->theEdge())) - { - node origNode = S.original(ae->theNode()); - edge origEdge = S.realEdge(ae->theEdge()); - if (origNode == origEdge->source()) - { - if (!before.valid()) - before = newOrder[origNode].pushBack(origEdge->adjSource()); - else - before = newOrder[origNode].insertBefore(origEdge->adjSource(), before); - } - else - { - if (!before.valid()) - before = newOrder[origNode].pushBack(origEdge->adjTarget()); - else - before = newOrder[origNode].insertBefore(origEdge->adjTarget(), before); - } - } //else //!(S.isVirtual(ae->theEdge())) -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::expandEdge( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal, - const node& n /*= 0*/) -{ - treeNodeTreated[mu] = true; - - switch(spqrTree.typeOf(mu)) - { - case SPQRTree::SNode: - expandEdgeSNode(spqrTree, treeNodeTreated, mu, leftNode, - nodeLength, edgeLength, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, adjExternal); - break; - case SPQRTree::PNode: - expandEdgePNode(spqrTree, treeNodeTreated, mu, leftNode, - nodeLength, edgeLength, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, adjExternal); - break; - case SPQRTree::RNode: - expandEdgeRNode(spqrTree, treeNodeTreated, mu, leftNode, - nodeLength, edgeLength, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, adjExternal, n); - break; - OGDF_NODEFAULT - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::expandEdgeSNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal) -{ - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - adjEntry startAdjEntry; - if (leftNode == 0) - { - edge e; - forall_edges(e, S.getGraph()) - { - if (!S.isVirtual(e)) - { - startAdjEntry = e->adjSource(); - break; - } - } - } - else if (leftNode->firstAdj()->theEdge() == referenceEdge) - startAdjEntry = leftNode->lastAdj(); - else - startAdjEntry = leftNode->firstAdj(); - - adjEntry ae = startAdjEntry; - if (adjExternal == 0) - { - edge orgEdge = S.realEdge(ae->theEdge()); - if (orgEdge->source() == S.original(ae->theNode())) - adjExternal = orgEdge->adjSource()->twin(); - else - adjExternal = orgEdge->adjTarget()->twin(); - } - - ListIterator before; - if (!(referenceEdge == 0) && leftNode == referenceEdge->source()) - before = adjBeforeNodeArraySource[mu]; - else if (!(referenceEdge == 0)) - before = adjBeforeNodeArrayTarget[mu]; - ListIterator beforeSource; - - bool firstStep = true; - while (firstStep || ae != startAdjEntry) - { - //first treat ae with ae->theNode() is left node, then treat its twin: - node m_leftNode = ae->theNode(); - - if (ae->theEdge() == referenceEdge) - { - if (ae->theNode() == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = before; - else - adjBeforeNodeArrayTarget[mu] = before; - } - else - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - - if (firstStep) - { - beforeSource = before; - firstStep = false; - } - - ae = ae->twin(); - before = 0; - if (ae->theEdge() == referenceEdge) - { - if (ae->theNode() == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = beforeSource; - else - adjBeforeNodeArrayTarget[mu] = beforeSource; - } - else - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - - //set new adjacency entry pair (ae and its twin): - if (ae->theNode()->firstAdj() == ae) - ae = ae->theNode()->lastAdj(); - else - ae = ae->theNode()->firstAdj(); - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::expandEdgePNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal) -{ - //Choose face defined by virtual edge and the longest edge different from it. - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - edge altReferenceEdge = 0; - - node m_leftNode = leftNode; - if (m_leftNode == 0) - { - List nodeList; - S.getGraph().allNodes(nodeList); - m_leftNode = *(nodeList.begin()); - } - node m_rightNode = m_leftNode->firstAdj()->twinNode(); - - edge e; - if (referenceEdge == 0) - { - forall_edges(e, S.getGraph()) - { - if (!S.isVirtual(e)) - { - altReferenceEdge = e; - edge orgEdge = S.realEdge(e); - if (orgEdge->source() == S.original(m_leftNode)) - adjExternal = orgEdge->adjSource(); - else - adjExternal = orgEdge->adjTarget(); - - break; - } - } - } - - edge longestEdge = 0; - forall_edges(e, S.getGraph()) - { - if (e == referenceEdge || e == altReferenceEdge) - continue; - if (longestEdge == 0 || edgeLength[mu][e] > edgeLength[mu][longestEdge]) - longestEdge = e; - } - - List rightEdgeOrder; - ListIterator beforeAltRefEdge; - - //begin with left node and longest edge: - for (int i = 0; i < 2; i++) - { - ListIterator before; - node n; - if (i == 0) - n = m_leftNode; - else - { - n = m_rightNode; - before = beforeAltRefEdge; - } - - if (!(referenceEdge == 0)) - { - if (n == referenceEdge->source()) - before = adjBeforeNodeArraySource[mu]; - else - before = adjBeforeNodeArrayTarget[mu]; - } - - List edgeList; - S.getGraph().allEdges(edgeList); - adjEntry ae; - - //if left node, longest edge at first: - if (i == 0) - { - if (longestEdge->source() == n) - ae = longestEdge->adjSource(); - else - ae = longestEdge->adjTarget(); - - if (!(referenceEdge == 0) && S.isVirtual(longestEdge)) - { - node nu = S.twinTreeNode(longestEdge); - if (longestEdge->source() == n) - { - if (referenceEdge->source() == n) - adjBeforeNodeArrayTarget[nu] = adjBeforeNodeArrayTarget[mu]; - else - adjBeforeNodeArrayTarget[nu] = adjBeforeNodeArraySource[mu]; - } - else - { - if (referenceEdge->source() == n) - adjBeforeNodeArraySource[nu] = adjBeforeNodeArrayTarget[mu]; - else - adjBeforeNodeArraySource[nu] = adjBeforeNodeArraySource[mu]; - } - } - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - } - - //all edges except reference edge and longest edge: - if (i == 0) - { - //all virtual edges - for (ListIterator it = edgeList.begin(); it.valid(); it++) - { - if (*it == referenceEdge || *it == longestEdge || *it == altReferenceEdge || !S.isVirtual(*it)) - continue; - - node nu = S.twinTreeNode(*it); - if (!(referenceEdge == 0) && (*it)->source() == n) - { - if (referenceEdge->source() == n) - adjBeforeNodeArrayTarget[nu] = adjBeforeNodeArrayTarget[mu]; - else - adjBeforeNodeArrayTarget[nu] = adjBeforeNodeArraySource[mu]; - } - else if (!(referenceEdge == 0)) - { - if (referenceEdge->source() == n) - adjBeforeNodeArraySource[nu] = adjBeforeNodeArrayTarget[mu]; - else - adjBeforeNodeArraySource[nu] = adjBeforeNodeArraySource[mu]; - } - - rightEdgeOrder.pushFront(*it); - - if ((*it)->source() == n) - ae = (*it)->adjSource(); - else - ae = (*it)->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - } - - //all real edges - for (ListIterator it = edgeList.begin(); it.valid(); it++) - { - if (*it == referenceEdge || *it == longestEdge || *it == altReferenceEdge || S.isVirtual(*it)) - continue; - - rightEdgeOrder.pushFront(*it); - - if ((*it)->source() == n) - ae = (*it)->adjSource(); - else - ae = (*it)->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - } - } - else - { - for (ListIterator it = rightEdgeOrder.begin(); it.valid(); it++) - { - if ((*it)->source() == n) - ae = (*it)->adjSource(); - else - ae = (*it)->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - } - } - - //if not left node, longest edge: - if (i == 1) - { - if (longestEdge->source() == n) - ae = longestEdge->adjSource(); - else - ae = longestEdge->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - } - - //(alternative) reference edge at last: - if (!(referenceEdge == 0)) - { - if (n == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = before; - else - adjBeforeNodeArrayTarget[mu] = before; - } - else - { - node newLeftNode; - if (i == 0) - newLeftNode = m_leftNode->firstAdj()->twinNode(); - else - newLeftNode = m_leftNode; - - if (altReferenceEdge->source() == n) - ae = altReferenceEdge->adjSource(); - else - ae = altReferenceEdge->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - newLeftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - - if (i == 0 && S.isVirtual(altReferenceEdge)) - { - node nu = S.twinTreeNode(altReferenceEdge); - if (altReferenceEdge->source() == n) - beforeAltRefEdge = adjBeforeNodeArrayTarget[nu]; - else - beforeAltRefEdge = adjBeforeNodeArraySource[nu]; - } - } - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::expandEdgeRNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - adjEntry& adjExternal, - const node& n /* = 0 */) -{ - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - - //compute biggest face containing the reference edge: - face maxFaceContEdge; - List maxFaceNodes; - planarEmbed(S.getGraph()); - CombinatorialEmbedding combinatorialEmbedding(S.getGraph()); - T bigFaceSize = -1; - adjEntry m_adjExternal = 0; - face f; - forall_faces(f, combinatorialEmbedding) - { - bool containsVirtualEdgeOrN = false; - adjEntry this_m_adjExternal = 0; - T sizeOfFace = 0; - List faceNodes; - adjEntry ae; - forall_face_adj(ae, f) - { - faceNodes.pushBack(ae->theNode()); - if ( (n == 0 && (ae->theEdge() == referenceEdge || referenceEdge == 0)) - || S.original(ae->theNode()) == n) - { - containsVirtualEdgeOrN = true; - if (!(referenceEdge == 0)) - this_m_adjExternal = ae; - } - - if (referenceEdge == 0 && !S.isVirtual(ae->theEdge())) - this_m_adjExternal = ae; - - sizeOfFace += edgeLength[mu][ae->theEdge()] - + nodeLength[S.original(ae->theNode())]; - } - - if (containsVirtualEdgeOrN && !(this_m_adjExternal == 0) && sizeOfFace > bigFaceSize) - { - maxFaceNodes = faceNodes; - bigFaceSize = sizeOfFace; - maxFaceContEdge = f; - m_adjExternal = this_m_adjExternal; - } - } - - if (adjExternal == 0) - { - edge orgEdge = S.realEdge(m_adjExternal->theEdge()); - if (orgEdge->source() == S.original(m_adjExternal->theNode())) - adjExternal = orgEdge->adjSource(); - else - adjExternal = orgEdge->adjTarget(); - } - - adjEntry adjMaxFace = maxFaceContEdge->firstAdj(); - - //if embedding is mirror symmetrical embedding of desired embedding, - //invert adjacency list of all nodes: - if (!(referenceEdge == 0)) - { - //successor of adjEntry of virtual edge in adjacency list of leftNode: - adjEntry succ_virtualEdge_leftNode; - if (leftNode == referenceEdge->source()) - succ_virtualEdge_leftNode = referenceEdge->adjSource()->succ(); - else - succ_virtualEdge_leftNode = referenceEdge->adjTarget()->succ(); - if (!succ_virtualEdge_leftNode) - succ_virtualEdge_leftNode = leftNode->firstAdj(); - - bool succVELNAEInExtFace = false; - adjEntry aeExtFace; - forall_face_adj(aeExtFace, maxFaceContEdge) - { - if (aeExtFace->theEdge() == succ_virtualEdge_leftNode->theEdge()) - { - succVELNAEInExtFace = true; - break; - } - } - - if (!succVELNAEInExtFace) - { - node v; - forall_nodes(v, S.getGraph()) - { - List newAdjOrder; - for (adjEntry ae = v->firstAdj(); ae; ae = ae->succ()) - newAdjOrder.pushFront(ae); - S.getGraph().sort(v, newAdjOrder); - } - adjMaxFace = adjMaxFace->twin(); - } - } - - NodeArray nodeTreated(S.getGraph(), false); - adjEntry start_ae; - if (!(referenceEdge == 0)) - { - start_ae = adjMaxFace; - do - { - if (start_ae->theEdge() == referenceEdge) - { - start_ae = start_ae->faceCycleSucc(); - break; - } - start_ae = start_ae->faceCycleSucc(); - } while(start_ae != adjMaxFace); - } - else - start_ae = adjMaxFace; - - //For every edge a buffer saving adjacency entries written in embedding step - //for nodes on the maximum face, needed in step for other nodes. - EdgeArray< List > buffer(S.getGraph()); - - bool firstStep = true; - bool after_start_ae = true; - for (adjEntry ae = start_ae; - firstStep || ae != start_ae; - after_start_ae = (!after_start_ae || !ae->succ()) ? false : true, - ae = after_start_ae ? ae->faceCycleSucc() - : (!ae->faceCycleSucc() ? adjMaxFace : ae->faceCycleSucc())) - { - firstStep = false; - //node nodeG = S.original(ae->theNode()); - nodeTreated[ae->theNode()] = true; - - //copy adjacency list of nodes into newOrder: - ListIterator before; - edge vE = (ae->theEdge() == referenceEdge) ? referenceEdge : ae->theEdge(); - node nu = (ae->theEdge() == referenceEdge) ? mu : S.twinTreeNode(ae->theEdge()); - if (S.isVirtual(vE)) - { - if (ae->theNode() == vE->source()) - before = adjBeforeNodeArraySource[nu]; - else - before = adjBeforeNodeArrayTarget[nu]; - } - - bool after_ae = true; - adjEntry m_start_ae; - if (ae->theEdge() == referenceEdge) - { - if (ae->succ()) - m_start_ae = ae->succ(); - else - m_start_ae = ae->theNode()->firstAdj(); - } - else - m_start_ae = ae; - - for (adjEntry aeN = m_start_ae; - after_ae || aeN != m_start_ae; - after_ae = (!after_ae || !aeN->succ()) ? false : true, - aeN = after_ae ? aeN->succ() : (!aeN->succ() ? ae->theNode()->firstAdj() : aeN->succ()) - ) - { - node m_leftNode = 0; - if (S.isVirtual(aeN->theEdge()) && aeN->theEdge() != referenceEdge) - { - //Compute left node of aeN->theNode(). First get adjacency entry in ext. face - //(if edge is in ext. face) and compare face cycle successor with successor - //in node adjacency list. If it is the same, it is the right node, otherwise - //the left. - adjEntry aeExtFace = 0; - bool succInExtFace = false; - bool aeNInExtFace = false; - adjEntry aeNSucc = (aeN->succ()) ? aeN->succ() : ae->theNode()->firstAdj(); - aeExtFace = adjMaxFace; - do - { - if (aeExtFace->theEdge() == aeNSucc->theEdge()) - { - succInExtFace = true; - if (aeNInExtFace) - break; - } - if (aeExtFace->theEdge() == aeN->theEdge()) - { - aeNInExtFace = true; - if (succInExtFace) - break; - } - aeExtFace = aeExtFace->faceCycleSucc(); - } while(aeExtFace != adjMaxFace); - if (aeNInExtFace && succInExtFace) - m_leftNode = aeN->twinNode(); - else - m_leftNode = aeN->theNode(); - - node twinTN = S.twinTreeNode(aeN->theEdge()); - if (!(referenceEdge == 0)) - { - if (aeN->theEdge()->source() == aeN->theNode()) - { - if (aeN->theEdge()->target() == referenceEdge->source()) - adjBeforeNodeArrayTarget[twinTN] = adjBeforeNodeArraySource[mu]; - else if (aeN->theEdge()->target() == referenceEdge->target()) - adjBeforeNodeArrayTarget[twinTN] = adjBeforeNodeArrayTarget[mu]; - } - else - { - if (aeN->theEdge()->source() == referenceEdge->source()) - adjBeforeNodeArraySource[twinTN] = adjBeforeNodeArraySource[mu]; - else if (aeN->theEdge()->source() == referenceEdge->target()) - adjBeforeNodeArraySource[twinTN] = adjBeforeNodeArrayTarget[mu]; - } - } - } - - adjEntryForNode(aeN, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - - //if the other node adjacent to the current treated edge is not in the - //max face, put written edges into an buffer and clear the adjacency - //list of that node. - if (maxFaceNodes.search(aeN->twinNode()) == -1) - { - node orig_aeN_twin_theNode = S.original(aeN->twinNode()); - buffer[aeN->theEdge()] = newOrder[orig_aeN_twin_theNode]; - newOrder[orig_aeN_twin_theNode].clear(); - } - } //for (adjEntry aeN = m_start_ae; [...] - } //for (adjEntry ae = start_ae; [...] - - //Simple copy of not treated node's adjacency lists (internal nodes). Setting - //of left node not necessary, because all nodes are not in external face. - node v; - forall_nodes(v, S.getGraph()) - { - if (nodeTreated[v]) - continue; - - node v_original = S.original(v); - nodeTreated[v] = true; - ListIterator before; - for (adjEntry ae = v->firstAdj(); ae; ae = ae->succ()) - { - if (buffer[ae->theEdge()].empty()) - { - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - ae->theNode(), nodeLength, edgeLength, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - adjExternal); - - if (!nodeTreated[ae->twinNode()]) - { - node orig_ae_twin_theNode = S.original(ae->twinNode()); - buffer[ae->theEdge()] = newOrder[orig_ae_twin_theNode]; - newOrder[orig_ae_twin_theNode].clear(); - } - } - else - { - buffer[ae->theEdge()].reverse(); - for (ListIterator it = buffer[ae->theEdge()].begin(); it.valid(); it++) - { - if (!before.valid()) - before = newOrder[v_original].pushFront(*it); - else - before = newOrder[v_original].insertBefore(*it, before); - } - } - } - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::compute( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - if (G.numberOfNodes() <= 1 || G.numberOfEdges() <= 2) - return; - - //set length for all real edges in skeletons to length of the original edge - //and initialize edge lengths for virtual edges with 0: - edgeLengthSkel.init(spqrTree.tree()); - node v; - forall_nodes(v, spqrTree.tree()) - { - edgeLengthSkel[v].init(spqrTree.skeleton(v).getGraph()); - edge e; - forall_edges(e, spqrTree.skeleton(v).getGraph()) - { - if (spqrTree.skeleton(v).isVirtual(e)) - edgeLengthSkel[v][e] = 0; - else - edgeLengthSkel[v][e] = edgeLength[spqrTree.skeleton(v).realEdge(e)]; - } - } - - //set component-length for all non-reference edges: - bottomUpTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); - //set component length for all reference edges: - topDownTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()]+ nodeLength[e->target()]; - } - if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + nodeLength[e1->target()]; - } - StaticSPQRTree spqrTree(G); - NodeArray< EdgeArray > edgeLengthSkel; - return computeSize(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()]+ nodeLength[e->target()]; - } - if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + nodeLength[e1->target()]; - } - - //set length for all real edges in skeletons to length of the original edge - //and initialize edge lengths for virtual edges with 0: - edgeLengthSkel.init(spqrTree.tree()); - node v; - forall_nodes(v, spqrTree.tree()) - { - edgeLengthSkel[v].init(spqrTree.skeleton(v).getGraph()); - edge e; - forall_edges(e, spqrTree.skeleton(v).getGraph()) - { - if (spqrTree.skeleton(v).isVirtual(e)) - edgeLengthSkel[v][e] = 0; - else - edgeLengthSkel[v][e] = edgeLength[spqrTree.skeleton(v).realEdge(e)]; - } - } - - //set component-length for all non-reference edges: - bottomUpTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); - //set component length for all reference edges: - topDownTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); - - T biggestFace = -1; - node mu; - forall_nodes(mu, spqrTree.tree()) - { - //Expand all faces in skeleton(mu) and get size of the largest of them: - T sizeMu = largestFaceInSkeleton(spqrTree, mu, nodeLength, edgeLengthSkel); - if (sizeMu > biggestFace) - biggestFace = sizeMu; - } - - return biggestFace; -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()] + nodeLength[e->target()]; - } - if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + nodeLength[e1->target()]; - } - StaticSPQRTree spqrTree(G); - NodeArray< EdgeArray > edgeLengthSkel; - compute(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); - return computeSize(G, n, nodeLength, edgeLength, spqrTree, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree) -{ - NodeArray< EdgeArray > edgeLengthSkel; - compute(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); - return computeSize(G, n, nodeLength, edgeLength, spqrTree, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - const NodeArray< EdgeArray >& edgeLengthSkel) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()] + nodeLength[e->target()]; - } - else if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + nodeLength[e1->target()]; - } - - edge nAdjEdges; - node* mus = new node[n->degree()]; - int i = 0; - T biggestFace = -1; - forall_adj_edges(nAdjEdges, n) - { - mus[i] = spqrTree.skeletonOfReal(nAdjEdges).treeNode(); - bool alreadySeenMu = false; - for (int j = 0; j < i && !alreadySeenMu; j++) - { - if (mus[i] == mus[j]) - alreadySeenMu = true; - } - if (alreadySeenMu) - { - i++; - continue; - } - else - { - //Expand all faces in skeleton(mu) containing n and get size of the largest of them: - T sizeInMu = largestFaceContainingNode(spqrTree, mus[i], n, nodeLength, edgeLengthSkel); - if (sizeInMu > biggestFace) - biggestFace = sizeInMu; - - i++; - } - } - delete mus; - - return biggestFace; -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::bottomUpTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength) -{ - //Recursion: - edge ed; - forall_adj_edges(ed, mu) - { - if (ed->source() == mu) - bottomUpTraversal(spqrTree, ed->target(), nodeLength, edgeLength); - } - - edge e; - forall_edges(e, spqrTree.skeleton(mu).getGraph()) - { - //do not treat real edges here and do not treat reference edges: - if (!spqrTree.skeleton(mu).isVirtual(e) || e == spqrTree.skeleton(mu).referenceEdge()) - continue; - - //pertinent node of e in the SPQR-tree: - node nu = spqrTree.skeleton(mu).twinTreeNode(e); - //reference edge of nu (virtual edge in nu associated with mu): - edge er = spqrTree.skeleton(nu).referenceEdge(); - //sum of the lengths of the two poles of mu: - node refEdgeSource = spqrTree.skeleton(nu).referenceEdge()->source(); - node origRefEdgeSource = spqrTree.skeleton(nu).original(refEdgeSource); - node refEdgeTarget = spqrTree.skeleton(nu).referenceEdge()->target(); - node origRefEdgeTarget = spqrTree.skeleton(nu).original(refEdgeTarget); - T ell = nodeLength[origRefEdgeSource] + nodeLength[origRefEdgeTarget]; - - if (spqrTree.typeOf(nu) == SPQRTree::SNode) - { - //size of a face in skeleton(nu) minus ell - T sizeOfFace = 0; - node nS; - forall_nodes(nS, spqrTree.skeleton(nu).getGraph()) - sizeOfFace += nodeLength[spqrTree.skeleton(nu).original(nS)]; - - edge eS; - forall_edges(eS, spqrTree.skeleton(nu).getGraph()) - sizeOfFace += edgeLength[nu][eS]; - - edgeLength[mu][e] = sizeOfFace - ell; - } - else if (spqrTree.typeOf(nu) == SPQRTree::PNode) - { - //length of the longest edge different from er in skeleton(nu) - edge longestEdge = 0; - forall_edges(ed, spqrTree.skeleton(nu).getGraph()) - { - if (!(ed == er) && ( longestEdge == 0 - || edgeLength[nu][ed] > edgeLength[nu][longestEdge])) - { - longestEdge = ed; - } - } - edgeLength[mu][e] = edgeLength[nu][longestEdge]; - } - else if (spqrTree.typeOf(nu) == SPQRTree::RNode) - { - //size of the largest face containing er in skeleton(nu) minus ell - //Calculate an embedding of the graph (it exists only two which are - //mirror-symmetrical): - planarEmbed(spqrTree.skeleton(nu).getGraph()); - CombinatorialEmbedding combinatorialEmbedding(spqrTree.skeleton(nu).getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - T sizeOfFace = 0; - bool containsEr = false; - adjEntry ae; - forall_face_adj(ae, f) - { - if (ae->theEdge() == er) - containsEr = true; - sizeOfFace += edgeLength[nu][ae->theEdge()] - + nodeLength[spqrTree.skeleton(nu).original(ae->theNode())]; - } - - if (containsEr && sizeOfFace > biggestFaceSize) - biggestFaceSize = sizeOfFace; - } - - edgeLength[mu][e] = biggestFaceSize - ell; - } - else //should never happen - edgeLength[mu][e] = 1; - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphs::topDownTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength) -{ - //S: skeleton of mu - Skeleton& S = spqrTree.skeleton(mu); - - //Get all reference edges of the children nu of mu and set their component length: - edge ed; - forall_adj_edges(ed, mu) - { - if (ed->source() != mu) - continue; - - node nu = ed->target(); - edge referenceEdgeOfNu = spqrTree.skeleton(nu).referenceEdge(); - edge eSnu = spqrTree.skeleton(nu).twinEdge(referenceEdgeOfNu); - if (spqrTree.typeOf(mu) == SPQRTree::SNode) - { - //Let L be the sum of the length of all vertices and edges in S. The component - //length of the reference edge of nu is L minus the length of e_{S, nu} minus - //the lengths of the two vertices incident to e_{S, nu}. - T L = 0; - edge ed2; - forall_edges(ed2, S.getGraph()) - L += edgeLength[mu][ed2]; - node no; - forall_nodes(no, S.getGraph()) - L += nodeLength[S.original(no)]; - - edgeLength[nu][referenceEdgeOfNu] = - L - edgeLength[mu][eSnu] - nodeLength[S.original(eSnu->source())] - nodeLength[S.original(eSnu->target())]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::PNode) - { - //The component length of the reference edge of nu is the length of the longest - //edge in S different from e_{S, nu}. - edge ed2; - edge longestEdge = 0; - forall_edges(ed2, S.getGraph()) - { - if (ed2 != eSnu && ( longestEdge == 0 || edgeLength[mu][ed2] > edgeLength[mu][longestEdge] )) - { - longestEdge = ed2; - } - } - edgeLength[nu][referenceEdgeOfNu] = edgeLength[mu][longestEdge]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::RNode) - { - //Let f be the largest face in S containing e_{S, nu}. The component length of - //the reference edge of nu is the size of f minus the length of e_{S, nu} minus - //the lengths of the two vertices incident to e_{S, nu}. - - //Calculate an embedding of the graph (it exists only two which are - //mirror-symmetrical): - planarEmbed(S.getGraph()); - CombinatorialEmbedding combinatorialEmbedding(S.getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - T sizeOfFace = 0; - bool containsESnu = false; - adjEntry ae; - forall_face_adj(ae, f) - { - if (ae->theEdge() == eSnu) - containsESnu = true; - sizeOfFace += edgeLength[mu][ae->theEdge()] - + nodeLength[S.original(ae->theNode())]; - } - if (containsESnu && sizeOfFace > biggestFaceSize) - biggestFaceSize = sizeOfFace; - } - edgeLength[nu][referenceEdgeOfNu] = - biggestFaceSize - edgeLength[mu][eSnu] - - nodeLength[S.original(eSnu->source())] - - nodeLength[S.original(eSnu->target())]; - } - else //should never happen - edgeLength[nu][referenceEdgeOfNu] = 0; - - //Recursion: - topDownTraversal(spqrTree, ed->target(), nodeLength, edgeLength); - } -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::largestFaceContainingNode( - const StaticSPQRTree& spqrTree, - const node& mu, - const node& n, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength) -{ - bool containsARealEdge = false; - if (spqrTree.typeOf(mu) == SPQRTree::RNode) - { - //The largest face containing n is the largest face containg n in any embedding of S. - planarEmbed(spqrTree.skeleton(mu).getGraph()); - CombinatorialEmbedding combinatorialEmbedding(spqrTree.skeleton(mu).getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - T sizeOfFace = 0; - bool containingN = false; - bool m_containsARealEdge = false; - adjEntry ae; - forall_face_adj(ae, f) - { - if (spqrTree.skeleton(mu).original(ae->theNode()) == n) - containingN = true; - if (!spqrTree.skeleton(mu).isVirtual(ae->theEdge())) - m_containsARealEdge = true; - sizeOfFace += edgeLength[mu][ae->theEdge()]; - sizeOfFace += nodeLength[spqrTree.skeleton(mu).original(ae->theNode())]; - } - if (containingN && sizeOfFace > biggestFaceSize) - { - biggestFaceSize = sizeOfFace; - containsARealEdge = m_containsARealEdge; - } - } - - if (!containsARealEdge) - return -1; - return biggestFaceSize; - } - else if (spqrTree.typeOf(mu) == SPQRTree::PNode) - { - //Find the two longest edges, they define the largest face containg n. - edge edgeWalker; - edge longestEdges[2] = {0, 0}; - forall_edges(edgeWalker, spqrTree.skeleton(mu).getGraph()) - { - if ( longestEdges[1] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[1]]) - { - if ( longestEdges[0] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[0]]) - { - longestEdges[1] = longestEdges[0]; - longestEdges[0] = edgeWalker; - } - else - longestEdges[1] = edgeWalker; - } - } - - if ( !spqrTree.skeleton(mu).isVirtual(longestEdges[0]) - || !spqrTree.skeleton(mu).isVirtual(longestEdges[1])) - { - containsARealEdge = true; - } - - if (!containsARealEdge) - return -1; - - return edgeLength[mu][longestEdges[0]] + edgeLength[mu][longestEdges[1]]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::SNode) - { - //The largest face containing n is any face in the single existing embedding of S. - T sizeOfFace = 0; - node nS; - forall_nodes(nS, spqrTree.skeleton(mu).getGraph()) - sizeOfFace += nodeLength[spqrTree.skeleton(mu).original(nS)]; - - edge eS; - forall_edges(eS, spqrTree.skeleton(mu).getGraph()) - { - if (!spqrTree.skeleton(mu).isVirtual(eS)) - containsARealEdge = true; - sizeOfFace += edgeLength[mu][eS]; - } - - if (!containsARealEdge) - return -1; - - return sizeOfFace; - } - - //should never end here... - return 42; -} - - -template -T EmbedderMaxFaceBiconnectedGraphs::largestFaceInSkeleton( - const StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength) -{ - bool containsARealEdge = false; - if (spqrTree.typeOf(mu) == SPQRTree::RNode) - { - //The largest face is a largest face in any embedding of S. - planarEmbed(spqrTree.skeleton(mu).getGraph()); - CombinatorialEmbedding combinatorialEmbedding(spqrTree.skeleton(mu).getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - bool m_containsARealEdge = false; - T sizeOfFace = 0; - adjEntry ae; - forall_face_adj(ae, f) - { - //node originalNode = spqrTree.skeleton(mu).original(ae->theNode()); - if (!spqrTree.skeleton(mu).isVirtual(ae->theEdge())) - m_containsARealEdge = true; - sizeOfFace += edgeLength[mu][ae->theEdge()] - + nodeLength[spqrTree.skeleton(mu).original(ae->theNode())]; - } - - if (sizeOfFace > biggestFaceSize) - { - biggestFaceSize = sizeOfFace; - containsARealEdge = m_containsARealEdge; - } - } - - if (!containsARealEdge) - return -1; - - return biggestFaceSize; - } - else if (spqrTree.typeOf(mu) == SPQRTree::PNode) - { - //Find the two longest edges, they define the largest face. - edge edgeWalker; - edge longestEdges[2] = {0, 0}; - forall_edges(edgeWalker, spqrTree.skeleton(mu).getGraph()) - { - if ( longestEdges[1] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[1]]) - { - if ( longestEdges[0] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[0]]) - { - longestEdges[1] = longestEdges[0]; - longestEdges[0] = edgeWalker; - } - else - longestEdges[1] = edgeWalker; - } - } - - if ( !spqrTree.skeleton(mu).isVirtual(longestEdges[0]) - || !spqrTree.skeleton(mu).isVirtual(longestEdges[1])) - { - containsARealEdge = true; - } - - if (!containsARealEdge) - return -1; - - return edgeLength[mu][longestEdges[0]] + edgeLength[mu][longestEdges[1]]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::SNode) - { - //The largest face is any face in the single existing embedding of S. - T sizeOfFace = 0; - node nS; - forall_nodes(nS, spqrTree.skeleton(mu).getGraph()) - sizeOfFace += nodeLength[spqrTree.skeleton(mu).original(nS)]; - - edge eS; - forall_edges(eS, spqrTree.skeleton(mu).getGraph()) - { - if (!spqrTree.skeleton(mu).isVirtual(eS)) - containsARealEdge = true; - sizeOfFace += edgeLength[mu][eS]; - } - - if (!containsARealEdge) - return -1; - - return sizeOfFace; - } - - //should never end here... - return 42; -} - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphsLayers.h b/ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphsLayers.h deleted file mode 100644 index cf28ae2c8..000000000 --- a/ext/OGDF/ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphsLayers.h +++ /dev/null @@ -1,2688 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a biconnected graph with maximum - * external face. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MAX_FACE_BICONNECTED_GRAPHS_Layers_H -#define OGDF_EMBEDDER_MAX_FACE_BICONNECTED_GRAPHS_Layers_H - -#include -#include -#include -#include - - -namespace ogdf { - -//! Computes an embedding of a biconnected graph with maximum external face (plus layers approach). -/** - * See the paper "Graph Embedding with Minimum Depth and - * Maximum External Face" by C. Gutwenger and P. Mutzel (2004) for - * details. - * The algorithm for maximum external face is combined with the - * algorithm for maximum external layers which defines how to embed - * blocks into inner faces. See diploma thesis "Algorithmen zur - * Bestimmung von guten Graph-Einbettungen für orthogonale - * Zeichnungen" (in german) by Thorsten Kerkhof (2007) for details. - */ -template -class EmbedderMaxFaceBiconnectedGraphsLayers -{ -public: - //! Creates an embedder. - EmbedderMaxFaceBiconnectedGraphsLayers() { } - - /** - * \brief Embeds \a G by computing and extending a maximum face in \a G - * containg \a n. - * \param G is the original graph. - * \param adjExternal is assigned an adjacency entry of the external face. - * \param nodeLength stores for each vertex in \a G its length. - * \param edgeLength stores for each edge in \a G its length. - * \param n is a node of the original graph. If n is given, a maximum face - * containing n is computed, otherwise any maximum face. - */ - static void embed( - Graph& G, - adjEntry& adjExternal, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - const node& n = 0); - - /** - * \brief Computes the component lengths of all virtual edges in spqrTree. - * \param G is the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of \a G. - * \param edgeLengthSkel is saving for each skeleton graph of the SPQR-tree - * all edge lengths. - */ - static void compute( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel); - - /** - * \brief Returns the size of a maximum external face in \a G containing the node \a n. - * \param G is the original graph. - * \param n is a node of the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \return The size of a maximum external face in \a G containing the node \a n. - */ - static T computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength); - - /** - * \brief Returns the size of a maximum external face in \a G containing - * the node \a n. - * - * \param G is the original graph. - * \param n is a node of the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of G. - * \return The size of a maximum external face in \a G containing the node \a n. - */ - static T computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree); - - /** - * \brief Returns the size of a maximum external face in \a G containing - * the node \a n. - * - * \param G is the original graph. - * \param n is a node of the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of G. - * \param edgeLengthSkel is saving for each skeleton graph the length - * of each edge. - * \return The size of a maximum external face in \a G containing the node \a n. - */ - static T computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - const NodeArray< EdgeArray >& edgeLengthSkel); - - /** - * \brief Returns the size of a maximum external face in \a G. - * \param G is the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \return The size of a maximum external face in \a G. - */ - static T computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength); - - /** - * \brief Returns the size of a maximum external face in \a G. - * The SPQR-tree is given. The computed component lengths are - * computed and returned. - * - * \param G is the original graph. - * \param nodeLength is saving for each vertex in \a G its length. - * \param edgeLength is saving for each edge in \a G its length. - * \param spqrTree is the SPQR-tree of G. - * \param edgeLengthSkel is saving for each skeleton graph the length - * of each edge. - * \return The size of a maximum external face in \a G. - */ - static T computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel); - -private: - /** - * \brief Bottom up traversal of SPQR-tree computing the component length of - * all non-reference edges. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static void bottomUpTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength); - - /** - * \brief Top down traversal of SPQR-tree computing the component length of - * all reference edges. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static void topDownTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength); - - /** - * \brief Computes the size of a maximum face in the skeleton graph of \a mu - * containing \a n. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param n is a node of the original graph \a G. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static T largestFaceContainingNode( - const StaticSPQRTree& spqrTree, - const node& mu, - const node& n, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength); - - /** - * \brief Computes the size of a maximum face in the skeleton graph of \a mu. - * \param spqrTree is the SPQR-tree of \a G. - * \param mu is the SPQR-tree node treated in this function call. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving for each skeleton graph the length of each - * edge. - */ - static T largestFaceInSkeleton( - const StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength); - - /* \brief Computes recursively the thickness of the skeleton graph of all - * nodes in the SPQR-tree. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param mu a node in the SPQR-tree. - * \param thickness saving the computed results - the thickness of each - * skeleton graph. - * \param nodeLength is saving for each node of the original graph \a G its - * length. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - */ - static void bottomUpThickness( - const StaticSPQRTree& spqrTree, - const node& mu, - NodeArray& thickness, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength); - - /* \brief ExpandEdge embeds all edges in the skeleton graph \a S into an - * existing embedding and calls recursively itself for all virtual edges - * in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param thickness of each skeleton graph. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param delta_u the distance from the second adjacent face of the reference edge - * except the external face to the external face of G. - * \param delta_d the distance from the external face to the external face of G. - * \param adjExternal is an adjacency entry in the external face. - * \param n is only set, if ExpandEdge is called for the first time, because - * then there is no virtual edge which has to be expanded, but the max face - * has to contain a certain node \a n. - */ - static void expandEdge( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal, - const node& n = 0); - - /* \brief Embeds all edges in the skeleton graph \a S of an S-node of the - * SPQR-tree into an existing embedding and calls recursively itself for - * all virtual edges in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param thickness of each skeleton graph. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param delta_u the distance from the second adjacent face of the reference edge - * except the external face to the external face of G. - * \param delta_d the distance from the external face to the external face of G. - * \param adjExternal is an adjacency entry in the external face. - */ - static void expandEdgeSNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal); - - /* \brief Embeds all edges in the skeleton graph \a S of an P-node of the - * SPQR-tree into an existing embedding and calls recursively itself for - * all virtual edges in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param thickness of each skeleton graph. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param delta_u the distance from the second adjacent face of the reference edge - * except the external face to the external face of G. - * \param delta_d the distance from the external face to the external face of G. - * \param adjExternal is an adjacency entry in the external face. - */ - static void expandEdgePNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal); - - /* \brief Embeds all edges in the skeleton graph \a S of an R-node of the - * SPQR-tree into an existing embedding and calls recursively itself for - * all virtual edges in S. - * - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param thickness of each skeleton graph. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param delta_u the distance from the second adjacent face of the reference edge - * except the external face to the external face of G. - * \param delta_d the distance from the external face to the external face of G. - * \param adjExternal is an adjacency entry in the external face. - * \param n is only set, if ExpandEdge is called for the first time, because - * then there is no virtual edge which has to be expanded, but the max face - * has to contain a certain node \a n. - */ - static void expandEdgeRNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal, - const node& n = 0); - - /* \brief Writes a given adjacency entry into the newOrder. If the edge - * belonging to ae is a virtual edge, it is expanded. - * - * \param ae is the adjacency entry which has to be expanded. - * \param before is the adjacency entry of the node in \a G, before - * which ae has to be inserted. - * \param spqrTree The SPQR-tree of the treated graph. - * \param treeNodeTreated is an array saving for each SPQR-tree node \a mu - * whether it was already treated by any call of ExpandEdge or not. Every - * \a mu should only be treated once. - * \param mu is a node in the SPQR-tree. - * \param leftNode is the node adjacent to referenceEdge, which should be "left" - * in the embedding - * \param nodeLength is an array saving the lengths of the nodes of \a G. - * \param edgeLength is saving the edge lengths of all edges in each skeleton - * graph of all tree nodes. - * \param thickness of each skeleton graph. - * \param newOrder is saving for each node \a n in \a G the new adjacency - * list. This is an output parameter. - * \param adjBeforeNodeArraySource is saving for the source of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param adjBeforeNodeArrayTarget is saving for the target of the reference edge - * of the skeleton of mu the adjacency entry, before which new entries have - * to be inserted. - * \param delta_u the distance from the second adjacent face of the reference edge - * except the external face to the external face of G. - * \param delta_d the distance from the external face to the external face of G. - * \param adjExternal is an adjacency entry in the external face. - */ - static void adjEntryForNode( - adjEntry& ae, - ListIterator& before, - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal); - - /* \brief Single source shortest path. - * - * \param G directed graph - * \param s source node - * \param length length of an edge - * \param d contains shortest path distances after call - */ - static bool sssp( - const Graph& G, - const node& s, - const EdgeArray& length, - NodeArray& d); -}; - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::embed( - Graph& G, - adjEntry& adjExternal, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - const node& n /* = 0*/) -{ - //Base cases (SPQR-Tree-implementatioin would crash with these inputs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() <= 2) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //**************************************************************************** - //First step: calculate maximum face and edge lengths for virtual edges - //**************************************************************************** - StaticSPQRTree spqrTree(G); - NodeArray< EdgeArray > edgeLengthSkel; - compute(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); - - //**************************************************************************** - //Second step: Embed G - //**************************************************************************** - T biggestFace = -1; - node bigFaceMu; - if (n == 0) - { - node mu; - forall_nodes(mu, spqrTree.tree()) - { - //Expand all faces in skeleton(mu) and get size of the largest of them: - T sizeMu = largestFaceInSkeleton(spqrTree, mu, nodeLength, edgeLengthSkel); - if (sizeMu > biggestFace) - { - biggestFace = sizeMu; - bigFaceMu = mu; - } - } - } - else - { - edge nAdjEdge; - node* mus = new node[n->degree()]; - int i = 0; - forall_adj_edges(nAdjEdge, n) - { - mus[i] = spqrTree.skeletonOfReal(nAdjEdge).treeNode(); - bool alreadySeenMu = false; - for (int j = 0; j < i && !alreadySeenMu; j++) - { - if (mus[i] == mus[j]) - alreadySeenMu = true; - } - if (alreadySeenMu) - { - i++; - continue; - } - else - { - //Expand all faces in skeleton(mu) containing n and get size of - //the largest of them: - T sizeInMu = largestFaceContainingNode(spqrTree, mus[i], n, nodeLength, edgeLengthSkel); - if (sizeInMu > biggestFace) - { - biggestFace = sizeInMu; - bigFaceMu = mus[i]; - } - - i++; - } - } - delete mus; - } - - bigFaceMu = spqrTree.rootTreeAt(bigFaceMu); - - NodeArray thickness(spqrTree.tree()); - bottomUpThickness(spqrTree, bigFaceMu, thickness, nodeLength, edgeLengthSkel); - - NodeArray< List > newOrder(G); - NodeArray treeNodeTreated(spqrTree.tree(), false); - ListIterator it; - adjExternal = 0; - NodeArray< ListIterator > adjBeforeNodeArraySource(spqrTree.tree()); - NodeArray< ListIterator > adjBeforeNodeArrayTarget(spqrTree.tree()); - expandEdge(spqrTree, treeNodeTreated, bigFaceMu, 0, nodeLength, - edgeLengthSkel, thickness, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, 0, 0, adjExternal, n); - - node v; - forall_nodes(v, G) - G.sort(v, newOrder[v]); -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::adjEntryForNode( - adjEntry& ae, - ListIterator& before, - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal) -{ - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - if (S.isVirtual(ae->theEdge())) - { - edge twinE = S.twinEdge(ae->theEdge()); - node twinNT = S.twinTreeNode(ae->theEdge()); - //Skeleton& twinS = spqrTree.skeleton(twinNT); - - if (!treeNodeTreated[twinNT]) - { - node m_leftNode; - if (ae->theEdge()->source() == leftNode) - m_leftNode = twinE->source(); - else - m_leftNode = twinE->target(); - - if (ae->theEdge()->source() == ae->theNode()) - adjBeforeNodeArraySource[twinNT] = before; - else - adjBeforeNodeArrayTarget[twinNT] = before; - - //recursion call: - expandEdge(spqrTree, treeNodeTreated, twinNT, m_leftNode, - nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - delta_u, delta_d, adjExternal); - } //if (!treeNodeTreated[twinNT]) - - if (ae->theEdge() == referenceEdge) - { - if (ae->theNode() == ae->theEdge()->source()) - { - ListIterator tmpBefore = adjBeforeNodeArraySource[mu]; - adjBeforeNodeArraySource[mu] = before; - before = tmpBefore; - } - else - { - ListIterator tmpBefore = adjBeforeNodeArrayTarget[mu]; - adjBeforeNodeArrayTarget[mu] = before; - before = tmpBefore; - } - } - else //!(ae->theEdge() == referenceEdge) - { - if (ae->theNode() == ae->theEdge()->source()) - before = adjBeforeNodeArraySource[twinNT]; - else - before = adjBeforeNodeArrayTarget[twinNT]; - } - } - else //!(S.isVirtual(ae->theEdge())) - { - node origNode = S.original(ae->theNode()); - edge origEdge = S.realEdge(ae->theEdge()); - - if (origNode == origEdge->source()) - { - if (!before.valid()) - before = newOrder[origNode].pushBack(origEdge->adjSource()); - else - before = newOrder[origNode].insertBefore(origEdge->adjSource(), before); - } - else - { - if (!before.valid()) - before = newOrder[origNode].pushBack(origEdge->adjTarget()); - else - before = newOrder[origNode].insertBefore(origEdge->adjTarget(), before); - } - } //else //!(S.isVirtual(ae->theEdge())) -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::expandEdge( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal, - const node& n /*= 0*/) -{ - treeNodeTreated[mu] = true; - - switch(spqrTree.typeOf(mu)) - { - case SPQRTree::SNode: - expandEdgeSNode(spqrTree, treeNodeTreated, mu, leftNode, - nodeLength, edgeLength, thickness, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, delta_u, delta_d, adjExternal); - break; - case SPQRTree::PNode: - expandEdgePNode(spqrTree, treeNodeTreated, mu, leftNode, - nodeLength, edgeLength, thickness, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, delta_u, delta_d, adjExternal); - break; - case SPQRTree::RNode: - expandEdgeRNode(spqrTree, treeNodeTreated, mu, leftNode, - nodeLength, edgeLength, thickness, newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, delta_u, delta_d, adjExternal, n); - break; - OGDF_NODEFAULT - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::expandEdgeSNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal) -{ - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - adjEntry startAdjEntry; - if (leftNode == 0) - { - edge e; - forall_edges(e, S.getGraph()) - { - if (!S.isVirtual(e)) - { - startAdjEntry = e->adjSource(); - break; - } - } - } - else if (leftNode->firstAdj()->theEdge() == referenceEdge) - startAdjEntry = leftNode->lastAdj(); - else - startAdjEntry = leftNode->firstAdj(); - - adjEntry ae = startAdjEntry; - if (adjExternal == 0) - { - edge orgEdge = S.realEdge(ae->theEdge()); - if (orgEdge->source() == S.original(ae->theNode())) - adjExternal = orgEdge->adjSource()->twin(); - else - adjExternal = orgEdge->adjTarget()->twin(); - } - - ListIterator before; - if (!(referenceEdge == 0) && leftNode == referenceEdge->source()) - before = adjBeforeNodeArraySource[mu]; - else if (!(referenceEdge == 0)) - before = adjBeforeNodeArrayTarget[mu]; - ListIterator beforeSource; - - bool firstStep = true; - while (firstStep || ae != startAdjEntry) - { - //first treat ae with ae->theNode() is left node, then treat its twin: - node m_leftNode = ae->theNode(); - - if (ae->theEdge() == referenceEdge) - { - if (ae->theNode() == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = before; - else - adjBeforeNodeArrayTarget[mu] = before; - } - else - { - if (S.isVirtual(ae->theEdge()) && !(referenceEdge == 0)) - { - node twinTN = S.twinTreeNode(ae->theEdge()); - if (ae->theEdge()->source() == ae->theNode()) - { - if (ae->theEdge()->target() == referenceEdge->source()) - adjBeforeNodeArrayTarget[twinTN] = adjBeforeNodeArraySource[mu]; - else if (ae->theEdge()->target() == referenceEdge->target()) - adjBeforeNodeArrayTarget[twinTN] = adjBeforeNodeArrayTarget[mu]; - } - else - { - if (ae->theEdge()->source() == referenceEdge->source()) - adjBeforeNodeArraySource[twinTN] = adjBeforeNodeArraySource[mu]; - else if (ae->theEdge()->source() == referenceEdge->target()) - adjBeforeNodeArraySource[twinTN] = adjBeforeNodeArrayTarget[mu]; - } - } - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - delta_u, delta_d, adjExternal); - } - - if (firstStep) - { - beforeSource = before; - firstStep = false; - } - - ae = ae->twin(); - if (referenceEdge == 0) - before = 0; - else if (ae->theNode() == referenceEdge->source()) - before = adjBeforeNodeArraySource[mu]; - else if (ae->theNode() == referenceEdge->target()) - before = adjBeforeNodeArrayTarget[mu]; - else - before = 0; - if (ae->theEdge() == referenceEdge) - { - if (ae->theNode() == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = beforeSource; - else - adjBeforeNodeArrayTarget[mu] = beforeSource; - } - else - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - delta_u, delta_d, adjExternal); - - //set new adjacency entry pair (ae and its twin): - if (ae->theNode()->firstAdj() == ae) - ae = ae->theNode()->lastAdj(); - else - ae = ae->theNode()->firstAdj(); - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::expandEdgePNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal) -{ - //Choose face defined by virtual edge and the longest edge different from it. - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - edge altReferenceEdge = 0; - - node m_leftNode = leftNode; - if (m_leftNode == 0) - { - List nodeList; - S.getGraph().allNodes(nodeList); - m_leftNode = *(nodeList.begin()); - } - node m_rightNode = m_leftNode->firstAdj()->twinNode(); - - edge e; - if (referenceEdge == 0) - { - forall_edges(e, S.getGraph()) - { - if (!S.isVirtual(e)) - { - altReferenceEdge = e; - edge orgEdge = S.realEdge(e); - if (orgEdge->source() == S.original(m_leftNode)) - adjExternal = orgEdge->adjSource(); - else - adjExternal = orgEdge->adjTarget(); - break; - } - } - } - - //sort edges by length: - List graphEdges; - forall_edges(e, S.getGraph()) - { - if (e == referenceEdge || e == altReferenceEdge) - continue; - - if (!graphEdges.begin().valid()) - graphEdges.pushBack(e); - else - { - for (ListIterator it = graphEdges.begin(); it.valid(); it++) - { - if (edgeLength[mu][e] > edgeLength[mu][*it]) - { - graphEdges.insertBefore(e, it); - break; - } - ListIterator next = it; - next++; - if (!next.valid()) - { - graphEdges.pushBack(e); - break; - } - } - } - } - - List rightEdgeOrder; - ListIterator beforeAltRefEdge; - ListIterator beforeLeft; - - //begin with left node and longest edge: - for (int i = 0; i < 2; i++) - { - ListIterator before; - node n; - if (i == 0) - n = m_leftNode; - else - { - n = m_rightNode; - before = beforeAltRefEdge; - } - - if (!(referenceEdge == 0)) - { - if (n == referenceEdge->source()) - before = adjBeforeNodeArraySource[mu]; - else - before = adjBeforeNodeArrayTarget[mu]; - } - - adjEntry ae; - - //all edges except reference edge: - if (i == 0) - { - ListIterator lastPos; - ListIterator beforeRight; - if (!(referenceEdge == 0)) - { - if (referenceEdge->source() == m_rightNode) - beforeRight = adjBeforeNodeArraySource[mu]; - else //referenceEdge->target() == rightnode - beforeRight = adjBeforeNodeArrayTarget[mu]; - } - bool insertBeforeLast = false; - bool oneEdgeInE_a = false; - T sum_E_a = 0; - T sum_E_b = 0; - - for (int looper = 0; looper < graphEdges.size(); looper++) - { - edge e = *(graphEdges.get(looper)); - - if (!lastPos.valid()) - lastPos = rightEdgeOrder.pushBack(e); - else if (insertBeforeLast) - lastPos = rightEdgeOrder.insertBefore(e, lastPos); - else - lastPos = rightEdgeOrder.insertAfter(e, lastPos); - - //decide whether to choose face f_a or f_b as f_{mu, mu'}: - if (delta_u + sum_E_a < delta_d + sum_E_b) - { - ListIterator beforeU = before; - - if (e->source() == n) - ae = e->adjSource(); - else - ae = e->adjTarget(); - - if (S.isVirtual(e)) - { - node nu = S.twinTreeNode(e); - - T delta_u_nu = delta_u + sum_E_a; - T delta_d_nu = delta_d + sum_E_b; - - //buffer computed embedding: - NodeArray< List > tmp_newOrder(spqrTree.originalGraph()); - ListIterator tmp_before; - - adjEntryForNode(ae, tmp_before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, - tmp_newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, delta_d_nu, delta_u_nu, adjExternal); - - //copy buffered embedding reversed into newOrder: - node leftOrg = S.original(m_leftNode); - node rightOrg = S.original(m_rightNode); - node nOG; - forall_nodes(nOG, spqrTree.originalGraph()) - { - List nOG_tmp_adjList = tmp_newOrder[nOG]; - if (nOG_tmp_adjList.size() == 0) - continue; - - ListIterator* m_before; - if (nOG == leftOrg) - m_before = &beforeU; - else if (nOG == rightOrg && !(referenceEdge == 0)) - m_before = &beforeRight; - else - m_before = OGDF_NEW ListIterator(); - - for (ListIterator ae_it = nOG_tmp_adjList.begin(); ae_it.valid(); ae_it++) - { - adjEntry adjaEnt = *ae_it; - if (!m_before->valid()) - *m_before = newOrder[nOG].pushBack(adjaEnt); - else - *m_before = newOrder[nOG].insertBefore(adjaEnt, *m_before); - - if (nOG == leftOrg || nOG == rightOrg) - { - if (S.original(e->source()) == nOG) - adjBeforeNodeArraySource[nu] = *m_before; - else - adjBeforeNodeArrayTarget[nu] = *m_before; - } - } - - if (nOG != leftOrg && (nOG != rightOrg || referenceEdge == 0)) - delete m_before; - } //forall_nodes(nOG, spqrTree.originalGraph()) - - sum_E_a += thickness[nu]; - } - else //!(S.isVirtual(e)) - { - adjEntryForNode(ae, beforeU, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, - newOrder, adjBeforeNodeArraySource, - adjBeforeNodeArrayTarget, 0, 0, adjExternal); - - sum_E_a += 1; - } - - insertBeforeLast = false; - if (!oneEdgeInE_a) - { - beforeLeft = beforeU; - oneEdgeInE_a = true; - } - } - else //!(delta_u + sum_E_a <= delta_d + sum_E_b) - { - if (S.isVirtual(e)) - { - node nu = S.twinTreeNode(e); - if (!(referenceEdge == 0)) - { - if (e->source() == n) - adjBeforeNodeArrayTarget[nu] = beforeRight; - else - adjBeforeNodeArraySource[nu] = beforeRight; - } - } - - T delta_u_nu = delta_u + sum_E_a; - T delta_d_nu = delta_d + sum_E_b; - - if (e->source() == n) - ae = e->adjSource(); - else - ae = e->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - delta_u_nu, delta_d_nu, adjExternal); - - if (S.isVirtual(e)) - sum_E_b += thickness[S.twinTreeNode(e)]; - else - sum_E_b += 1; - - insertBeforeLast = true; - if (!oneEdgeInE_a) - beforeLeft = before; - } - } - } - else - { - for (ListIterator it = rightEdgeOrder.begin(); it.valid(); it++) - { - if ((*it)->source() == n) - ae = (*it)->adjSource(); - else - ae = (*it)->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - 0, 0, adjExternal); - } - } - - //(alternative) reference edge at last: - if (!(referenceEdge == 0)) - { - if (i == 0) - { - if (n == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = beforeLeft; - else - adjBeforeNodeArrayTarget[mu] = beforeLeft; - } - else - { - if (n == referenceEdge->source()) - adjBeforeNodeArraySource[mu] = before; - else - adjBeforeNodeArrayTarget[mu] = before; - } - } - else - { - if (altReferenceEdge->source() == n) - ae = altReferenceEdge->adjSource(); - else - ae = altReferenceEdge->adjTarget(); - - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - 0, 0, adjExternal); - } - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::expandEdgeRNode( - const StaticSPQRTree& spqrTree, - NodeArray& treeNodeTreated, - const node& mu, - const node& leftNode, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength, - const NodeArray& thickness, - NodeArray< List >& newOrder, - NodeArray< ListIterator >& adjBeforeNodeArraySource, - NodeArray< ListIterator >& adjBeforeNodeArrayTarget, - const T& delta_u, - const T& delta_d, - adjEntry& adjExternal, - const node& n /* = 0 */) -{ - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - - //compute biggest face containing the reference edge: - face maxFaceContEdge; - List maxFaceNodes; - planarEmbed(S.getGraph()); - CombinatorialEmbedding combinatorialEmbedding(S.getGraph()); - T bigFaceSize = -1; - adjEntry m_adjExternal = 0; - face f; - forall_faces(f, combinatorialEmbedding) - { - bool containsVirtualEdgeOrN = false; - adjEntry this_m_adjExternal = 0; - T sizeOfFace = 0; - List faceNodes; - adjEntry ae; - forall_face_adj(ae, f) - { - faceNodes.pushBack(ae->theNode()); - if ( (n == 0 && (ae->theEdge() == referenceEdge || referenceEdge == 0)) - || S.original(ae->theNode()) == n) - { - containsVirtualEdgeOrN = true; - if (!(referenceEdge == 0)) - this_m_adjExternal = ae; - } - - if (referenceEdge == 0 && !S.isVirtual(ae->theEdge())) - this_m_adjExternal = ae; - - sizeOfFace += edgeLength[mu][ae->theEdge()] - + nodeLength[S.original(ae->theNode())]; - } - - if (containsVirtualEdgeOrN && !(this_m_adjExternal == 0) && sizeOfFace > bigFaceSize) - { - maxFaceNodes = faceNodes; - bigFaceSize = sizeOfFace; - maxFaceContEdge = f; - m_adjExternal = this_m_adjExternal; - } - } - - if (adjExternal == 0) - { - edge orgEdge = S.realEdge(m_adjExternal->theEdge()); - if (orgEdge->source() == S.original(m_adjExternal->theNode())) - adjExternal = orgEdge->adjSource(); - else - adjExternal = orgEdge->adjTarget(); - } - - adjEntry adjMaxFace = m_adjExternal; - - //if embedding is mirror symmetrical embedding of desired embedding, - //invert adjacency list of all nodes: - if (!(referenceEdge == 0)) - { - //successor of adjEntry of virtual edge in adjacency list of leftNode: - adjEntry succ_virtualEdge_leftNode; - if (leftNode == referenceEdge->source()) - succ_virtualEdge_leftNode = referenceEdge->adjSource()->succ(); - else - succ_virtualEdge_leftNode = referenceEdge->adjTarget()->succ(); - if (!succ_virtualEdge_leftNode) - succ_virtualEdge_leftNode = leftNode->firstAdj(); - - bool succVELNAEInExtFace = false; - adjEntry aeExtFace; - forall_face_adj(aeExtFace, maxFaceContEdge) - { - if (aeExtFace->theEdge() == succ_virtualEdge_leftNode->theEdge()) - { - succVELNAEInExtFace = true; - break; - } - } - - if (!succVELNAEInExtFace) - { - node v; - forall_nodes(v, S.getGraph()) - { - List newAdjOrder; - for (adjEntry ae = v->firstAdj(); ae; ae = ae->succ()) - newAdjOrder.pushFront(ae); - S.getGraph().sort(v, newAdjOrder); - } - adjMaxFace = adjMaxFace->twin(); - } - } - - NodeArray nodeTreated(S.getGraph(), false); - adjEntry start_ae; - if (!(referenceEdge == 0)) - { - start_ae = adjMaxFace; - do - { - if (start_ae->theEdge() == referenceEdge) - { - start_ae = start_ae->faceCycleSucc(); - break; - } - start_ae = start_ae->faceCycleSucc(); - } while(start_ae != adjMaxFace); - } - else - start_ae = adjMaxFace; - - //For every edge a buffer saving adjacency entries written in embedding step - //for nodes on the maximum face, needed in step for other nodes. - EdgeArray< List > buffer(S.getGraph()); - - bool firstStep = true; - bool after_start_ae = true; - for (adjEntry ae = start_ae; - firstStep || ae != start_ae; - after_start_ae = (!after_start_ae || !ae->succ()) ? false : true, - ae = after_start_ae ? ae->faceCycleSucc() - : (!ae->faceCycleSucc() ? adjMaxFace : ae->faceCycleSucc())) - { - firstStep = false; - //node nodeG = S.original(ae->theNode()); - nodeTreated[ae->theNode()] = true; - - //copy adjacency list of nodes into newOrder: - ListIterator before; - edge vE = (ae->theEdge() == referenceEdge) ? referenceEdge : ae->theEdge(); - node nu = (ae->theEdge() == referenceEdge) ? mu : S.twinTreeNode(ae->theEdge()); - if (S.isVirtual(vE)) - { - if (ae->theNode() == vE->source()) - before = adjBeforeNodeArraySource[nu]; - else - before = adjBeforeNodeArrayTarget[nu]; - } - - bool after_ae = true; - adjEntry m_start_ae; - if (!(referenceEdge == 0)) - { - if (ae->theNode() == referenceEdge->source()) - m_start_ae = referenceEdge->adjSource(); - else if (ae->theNode() == referenceEdge->target()) - m_start_ae = referenceEdge->adjTarget(); - else - m_start_ae = ae; - } - else - m_start_ae = ae; - - adjEntry m_stop_ae; - bool hit_stop_twice = false; - int numOfHits = 0; - if ( !(referenceEdge == 0) - && ( ae->theNode() == referenceEdge->source() - || ae->theNode() == referenceEdge->target())) - { - if (m_start_ae->succ()) - m_stop_ae = m_start_ae->succ(); - else - { - m_stop_ae = m_start_ae->theNode()->firstAdj(); - hit_stop_twice = true; - } - } - else - m_stop_ae = m_start_ae; - - for (adjEntry aeN = m_start_ae; - after_ae || (hit_stop_twice && numOfHits != 2) || aeN != m_stop_ae; - after_ae = (!after_ae || !aeN->succ()) ? false : true, - aeN = after_ae ? aeN->succ() - : (!aeN->succ() ? ae->theNode()->firstAdj() : aeN->succ()), - numOfHits = (aeN == m_stop_ae) ? numOfHits + 1 : numOfHits) - { - node m_leftNode = 0; - if (S.isVirtual(aeN->theEdge()) && aeN->theEdge() != referenceEdge) - { - //Compute left node of aeN->theNode(). First get adjacency entry in ext. face - //(if edge is in ext. face) and compare face cycle successor with successor - //in node adjacency list. If it is the same, it is the right node, otherwise - //the left. - adjEntry aeExtFace = 0; - bool succInExtFace = false; - bool aeNInExtFace = false; - adjEntry aeNSucc = (aeN->succ()) ? aeN->succ() : ae->theNode()->firstAdj(); - aeExtFace = adjMaxFace; - do - { - if (aeExtFace->theEdge() == aeNSucc->theEdge()) - { - succInExtFace = true; - if (aeNInExtFace) - break; - } - if (aeExtFace->theEdge() == aeN->theEdge()) - { - aeNInExtFace = true; - if (succInExtFace) - break; - } - aeExtFace = aeExtFace->faceCycleSucc(); - } while(aeExtFace != adjMaxFace); - if (aeNInExtFace && succInExtFace) - m_leftNode = aeN->twinNode(); - else - m_leftNode = aeN->theNode(); - - node twinTN = S.twinTreeNode(aeN->theEdge()); - if (!(referenceEdge == 0)) - { - if (aeN->theEdge()->source() == aeN->theNode()) - { - if (aeN->theEdge()->target() == referenceEdge->source()) - adjBeforeNodeArrayTarget[twinTN] = adjBeforeNodeArraySource[mu]; - else if (aeN->theEdge()->target() == referenceEdge->target()) - adjBeforeNodeArrayTarget[twinTN] = adjBeforeNodeArrayTarget[mu]; - } - else - { - if (aeN->theEdge()->source() == referenceEdge->source()) - adjBeforeNodeArraySource[twinTN] = adjBeforeNodeArraySource[mu]; - else if (aeN->theEdge()->source() == referenceEdge->target()) - adjBeforeNodeArraySource[twinTN] = adjBeforeNodeArrayTarget[mu]; - } - } - } - - adjEntryForNode(aeN, before, spqrTree, treeNodeTreated, mu, - m_leftNode, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - 0, 0, adjExternal); - - //if the other node adjacent to the current treated edge is not in the - //max face, put written edges into an buffer and clear the adjacency - //list of that node. - if (maxFaceNodes.search(aeN->twinNode()) == -1) - { - node orig_aeN_twin_theNode = S.original(aeN->twinNode()); - buffer[aeN->theEdge()] = newOrder[orig_aeN_twin_theNode]; - newOrder[orig_aeN_twin_theNode].clear(); - } - } //for (adjEntry aeN = m_start_ae; [...] - } //for (adjEntry ae = start_ae; [...] - - //Copy of not treated node's adjacency lists (internal nodes). Setting - //of left node depending on minimal distance to external face of the - //face defined by left node. - bool DGcomputed = false; - int f_ext_id = 0; - int f_ref_id = 0; - Graph* p_DG; - List* p_fPG_to_nDG; - NodeArray* p_nDG_to_fPG; - NodeArray< List >* p_adjacencyList; - List< List >* p_faces; - NodeArray* p_dist_f_ref; - NodeArray* p_dist_f_ext; - AdjEntryArray* p_ae_to_face; - - node v; - forall_nodes(v, S.getGraph()) - { - if (nodeTreated[v]) - continue; - - node v_original = S.original(v); - nodeTreated[v] = true; - ListIterator before; - for (adjEntry ae = v->firstAdj(); ae; ae = ae->succ()) - { - if (buffer[ae->theEdge()].empty()) - { - T delta_u_nu = 0; - T delta_d_nu = 0; - bool frauenlinks = false; - if (S.isVirtual(ae->theEdge())) - { - if (!DGcomputed) - { - p_DG = new Graph(); - p_fPG_to_nDG = OGDF_NEW List(); - p_nDG_to_fPG = OGDF_NEW NodeArray(); - p_adjacencyList = OGDF_NEW NodeArray< List >(); - p_faces = OGDF_NEW List< List >(); - p_dist_f_ref = OGDF_NEW NodeArray(); - p_dist_f_ext = OGDF_NEW NodeArray(); - p_ae_to_face = OGDF_NEW AdjEntryArray(S.getGraph()); - EdgeArray edgeLengthDG(*p_DG); - DGcomputed = true; - - //compute dual graph of skeleton graph: - p_adjacencyList->init(S.getGraph()); - node nBG; - forall_nodes(nBG, S.getGraph()) - { - adjEntry ae_nBG; - forall_adj(ae_nBG, nBG) - (*p_adjacencyList)[nBG].pushBack(ae_nBG); - } - - NodeArray< List > adjEntryTreated(S.getGraph()); - forall_nodes(nBG, S.getGraph()) - { - adjEntry adj; - forall_adj(adj, nBG) - { - if (adjEntryTreated[nBG].search(adj) != -1) - continue; - - List newFace; - adjEntry adj2 = adj; - do - { - newFace.pushBack(adj2); - (*p_ae_to_face)[adj2] = p_faces->size(); - adjEntryTreated[adj2->theNode()].pushBack(adj2); - node tn = adj2->twinNode(); - int idx = (*p_adjacencyList)[tn].search(adj2->twin()); - if (idx - 1 < 0) - idx = (*p_adjacencyList)[tn].size() - 1; - else - idx -= 1; - adj2 = *((*p_adjacencyList)[tn].get(idx)); - } while (adj2 != adj); - p_faces->pushBack(newFace); - } - } - - p_nDG_to_fPG->init(*p_DG); - - for (ListIterator< List > it = p_faces->begin(); it.valid(); it++) - { - node nn = p_DG->newNode(); - (*p_nDG_to_fPG)[nn] = p_fPG_to_nDG->search(*(p_fPG_to_nDG->pushBack(nn))); - } - - NodeArray< List > adjFaces(*p_DG); - int i = 0; - for (ListIterator< List > it = p_faces->begin(); it.valid(); it++) - { - int f1_id = i; - for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - { - int f2_id = 0; - int j = 0; - for (ListIterator< List > it3 = p_faces->begin(); it3.valid(); it3++) - { - bool do_break = false; - for (ListIterator it4 = (*it3).begin(); it4.valid(); it4++) - { - if ((*it4) == (*it2)->twin()) - { - f2_id = j; - do_break = true; - break; - } - } - if (do_break) - break; - j++; - } - - if ( f1_id != f2_id - && adjFaces[*(p_fPG_to_nDG->get(f1_id))].search(*(p_fPG_to_nDG->get(f2_id))) == -1 - && adjFaces[*(p_fPG_to_nDG->get(f2_id))].search(*(p_fPG_to_nDG->get(f1_id))) == -1) - { - adjFaces[*(p_fPG_to_nDG->get(f1_id))].pushBack(*(p_fPG_to_nDG->get(f2_id))); - edge e1 = p_DG->newEdge(*(p_fPG_to_nDG->get(f1_id)), *(p_fPG_to_nDG->get(f2_id))); - edge e2 = p_DG->newEdge(*(p_fPG_to_nDG->get(f2_id)), *(p_fPG_to_nDG->get(f1_id))); - - //set edge length: - T e_length = -1; - for (ListIterator it_f1 = (*it).begin(); it_f1.valid(); it_f1++) - { - edge e = (*it_f1)->theEdge(); - for (ListIterator it_f2 = (*(p_faces->get(f2_id))).begin(); - it_f2.valid(); - it_f2++) - { - if ((*it_f2)->theEdge() == e) - { - if (e_length == -1 || edgeLength[mu][e] < e_length) - e_length = edgeLength[mu][e]; - } - } - } - edgeLengthDG[e1] = e_length; - edgeLengthDG[e2] = e_length; - } - - if (*it2 == adjMaxFace) - f_ext_id = f1_id; - if (!(referenceEdge == 0) && *it2 == adjMaxFace->twin()) - f_ref_id = f1_id; - } - i++; - } //for (ListIterator< List > it = faces.begin(); it.valid(); it++) - - //compute shortest path from every face to the external face: - node f_ext_DG = *(p_fPG_to_nDG->get(f_ext_id)); - p_dist_f_ext->init(*p_DG); - sssp(*p_DG, f_ext_DG, edgeLengthDG, *p_dist_f_ext); - if (!(referenceEdge == 0)) - { - node f_ref_DG = *(p_fPG_to_nDG->get(f_ref_id)); - p_dist_f_ref->init(*p_DG); - sssp(*p_DG, f_ref_DG, edgeLengthDG, *p_dist_f_ref); - } - } //if (!DGcomputed) - - //choose face with minimal shortest path: - T min1, min2; - T pi_f_0_f_ext = (*p_dist_f_ext)[*(p_fPG_to_nDG->get((*p_ae_to_face)[ae]))]; - T pi_f_1_f_ext = (*p_dist_f_ext)[*(p_fPG_to_nDG->get((*p_ae_to_face)[ae->twin()]))]; - if (!(referenceEdge == 0)) - { - T pi_f_0_f_ref = (*p_dist_f_ref)[*(p_fPG_to_nDG->get((*p_ae_to_face)[ae]))]; - T pi_f_1_f_ref = (*p_dist_f_ref)[*(p_fPG_to_nDG->get((*p_ae_to_face)[ae->twin()]))]; - - if (delta_u + pi_f_0_f_ref < delta_d + pi_f_0_f_ext) - min1 = delta_u + pi_f_0_f_ref; - else - min1 = delta_d + pi_f_0_f_ext; - - if (delta_u + pi_f_1_f_ref < delta_d + pi_f_1_f_ext) - min2 = delta_u + pi_f_1_f_ref; - else - min2 = delta_d + pi_f_1_f_ext; - - if (min1 > min2) - { - delta_u_nu = delta_u; - if (pi_f_0_f_ref < pi_f_0_f_ext) - delta_u_nu += pi_f_0_f_ref; - else - delta_u_nu += pi_f_0_f_ext; - delta_d_nu = delta_d; - if (pi_f_1_f_ref < pi_f_1_f_ext) - delta_d_nu += pi_f_1_f_ref; - else - delta_d_nu += pi_f_1_f_ext; - } - else - { - frauenlinks = true; - delta_u_nu = delta_u; - if (pi_f_1_f_ref < pi_f_1_f_ext) - delta_u_nu += pi_f_1_f_ref; - else - delta_u_nu += pi_f_1_f_ext; - delta_d_nu = delta_d; - if (pi_f_0_f_ref < pi_f_0_f_ext) - delta_d_nu += pi_f_0_f_ref; - else - delta_d_nu += pi_f_0_f_ext; - } - } - else - { - min1 = delta_d + pi_f_0_f_ext; - min2 = delta_d + pi_f_1_f_ext; - - if (min1 > min2) - { - delta_u_nu = delta_u + pi_f_0_f_ext; - delta_d_nu = delta_d + pi_f_1_f_ext; - } - else - { - frauenlinks = true; - delta_u_nu = delta_u + pi_f_1_f_ext; - delta_d_nu = delta_d + pi_f_0_f_ext; - } - } - } - - if (frauenlinks) - { - node nu = S.twinTreeNode(ae->theEdge()); - - //buffer computed embedding: - NodeArray< List > tmp_newOrder(spqrTree.originalGraph()); - ListIterator tmp_before; - - adjEntryForNode( - ae, tmp_before, spqrTree, treeNodeTreated, mu, - v, nodeLength, edgeLength, thickness, tmp_newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - delta_u_nu, delta_d_nu, adjExternal); - - //copy buffered embedding reversed into newOrder: - //node m_leftNode = v; - node m_rightNode = ae->twinNode(); - node leftOrg = v_original; - node rightOrg = S.original(m_rightNode); - node nOG; - forall_nodes(nOG, spqrTree.originalGraph()) - { - List nOG_tmp_adjList = tmp_newOrder[nOG]; - if (nOG_tmp_adjList.size() == 0) - continue; - - ListIterator* m_before; - if (nOG == leftOrg) - m_before = &before; - else - m_before = OGDF_NEW ListIterator(); - - for (ListIterator ae_it = nOG_tmp_adjList.begin(); ae_it.valid(); ae_it++) - { - adjEntry adjaEnt = *ae_it; - if (!m_before->valid()) - *m_before = newOrder[nOG].pushBack(adjaEnt); - else - *m_before = newOrder[nOG].insertBefore(adjaEnt, *m_before); - - if (nOG == leftOrg || nOG == rightOrg) - { - if (S.original(ae->theEdge()->source()) == nOG) - adjBeforeNodeArraySource[nu] = *m_before; - else - adjBeforeNodeArrayTarget[nu] = *m_before; - } - } - - if (nOG != leftOrg) - delete m_before; - } //forall_nodes(nOG, spqrTree.originalGraph()) - } - else - adjEntryForNode(ae, before, spqrTree, treeNodeTreated, mu, - v, nodeLength, edgeLength, thickness, newOrder, - adjBeforeNodeArraySource, adjBeforeNodeArrayTarget, - delta_u_nu, delta_d_nu, adjExternal); - - if (!nodeTreated[ae->twinNode()]) - { - node orig_ae_twin_theNode = S.original(ae->twinNode()); - buffer[ae->theEdge()] = newOrder[orig_ae_twin_theNode]; - newOrder[orig_ae_twin_theNode].clear(); - } - } - else - { - buffer[ae->theEdge()].reverse(); - for (ListIterator it = buffer[ae->theEdge()].begin(); it.valid(); it++) - { - if (!before.valid()) - before = newOrder[v_original].pushFront(*it); - else - before = newOrder[v_original].insertBefore(*it, before); - } - } - } - } - - if (DGcomputed) - { - delete p_DG; - delete p_fPG_to_nDG; - delete p_nDG_to_fPG; - delete p_adjacencyList; - delete p_faces; - delete p_dist_f_ext; - delete p_dist_f_ref; - delete p_ae_to_face; - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::compute( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - if (G.numberOfNodes() <= 1 || G.numberOfEdges() <= 2) - return; - - //set length for all real edges in skeletons to length of the original edge - //and initialize edge lengths for virtual edges with 0: - edgeLengthSkel.init(spqrTree.tree()); - node v; - forall_nodes(v, spqrTree.tree()) - { - edgeLengthSkel[v].init(spqrTree.skeleton(v).getGraph()); - edge e; - forall_edges(e, spqrTree.skeleton(v).getGraph()) - { - if (spqrTree.skeleton(v).isVirtual(e)) - edgeLengthSkel[v][e] = 0; - else - edgeLengthSkel[v][e] = edgeLength[spqrTree.skeleton(v).realEdge(e)]; - } - } - - //set component-length for all non-reference edges: - bottomUpTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); - //set component length for all reference edges: - topDownTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); -} - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()]+ nodeLength[e->target()]; - } - else if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + \ - nodeLength[e1->target()]; - } - StaticSPQRTree spqrTree(G); - NodeArray< EdgeArray > edgeLengthSkel; - return computeSize(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - const Graph& G, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - NodeArray< EdgeArray >& edgeLengthSkel) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()]+ nodeLength[e->target()]; - } - else if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + \ - nodeLength[e1->target()]; - } - - //set length for all real edges in skeletons to length of the original edge - //and initialize edge lengths for virtual edges with 0: - edgeLengthSkel.init(spqrTree.tree()); - node v; - forall_nodes(v, spqrTree.tree()) - { - edgeLengthSkel[v].init(spqrTree.skeleton(v).getGraph()); - edge e; - forall_edges(e, spqrTree.skeleton(v).getGraph()) - { - if (spqrTree.skeleton(v).isVirtual(e)) - edgeLengthSkel[v][e] = 0; - else - edgeLengthSkel[v][e] = edgeLength[spqrTree.skeleton(v).realEdge(e)]; - } - } - - //set component-length for all non-reference edges: - bottomUpTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); - //set component length for all reference edges: - topDownTraversal(spqrTree, spqrTree.rootNode(), nodeLength, edgeLengthSkel); - - T biggestFace = -1; - node mu; - forall_nodes(mu, spqrTree.tree()) - { - //Expand all faces in skeleton(mu) and get size of the largest of them: - T sizeMu = largestFaceInSkeleton(spqrTree, mu, nodeLength, edgeLengthSkel); - if (sizeMu > biggestFace) - biggestFace = sizeMu; - } - - return biggestFace; -} - - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()] + nodeLength[e->target()]; - } - else if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + \ - nodeLength[e1->target()]; - } - - StaticSPQRTree spqrTree(G); - NodeArray< EdgeArray > edgeLengthSkel; - compute(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); - return computeSize(G, n, nodeLength, edgeLength, spqrTree, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree) -{ - NodeArray< EdgeArray > edgeLengthSkel; - compute(G, nodeLength, edgeLength, spqrTree, edgeLengthSkel); - return computeSize(G, n, nodeLength, edgeLength, spqrTree, edgeLengthSkel); -} - - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - const Graph& G, - const node& n, - const NodeArray& nodeLength, - const EdgeArray& edgeLength, - StaticSPQRTree& spqrTree, - const NodeArray< EdgeArray >& edgeLengthSkel) -{ - //base cases (SPQR-tree implementation would crash for such graphs): - OGDF_ASSERT(G.numberOfNodes() >= 2) - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - return edgeLength[e] + nodeLength[e->source()] + nodeLength[e->target()]; - } - else if (G.numberOfEdges() == 2) - { - edge e1 = G.firstEdge(); - edge e2 = e1->succ(); - return edgeLength[e1] + edgeLength[e2] + nodeLength[e1->source()] + \ - nodeLength[e1->target()]; - } - - edge nAdjEdges; - node* mus = new node[n->degree()]; - int i = 0; - T biggestFace = -1; - forall_adj_edges(nAdjEdges, n) - { - mus[i] = spqrTree.skeletonOfReal(nAdjEdges).treeNode(); - bool alreadySeenMu = false; - for (int j = 0; j < i && !alreadySeenMu; j++) - { - if (mus[i] == mus[j]) - alreadySeenMu = true; - } - if (alreadySeenMu) - { - i++; - continue; - } - else - { - //Expand all faces in skeleton(mu) containing n and get size of the largest of them: - T sizeInMu = largestFaceContainingNode(spqrTree, mus[i], n, nodeLength, edgeLengthSkel); - if (sizeInMu > biggestFace) - biggestFace = sizeInMu; - - i++; - } - } - delete mus; - - return biggestFace; -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::bottomUpTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength) -{ - //Recursion: - edge ed; - forall_adj_edges(ed, mu) - { - if (ed->source() == mu) - bottomUpTraversal(spqrTree, ed->target(), nodeLength, edgeLength); - } - - edge e; - forall_edges(e, spqrTree.skeleton(mu).getGraph()) - { - //do not treat real edges here and do not treat reference edges: - if (!spqrTree.skeleton(mu).isVirtual(e) || e == spqrTree.skeleton(mu).referenceEdge()) - continue; - - //pertinent node of e in the SPQR-tree: - node nu = spqrTree.skeleton(mu).twinTreeNode(e); - //reference edge of nu (virtual edge in nu associated with mu): - edge er = spqrTree.skeleton(nu).referenceEdge(); - //sum of the lengths of the two poles of mu: - node refEdgeSource = spqrTree.skeleton(nu).referenceEdge()->source(); - node origRefEdgeSource = spqrTree.skeleton(nu).original(refEdgeSource); - node refEdgeTarget = spqrTree.skeleton(nu).referenceEdge()->target(); - node origRefEdgeTarget = spqrTree.skeleton(nu).original(refEdgeTarget); - T ell = nodeLength[origRefEdgeSource] + nodeLength[origRefEdgeTarget]; - - if (spqrTree.typeOf(nu) == SPQRTree::SNode) - { - //size of a face in skeleton(nu) minus ell - T sizeOfFace = 0; - node nS; - forall_nodes(nS, spqrTree.skeleton(nu).getGraph()) - sizeOfFace += nodeLength[spqrTree.skeleton(nu).original(nS)]; - - edge eS; - forall_edges(eS, spqrTree.skeleton(nu).getGraph()) - sizeOfFace += edgeLength[nu][eS]; - - edgeLength[mu][e] = sizeOfFace - ell; - } - else if (spqrTree.typeOf(nu) == SPQRTree::PNode) - { - //length of the longest edge different from er in skeleton(nu) - edge longestEdge = 0; - forall_edges(ed, spqrTree.skeleton(nu).getGraph()) - { - if (!(ed == er) && ( longestEdge == 0 - || edgeLength[nu][ed] > edgeLength[nu][longestEdge])) - { - longestEdge = ed; - } - } - edgeLength[mu][e] = edgeLength[nu][longestEdge]; - } - else if (spqrTree.typeOf(nu) == SPQRTree::RNode) - { - //size of the largest face containing er in skeleton(nu) minus ell - //Calculate an embedding of the graph (it exists only two which are - //mirror-symmetrical): - planarEmbed(spqrTree.skeleton(nu).getGraph()); - CombinatorialEmbedding combinatorialEmbedding(spqrTree.skeleton(nu).getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - T sizeOfFace = 0; - bool containsEr = false; - adjEntry ae; - forall_face_adj(ae, f) - { - if (ae->theEdge() == er) - containsEr = true; - sizeOfFace += edgeLength[nu][ae->theEdge()] - + nodeLength[spqrTree.skeleton(nu).original(ae->theNode())]; - } - - if (containsEr && sizeOfFace > biggestFaceSize) - biggestFaceSize = sizeOfFace; - } - - edgeLength[mu][e] = biggestFaceSize - ell; - } - else //should never happen - edgeLength[mu][e] = 1; - } -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::topDownTraversal( - StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - NodeArray< EdgeArray >& edgeLength) -{ - //S: skeleton of mu - Skeleton& S = spqrTree.skeleton(mu); - - //Get all reference edges of the children nu of mu and set their component length: - edge ed; - forall_adj_edges(ed, mu) - { - if (ed->source() != mu) - continue; - - node nu = ed->target(); - edge referenceEdgeOfNu = spqrTree.skeleton(nu).referenceEdge(); - edge eSnu = spqrTree.skeleton(nu).twinEdge(referenceEdgeOfNu); - if (spqrTree.typeOf(mu) == SPQRTree::SNode) - { - //Let L be the sum of the length of all vertices and edges in S. The component - //length of the reference edge of nu is L minus the length of e_{S, nu} minus - //the lengths of the two vertices incident to e_{S, nu}. - T L = 0; - edge ed2; - forall_edges(ed2, S.getGraph()) - L += edgeLength[mu][ed2]; - node no; - forall_nodes(no, S.getGraph()) - L += nodeLength[S.original(no)]; - - edgeLength[nu][referenceEdgeOfNu] = L - edgeLength[mu][eSnu] - - nodeLength[S.original(eSnu->source())] - - nodeLength[S.original(eSnu->target())]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::PNode) - { - //The component length of the reference edge of nu is the length of the longest - //edge in S different from e_{S, nu}. - edge ed2; - edge longestEdge = 0; - forall_edges(ed2, S.getGraph()) - { - if (ed2 != eSnu && ( longestEdge == 0 - || edgeLength[mu][ed2] > edgeLength[mu][longestEdge])) - { - longestEdge = ed2; - } - } - edgeLength[nu][referenceEdgeOfNu] = edgeLength[mu][longestEdge]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::RNode) - { - //Let f be the largest face in S containing e_{S, nu}. The component length of - //the reference edge of nu is the size of f minus the length of e_{S, nu} minus - //the lengths of the two vertices incident to e_{S, nu}. - - //Calculate an embedding of the graph (it exists only two which are - //mirror-symmetrical): - planarEmbed(S.getGraph()); - CombinatorialEmbedding combinatorialEmbedding(S.getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - T sizeOfFace = 0; - bool containsESnu = false; - adjEntry ae; - forall_face_adj(ae, f) - { - if (ae->theEdge() == eSnu) - containsESnu = true; - sizeOfFace += edgeLength[mu][ae->theEdge()] - + nodeLength[S.original(ae->theNode())]; - } - if (containsESnu && sizeOfFace > biggestFaceSize) - biggestFaceSize = sizeOfFace; - } - edgeLength[nu][referenceEdgeOfNu] = biggestFaceSize - edgeLength[mu][eSnu] - - nodeLength[S.original(eSnu->source())] - - nodeLength[S.original(eSnu->target())]; - } - else //should never happen - edgeLength[nu][referenceEdgeOfNu] = 0; - - //Recursion: - topDownTraversal(spqrTree, ed->target(), nodeLength, edgeLength); - } -} - - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::largestFaceContainingNode( - const StaticSPQRTree& spqrTree, - const node& mu, - const node& n, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength) -{ - bool containsARealEdge = false; - if (spqrTree.typeOf(mu) == SPQRTree::RNode) - { - //The largest face containing n is the largest face containg n in any embedding of S. - planarEmbed(spqrTree.skeleton(mu).getGraph()); - CombinatorialEmbedding combinatorialEmbedding(spqrTree.skeleton(mu).getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - T sizeOfFace = 0; - bool containingN = false; - bool m_containsARealEdge = false; - adjEntry ae; - forall_face_adj(ae, f) - { - if (spqrTree.skeleton(mu).original(ae->theNode()) == n) - containingN = true; - if (!spqrTree.skeleton(mu).isVirtual(ae->theEdge())) - m_containsARealEdge = true; - sizeOfFace += edgeLength[mu][ae->theEdge()]; - sizeOfFace += nodeLength[spqrTree.skeleton(mu).original(ae->theNode())]; - } - if (containingN && sizeOfFace > biggestFaceSize) - { - biggestFaceSize = sizeOfFace; - containsARealEdge = m_containsARealEdge; - } - } - - if (!containsARealEdge) - return -1; - return biggestFaceSize; - } - else if (spqrTree.typeOf(mu) == SPQRTree::PNode) - { - //Find the two longest edges, they define the largest face containg n. - edge edgeWalker; - edge longestEdges[2] = {0, 0}; - forall_edges(edgeWalker, spqrTree.skeleton(mu).getGraph()) - { - if ( longestEdges[1] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[1]]) - { - if ( longestEdges[0] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[0]]) - { - longestEdges[1] = longestEdges[0]; - longestEdges[0] = edgeWalker; - } - else - longestEdges[1] = edgeWalker; - } - } - - if ( !spqrTree.skeleton(mu).isVirtual(longestEdges[0]) - || !spqrTree.skeleton(mu).isVirtual(longestEdges[1])) - { - containsARealEdge = true; - } - - if (!containsARealEdge) - return -1; - - return edgeLength[mu][longestEdges[0]] + edgeLength[mu][longestEdges[1]]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::SNode) - { - //The largest face containing n is any face in the single existing embedding of S. - T sizeOfFace = 0; - node nS; - forall_nodes(nS, spqrTree.skeleton(mu).getGraph()) - sizeOfFace += nodeLength[spqrTree.skeleton(mu).original(nS)]; - - edge eS; - forall_edges(eS, spqrTree.skeleton(mu).getGraph()) - { - if (!spqrTree.skeleton(mu).isVirtual(eS)) - containsARealEdge = true; - sizeOfFace += edgeLength[mu][eS]; - } - - if (!containsARealEdge) - return -1; - - return sizeOfFace; - } - - //should never end here... - return 42; -} - - -template -T EmbedderMaxFaceBiconnectedGraphsLayers::largestFaceInSkeleton - (const StaticSPQRTree& spqrTree, - const node& mu, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength) -{ - bool containsARealEdge = false; - if (spqrTree.typeOf(mu) == SPQRTree::RNode) - { - //The largest face is a largest face in any embedding of S. - planarEmbed(spqrTree.skeleton(mu).getGraph()); - CombinatorialEmbedding combinatorialEmbedding(spqrTree.skeleton(mu).getGraph()); - T biggestFaceSize = -1; - face f; - forall_faces(f, combinatorialEmbedding) - { - bool m_containsARealEdge = false; - T sizeOfFace = 0; - adjEntry ae; - forall_face_adj(ae, f) - { - //node originalNode = spqrTree.skeleton(mu).original(ae->theNode()); - if (!spqrTree.skeleton(mu).isVirtual(ae->theEdge())) - m_containsARealEdge = true; - sizeOfFace += edgeLength[mu][ae->theEdge()] - + nodeLength[spqrTree.skeleton(mu).original(ae->theNode())]; - } - - if (sizeOfFace > biggestFaceSize) - { - biggestFaceSize = sizeOfFace; - containsARealEdge = m_containsARealEdge; - } - } - - if (!containsARealEdge) - return -1; - - return biggestFaceSize; - } - else if (spqrTree.typeOf(mu) == SPQRTree::PNode) - { - //Find the two longest edges, they define the largest face. - edge edgeWalker; - edge longestEdges[2] = {0, 0}; - forall_edges(edgeWalker, spqrTree.skeleton(mu).getGraph()) - { - if ( longestEdges[1] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[1]]) - { - if ( longestEdges[0] == 0 - || edgeLength[mu][edgeWalker] > edgeLength[mu][longestEdges[0]]) - { - longestEdges[1] = longestEdges[0]; - longestEdges[0] = edgeWalker; - } - else - longestEdges[1] = edgeWalker; - } - } - - if ( !spqrTree.skeleton(mu).isVirtual(longestEdges[0]) - || !spqrTree.skeleton(mu).isVirtual(longestEdges[1])) - { - containsARealEdge = true; - } - - if (!containsARealEdge) - return -1; - - return edgeLength[mu][longestEdges[0]] + edgeLength[mu][longestEdges[1]]; - } - else if (spqrTree.typeOf(mu) == SPQRTree::SNode) - { - //The largest face is any face in the single existing embedding of S. - T sizeOfFace = 0; - node nS; - forall_nodes(nS, spqrTree.skeleton(mu).getGraph()) - sizeOfFace += nodeLength[spqrTree.skeleton(mu).original(nS)]; - - edge eS; - forall_edges(eS, spqrTree.skeleton(mu).getGraph()) - { - if (!spqrTree.skeleton(mu).isVirtual(eS)) - containsARealEdge = true; - sizeOfFace += edgeLength[mu][eS]; - } - - if (!containsARealEdge) - return -1; - - return sizeOfFace; - } - - //should never end here... - return 42; -} - - -template -void EmbedderMaxFaceBiconnectedGraphsLayers::bottomUpThickness( - const StaticSPQRTree& spqrTree, - const node& mu, - NodeArray& thickness, - const NodeArray& nodeLength, - const NodeArray< EdgeArray >& edgeLength) -{ - //recursion: - edge e_mu_to_nu; - forall_adj_edges(e_mu_to_nu, mu) - { - if (e_mu_to_nu->source() != mu) - continue; - else - { - node nu = e_mu_to_nu->target(); - bottomUpThickness(spqrTree, nu, thickness, nodeLength, edgeLength); - } - } - - Skeleton& S = spqrTree.skeleton(mu); - edge referenceEdge = S.referenceEdge(); - - if (referenceEdge == 0) //root of SPQR-tree - { - thickness[mu] = 0; - return; - } - - //set dLengths for all edges in skeleton graph: - EdgeArray dLength(S.getGraph()); - edge eSG; - forall_edges(eSG, S.getGraph()) - { - if (eSG == referenceEdge) - continue; - - if (S.isVirtual(eSG)) - { - node twinTN = S.twinTreeNode(eSG); - dLength[eSG] = thickness[twinTN]; - } - else - dLength[eSG] = edgeLength[mu][eSG]; - } - - //compute thickness of skeleton(mu): - switch (spqrTree.typeOf(mu)) - { - case SPQRTree::SNode: - { - //thickness(mu) = min_{edges e != referenceEdge} dLength(e) - T min_dLength = -1; - forall_edges(eSG, S.getGraph()) - { - if (eSG == referenceEdge) - continue; - if (min_dLength == -1 || dLength[eSG] < min_dLength) - min_dLength = dLength[eSG]; - } - thickness[mu] = min_dLength; - } break; - case SPQRTree::PNode: - { - //thickness(mu) = sum_{edges e != referenceEdge} dLength(e) - T sumof_dLength = 0; - forall_edges(eSG, S.getGraph()) - { - if (eSG == referenceEdge) - continue; - sumof_dLength += dLength[eSG]; - } - thickness[mu] = sumof_dLength; - } break; - case SPQRTree::RNode: - { - /* Let f^ref_0, ... , f^ref_k be the faces sharing at least one edge with - * f_ref - the face adjacent to the reference edge not equal to the - * external face f_ext. Compute the dual graph and set edge lengths for - * two faces f_i, f_j, i != j, with at least one shared edge, to the - * minimal dLength of the shared edges of f_i and f_j. Remove the node - * related to face f_ref. thickness(mu) is then the length of the shortest - * path from any of the faces f^ref_0, ... , f^ref_k to f_ext plus 1. - */ - CombinatorialEmbedding CE(S.getGraph()); - adjEntry ae_f_ext = referenceEdge->adjSource(); - adjEntry ae_f_ref = referenceEdge->adjTarget(); - T faceSize_f_ext = 0; - adjEntry ae_f_ext_walker = ae_f_ext; - do - { - faceSize_f_ext += nodeLength[S.original(ae_f_ext_walker->theNode())] - + edgeLength[mu][ae_f_ext_walker->theEdge()]; - ae_f_ext_walker = ae_f_ext_walker->faceCycleSucc(); - } while (ae_f_ext_walker != ae_f_ext); - T faceSize_f_ref = 0; - adjEntry ae_f_ref_walker = ae_f_ref; - do - { - faceSize_f_ref += nodeLength[S.original(ae_f_ref_walker->theNode())] - + edgeLength[mu][ae_f_ref_walker->theEdge()]; - ae_f_ref_walker = ae_f_ref_walker->faceCycleSucc(); - } while (ae_f_ref_walker != ae_f_ref); - if (faceSize_f_ext < faceSize_f_ref) - { - adjEntry ae_tmp = ae_f_ext; - ae_f_ext = ae_f_ref; - ae_f_ref = ae_tmp; - } - - //compute dual graph: - Graph DG; - List fPG_to_nDG; - NodeArray nDG_to_fPG(DG); - NodeArray< List > adjacencyList(S.getGraph()); - List< List > faces; - NodeArray distances; - EdgeArray edgeLengthDG(DG); - int f_ref_id = -1; - int f_ext_id = -1; - - node nBG; - forall_nodes(nBG, S.getGraph()) - { - adjEntry ae_nBG; - forall_adj(ae_nBG, nBG) - adjacencyList[nBG].pushBack(ae_nBG); - } - - NodeArray< List > adjEntryTreated(S.getGraph()); - forall_nodes(nBG, S.getGraph()) - { - adjEntry adj; - forall_adj(adj, nBG) - { - if (adjEntryTreated[nBG].search(adj) != -1) - continue; - - List newFace; - adjEntry adj2 = adj; - do - { - newFace.pushBack(adj2); - adjEntryTreated[adj2->theNode()].pushBack(adj2); - node tn = adj2->twinNode(); - int idx = adjacencyList[tn].search(adj2->twin()); - if (idx - 1 < 0) - idx = adjacencyList[tn].size() - 1; - else - idx -= 1; - adj2 = *(adjacencyList[tn].get(idx)); - } while (adj2 != adj); - faces.pushBack(newFace); - } - } //forall_nodes(nBG, blockG[bT]) - - for (ListIterator< List > it = faces.begin(); it.valid(); it++) - { - node nn = DG.newNode(); - nDG_to_fPG[nn] = fPG_to_nDG.search(*(fPG_to_nDG.pushBack(nn))); - } - - NodeArray< List > adjFaces(DG); - int i = 0; - for (ListIterator< List > it = faces.begin(); it.valid(); it++) - { - int f1_id = i; - for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - { - int f2_id = 0; - int j = 0; - for (ListIterator< List > it3 = faces.begin(); it3.valid(); it3++) - { - bool do_break = false; - for (ListIterator it4 = (*it3).begin(); it4.valid(); it4++) - { - if ((*it4) == (*it2)->twin()) - { - f2_id = j; - do_break = true; - break; - } - } - if (do_break) - break; - j++; - } - - if ( f1_id != f2_id - && adjFaces[*(fPG_to_nDG.get(f1_id))].search(*(fPG_to_nDG.get(f2_id))) == -1 - && adjFaces[*(fPG_to_nDG.get(f2_id))].search(*(fPG_to_nDG.get(f1_id))) == -1) - { - adjFaces[*(fPG_to_nDG.get(f1_id))].pushBack(*(fPG_to_nDG.get(f2_id))); - adjFaces[*(fPG_to_nDG.get(f2_id))].pushBack(*(fPG_to_nDG.get(f1_id))); - edge e1 = DG.newEdge(*(fPG_to_nDG.get(f1_id)), *(fPG_to_nDG.get(f2_id))); - edge e2 = DG.newEdge(*(fPG_to_nDG.get(f2_id)), *(fPG_to_nDG.get(f1_id))); - - //set edge length: - T e_length = -1; - for (ListIterator it_f1 = (*it).begin(); it_f1.valid(); it_f1++) - { - edge e = (*it_f1)->theEdge(); - for (ListIterator it_f2 = (*(faces.get(f2_id))).begin(); - it_f2.valid(); - it_f2++) - { - if ((*it_f2)->theEdge() == e) - { - if (e_length == -1 || edgeLength[mu][e] < e_length) - e_length = edgeLength[mu][e]; - } - } - } - edgeLengthDG[e1] = e_length; - edgeLengthDG[e2] = e_length; - } - - if (*it2 == ae_f_ext) - f_ext_id = f1_id; - if (*it2 == ae_f_ref) - f_ref_id = f1_id; - } //for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - i++; - } //for (ListIterator< List > it = faces.begin(); it.valid(); it++) - - //the faces sharing at least one edge with f_ref: - node nDG_f_ref = *(fPG_to_nDG.get(f_ref_id)); - List& f_ref_adj_faces = adjFaces[nDG_f_ref]; - - //remove node related to f_ref from dual graph: - DG.delNode(*(fPG_to_nDG.get(f_ref_id))); - - //compute shortest path and set thickness: - NodeArray dist(DG); - node nDG_f_ext = *(fPG_to_nDG.get(f_ext_id)); - sssp(DG, nDG_f_ext, edgeLengthDG, dist); - T minDist = -1; - for (ListIterator it_adj_faces = f_ref_adj_faces.begin(); - it_adj_faces.valid(); - it_adj_faces++) - { - node fDG = *it_adj_faces; - if (fDG != nDG_f_ext) - { - T d = dist[fDG]; - if (minDist == -1 || d < minDist) - minDist = d; - } - } - thickness[mu] = minDist + 1; - } break; - OGDF_NODEFAULT - } -} - - -template -bool EmbedderMaxFaceBiconnectedGraphsLayers::sssp( - const Graph& G, - const node& s, - const EdgeArray& length, - NodeArray& d) -{ - const T infinity = 20000000; // big number. danger. think about it. - - //Initialize-Single-Source(G, s): - d.init(G); - node v; - edge e; - forall_nodes (v, G) - d[v] = infinity; - - d[s] = 0; - for (int i = 1; i < G.numberOfNodes(); ++i) - { - forall_edges (e, G) - { - //relax(u, v, w): // e == (u, v), length == w - if (d[e->target()] > d[e->source()] + length[e]) - d[e->target()] = d[e->source()] + length[e]; - } - } - - //check for negative cycle: - forall_edges (e, G) - { - if (d[e->target()] > d[e->source()] + length[e]) - return false; - } - - return true; -} - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/FindKuratowskis.h b/ext/OGDF/ogdf/internal/planarity/FindKuratowskis.h deleted file mode 100644 index cb5dfc34e..000000000 --- a/ext/OGDF/ogdf/internal/planarity/FindKuratowskis.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class FindKuratowskis - * - * \author Jens Schmidt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FIND_KURATOWSKIS_H -#define OGDF_FIND_KURATOWSKIS_H - -#include - - -namespace ogdf { - - -//! List of externally active nodes strictly between x and y for minortypes \a B and \a E -/** In case of extracting without bundles, all external paths and lists of their start- - * and endnodes are added. - */ -struct ExternE { - node theNode; - SListPure startnodes; - SListPure endnodes; - SListPure > externalPaths; -}; - -//! Saves information about a pertinent node w between two stopping vertices. -/** In particular links to appropriate highest-XY-Path and z-nodes are maintained - */ -struct WInfo { - public: - node w; - - //! All possible base minortypes on w - enum enumMinorType { - A=0x0001, // minor A - B=0x0002, // minor B - C=0x0004, // minor C - D=0x0008, // minor D - E=0x0010 // minor E - }; - int minorType; - - SListPure* highestXYPath; - SListPure* zPath; - - bool pxAboveStopX; - bool pyAboveStopY; - - SListPure > pertinentPaths; - - SListIterator externEStart; - SListIterator externEEnd; - node firstExternEAfterW; -}; - -//! A Kuratowski Structure is a special graph structure containing severals subdivisions -class OGDF_EXPORT KuratowskiStructure { - friend class FindKuratowskis; - friend class ExtractKuratowskis; - public: - //! Constructor - KuratowskiStructure() { } - //! Destructor - ~KuratowskiStructure() { } - - //! Copy constructor - KuratowskiStructure(const KuratowskiStructure& orig) { - copy(orig); - } - - //! Assignment - KuratowskiStructure& operator=(const KuratowskiStructure& orig) { - copy(orig); - return *this; - } - - //! Reset all data members - void clear(); - - //! The current node to embed - node V; - //! DFI of the current node to embed - int V_DFI; - - //! The root of the bicomp containing \a stopX and \a stopY - node R; - //! Real node of virtual node \a R. - /** This is redundant, but virtual node will be deleted later on - */ - node RReal; - //! First stopping node - node stopX; - //! Second stopping node - node stopY; - - protected: - //! Holds information about all pertinent nodes \a w of the bicomp containing \a V - /** Those were not embedded because of the two stopping nodes. In addition, - * links to the highest-XY-path and the z-nodes of w and the minortype is saved. - */ - SListPure wNodes; - - //! The whole highestFacePath of the bicomp containing \a V - /** The construct the highestFacePath, delete all edges of \a V except the two - * edges on the external face. The highestFacePath is the path starting at the - * first external edge along the unique face back to \a V. - */ - ListPure highestFacePath; - - //! The appropriate paths of the highestFacePath for each wNode - SListPure > highestXYPaths; - - //! External face path of bicomp containing \a V in direction CCW - SListPure externalFacePath; - - //! A list of all edges in all externally active paths (bundles only) - SListPure externalSubgraph; - - //! A list of all edges in pertinent paths (bundles only) - SListPure pertinentSubgraph; - - //! A path from the \a zNode in minortype \a D to node \a V for each highest XY-Path - /** zNodes are cut-vertices not contained in the external face path - */ - SListPure > zPaths; - - //! List of externally active nodes strictly between x and y for minortypes \a B and \a E - SListPure externE; - - //! List of all virtual startnodes of paths starting at \a stopX (only without bundles) - SListPure stopXStartnodes; - //! List of all virtual startnodes of paths starting at \a stopY (only without bundles) - SListPure stopYStartnodes; - //! List of all endnodes of paths starting at \a stopX (only without bundles) - SListPure stopXEndnodes; - //! List of all endnodes of paths starting at \a stopY (only without bundles) - SListPure stopYEndnodes; - - //! Copies class - void copy(const KuratowskiStructure& orig); - //! Used in copy constructor - void copyPointer(const KuratowskiStructure& orig, SListPure& list); -}; - -//! This class collects information about Kuratowski Subdivisions which is used for extraction later. -/** \pre Graph has to be simple. - */ -class FindKuratowskis { - public: - //! Constructor - FindKuratowskis(BoyerMyrvoldPlanar* bm); - //! Destructor - ~FindKuratowskis() { } - - //! Adds Kuratowski Structure on current node with root \a root and stopping nodes \a stopx and \a stopy - void addKuratowskiStructure( - const node currentNode, - const node root, - const node stopx, - const node stopy); - - //! Get-method for the list of all KuratowskiStructures - inline SListPure& getAllKuratowskis() { - return allKuratowskis; - } - - //! Constant get-method for the list of all KuratowskiStructures - inline const SListPure& getAllKuratowskis() const { - return allKuratowskis; - } - - // avoid automatic creation of assignment operator - //! Assignment operator is undefined! - FindKuratowskis &operator=(const FindKuratowskis &); - - protected: - //! Link to class BoyerMyrvoldPlanar - BoyerMyrvoldPlanar* pBM; - - //! Input graph - Graph& m_g; - - //! The embedding grade - const int& m_embeddingGrade; - - //! If true, bundles are extracted, otherwise single paths? - const bool m_bundles; - - //! Links appropriate \a WInfo to node - NodeArray m_getWInfo; - - //! List of all Kuratowski Structures - SListPure allKuratowskis; - - //! Current Kuratowski Structure - KuratowskiStructure k; - - //! Value used as marker for visited nodes etc. - /** Used during computation of the external face path and the highest x-y-path - */ - int m_nodeMarker; - //! Array maintaining visited bits on each node - NodeArray m_wasHere; - - //! Link to non-virtual vertex of a virtual Vertex. - /** A virtual vertex has negative DFI of the DFS-Child of related non-virtual Vertex - */ - const NodeArray& m_realVertex; - - //! The one and only DFI-NodeArray - const NodeArray& m_dfi; - - //! Returns appropriate node from given DFI - const Array& m_nodeFromDFI; - - //! Links to opposite adjacency entries on external face in clockwise resp. ccw order - /** m_link[0]=CCW, m_link[1]=CW - */ - const NodeArray(& m_link)[2]; - - //! The adjEntry which goes from DFS-parent to current vertex - const NodeArray& m_adjParent; - - //! The DFI of the least ancestor node over all backedges - /** If no backedge exists, the least ancestor is the DFI of that node itself - */ - const NodeArray& m_leastAncestor; - - //! Contains the type of each \a edge - /** @param 0 = EDGE_UNDEFINED - * @param 1 = EDGE_SELFLOOP - * @param 2 = EDGE_BACK - * @param 3 = EDGE_DFS - * @param 4 = EDGE_DFS_PARALLEL - * @param 5 = EDGE_BACK_DELETED - */ - EdgeArray& m_edgeType; - - //! The lowpoint of each \a node - NodeArray& m_lowPoint; - - //! The highest DFI in a subtree with \a node as root - const NodeArray& m_highestSubtreeDFI; - - //! A list to all separated DFS-children of \a node - /** The list is sorted by lowpoint values (in linear time) - */ - const NodeArray >& m_separatedDFSChildList; - - //! Identifies the rootnode of the child bicomp the given backedge points to - const EdgeArray& m_pointsToRoot; - - //! Keeps track of all vertices that are visited by the walkup through a specific backedge - /** This is done in order to refer to the unique child-bicomp of v. - */ - NodeArray& m_visitedWithBackedge; - - //! Holds information, if node is the source of a backedge. - /** This information refers to the adjEntries on the targetnode - * and is used during the walkdown - */ - NodeArray >& m_backedgeFlags; - - //! List of virtual bicomp roots, that are pertinent to the current embedded node - NodeArray >& m_pertinentRoots; - - //! Finds root node of the bicomp containing the stopping node \a stopX - node findRoot(node stopX); - - //! Extracts the highestFace Path of the bicomp containing both stopping nodes - void extractHighestFacePath(ListPure& highestFacePath, int marker); - - //! Extracts externalFacePath in direction CCW and splits highestFacePath in highestXYPaths - void extractExternalFacePath( - SListPure& externalFacePath, - const ListPure& highestFacePath, - int marker, - int highMarker); - - //! Assign pertinent nodes to the different minortypes and extracts inner externalPaths - void splitInMinorTypes( - const SListPure& externalFacePath, - int marker); - - //! Extracts external subgraph from node \a stop to ancestors of node with DFI \a root (without bundles) - void extractExternalSubgraph( - const node stop, - int root, - SListPure& externalStartnodes, - SListPure& externalEndnodes); - //! Extracts external subgraph from node \a stop to ancestors of node with DFI \a root (with bundles) - void extractExternalSubgraphBundles( - const node stop, - int root, - SListPure& externalSubgraph, - int nodeMarker); - - //! Extracts pertinent subgraph from all wNodes to \a V (without bundles) - void extractPertinentSubgraph( - SListPure& W_All/*, - const node V*/); - //! Extracts pertinent subgraph from all wNodes to \a V (with bundles) - void extractPertinentSubgraphBundles( - const SListPure& W_All, - const node V, - SListPure& pertinentSubgraph, - int nodeMarker); -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/IndInfo.h b/ext/OGDF/ogdf/internal/planarity/IndInfo.h deleted file mode 100644 index 234ebe0b5..000000000 --- a/ext/OGDF/ogdf/internal/planarity/IndInfo.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class EmbedKey. - * - * Implements the Key of the direction Indicator. Used by class EmbedPQTree. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - - -#ifndef OGDF_EMBED_KEY_H -#define OGDF_EMBED_KEY_H - -#include - -namespace ogdf { - - -class IndInfo -{ - friend class EmbedPQTree; - -public: - IndInfo(node w) { v = w; changeDir = false; } - ~IndInfo() { } - - void resetAssociatedNode(node w) { v = w; } - node getAssociatedNode() { return v; } - -private: - node v; - bool changeDir; - - - OGDF_NEW_DELETE -}; - - -} -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/MDMFLengthAttribute.h b/ext/OGDF/ogdf/internal/planarity/MDMFLengthAttribute.h deleted file mode 100644 index 17c682c5b..000000000 --- a/ext/OGDF/ogdf/internal/planarity/MDMFLengthAttribute.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Length attribute used in EmbedderMinDepthMaxFace. - * It contains two components (d, l) and a linear order is defined by: - * (d, l) > (d', l') iff d > d' or (d = d' and l > l') - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MDMF_LENGTH_ATTRIBUTE_H -#define OGDF_EMBEDDER_MDMF_LENGTH_ATTRIBUTE_H - -#include - -namespace ogdf { - -class MDMFLengthAttribute -{ -public: - //constructors and destructor - MDMFLengthAttribute() { d = l = 0; } - MDMFLengthAttribute(const int& d, const int& l) : d(d), l(l) { } - MDMFLengthAttribute(const int& d) : d(d), l(0) { } - MDMFLengthAttribute(const MDMFLengthAttribute& x) : d(x.d), l(x.l) { } - ~MDMFLengthAttribute() { } - - MDMFLengthAttribute operator=(const MDMFLengthAttribute& x); - MDMFLengthAttribute operator=(const int& x); - bool operator==(const MDMFLengthAttribute& x); - bool operator!=(const MDMFLengthAttribute& x); - bool operator>(const MDMFLengthAttribute& x); - bool operator<(const MDMFLengthAttribute& x); - bool operator>=(const MDMFLengthAttribute& x); - bool operator<=(const MDMFLengthAttribute& x); - MDMFLengthAttribute operator+(const MDMFLengthAttribute& x); - MDMFLengthAttribute operator-(const MDMFLengthAttribute& x); - MDMFLengthAttribute operator+=(const MDMFLengthAttribute& x); - MDMFLengthAttribute operator-=(const MDMFLengthAttribute& x); - -public: - //the two components: - int d; - int l; -}; - -bool operator==(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -bool operator!=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -bool operator>(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -bool operator<(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -bool operator>=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -bool operator<=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -MDMFLengthAttribute operator+(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -MDMFLengthAttribute operator-(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -MDMFLengthAttribute operator+=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -MDMFLengthAttribute operator-=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y); -ostream& operator<<(ostream& s, const MDMFLengthAttribute& x); - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/MaxSequencePQTree.h b/ext/OGDF/ogdf/internal/planarity/MaxSequencePQTree.h deleted file mode 100644 index ba84706b3..000000000 --- a/ext/OGDF/ogdf/internal/planarity/MaxSequencePQTree.h +++ /dev/null @@ -1,1936 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and definition of the class MaxSequencePQTree. - * - * Derivedsfrom base class PQTree and computes a maximal sequence - * of pertinent leaves that can be reduced. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MAX_SEQUENCE_PQTREE_H -#define OGDF_MAX_SEQUENCE_PQTREE_H - - - -#include - -#include -#include -#include - -namespace ogdf{ - - - -/** - * The class template MaxSequencePQTree is designed to compute a maximal consecutive - * sequence of pertinent leaves in a PQ-tree. In order to achieve this - * goal, the class template MaxSequencePQTree is a derived class form the class - * template PQTree. We assume that the reader is familiar - * with the data structure of a PQ-Tree and therefore give only a very - * brief overview of the functionality of this data structure. - * - * The PQ-Tree is a tool to represent the permutations of a set \a U - * in which various subsets of \a U occur consecutively. More precisely, - * the PQ-tree together with a package of efficient algorithms, all - * included in this template class PQTree, finds permissible - * permutations on the set \a U. The permissible permutations are those, - * in which certain subsets \a S of \a U occur as consecutive subsets. - * A PQ-tree represents an equivalence class of permissible - * permutations and as the elements of any subset \a S are - * constraint to appear together, the number of permissible - * permutations is reduced. The corresponding PQ-tree operation is - * called reduction with respect to \a S. - * - * In case that a set \a S of \a U of pertinent elements is not reducible, - * it might be a necessary to compute a maximal subset \a S' of \a S - * deleting the elements of \a S - \a S' from the PQ-tree such that the - * elements of \a S' are reducible in the PQ-tree. The class template - * MaxSequencePQTree provides the user the functionality of computing a subset - * \a S'. In fact, MaxSequencePQTree depicts the user the elements of \a S - \a S'$ that - * have to be deleted in order to get a reducible PQ-tree. However, - * the class template MaxSequencePQTree does not delete the elements of - * \a S - \a S'. It is up the client using this class to manage the deletion of - * \a S - \a S'. - * - * All computation done by this class to obtain a maximal pertinent - * sequence is done according to the rules presented in - * [Jayakumar, Thulasiraman, Swamy, 1989]. For - * detailed information about the computation, we refer kindly to the - * authors paper. - * - * The declaration of the template class MaxSequencePQTree. - * The formal parameter \a T represents the user defined - * type of an element in the above mentioned set \a U. - * The formal parameter \a Y represents the user defined - * type of the information only available for internal nodes PQInternalKey - * The formal parameter \a X of the base class template PQTree was - * designed to hold the general node information PQNodeKey available - * at every node of the tree. The class template MaxSequencePQTree defines this - * parameter to be of type whaInfo. This allows the class template to - * store informations needed during the computation of a maximal - * pertinent sequence at every node. - */ - -template -class MaxSequencePQTree: public PQTree -{ -public: - using PQTree::emptyNode; - - MaxSequencePQTree() : PQTree() { } - - ~MaxSequencePQTree() { - while (!eliminatedNodes.empty()) - { - PQNode *nodePtr = eliminatedNodes.popFrontRet(); - CleanNode(nodePtr); - delete nodePtr; - } - } - - //! Frees the memory of the information PQNodeInfo of a node. - /** - * Called by emptyAllPertinentNodes() or the destructor. - */ - virtual void CleanNode(PQNode* nodePtr); - - //! Does a clean up of a node. Called by emptyAllPertinentNodes. - virtual void clientDefinedEmptyNode(PQNode* nodePtr); - - //! Does a clean up after a reduction. - virtual void emptyAllPertinentNodes(); - - /** - * determineMinRemoveSequence() computes the maximal pertinent sequence \a S' of - * elements of the set \a S, that can be reduced in a PQ-tree. The set \a S - * is stored in an SListPure of type PQLeafKey* called - * \a leafKeys. The elements of \a S - \a S' are returned in an SList - * \a eliminatedKeys. The return value of the function is |\a S - \a S'|. - */ - int determineMinRemoveSequence( - SListPure*> &leafKeys, - SList*> &eliminatedKeys); - -protected: - using PQTree::fullChildren; - using PQTree::partialChildren; - - //! Overloaded function Bubble() of the base class PQTree. - /** - * This Bubble() ensures that every node in the pertinent subtree has a valid - * parent pointer. (Different to the original Bubble() that only tests if every node - * has a valid parent pointer). - */ - virtual bool Bubble(SListPure*> &leafKeys); - - //! Function that computes for a node its valid parent in the PQTree. - PQNode* GetParent(PQNode* nodePtr); - - /** - * Used to store all pertinent Nodes of the pertinent subtree before - * removing the minimal pertinent subsequence. - * Necessary for updates and cleanups after a reduction on the maximal - * pertinent sequence was successful. - */ - SListPure*> cleanUp; - - /** - * Used to store all eliminated nodes (\a status == ELIMINATED) of the PQTree. - * An eliminated node is one that has been removed during the application - * of the template matching algorithm from the PQ-tree. These nodes - * are kept (and their memory is not freed) in order to find out - * if a node has a valid parent pointer. - */ - SListPure*> eliminatedNodes; - -private: - - /** - * findMinWHASequence() is called by the procedure determineMinRemoveSequence(). - * It checks the [\a w,\a h,\a a]-number of the pertinent root. In case that the - * min{\a a,\a h} = 0, where \a a, \a h belong to the pertinent root, the - * PQ-tree is reducible and nothing needs to be done. In case that - * min{\a a,\a h} > 0, a min{\a a,\a h} number of leaves have to be removed - * from the tree in order to achieve reducibility for the set S. - * The leaves that have to be removed are returend in the SList \a eliminatedKeys. - */ - void findMinWHASequence( - StackPure*> &archiv, - SList*> &eliminatedKeys); - - /** - * setHchild() processes the children of a Q-node, - * marking a full sequence of children with at most one incident partial child on - * one side of the Q-node, as b-nodes respectively as h-node. The - * pointer \a h_child1 depicts the endmost child of the Q-node, where - * the sequence starts. - * The function gets the \a h_child1 of the Q-node. Its return value - * is the number of pertinent children, corresponding the [\a w,\a h,\a a]-numbering. - */ - int setHchild(PQNode *h_child1); - - /** - * setAchildren() traces all children of the largest - * consecutive sequence of pertinent children of a Q-node. Notice, that - * it does not mark a single node as a-node, but a sequence of full - * children with possible a partial child at each end as b-nodes, - * respectively as h-nodes. - */ - int setAchildren( - PQNode *hChild2, - PQNode *hChild2Sib); - - /** - * markPertinentChildren() marks all full and/or partial children - * of \a nodePtr either as a-, b-, h- or w-node. - * The parameter \a label describes which children have to be - * marked. The \a label can be either \b FULL, \b PARTIAL or - * \b PERTINENT. The \a deleteType - * can be either \b W_TYPE, \b B_TYPE, \b H_TYPE or \b A_TYPE. - */ - void markPertinentChildren( - PQNode *nodePtr, - int label, - whaType deleteType); - - /** - * haNumPnode() computes the h- and a-number of a - * P-node \a nodePtr. - */ - void haNumPnode(PQNode *nodePtr); - - /** - * haNumQnode() computes the h- and a-number of the - * partial Q-node \a nodePtr. The procedure furthermore sets the - * children \a aChild, \a hChild1 and \a hChild2 of the node - * information class whaInfo of \a nodePtr. - */ - void haNumQnode(PQNode *nodePtr); - - //! Computes the a-number for function haNumQnode(). - void aNumQnode(PQNode *nodePtr, int sumAllW); - - //! Computes the h-number for function haNumQnode(). - void hNumQnode(PQNode *nodePtr, int sumAllW); - - /** - * alpha1beta1Number() returns - * alpha_1 = beta_1 = sum {i in P(\a nodePtr)} w_i - - * max_{i in P(\a nodePtr)} {(w_i = a_i)}, - * where P(\a nodePtr) denotes the set of all pertinent - * children of the node \a nodePtr regardless whether \a nodePtr is a - * P- or a Q-node. Depicts the a-number if just one - * child of \a nodePtr is made $a$-node. This child is returned by the function - * alpha1beta1Number() using the pointer \a aChild. - */ - int alpha1beta1Number( - PQNode *nodePtr, - PQNode **aChild); - - /** - * setPertChild() returns \a w = sum_{i in - * P(\a nodePtr)} w_i, where \a nodePTr is any pertinent node of - * the PQ-tree. - */ - int sumPertChild(PQNode *nodePtr); -}; - - -/************************************************************************ - Bubble -************************************************************************/ - -template -bool MaxSequencePQTree::Bubble(SListPure*> &leafKeys) -{ - /** - * The function Bubble() is an overloaded function of the base - * template class PQTree. This overloaded version - * of Bubble() covers several task. - * -# It bubbles the tree up from the pertinent leaves, stored in an - * SListPure of type PQLeafKey, to find all - * pertinent nodes. Every pertinent node is stored in the stack - * \a cleanUp for a valid cleanup after the reduction step. - * -# It makes sure that every pertinent node has a valid parent - * pointer. - * - * The function Bubble() needs the following input: - * @param leafKeys is a SListPure to the PQleafKey's of the pertinent leaves. - */ - - - // queue for storing all pertinent nodes that still have - // to be processed. - Queue*> processNodes; - - /* - Enter the [[Full]] leaves into the queue [[processNodes]]. - In a first step the pertinent leaves have to be identified in the tree - and entered on to the queue [[processNodes]]. The identification of - the leaves can be done with the help of a pointer stored in every - [[PQLeafKey]] (see \ref{PQLeafKey}) in constant time for every element. - */ - SListIterator*> it; - for (it = leafKeys.begin(); it.valid(); ++it) - { - PQNode* checkLeaf = (*it)->nodePointer(); - processNodes.append(checkLeaf); - cleanUp.pushBack(checkLeaf); - if (!checkLeaf->getNodeInfo()) // if leaf does not have an information - // class for storing the [wha]-number - // allocate one. - { - whaInfo *newInfo = OGDF_NEW whaInfo; - PQNodeKey *infoPtr = OGDF_NEW PQNodeKey(newInfo); - checkLeaf->setNodeInfo(infoPtr); - infoPtr->setNodePointer(checkLeaf); - } - checkLeaf->getNodeInfo()->userStructInfo()->m_notVisitedCount = 1; - checkLeaf->mark(PQNodeRoot::QUEUED); - } - - - - /* - For every node in [[processNodes]], its father is detected using the - function [[GetParent]] \ref{GetParent}. The father is placed onto the - queue as well, if [[_nodePtr]] is its first child, that is popped from - the queue. In that case, the father is marked as [[QUEUED]] to - prevent the node from queue more than once. In any case, the number - of pertinent children of the father is updated. This is an important - number for computing the maximal pertinent sequence. - */ - while (!processNodes.empty()) - { - PQNode* nodePtr = processNodes.pop(); - nodePtr->parent(GetParent(nodePtr)); - if (nodePtr->parent() && - !nodePtr->parent()->getNodeInfo()) - // if the parent does not have an information - // class for storing the [wha]-number - // allocate one. - { - whaInfo *newInfo = OGDF_NEW whaInfo; - PQNodeKey *infoPtr = OGDF_NEW PQNodeKey(newInfo); - nodePtr->parent()->setNodeInfo(infoPtr); - infoPtr->setNodePointer(nodePtr->parent()); - } - if (nodePtr != this->m_root) - { - if (nodePtr->parent()->mark() == PQNodeRoot::UNMARKED) - { - processNodes.append(nodePtr->parent()); - cleanUp.pushBack(nodePtr->parent()); - nodePtr->parent()->mark(PQNodeRoot::QUEUED); - } - nodePtr->parent()->getNodeInfo()->userStructInfo()->m_notVisitedCount++; - int childCount = nodePtr->parent()->pertChildCount(); - nodePtr->parent()->pertChildCount(++childCount); - } - } - - - /* - This chunk belongs to the function [[Bubble]]. After doing some - cleaning up and resetting the flags that have been left at the - pertinent nodes during the first bubble up, this chunk computes the - maximal pertinent sequence by calling the function [[determineMinRemoveSequence]]. - It then removes - all leaves from the tree that have been marked as [[ELIMINATED]] and - possibly some internal nodes of the $PQ$-tree and stores pointers of - type [[leafKey]] for the pertinent leaves in the maximal sequence in the - array [[survivedElements]]. - */ - - SListIterator*> itn; - for (itn = cleanUp.begin(); itn.valid(); itn++) - (*itn)->mark(PQNodeRoot::UNMARKED); - - return true; -} - - - -/************************************************************************************** - cleanNode -***************************************************************************************/ - -template -void MaxSequencePQTree::CleanNode(PQNode* nodePtr) -{ - /** - * CleanNode() frees the memory allocated for the node information class of a - * node in the PQTree. It is an overloaded function of PQTree and called - * before deallocating the memory of the node nodePtr. - */ - - if (nodePtr->getNodeInfo()) - { - delete nodePtr->getNodeInfo()->userStructInfo(); - delete nodePtr->getNodeInfo(); - } -} - - -/************************************************************************************** - clientDefinedEmptyNode -***************************************************************************************/ - -template -void MaxSequencePQTree::clientDefinedEmptyNode(PQNode* nodePtr) -{ - /** - * The function clientDefinedEmptyNode() is the overloaded virtual function of the - * template base class PQTree called by default - * by the function emptyAllPertinentNodes() of PQTree. - * The overloaded function handles the different labels used during the - * computation and reduction of the maximal pertinent sequence. - */ - - if (nodePtr->status() == PQNodeRoot::ELIMINATED) - { - emptyNode(nodePtr); - nodePtr->status(PQNodeRoot::ELIMINATED); - } - else if (nodePtr->status() == PQNodeRoot::PERTROOT) - emptyNode(nodePtr); - else { - // Node has an invalid status? - OGDF_ASSERT(nodePtr->status() == PQNodeRoot::EMPTY) - emptyNode(nodePtr); - } -} - - -/************************************************************************************** - emptyAllPertinentNodes -***************************************************************************************/ - -template -void MaxSequencePQTree::emptyAllPertinentNodes() -{ - /** - * The function emptyAllPertinentNodes() is the overloaded virtual - * function of the template base class PQTree. This function handles all - * necessary cleanup after the computation of the maximal pertinent sequence and - * the reduction of the maximal pertinent sequence and frees the memory - * of all nodes that are no longer in the PQ-tree. - * - * Most nodes that are regarded for deletion are marked with the status - * \a TO_BE_DELETED. This causes a valid removal by the function - * PQTree::emptyAllPertinentNodes() if the node is - * contained in the stack \a pertinentNodes of the - * base template class. Otherwise, the function - * emptyAllPertinentNodes() has to remove the nodes directly from the tree. - * - * The function emptyAllPertinentNodes() differs the following nodes by - * their labels or status. - * - \a WHA_DELETE the node had to be removed from the tree in order - * to get a maximal pertinent sequence. The memory of the nodes has to - * be freed. Hence mark it as \a TO_BE_DELETED. - * - \a leaf the node was a full leaf. Delete it immediately, if it - * was marked \a WHA_DELETE, since it is not contained in the - * \a pertinentNodes stack of the base class. - * - \a TO_BE_DELETED the node was a partial node in the remaining - * pertinent subtree and replaced during the template matching - * algorithm by some other node. For the computation of valid parent - * pointers during the Bubble phase, the node has to be kept. Hence it - * is marked as \a ELIMINATED, which leaves the node untouched by the - * base class call of emptyAllPertinentNodes(). Observe that the node - * is stored in a special stack called \a eliminatedNodes for a valid - * cleanup after the termination of the algorithm. - * - \a FULL the node is a full node of the pertinent subtree. Since - * the pertinent subtree is replaced by a single P-node and some - * leaves representing the incoming edges of a node, this node has to - * be removed from the tree. Hence it is marked as \a TO_BE_DELETED. - * Observe that the pertinent root was probably marked as \a PERTROOT - * and therefore is not removed from the tree. - * - * The function emptyAllPertinentNodes() handles another important - * fact. During the reduction of the maximal pertinent sequence, - * \a PARTIAL nodes have been introduced into the PQ-tree, that do not - * have a node information. The function emptyAllPertinentNodes() - * detects these nodes equipping them with the container class of type - * pqNodeKey. - */ - - PQNode* nodePtr = 0; - - while (!cleanUp.empty()) - { - nodePtr = cleanUp.popFrontRet(); - nodePtr->pertChildCount(0); - if (nodePtr->status() == PQNodeRoot::WHA_DELETE && nodePtr->type() == PQNodeRoot::leaf) - { - CleanNode(nodePtr); - delete nodePtr; - } - - else { - // node must have an Information if contained in cleanUp - OGDF_ASSERT(nodePtr->getNodeInfo() != 0) - - nodePtr->getNodeInfo()->userStructInfo()->m_notVisitedCount = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_pertLeafCount = 0; - } - } - - ListIterator*> it; - for (it = this->m_pertinentNodes->begin();it.valid();it++) - { - nodePtr = (*it); - if (nodePtr->status() == PQNodeRoot::TO_BE_DELETED) - { - nodePtr->status(PQNodeRoot::ELIMINATED); - eliminatedNodes.pushBack(nodePtr); - } - else if (nodePtr->status() == PQNodeRoot::FULL) - nodePtr->status(PQNodeRoot::TO_BE_DELETED); - else if (nodePtr->status() == PQNodeRoot::WHA_DELETE) - nodePtr->status(PQNodeRoot::TO_BE_DELETED); - else if (nodePtr->getNodeInfo()) - nodePtr->getNodeInfo()->userStructInfo()->defaultValues(); - } - PQTree::emptyAllPertinentNodes(); -} - - - -/************************************************************************ - determineMinRemoveSequence -************************************************************************/ - -template -int MaxSequencePQTree::determineMinRemoveSequence( - SListPure*> &leafKeys, - SList*> &eliminatedKeys) -{ - /** - * The function determineMinRemoveSequence() computes the maximal pertinent sequence - * \a S' of elements of the set \a S, that can be reduced in a PQ-tree. The - * function expects the set \a S stored in an SListPure called - * \a leafKeys. Since the elements of \a S - \a S' have to be removed from - * the PQ-tree by the client, the function determineMinRemoveSequence() returns - * the elements of \a S - \a S' in an array of type PQLeafKey** called - * \a EliminatedElements. The return value of the function is |\a S - \a S'|. - * - * In order to compute the maximal pertinent sequence the function - * determineMinRemoveSequence() computes the [w,h,a]-number of every pertinent - * node in the pertinent subtree of the PQ-tree. If the minimum - * of the h- and a-number of the root of the pertinent - * subtree is not 0, then the PQ-tree is not reducible. - * According to the [w,h,a]-numbering, this procedure computes a minimal number of - * pertinent leaves that have to be removed from of the PQ-tree to gain reducibility. - * - * The user should observe that removing the leaves from the PQ-tree, - * depicted by the pointers to their information class stored in - * \a EliminatedElements is a necessary but not sufficient action to - * gain reducibility. The client calling this function has to make sure - * that nodes, where the complete frontier has been removed during the - * process must be removed as well. This can easily be done using functions of - * the base class PQTree such as checkIfOnlyChild(). - */ - - PQNode *nodePtr = 0; // dummy - PQNode *checkLeaf = 0; // dummy - - //Number of leaves that have to be deleted - int countDeletedLeaves = 0; - //Number of pertinent leaves - int maxPertLeafCount = 0; - - - // A queue storing the nodes whose $[w,h,a]$-number has to be computed next. - // A node is stored in [[processNodes]], if for all of its children the - // [w,h,a]-number has been computed. - Queue*> processNodes; - - // A stack storing all nodes where a $[w,h,a]$-number - // has been computed. This is necessary for a valid cleanup. - StackPure*> archiv; - - - - - - // Compute a valid parent pointer for every pertinent node. - Bubble(leafKeys); - - // Get all pertinent leaves and stores them on [[processNodes]] - // and [[_archiv]]. - SListIterator*> it; - for (it = leafKeys.begin(); it.valid(); ++it) - { - checkLeaf = (*it)->nodePointer(); - checkLeaf->getNodeInfo()->userStructInfo()->m_pertLeafCount = 1; - checkLeaf->getNodeInfo()->userStructInfo()->m_notVisitedCount--; - processNodes.append(checkLeaf); - archiv.push(checkLeaf); - - maxPertLeafCount++; - } - - while (!processNodes.empty()) - { - nodePtr = processNodes.pop(); - // Compute the $[w,h,a]$ number of [[nodePtr]]. Computing this number is - // trivial for leaves and full nodes. When considering a partial node, the - // computation has to distinguish between $P$- and $Q$-nodes. - if (nodePtr->getNodeInfo()->userStructInfo()->m_pertLeafCount < maxPertLeafCount) - { - // In case that the actual node, depicted by the pointer - // [[nodePtr]] is not the root, the counts of the pertinent - // children of [[nodePtr]]'s parent are - // updated. In case that all pertinent children of the parent of - // [[nodePtr]] have a valid $[w,h,a]$-number, it is possible to compute - // the $[w,h,a]$-number of parent. Hence the parent is placed onto - // [[processNodes]]and [[_archiv]]. - nodePtr->parent()->getNodeInfo()->userStructInfo()->m_pertLeafCount = - nodePtr->parent()->getNodeInfo()->userStructInfo()->m_pertLeafCount - + nodePtr->getNodeInfo()->userStructInfo()->m_pertLeafCount; - nodePtr->parent()->getNodeInfo()->userStructInfo()->m_notVisitedCount--; - if (!nodePtr->parent()->getNodeInfo()->userStructInfo()->m_notVisitedCount) - { - processNodes.append(nodePtr->parent()); - archiv.push(nodePtr->parent()); - } - } - if (nodePtr->type() == PQNodeRoot::leaf) - { - // Compute the $[w,h,a]$-number of a leaf. The computation is trivial. - nodePtr->status(PQNodeRoot::FULL); - nodePtr->getNodeInfo()->userStructInfo()->m_w = 1; - nodePtr->getNodeInfo()->userStructInfo()->m_h = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_a = 0; - if (nodePtr->getNodeInfo()->userStructInfo()->m_pertLeafCount < maxPertLeafCount) - fullChildren(nodePtr->parent())->pushFront(nodePtr); - } - else - { - // [[nodePtr]] is a $P$- or $Q$-node - // The $[w,h,a]$ number of $P$- or $Q$-nodes is computed identically. - // This is done calling the function [[sumPertChild]]. - nodePtr->getNodeInfo()->userStructInfo()->m_w = sumPertChild(nodePtr); - - if (fullChildren(nodePtr)->size() == nodePtr->childCount()) - { - // computes the $h$- and $a$-numbers of a full node. The computation - // is trivial. It also updates the list of full nodes of the parent - // of [[nodePtr]]. - nodePtr->status(PQNodeRoot::FULL); - if (nodePtr->getNodeInfo()->userStructInfo()->m_pertLeafCount - < maxPertLeafCount) - fullChildren(nodePtr->parent())->pushFront(nodePtr); - nodePtr->getNodeInfo()->userStructInfo()->m_h = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_a = 0; - } - else - { - // computes the $[w,h,a]$-number of a partial node. The computation is - // nontrivial for both $P$- and $Q$-nodes and is performed in the - // function [[haNumPnode]] for $P$-nodes and in the - // function [[haNumQnode]] for $Q$-nodes. - // This chunk also updates the partial children stack of the parent. - nodePtr->status(PQNodeRoot::PARTIAL); - if (nodePtr->getNodeInfo()->userStructInfo()->m_pertLeafCount < - maxPertLeafCount) - partialChildren(nodePtr->parent())->pushFront(nodePtr); - - if (nodePtr->type() == PQNodeRoot::PNode) - haNumPnode(nodePtr); - else - haNumQnode(nodePtr); - } - } - - } - - // Determine the root of the pertinent subtree, which the last processed node - //[[nodePtr]] and finds the minimum of the $h$- and $a$-number of - //[[m_pertinentRoot]]. In case that the minimum is equal to $0$, the - //[[m_pertinentRoot]] stays of type $B$. Otherwise the type is selected - //according to the minimum. - this->m_pertinentRoot = nodePtr; - if (this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_h < - this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_a) - countDeletedLeaves = this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_h; - else - countDeletedLeaves = this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_a; - - if (countDeletedLeaves > 0) - { - if (this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_h < - this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_a) - this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - else - this->m_pertinentRoot->getNodeInfo()->userStructInfo()->m_deleteType = A_TYPE; - } - - findMinWHASequence(archiv,eliminatedKeys); - - return countDeletedLeaves; -} - - - -/************************************************************************ - findMinWHASequence -************************************************************************/ - -template -void MaxSequencePQTree:: -findMinWHASequence(StackPure*> &archiv, - SList*> &eliminatedKeys) -{ - /** - * The procedure findMinWHASequence() is called by the procedure - * determineMinRemoveSequence(). - * It checks the [w,h,a]-number of the pertinent root. In case that the - * min{\a a,\a h} = 0, where \a a, \a h belong to the pertinent root, the - * PQ-tree is reducible and nothing needs to be done. In case that - * min{\a a,\a h} > 0, a min{\a a,\a h} number of leaves have to be removed - * from the tree in order to achieve reducibility for the set \a S. - * - * Knowing precisely the [w,h,a] number of every pertinent node, this - * can be achieved in a top down manner, according to the rules presented - * in Jayakumar et al. The procedure findMinWHASequence() implements this using - * the stack of nodes called \a archiv. This archiv contains all - * pertinent nodes. Since parents have been stored on top of their - * children in the stack which supports the top down method of the - * procedure. - * - * Function findMinWHASequence() returns an SList \a eliminatedKeys - * of pointers to PQLeafKey, describing the leaves that have to be removed. - */ - - //a pointer to a pertinent node of the $PQ$-tree that is currently examined. - PQNode *nodePtr = 0; - - //a pointer to the first child of type $h$ of [[nodePtr]]. - PQNode *hChild1 = 0; - - //a pointer to the second child of type $h$ of [[nodePtr]]. - PQNode *hChild2 = 0; - - //a pointer to the child of type $a$ of [[nodePtr]]. - PQNode *aChild = 0; - - // pertinent sibling of hChild1 - PQNode *hChild2Sib = 0; - - //counts the number of children of [[nodePtr]]. - int childCount = 0; - - while (!archiv.empty()) - { - childCount = 0; - nodePtr = archiv.pop(); - /* - Check if [[nodePtr]] is a full node whose delete type is either of - type $h$ or type $a$. Since there are no empty leaves in its - frontier, the node must therefore keep all its pertinent leaves - in its frontier and is depicted to be of type $b$. - */ - if (nodePtr->status() == PQNodeRoot::FULL && - (nodePtr->getNodeInfo()->userStructInfo()->m_deleteType == H_TYPE || - nodePtr->getNodeInfo()->userStructInfo()->m_deleteType == A_TYPE)) - { - nodePtr->getNodeInfo()->userStructInfo()->m_deleteType = B_TYPE; - this->m_pertinentNodes->pushFront(nodePtr); - } - - /* - Check if [[nodePtr]] is a leaf whose delete type is either of type $w$ or - $b$. In case it is of type $w$, the leaf has to be removed from the - tree to gain reducibility of the set $S$. - */ - else if (nodePtr->type() == PQNodeRoot::leaf) - { - if (nodePtr->getNodeInfo()->userStructInfo()->m_deleteType == W_TYPE) - eliminatedKeys.pushBack(nodePtr->getKey()); - else - this->m_pertinentNodes->pushFront(nodePtr); - } - - /* - Manage the case of [[nodePtr]] being either a partial $P$-node, a partial - $Q$-node, or a full $P$- or $Q$-node, where in the latter case the - delete type of [[nodePtr]] is of type $b$. - */ - else - switch (nodePtr->getNodeInfo()->userStructInfo()->m_deleteType) - { - case B_TYPE: - this->m_pertinentNodes->pushFront(nodePtr); - break; - - case W_TYPE: - markPertinentChildren(nodePtr,PQNodeRoot::PERTINENT,W_TYPE); - nodePtr->pertChildCount(0); - this->m_pertinentNodes->pushFront(nodePtr); - break; - - case H_TYPE: - if (nodePtr->type() == PQNodeRoot::PNode) - { - /* - [[nodePtr]] is a $P$-node of type $h$. Mark all full - children of [[nodePtr]] to be of type $b$ (by doing nothing, since - the default is type $b$). It furthermore marks all partial children to - be of type $w$ except for the child stored in [[hChild1]] of the - information class of type [[whaInfo*]] of [[nodePtr]]. This child is - marked to be of type $h$. - */ - markPertinentChildren(nodePtr,PQNodeRoot::PARTIAL,W_TYPE); - markPertinentChildren(nodePtr,PQNodeRoot::FULL,B_TYPE); - if (nodePtr->getNodeInfo()->userStructInfo()->m_hChild1) - { - hChild1 = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1; - hChild1->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - if (hChild1->getNodeInfo()->userStructInfo()->m_h < - hChild1->getNodeInfo()->userStructInfo()->m_w ) - childCount = 1; - } - nodePtr->pertChildCount(nodePtr->pertChildCount() + - childCount - partialChildren(nodePtr)->size()); - } - else - { - /* - [[nodePtr]] is a $Q$-node. Mark all pertinent children - to be of type $w$, except for the full children between the - [[hChild1]] and the endmost child of [[nodePtr]]. These full - children are marked $b$ while [[hChild1]] is marked to be of type - $h$. Setting the type of children to $b$ or $h$ is hidden in the - function call [[setHchild]] \label{setHChild}. - */ - markPertinentChildren(nodePtr,PQNodeRoot::PERTINENT,W_TYPE); - hChild1 = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1; - nodePtr->pertChildCount(setHchild(hChild1)); - } - this->m_pertinentNodes->pushFront(nodePtr); - break; - - - case A_TYPE: - if (nodePtr->type() == PQNodeRoot::PNode) - { - /* - [[nodePtr]] is a $P$-node of type $a$. - Distinguish two main cases, based on the existence of a - child of [[nodePtr]] stored in [[aChild]] of the information - class of type [[_whaInfo]] of [[nodePtr]]. - \begin{enumerate} - \item - If [[aChild]] is not empty, the chunk marks all full - and partial children of [[nodePtr]] to be of type $w$ and - marks the child [[aChild]] to be of type $a$. - \item - If [[aChild]] is empty, the chunk - marks all full children of [[nodePtr]] to be of type $b$ - (by doing nothing, since the default is type $b$). - It furthermore marks all partial children to be of type $w$ - except for the children stored in [[hChild1]] and - [[hChild2]] of the information class of type [[whaInfo*]] of - [[nodePtr]] which are marked to be of type $h$. Observe that - we have to distinguish the cases where both, [[_hChild]] and - [[hChild2]] are available, just [[_h_Child1]] is available or - none of the nodes exist. - \end{enumerate} - */ - if (nodePtr->getNodeInfo()->userStructInfo()->m_aChild) - { - markPertinentChildren(nodePtr,PQNodeRoot::PERTINENT,W_TYPE); - aChild = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_aChild; - aChild->getNodeInfo()->userStructInfo()->m_deleteType = A_TYPE; - nodePtr->pertChildCount(1); - } - else - { - markPertinentChildren(nodePtr,PQNodeRoot::FULL,B_TYPE); - markPertinentChildren(nodePtr,PQNodeRoot::PARTIAL,W_TYPE); - if (nodePtr->getNodeInfo()->userStructInfo()->m_hChild1) - { - hChild1 = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1; - hChild1->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - if (hChild1->getNodeInfo()->userStructInfo()->m_h < - hChild1->getNodeInfo()->userStructInfo()->m_w) - childCount = 1; - } - if (nodePtr->getNodeInfo()->userStructInfo()->m_hChild2) - { - hChild2 = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2; - hChild2->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - if (hChild2->getNodeInfo()->userStructInfo()->m_h < - hChild2->getNodeInfo()->userStructInfo()->m_w) - childCount++; - } - nodePtr->pertChildCount(nodePtr->pertChildCount() + childCount - - partialChildren(nodePtr)->size()); - } - } - else - { - /* - [[nodePtr]] is a $Q$-node of type $a$. - Distinguish two main cases, based on the existence of a child of - [[nodePtr]] stored in [[aChild]] of the information class of type - [[_whaInfo]] of [[nodePtr]]. - \begin{enumerate} - \item - If [[aChild]] is not empty, the chunk marks all full - and partial children of [[nodePtr]] to be of type $w$ and marks the - child [[aChild]] to be of type $a$. - \item - If [[aChild]] is empty, the chunk - marks all full and partial children of [[nodePtr]] to be of type $w$ - except for the ones in the largest consecutive sequence of pertinent - children. This sequence - is depicted by the children [[hChild1]] and [[hChild2]] which may be - either full or partial. The children between [[hChild1]] and - [[hChild2]] are full and are marked $b$, while [[hChild1]] and - [[hChild2]] are marked $b$ or $h$, according to their status (see \cite{Lei97}). - Setting the type of the nodes is hidden in calling the function - [[setAchildren]] (see \ref{setAchildren}). - \end{enumerate} - */ - if (nodePtr->getNodeInfo()->userStructInfo()->m_aChild) - { - aChild = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_aChild; - markPertinentChildren(nodePtr,PQNodeRoot::PERTINENT,W_TYPE); - aChild->getNodeInfo()->userStructInfo()->m_deleteType = A_TYPE; - nodePtr->pertChildCount(1); - } - else - { - markPertinentChildren(nodePtr,PQNodeRoot::PERTINENT,W_TYPE); - hChild2 = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2; - hChild2Sib = (PQNode*) - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2Sib; - nodePtr->pertChildCount(setAchildren(hChild2,hChild2Sib)); - } - } - this->m_pertinentNodes->pushFront(nodePtr); - break; - } - - /* - After successfully determining the type of the children of [[nodePtr]], - this chunk cleans up the information needed during the - computation at the [[nodePtr]]. - */ - fullChildren(nodePtr)->clear(); - partialChildren(nodePtr)->clear(); - nodePtr->status(PQNodeRoot::EMPTY); - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1 = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2 = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_aChild = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_w = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_h = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_a = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_deleteType = B_TYPE; - - } - -} - - -/************************************************************************ - setHchild -************************************************************************/ - -template -int MaxSequencePQTree::setHchild(PQNode *hChild1) - -{ - /** - * The function setHchild() processes the children of a Q-node, - * marking a full sequence of children with at most incident partial child on - * one side of the Q-node, as b-nodes respectively as h-node. The - * pointer \a h_child1 depicts the endmost child of the Q-node, where - * the sequence starts. - * - * The function gets the \a hChild1 of the Q-node. Its return value - * is the number of pertinent children, corresponding the [w,h,a]-numbering. - * The function uses the following variables. - */ - - // counts the number of pertinent children corresponding to the $[w,h,a]$-numbering. - int pertinentChildCount = 0; - - // is [[true]] as long as children with a full label are found, [[false]] otherwise. - bool fullLabel = false; - - - PQNode *currentNode = hChild1; // dummy - PQNode *nextSibling = 0; // dummy - PQNode *oldSibling = 0; // dummy - - if (hChild1 != 0) - fullLabel = true; - - - /* - Trace the sequence of full children with at most one incident - pertinent child. It marks all full nodes as $b$-node and the partial - child, if available as $h$-child. The beginning of the sequence is - stored in [[currentNode]] which is equal to [[h_child1]] before - entering the while loop. Observe that this chunk cases if the while - loop while scanning the sequence has reached the second endmost child - of the $Q$-node (see [[if (nextSibling == 0)]]). This case may - appear, if all children of the $Q$-node are pertinent and the second - endmost child is the only partial child. The value [[fullLabel]] is - set to [[false]] as soon as the end of the sequence is detected. - */ - while (fullLabel) - { - nextSibling = currentNode->getNextSib(oldSibling); - if (!nextSibling) - fullLabel = false; - - if (currentNode->status() == PQNodeRoot::FULL) - { - currentNode->getNodeInfo()->userStructInfo()->m_deleteType = B_TYPE; - pertinentChildCount++; - } - - else - { - if (currentNode->status() == PQNodeRoot::PARTIAL) - { - currentNode->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - if ((currentNode->getNodeInfo()->userStructInfo()->m_pertLeafCount - - currentNode->getNodeInfo()->userStructInfo()->m_h) > 0) - pertinentChildCount++; - } - fullLabel = false; - } - oldSibling = currentNode; - currentNode = nextSibling; - } - - - return pertinentChildCount; -} - - - - -/************************************************************************ - setAchildren -************************************************************************/ - -template -int MaxSequencePQTree:: -setAchildren(PQNode *hChild2, - PQNode *hChild2Sib) -{ - /** - * The function setAchildren() traces all children of the largest - * consecutive sequence of pertinent children of a Q-node. Notice, that - * it does not mark a single node as a-node, but a sequence of full - * children with possible a partial child at each end as b-nodes, - * respectively as h-nodes. - * - * The function setAchildren() needs the first node of the sequence - * denoted by the pointer \a hChild2 and its pertinent sibling denoted - * by \a hChild2Sib. The latter pointer allows immediate scanning of - * the sequence. - * - * The return value of the function setAchildren() is the number of - * pertinent children of the Q-node according to the [w,h,a]-numbering. - * - * The function setAchildren() uses the following variables. - * - \a pertinentChildCount - * - \a reachedEnd - * - \a _sum denotes the number of pertinent leaves in the frontier - * of the sequence. - * - \a currentNode is the currently examined node of the sequence. - * - \a nextSibling is a pointer needed for tracing the sequence. - * - \a oldSibling is a pointer needed for tracing the sequence. - */ - - // counts the pertinent children of the sequence. - int pertinentChildCount = 0; - - //is [[false]] as long as the end of the sequence is not detected. - //[[true]] otherwise. - bool reachedEnd = false; - - PQNode *currentNode = hChild2; // dummy - PQNode *nextSibling = 0; // dummy - PQNode *oldSibling = 0; // dummy - - - //Mark [[hChild2]] either as $b$- or as $h$-node. - if (hChild2->status() == PQNodeRoot::FULL) - hChild2->getNodeInfo()->userStructInfo()->m_deleteType = B_TYPE; - else { - //1. node of sequence is EMPTY? - OGDF_ASSERT(hChild2->status() == PQNodeRoot::PARTIAL) - hChild2->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - } - - if (currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_h > 0) - pertinentChildCount++; - - //Trace the sequence of pertinent children, marking the full children as $b$-node. - //If a partial or empty node is detected, the end of the sequence is - //reached and the partial node is marked as $h$-node. - nextSibling = hChild2Sib; - oldSibling = hChild2; - - if (nextSibling != 0) - { - currentNode = nextSibling; - reachedEnd = false; - while(!reachedEnd) - { - if (currentNode->status() == PQNodeRoot::FULL) - { - currentNode->getNodeInfo()->userStructInfo()->m_deleteType = B_TYPE; - pertinentChildCount++; - } - else - { - if (currentNode->status() == PQNodeRoot::PARTIAL) - { - currentNode->getNodeInfo()->userStructInfo()->m_deleteType = H_TYPE; - if ((currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_h) > 0) - pertinentChildCount++; - } - reachedEnd = true; - } - if (!reachedEnd) - { - nextSibling = currentNode->getNextSib(oldSibling); - if (nextSibling == 0) - reachedEnd = true; - oldSibling = currentNode; - currentNode = nextSibling; - } - } - } - - return pertinentChildCount; -} - - - - -/************************************************************************ - markPertinentChildren -************************************************************************/ - -template -void MaxSequencePQTree::markPertinentChildren( - PQNode *nodePtr, - int label, - whaType deleteType) -{ - /** - * The procedure markPertinentChildren() makes all full and/or partial children - * of \a nodePtr either an a-, b-, h- or w-node. - * The parameter \a label describes which children have to be - * marked. The \a label can be either \a FULL, \a PARTIAL or - * \a PERTINENT. The \a deleteType - * can be either \a W_TYPE, \a B_TYPE, \a H_TYPE or \a A_TYPE (see also - * MaxSequencePQTree. - * - * The function markPertinentChildren() uses just a pointer - * \a currentNode for tracing the pertinent children of \a nodePtr. - */ - - //PQNode *currentNode = 0; - - if (label == PQNodeRoot::PERTINENT) - { - ListIterator*> it; - for (it = partialChildren(nodePtr)->begin(); it.valid(); it++) - (*it)->getNodeInfo()->userStructInfo()->m_deleteType = deleteType; - for (it = fullChildren(nodePtr)->begin(); it.valid(); it++) - (*it)->getNodeInfo()->userStructInfo()->m_deleteType = deleteType; - } - else if (label == PQNodeRoot::PARTIAL) - { - ListIterator*> it; - for (it = partialChildren(nodePtr)->begin(); it.valid(); it++) - (*it)->getNodeInfo()->userStructInfo()->m_deleteType = deleteType; - } - - else - { - ListIterator*> it; - for (it = fullChildren(nodePtr)->begin(); it.valid(); it++) - (*it)->getNodeInfo()->userStructInfo()->m_deleteType = deleteType; - } -} - - - -/************************************************************************ - haNumPnode -************************************************************************/ - -template -void MaxSequencePQTree::haNumPnode(PQNode *nodePtr) - - -{ - /** - * The procedure haNumPnode() computes the h- and a-number of a - * P-node \a nodePtr. - * - * The procedure \a haNumPnode uses the following variables. - * - \a sumParW = sum_{i in Par(\a nodePtr)} w_i, where - * Par(\a nodePtr) denotes the set of partial children of \a nodePtr. - * - \a sumMax1 = max_{i in Par(\a nodePtr)}1 {(w_i - h_i)} - * where Par(\a nodePtr) denotes the set of partial children of - * - \a nodePtr and max 1 the first maximum. - * - \a sumMax2 = max_{i in Par(\a nodePtr)}2 {(w_i - h_i)} - * where Par(\a nodePtr) denotes the set of partial children of - * \a nodePtr and max2 the second maximum. - * - \a currentNode - * - \a hChild1 is a pointer to the \a hChild1 of \a nodePtr. - * - \a hChild2 is a pointer to the \a hChild2 of \a nodePtr. - * - \a aChild is a pointer to the \a aChild of \a nodePtr. - */ - - int sumParW = 0; - int sumMax1 = 0; - int sumMax2 = 0; - int sumHelp = 0; - PQNode *currentNode = 0; - PQNode *hChild1 = 0; - PQNode *hChild2 = 0; - PQNode *aChild = 0; - - /* - Computes the $h$-number - \[ h = \sum_{i \in Par(\mbox{[[nodePtr]]})}w_i - \max_{i\in - Par(\mbox{[[nodePtr]]})}1\left\{(w_i - h_i)\right\}\] - of the $P$-node [[nodePtr]]. - This is done by scanning all partial children stored in the - [[partialChildrenStack]] of [[nodePtr]] summing up the $w_i$ for every - $i \in Par(\mbox{[[nodePtr]]})$ and detecting - \[\max_{i\in Par(\mbox{[[nodePtr]]})}1\left\{(w_i - h_i)\right\}.\] - Since this can be simultaneously it also computes - \[\max_{i\in Par(\mbox{[[nodePtr]]})}2\left\{(w_i - h_i)\right\}\] - which is needed to determine the $a$-number. - After successfully determining the $h$-number, the [[hChild1]] and - [[hChild2]] of [[nodePtr]] are set. - */ - - ListIterator*> it; - for (it = partialChildren(nodePtr)->begin(); it.valid(); it++) - { - currentNode = (*it); - sumParW = sumParW + currentNode->getNodeInfo()->userStructInfo()->m_w; - sumHelp = currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_h; - if (sumMax1 <= sumHelp) - { - sumMax2 = sumMax1; - hChild2 = hChild1; - sumMax1 = sumHelp; - hChild1 = currentNode; - } - else if (sumMax2 <= sumHelp) - { - sumMax2 = sumHelp; - hChild2 = currentNode; - } - } - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1 = hChild1; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2 = hChild2; - nodePtr->getNodeInfo()->userStructInfo()->m_h = sumParW - sumMax1; - - /* - Compute the $a$-number of the $P$-node [[nodePtr]] where - \[ a = \min \{ \alpha_1, \alpha_2\}\] - such that - \[\alpha_1 = \sum_{i \in P(\mbox{[[nodePtr]]})}w_i - \max_{i\in - P(\mbox{[[nodePtr]]})}\left\{(w_i - h_i)\right\} \] - which can be computed calling the function [[alpha1beta1Number]] and - \[{\alpha}_2 \sum_{i \in Par(\mbox{[[nodePtr]]})}w_i - - \max_{i\in Par(\mbox{[[nodePtr]]})}1\left\{(w_i - h_i)\right\} - - \max_{i\in Par(\mbox{[[nodePtr]]})}2\left\{(w_i - h_i)\right\}\] - This chunk uses two extra variables - \begin{description} - \item[[alpha1]] $ = \alpha_1$. - \item[[alpha2]] $ = \alpha_2$. - \end{description} - */ - int alpha2 = sumParW - sumMax1 - sumMax2; - int alpha1 = alpha1beta1Number(nodePtr,&aChild); - - if (alpha1 <= alpha2) - { - nodePtr->getNodeInfo()->userStructInfo()->m_a = alpha1; - nodePtr->getNodeInfo()->userStructInfo()->m_aChild = aChild; - } - else - { - nodePtr->getNodeInfo()->userStructInfo()->m_a = alpha2; - nodePtr->getNodeInfo()->userStructInfo()->m_aChild = 0; - } - -}// haNumPnode - - - - -/************************************************************************ - haNumQnode -************************************************************************/ - -template -void MaxSequencePQTree::haNumQnode(PQNode *nodePtr) - -{ - /** - * The procedure haNumQnode() computes the h- and a-number of the - * partial Q-node \a nodePtr. The procedure furthermore sets the - * children \a aChild, \a hChild1 and \a hChild2 of the node - * information class whaInfo* of \a nodePtr. - * - * The procedure uses the following variables. - * - sumAllW = sum_{i in P(\a nodePtr)} w_i, where - * P(\a nodePtr) denotes the set of pertinent children of \a nodePtr. - */ - - int sumAllW = sumPertChild(nodePtr); - - hNumQnode(nodePtr,sumAllW); - aNumQnode(nodePtr,sumAllW); -} - - -/************************************************************************ - hNumQnode -************************************************************************/ - -template -void MaxSequencePQTree::hNumQnode( - PQNode *nodePtr, - int sumAllW) -{ - /** - * The procedure hNumQnode() computes the h-number of the - * partial Q-node \a nodePtr. The procedure furthermore sets the - * child \a hChild1 of the node information class whaInfo* of \a nodePtr. - * - * The procedure uses the following variables. - * - \a sumLeft = sum_{i in P(\a nodePtr)} w_i - sum_{i - * in P_L(\a nodePtr)}(w_i - h_i), where - * P_L(\a nodePtr) denotes the maximal consecutive sequence - * of pertinent children on the left side of the Q-node - * \a nodePtr such that only the rightmost node in - * P_L(\a nodePtr) may be partial. - * - \a sumRight = sum_{i in P(\a [nodePtr)}w_i - sum_{i - * in P_L(\a nodePtr)}(w_i - h_i), where - * P_L(\a nodePtr) denotes the maximal consecutive sequence - * of pertinent children on the left side of the Q-node - * \a nodePtr such that only the rightmost node in - * P_L(\a nodePtr) may be partial. - * - \a fullLabel - * - \a aChild is a pointer to the a-child of \a nodePtr. - * - \a leftChild is a pointer to the left endmost child of \a nodePtr. - * - \a rightChild is a pointer to the right endmost child of \a nodePtr. - * - \a holdSibling is a pointer to a child of \a nodePtr, needed - * to proceed through sequences of pertinent children. - * - \a checkSibling is a pointer to a currently examined child of \a nodePtr. - */ - - int sumLeft = 0; - int sumRight = 0; - bool fullLabel = true; - PQNode *leftChild = 0; - PQNode *rightChild = 0; - PQNode *holdSibling = 0; - PQNode *checkSibling = 0; - - - - //Compute the $h$-number of the $Q$-node [[nodePtr]] - - //Get endmost children of the $Q$-node [[nodePtr]]. - leftChild = nodePtr->getEndmost(0); - rightChild = nodePtr->getEndmost(leftChild); - OGDF_ASSERT(leftChild && rightChild) - - /* - Check the left - side of the $Q$-node [[nodePtr]] for the maximal consecutive sequence - of full nodes, including at most one partial child at the end of the sequence. - - The variable [[fullLabel]] is [[true]] as long as the [[while]]-loop - has not detected an partial {\bf or} empty child (see case [[if - (leftChild->status() != FULL)]]. Observe that the - construction of the [[while]]-loop examines the last child if it is a - partial child as well (see case [[if (leftChild->status() != - EMPTY)]] where in the computation in [[sumLeft]] we take advantage - of the fact, that the $h$-number of a full child is zero). - */ - while (fullLabel) - { - if (leftChild->status() != PQNodeRoot::FULL) - fullLabel = false; - if (leftChild->status() != PQNodeRoot::EMPTY) - { - sumLeft = sumLeft + - leftChild->getNodeInfo()->userStructInfo()->m_w - - leftChild->getNodeInfo()->userStructInfo()->m_h; - checkSibling = leftChild->getNextSib(holdSibling); - if (checkSibling == 0) - fullLabel = false; - holdSibling = leftChild; - leftChild = checkSibling; - } - } - - /* - Check the right - side of the $Q$-node [[nodePtr]] for the maximal consecutive sequence - of full nodes, including at most one partial child at the end of the sequence. - - The variable [[fullLabel]] is [[true]] as long as the [[while]]-loop - has not detected an partial {\bf or} empty child (see case [[if - (leftChild->status() != FULL)]]. Observe that the - construction of the [[while]]-loop examines the last child if it is a - partial child as well (see case [[if (leftChild->status() != - EMPTY)]] where in the computation in [[sumLeft]] we take advantage - of the fact, that the $h$-number of a full child is zero). - */ - holdSibling = 0; - checkSibling = 0; - fullLabel = true; - while (fullLabel) - { - if (rightChild->status() != PQNodeRoot::FULL) - fullLabel = false; - if (rightChild->status() != PQNodeRoot::EMPTY) - { - sumRight = sumRight + - rightChild->getNodeInfo()->userStructInfo()->m_w - - rightChild->getNodeInfo()->userStructInfo()->m_h; - - checkSibling = rightChild->getNextSib(holdSibling); - - if (checkSibling == 0) - fullLabel = false; - - holdSibling = rightChild; - rightChild = checkSibling; - } - } - - /* - After computing the number of pertinent leaves that stay in the $PQ$-tree - when keeping either the left pertinent or the right pertinent side of - the $Q$-node in the tree, this chunk chooses the side where the - maximum number of leaves stay in the tree. - Observe that we have to case the fact, that on both sides of the - $Q$-node [[nodePtr]] no pertinent children are. - */ - leftChild = nodePtr->getEndmost(0); - rightChild = nodePtr->getEndmost(leftChild); - if (sumLeft == 0 && sumRight == 0) - { - nodePtr->getNodeInfo()->userStructInfo()->m_h = sumAllW; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1 = 0; - } - else if (sumLeft < sumRight) - { - nodePtr->getNodeInfo()->userStructInfo()->m_h = sumAllW - sumRight; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1 = rightChild; - } - else - { - nodePtr->getNodeInfo()->userStructInfo()->m_h = sumAllW - sumLeft; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild1 = leftChild; - } -} - - - -/************************************************************************ - aNumQnode -************************************************************************/ - -template -void MaxSequencePQTree::aNumQnode( - PQNode *nodePtr, - int sumAllW) -{ - /** - * The procedure aNumQnode() computes the a-number of the - * partial Q-node \a nodePtr. The procedure furthermore sets the - * children \a aChild, \a hChild1 and \a hChild2 of the node - * information class whaInfo* of \a nodePtr. - * - * It Checks for consecutive sequences between all children of the Q-node - * \a nodePtr. The children which form a consecutive sequence are stored - * in a stack called \a sequence that is emptied, as soon as the end of - * the sequence is reached. When the stack is emptied, we count for the - * pertinent leaves in the front of the sequence, and update if necessary - * the sequence holding the maximum number of pertinent leaves in its - * frontier. - * - * Observe that if the sequence ends with a partial node, this node may - * form a consecutive sequence with its other siblings. Hence the - * partial node is pushed back onto the stack \a sequence after the - * stack has been emptied. - * - * This chunk uses a number of extra variables that are explained below. - * - \a beta1 = beta_1 = sum_{i in P(\a nodePtr} w_i - max_{i in P(\a nodePtr)}{(w_i = - * a_i)}, where $P(\a nodePtr) denotes the set of all pertinent - * children of the Q-node \a nodePtr. Depicts the a-number if just one - * child of \a nodePtr is made a-node. Computed by calling the function alpha1beta1Number(). - * - \a beta2 = beta_2 = sum_{i in P(\a nodePtr)} w_i - max_{P_A(\a nodePtr)}{sum_{i in - * P_A(\a nodePtr)}(w_i-h_i)}, where $P_A(\a nodePtr) is a maximal consecutive - * sequence of pertinent children of the Q-node \a nodePtr such that all - * nodes in P_A(\a nodePtr) except for the leftmost and rightmost ones are - * full. Computed by this chunk. - * - \a aSum depicts the number of pertinent leaves of the actual visited sequence. - * - \a aHoldSum depicts the number of leaves in the actual maximum sequence. - * - \a endReached is true if reached the end of the Q-node \a nodePtr and false otherwise. - * - \a leftMost pointer to the leftmost end of the actual visited sequence. - * - \a leftMostHold pointer to the leftmost end of the current maximum sequence. - * - \a actualNode pointer to a child of the Q-node. It is the - * node that is actually processed in the sequence of children. - * - \a currentNode pointer to a node in a consecutive pertinent - * sequence. Needed to process all nodes stored in \a sequence. - * - \a lastChild is a pointer to the endmost child of the Q-node - * that is opposite to the endmost child, where this chunk starts - * processing the sequence of children. - * - \a sequence is a SList of type PQNode* storing - * the nodes of a consecutive sequence that is actually processed. - */ - - PQNode *aChild = 0; - int beta1 = alpha1beta1Number(nodePtr,&aChild); - int beta2 = 0; - int aSum = 0; - int aHoldSum = 0; - bool endReached = 0; - PQNode *leftMost = 0; - PQNode *leftSib = 0; - PQNode *leftMostHold = 0; - PQNode *leftSibHold = 0; - PQNode *actualNode = 0; - PQNode *currentNode = 0; - PQNode *lastChild = 0; - PQNode *holdSibling = 0; - PQNode *checkSibling = 0; - // pointer to the second endmost child - - SList*> sequence; - - actualNode = nodePtr->getEndmost(0); - lastChild = nodePtr->getEndmost(actualNode); - - endReached = false; - while (!endReached) - { - /* - Process the children of a $Q$-node [[nodePtr]] from one end of [[nodePtr]] to the - other, searching for a consecutive sequence of pertinent nodes with - the maximum number of pertinent leaves, such that all nodes of the - pertinent sequence are full except possibly the two endmost children - which are allowed to be partial. - */ - if (sequence.empty()) - { - /* - Currently no consecutive sequence of pertinent children - is detected while scanning the children of the $Q$-node. - Check the [[actualNode]] if it is the first child of - such a sequence. If so, place [[actualNode]] on the stack [[sequence]]. - */ - if (actualNode->status() != PQNodeRoot::EMPTY) - { - sequence.pushFront(actualNode); - leftMost = 0; - leftSib = 0; - } - } - else - { - /* - [[actualNode]] is a sibling of a consecutive pertinent sequence that has - been detected in an earlier step, while scanning the children of the $Q$-node. - This chunk cases on the status of the [[actualNode]]. - - In case that the status of - the [[actualNode]] is [[Full]], [[actualNode]] is included into the - sequence of pertinent children by pushing it onto the stack - [[sequence]]. - - If [[actualNode]] is EMPTY, we have reached the end of - the actual consecutive sequence of pertinent children. In this case - the $a$-numbers of the nodes in the sequence have to be summed up. - - If the [[actualNode]] is [[PARTIAL]], the end of the consecutive sequence - is reached and similar actions to the [[EMPTY]] have to be - performed. However, [[actualNode]] might mark the beginning of - another pertinent sequence. Hence it has to be stored again in [[sequence]]. - */ - if (actualNode->status() == PQNodeRoot::FULL) - sequence.pushFront(actualNode); - - else if (actualNode->status() == PQNodeRoot::EMPTY) - { - /* - If [[actualNode]] is EMPTY, the end of - the actual consecutive sequence of pertinent children is reached . In - this case, all nodes of the currently examined consecutive sequence are stored in - [[sequence]]. - They are removed from the stack and their $a$-numbers are summed up. - If necessary, the sequence with the largest number of full leaves in - its frontier is updated. - */ - aSum = 0; - - while (!sequence.empty()) - { - currentNode = sequence.popFrontRet(); - aSum = aSum + currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_h; - if (sequence.size() == 1) - leftSib = currentNode; - } - leftMost = currentNode; - - if (aHoldSum < aSum) - { - aHoldSum = aSum; - leftMostHold = leftMost; - leftSibHold = leftSib; - } - - } - else - { - /* - If the [[actualNode]] is [[PARTIAL]], the end of the consecutive sequence - is reached. In - this case, all nodes of the currently examined consecutive sequence are stored in - [[sequence]]. - They are removed from the stack and their $a$-numbers are summed up. - If necessary, the sequence with the largest number of full leaves in - its frontier is updated. - However, [[actualNode]] might mark the beginning of - another pertinent sequence. Hence it has to be stored again in [[sequence]]. - */ - sequence.pushFront(actualNode); - aSum = 0; - while (!sequence.empty()) - { - currentNode = sequence.popFrontRet(); - aSum = aSum + currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_h; - if (sequence.size() == 1) - leftSib = currentNode; - } - if (leftSib == 0) - leftSib = actualNode; - leftMost = currentNode; - - if (aHoldSum < aSum) - { - aHoldSum = aSum; - leftMostHold = leftMost; - leftSibHold = leftSib; - } - - sequence.pushFront(actualNode); - - } - } - - // Get the next sibling - if (actualNode != lastChild) - { - checkSibling = actualNode->getNextSib(holdSibling); - holdSibling = actualNode; - actualNode = checkSibling; - } - else - // End of Q-node reached. - endReached = true; - } - - - /* - After processing - the last child of the $Q$-node, this chunk checks, if this child was - part of a pertinent consecutive sequence. If this is the case, the - stack storing this seuquence was not emptied and the number of - pertinent leaves in its frontier was not computed. Furhtermore the - last child was not stored in [[sequence]]. - This chunk does the necessary updates for the last consecutive sequence. - */ - if (!sequence.empty()) - { - aSum = 0; - while (!sequence.empty()) - { - currentNode = sequence.popFrontRet(); - aSum = aSum + currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_h; - if (sequence.size() == 1) - leftSib = currentNode; - } - leftMost = currentNode; - - if (aHoldSum < aSum) - { - aHoldSum = aSum; - leftMostHold = leftMost; - leftSibHold = leftSib; - } - } - /* - After computing - ${\beta}_1$ and ${\beta}_2$, describing the number of pertinent leaves - that have to be deleted when choosing either one node to be an - $a$-node or a complete sequence, this chunk gets the $a$-number of the - $Q$-node [[nodePtr]] by choosing - \[a = \min\{{\beta}_1,{\beta}_2\] - Also set [[aChild]] and [[hChild2]] of [[nodePtr]] according to the - chosen minimum. - */ - beta2 = sumAllW - aHoldSum; - if (beta2 < beta1) - { - nodePtr->getNodeInfo()->userStructInfo()->m_a = beta2; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2 = leftMostHold; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2Sib = leftSibHold; - nodePtr->getNodeInfo()->userStructInfo()->m_aChild = 0; - } - else - { - nodePtr->getNodeInfo()->userStructInfo()->m_a = beta1; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2 = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_hChild2Sib = 0; - nodePtr->getNodeInfo()->userStructInfo()->m_aChild = aChild; - } - -} - - -/************************************************************************ - alpha1beta1Number -************************************************************************/ - -template -int MaxSequencePQTree::alpha1beta1Number( - PQNode *nodePtr, - PQNode **aChild) -{ - /** - * The function alpha1beta1Number() returns - * alpha_1 = beta_1 = sum_{i in P(\a nodePtr)} w_i - max_{i in P(\a nodePtr)}{(w_i = a_i)}, - * where $P(\a nodePtr) denotes the set of all pertinent - * children of the node \a nodePtr regardless whether \a nodePtr is a - * P- or a Q-node. Depicts the a-number if just one - * child of \a nodePtr is made a-node. This child is returned by the function - * alpha1beta1Number() using the pointer \a aChild. - * - * The function uses the following variables. - * - \a sumMaxA = max_{i in P(\a nodePtr)}{(w_i = a_i)}. - * - \a sumAllW = w = sum_{i in P(\a nodePtr)}w_i. - * - \a sumHelp is a help variable. - * - \a currentNode depicts a currently examined pertinent node. - * - * The function uses two while loops over the parial and the full - * children of \a nodePtr. It hereby computes the values \a w and - * max_{i in P(\a nodePtr}{(w_i = a_i)}. - * After finishing the while loops, the function - * alpha1beta1Number() returns the numbers alpha_1 = beta_1 - * and the \a aChild. - */ - - int sumMaxA = 0; - int sumAllW = 0; - int sumHelp = 0; - PQNode *currentNode = 0; - - ListIterator*> it; - for (it = fullChildren(nodePtr)->begin(); it.valid(); it++) - { - currentNode = (*it); - sumAllW = sumAllW + - currentNode->getNodeInfo()->userStructInfo()->m_w; - sumHelp = currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_a; - if (sumMaxA < sumHelp) - { - sumMaxA = sumHelp; - (*aChild) = currentNode; - } - } - - for (it = partialChildren(nodePtr)->begin(); it.valid(); it++) - { - currentNode = (*it); - sumAllW = sumAllW + - currentNode->getNodeInfo()->userStructInfo()->m_w; - sumHelp = currentNode->getNodeInfo()->userStructInfo()->m_w - - currentNode->getNodeInfo()->userStructInfo()->m_a; - if (sumMaxA < sumHelp) - { - sumMaxA = sumHelp; - (*aChild) = currentNode; - } - } - return (sumAllW - sumMaxA); -} - - -/************************************************************************ - sumPertChild -************************************************************************/ - -template -int MaxSequencePQTree::sumPertChild(PQNode *nodePtr) - -{ - /** - * The function sumPertChild() returns \a w = sum_{i in - * P(\a nodePtr)}w_i, where \a nodePTr is any pertinent node of - * the PQ-tree. - * - * The function sunPertChild() uses the following variables. - * - \a it depicts a currently examined pertinent node. - * - \a sum = \a w = sum_{i in P(\a nodePtr)}w_i. - * - * The function uses two for loops over the parial and the full - * children of \a nodePtr. It hereby computes the values $w$ stored in \a sum. - * After finishing the while loops, the function - * sumPertChild() returns the number \a w. - */ - - int sum = 0; - ListIterator*> it; - for (it = fullChildren(nodePtr)->begin(); it.valid(); it++) - sum = sum + (*it)->getNodeInfo()->userStructInfo()->m_w; - for (it = partialChildren(nodePtr)->begin(); it.valid(); it++) - sum = sum + (*it)->getNodeInfo()->userStructInfo()->m_w; - - return sum; -} - - -/************************************************************************************** - GetParent -***************************************************************************************/ - -template -PQNode* MaxSequencePQTree:: -GetParent(PQNode* nodePtr) - -{ - /** - * The function GetParent() computes for the node \a nodePtr its - * parent. The parent pointer is needed during the Bubble() phase. - * - * In case that \a nodePtr has not a valid pointer to its parent, it points to a - * node that is not contained in the tree anymore. Since we do not free - * the memory of such nodes, using the parent pointer of \a nodePtr does - * not cause runtime errors. The previous parent of \a nodePtr itself is - * marked as \a ELIMINATED, denoting a node, that has been removed from - * the tree. Since such a \a nodePtr with a non valid parent pointer can - * only appear somewhere between the children of a Q-node, the function - * GetParent() sweeps through the siblings of \a nodePtr to get a - * valid parent pointer from the endmost child, thereby updating the - * parent pointers of all the - * siblings between the endmost child and \a nodePtr. Since the number - * of children of Q-nodes corresponds to the number of cutvertices in - * the bushform, the total number of children updated by GetParent() is - * in O(n) for every call of Bubble(). Hence the complexity of the - * update procedure is bounded by O(n^2). - */ - - if (nodePtr->parent() == 0) - return 0; - else if (nodePtr->parent()->status() != PQNodeRoot::ELIMINATED) - return nodePtr->parent(); - else - { - PQNode *nextNode = nodePtr; - PQNode *currentNode = 0; - PQNode *oldSib = 0; - SListPure*> L; - - currentNode = nodePtr->getNextSib(0); - oldSib = nodePtr; - L.pushFront(nodePtr); - while (currentNode->parent()->status() == PQNodeRoot::ELIMINATED) - { - L.pushFront(currentNode); - nextNode = currentNode->getNextSib(oldSib); - oldSib = currentNode; - currentNode = nextNode; - } - while (!L.empty()) - L.popFrontRet()->parent(currentNode->parent()); - return currentNode->parent(); - } -} - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PQBasicKey.h b/ext/OGDF/ogdf/internal/planarity/PQBasicKey.h deleted file mode 100644 index 1349c75f9..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQBasicKey.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQBasicKey. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_BASICKEY_H -#define OGDF_PQ_BASICKEY_H - - - -#include -#include - - -namespace ogdf { - -/** - * The class template PQBasicKey is an abstract base class. It enables the user - * of the PQ-tree to store different informations at every node of - * the tree. - * - * The implementation of the PQ-tree provides the storage of three - * different types of information. - * - General information that is stored at P- and Q-nodes and - * leaves likewise (see also PQNodeKey). - * - Information that is only supported for internal nodes (see - * also internalKey). - * - The keys of the leaves (see also leafKey). - * The keys are constructed to carry the - * elements of a user defined set of any type, where permissible - * permutations have to be - * found. In order to use the datastructure PQ-tree as class template - * PQTree, the user has to specify a set of arbitrary elements that - * form the leaves of the PQ-tree. The keys function as storage class - * of the elements of the set. - * - * All three storage classes are derived class templates of - * PQBasicKey. The class PQBasicKey has a pointer \a m_nodePointer to a PQNode, - * beeing either a leaf or an internal - * PQInternalNode. The base class itself does not provide any storage of - * the informations, it is hidden in the derived classes. PQBasicKey - * only declares a few pure virtual functions that are overloaded in - * the derived classes and which give access to the information stored - * in the derived classes. - * - * The information stored in an element of a derived class of - * PQBasicKey is assigned to a unique node in the PQ-tree. This - * unique node can be identified with the \a m_nodePointer. The - * maintenance of this pointer is left to the user in the derived - * concrete classes PQNodeKey and internalKey. By keeping the - * responsibillity for these classes by the client, - * nodes with certain informations can - * be accessed by the client in constant time. This makes - * the adaption of algorithms fast and easy. - * - * Only the derived concrete class template leafKey - * is treated in a different way by the class template PQTree. - * When initializing the PQTree with a set of elements of type leafKey, the - * class template PQTree sets the pointer \a m_nodePointer of every element. - * This is due to the fact that a PQ-tree is always defined over some set, - * whose elements are - * stored in the leaves. Hence the class PQtree expects such a set - * and supports its maintainance. Storing extra information at every - * node may be omitted and makes the PQtree easy applicable. - * - * We now give a short overview of the class template declaration - * PQBasicKey. The class template PQBasicKey is used as a base - * class template that specifies three different types of information. - * The type of information used at a node is depending on the type of - * the node. These - * informations have to be specified by the user. - * - * The formal type parameters of the class template PQBasicKey are - * categorized as follows. - * - \a T is a formal type parameter for the information stored in - * leafKey. - * - \a X is a formal type parameter for the information stored in - * PQNodeKey. - * - \a Y is a formal type parameter for the information stored in - * internalKey. - * - * The class template PQBasicKey contains a few pure virtual member - * functions that are overloaded in the derived class leafKey, - * PQNodeKey and internalKey. These functions enable the client to - * access the information stored at a node. - */ - -template class PQNode; - - - -template -class PQBasicKey: public PQBasicKeyRoot { - -public: - - // Constructor - PQBasicKey() : m_nodePointer(0) { } - - - /** - * The function nodePointer() - * returns a pointer to an element of type - * PQNode. This element can be either of type leaf or - * PQInternalNode. PQBasicKey, or rather its derived classes store - * informations of this PQNode. The user is able identify with the - * help of this function for every information its corresponding node. - * Nevertheless, the private member \a m_nodePointer that stores - * the pointer to this member is not set within the PQ-tree, - * unless it is a derived class template of type leafKey. - * - * Setting the \a m_nodePointer has to be done explicitly by - * the client with the help of the - * function setNodePointer(). - * This offers as much freedom to the - * client as possible, since this enables the client to keep control - * over the informations stored at different nodes and to access - * nodes with specified informations in constant time. - */ - PQNode* nodePointer() { return m_nodePointer; } - - /** - * The function print() is a virtual function, that can be overloaded - * by the user in order to print out the information stored at any of - * the derived classes. Deriving this function, the user can choose any - * format for printing out the information. Currently, the return value - * of the function print() is an empty string. - */ - - virtual ostream &print(ostream &os) { return os; } - - /** - * The function setNodePointer() sets the private member - * \a m_nodePointer. The private member \a m_nodePointer stores the - * address of the corresponding node in the PQTree. - * Using this function enables the client to identify - * certain informations with a node in the PQ-tree. - */ - void setNodePointer(PQNode* node) { m_nodePointer = node; } - - //! Returns the key of a leaf. - virtual T userStructKey() = 0; - - //! Returns the information of any node. - virtual X userStructInfo() = 0; - - //! Returns the information of any internal node. - virtual Y userStructInternal() = 0; - - -private: - - /** Stores the adress of a node. This node has to - * be specified by the client via the function \a setNodePointer. - */ - PQNode* m_nodePointer; - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PQBasicKeyRoot.h b/ext/OGDF/ogdf/internal/planarity/PQBasicKeyRoot.h deleted file mode 100644 index d2a60f542..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQBasicKeyRoot.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQBasicKeyRoot. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_BASIC_KEY_ROOT_H -#define OGDF_PQ_BASIC_KEY_ROOT_H - - - -namespace ogdf { - - - /** - * The class PQBasicKeyRoot is used as a base class of the class template - * basicKey. Using the class PQBasicKeyRoot, a user may - * refer to an information class without the class template structure. - */ - - class PQBasicKeyRoot { - - public: - - //Constructor - PQBasicKeyRoot() { } - - //Destructor - ~PQBasicKeyRoot() { } - - OGDF_NEW_DELETE - }; - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/planarity/PQInternalKey.h b/ext/OGDF/ogdf/internal/planarity/PQInternalKey.h deleted file mode 100644 index c93cbe826..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQInternalKey.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQInternalKey. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_INTERNAL_KEY_H -#define OGDF_PQ_INTERNAL_KEY_H - - -#include -#include - -namespace ogdf { - - -template class PQNode; - -/** - * The class template PQInternalKey is a derived class of class template - * PQBasicKey. PQInternalKey is a concrete class. - * It is constructed to store any kind of information of internal nodes of the - * PQ-tree. It may only be used for internal nodes as P- and - * Q-nodes. This information is not allowed to leaves. - * - * The information is stored in \a m_userStructInternal and - * is assigned to a unique node in the PQ-tree. This - * unique node can be identified with the \a m_nodePointer of the - * astract base class PQBasicKey. The - * maintainance of this pointer is left to the user. By keeping the - * responsibillity by the user, nodes with certain informations can - * be identified and accessed by him in constant time. This makes - * the adaption of algorithms fast and easy. - */ - -template -class PQInternalKey : public PQBasicKey -{ -public: - /** - * The class template PQInternalKey has only one public member: the - * \a m_userStructInternal that has to be overloaded by the client. This - * element is kept public, since the user has to have the opportunity - * to manipulate the information that was stored by his algorithm at a - * node. - */ - Y m_userStructInternal; - - //Constructor - PQInternalKey(Y element) { m_userStructInternal = element; } - - //Destructor - virtual ~PQInternalKey() {} - - //! Overloaded pure virtual function returning 0. - virtual T userStructKey() { return 0; } - - //! Overloaded pure virtual function returning 0. - virtual X userStructInfo() { return 0; } - - //! Overloaded pure virtual function returning \a m_userStructInternal. - virtual Y userStructInternal() { return m_userStructInternal; } -}; - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/planarity/PQInternalNode.h b/ext/OGDF/ogdf/internal/planarity/PQInternalNode.h deleted file mode 100644 index 91b7d5d66..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQInternalNode.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQInternalNode. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_INTERNAL_NODE_H -#define OGDF_PQ_INTERNAL_NODE_H - - - -#include - -namespace ogdf { - - -/** - * The class template PQInternalNode is used to present - * P-nodes and Q-nodes in the PQ-Tree. This implementation does not - * provide different classes for both, P- and Q-nodes, although this might - * seem necessary in the first place. The reason why this is not done, is - * supported by the fact that the maintainance of both nodes in the tree - * is similar and using the same class for P- and Q-nodes - * makes the application of the templates by - * Booth and Lueker much easier. - * - * The template class PQInternalNode offers the possibility of using - * four different kinds of constructors, depending on the usage of - * the different possible information classes PQInternalKey - * and PQNodeKey. - * - * In all four cases the constructor expects an integer value \a count, - * setting the value of the variable \a m_identificationNumber in the base class, - * an integer value \a type setting the variable \a m_type of - * PQInternalNode and an integer value \a status setting the variable \a m_status of - * PQInternalNode. - * - * Besides, the constructors accept additional information of type - * PQNodeKey and PQInternalKey. - * This information is not necessary when allocating an element of type - * PQInternalNode and results in the four constructors that handle all cases. - * - * Using a constructor with the \a infoPtr storing the adress of - * an element of type PQNodeKey automatically sets - * the \a m_nodePointer (see basicKey) of this element of type - * PQNodeKey to the newly allocated PQInternalNode. See also - * PQNode since this is done in the base class. - * - * Using a constructor with the PQInternalKeyPtr storing the adress of - * an element of type PQInternalKey automatically sets - * the \a m_nodePointer (see basicKey) of this element of type - * PQInternalKey to the newly allocated PQInternalNode. -*/ - -template -class PQInternalNode : public PQNode -{ -public: - - PQInternalNode( - int count, - PQNodeRoot::PQNodeType typ, - PQNodeRoot::PQNodeStatus stat, - PQInternalKey* internalPtr, - PQNodeKey* infoPtr) - : PQNode(count,infoPtr) - { - m_type = typ; - m_status = stat; - m_mark = PQNodeRoot::UNMARKED; - - m_pointerToInternal = internalPtr; - internalPtr->setNodePointer(this); - } - - PQInternalNode( - int count, - PQNodeRoot::PQNodeType typ, - PQNodeRoot::PQNodeStatus stat, - PQInternalKey* internalPtr) - : PQNode(count) - { - m_type = typ; - m_status = stat; - m_mark = PQNodeRoot::UNMARKED; - m_pointerToInternal = internalPtr; - internalPtr->setNodePointer(this); - } - - PQInternalNode( - int count, - PQNodeRoot::PQNodeType typ, - PQNodeRoot::PQNodeStatus stat, - PQNodeKey* infoPtr) - : PQNode(count,infoPtr) - { - m_type = typ; - m_status = stat; - m_mark = PQNodeRoot::UNMARKED; - m_pointerToInternal = 0; - } - - PQInternalNode( - int count, - PQNodeRoot::PQNodeType typ, - PQNodeRoot::PQNodeStatus stat) - : PQNode(count) - { - m_type = typ; - m_status = stat; - m_mark = PQNodeRoot::UNMARKED; - m_pointerToInternal = 0; - - } - - /** - * The destructor does not delete any - * accompanying information class as PQLeafKey, - * PQNodeKey and PQInternalKey. - * This has been avoided, since applications may need the existence of - * these information classes after the corresponding node has been - * deleted. If the deletion of an accompanying information class should - * be performed with the deletion of a node, either derive a new class - * with an appropriate destructor, or make use of the function - * CleanNode() of the class template PQTree. - */ - ~PQInternalNode() { } - - - //! Returns 0. An element of type PQInternalNode does not have a PQLeafKey. - virtual PQLeafKey* getKey() const { return 0; } - - /** - * Accepts only pointers \a pointerToKey = 0. - * The function setKey() is designed to set a - * specified pointer variable in a derived class - * of PQNode to the adress stored in \a pointerToKey that is - * of type PQLeafKey. The class template PQInternalNode does not store - * informations of type PQLeafKey. - * - * setKey() ignores the informations as long as - * \a pointerToKey = 0. The return value then is 1. - * In case that \a pointerToKey != 0, the return value is 0. - */ - virtual bool setKey(PQLeafKey* pointerToKey) - { - return (pointerToKey == 0); - } - - //! Returns a pointer to the PQInternalKey information. - virtual PQInternalKey* getInternal() const { return m_pointerToInternal; } - - /** - * setInternal() sets the pointer variable \a m_pointerToInternal to the - * specified adress of \a pointerToInternal that is of type PQInternalKey. - * Observe that \a pointerToInternal has - * to be instantiated by the client. The function setInternal() does - * not instantiate the corresponding variable in the derived class. - * Nevertheless, using this function will automatically set the \a m_nodePointer of the - * element of type PQInternalKey to this PQInternalNode. - * The return value is always 1 unless \a pointerInternal was - * equal to 0. - */ - virtual bool setInternal(PQInternalKey* pointerToInternal) - { - m_pointerToInternal = pointerToInternal; - if (pointerToInternal != 0) - { - m_pointerToInternal->setNodePointer(this); - return true; - } - else - return false; - } - - //! Returns the variable \ m_mark. - /** - * The variable \a m_mark describes the designation used in - * the first pass of Booth and Luekers algorithm called Bubble(). A - * P- or Q-node is either marked \b BLOCKED, \b UNBLOCKED or - * \b QUEUED (see PQNode). - */ - virtual PQNodeRoot::PQNodeMark mark() const { return m_mark; } - - //! Sets the variable \ m_mark. - virtual void mark(PQNodeRoot::PQNodeMark m) { m_mark = m; } - - //! Returns the variable \a m_status in the derived class PQInternalNode. - /** - * The functions manage the status of a node in the PQ-tree. A status is - * any kind of information of the current situation in the frontier of - * a node (the frontier of a node are all descendant leaves of the - * node). A status can be anything such as \b EMPTY, \b FULL or - * \b PARTIAL (see PQNode). Since there might be more than those three - * possibilities, (e.g. in computing planar subgraphs) this - * function may be overloaded by the client. - */ - virtual PQNodeRoot::PQNodeStatus status() const { return m_status; } - - //! Sets the variable \a m_status in the derived class PQInternalNode. - virtual void status(PQNodeRoot::PQNodeStatus s) { m_status = s; } - - //! Returns the variable \a m_type in the derived class PQInternalNode. - /** - * The type of a PQInternalNode is either \b PNode or \b QNode (see - * PQNodeRoot). - */ - virtual PQNodeRoot::PQNodeType type() const { return m_type; } - - //! Sets the variable \a m_type in the derived class PQInternalNode. - virtual void type(PQNodeRoot::PQNodeType t) { m_type = t; } - -private: - - /** - * \a m_mark is a variable, storing if a PQInternalNode is - * \b QUEUEUD, \b BLOCKED or \b UNBLOCKED (see PQNode) - * during the first phase of the procedure Bubble(). - */ - PQNodeRoot::PQNodeMark m_mark; - - - /** - * \a m_pointerToInternal stores the adress of the corresponding - * internal information. That is information not supposed to be - * available for leaves of the PQ-tree. The internal information must - * be of type PQInternalKey. - * The PQInternalKey information can be overloaded by the - * client in order to present different information classes, needed in - * the different applications of PQ-trees. - */ - PQInternalKey* m_pointerToInternal; - - /** - * \a m_status is a variable storing the status of a PQInternalNode. - * A P- or Q-node can be either \b FULL, \b PARTIAL or \b EMPTY - * (see PQNode). - */ - PQNodeRoot::PQNodeStatus m_status; - - /** - * \a m_status is a variable storing the status of a PQInternalNode. - * A P- or Q-node can be either \b FULL, \b PARTIAL or \b EMPTY - * (see PQNode). - */ - PQNodeRoot::PQNodeType m_type; -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PQLeaf.h b/ext/OGDF/ogdf/internal/planarity/PQLeaf.h deleted file mode 100644 index 0b64ef11f..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQLeaf.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQleaf. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_LEAF_H -#define OGDF_PQ_LEAF_H - - - -#include - -namespace ogdf { - - -/** - * The datastructure PQ-tree was designed to present a set of - * permutations on an arbitrary set of elements. These elements are the - * leafs of a PQ-tree. The client has to specify, what kind - * of elements he uses. The element of a node is stored in the PQLeafKey - * of a PQLeaf. The PQLeaf is the only concrete class - * template of the abstract base class template PQNode - * that is allowed to have a key. - */ - -template -class PQLeaf : public PQNode -{ -public: - - /** - * The client may choose between two different constructors. - * In both cases the constructor expects an integer value \a count, - * setting the value of the variable \a m_identificationNumber in the base class, - * an integer value \a status setting the variable \a m_status of - * PQLeaf and a pointer to an element of type PQLeafKey. - * - * One of the constructors expects additional information of type - * PQNodeKey and will automatically set - * the \a m_nodePointer (see basicKey) of the element of type - * PQNodeKey to the newly allocated PQLeaf (see also - * PQNode). The second constructor is called, if no - * information for the PQLeaf is available or necessary. - * Both constructors will automatically set the \a m_nodePointer of the - * \a keyPtr to the newly allocated PQLeaf. - */ - PQLeaf( - int count, - PQNodeRoot::PQNodeStatus stat, - PQLeafKey* keyPtr, - PQNodeKey* infoPtr) - : PQNode(count,infoPtr) - { - m_status = stat; - m_pointerToKey = keyPtr; - m_mark = PQNodeRoot::UNMARKED; - keyPtr->setNodePointer(this); - } - - // Constructor - PQLeaf( - int count, - PQNodeRoot::PQNodeStatus stat, - PQLeafKey* keyPtr) - : PQNode(count) - { - m_status = stat; - m_pointerToKey = keyPtr; - m_mark = PQNodeRoot::UNMARKED; - keyPtr->setNodePointer(this); - } - - /** - * The destructor does not delete any - * accompanying information class as PQLeafKey, - * PQNodeKey and PQInternalKey. - * This has been avoided, since applications may need the existence of - * these information classes after the corresponding node has been - * deleted. If the deletion of an accompanying information class should - * be performed with the deletion of a node, either derive a new class - * with an appropriate destructor, or make use of the function - * CleanNode() of the class template PQTree. - */ - virtual ~PQLeaf() {} - - /** - * getKey() returns a pointer to the PQLeafKey - * of PQLeaf. The adress of the PQLeafKey is stored in the - * private variable \a m_pointerToKey. - * The key contains informations of the element that is represented by - * the PQLeaf in the PQ-tree and is of type PQLeafKey. - */ - virtual PQLeafKey* getKey() const { return m_pointerToKey; } - - /** - * setKey() sets the pointer variable \a m_pointerToKey to the - * specified address of \a pointerToKey that is of type PQLeafKey. - * - * Observe that \a pointerToKey has - * to be instantiated by the client. The function setKey() does - * not instantiate the corresponding variable in the derived class. - * Using this function will automatically set the \a m_nodePointer - * of the element of type key (see PQLeafKey) - * to this PQLeaf. The return value is always 1 unless \a pointerKey - * was equal to 0. - */ - virtual bool setKey(PQLeafKey* pointerToKey) - { - m_pointerToKey = pointerToKey; - if (pointerToKey != 0) - { - m_pointerToKey->setNodePointer(this); - return true; - } - else - return false; - } - - /** - * getInternal() returns 0. The function is designed to - * return a pointer to the PQInternalKey - * information of a node, in case that - * the node is supposed to have internal information. The class - * template PQLeaf does not have PQInternalKey information. - */ - virtual PQInternalKey* getInternal() const { return 0; } - - /** - * setInternal() accepts only pointers \a pointerToInternal = 0. - * - * The function setInternal() is designed to set a - * specified pointer variable in a derived class - * of PQNode to the adress stored in \a pointerToInternal. - * which is of type PQInternalKey. - * The class template PQLeaf does not store - * informations of type PQInternalKey. - * - * setInternal() ignores the informations as long as - * \a pointerToInternal = 0. The return value then is 1. - * In case that \a pointerToInternal != 0, the return value is 0. - */ - virtual bool setInternal(PQInternalKey* pointerToInternal) - { - if (pointerToInternal != 0) - return false; - else - return true; - } - - //! Returns the variable \a m_mark. - /** - * The variable \a m_mark describes the designation used in - * the first pass of Booth and Luekers algorithm called Bubble(). A - * PQLeaf is either marked \b BLOCKED, \b UNBLOCKED or \b QUEUED (see - * PQNode). - */ - virtual PQNodeRoot::PQNodeMark mark() const { return m_mark; } - - //! Sets the variable \a m_mark. - virtual void mark(PQNodeRoot::PQNodeMark m) { m_mark = m; } - - //! Returns the variable \a m_status in the derived class PQLeaf. - /** - * The functions manage the status of a node in the PQ-tree. A status is - * any kind of information of the current situation in the frontier of - * a node (the frontier of a node are all descendant leaves of the - * node). A status can be anything such as \b EMPTY, \b FULL or - * \b PARTIAL (see PQNode). Since there might be more than those three - * possibilities, - * (e.g. in computing planar subgraphs) this - * function may to be overloaded by the client. - */ - virtual PQNodeRoot::PQNodeStatus status() const { return m_status; } - - //! Sets the variable \a m_status in the derived class PQLeaf. - virtual void status(PQNodeRoot::PQNodeStatus s) { m_status = s; } - - //! Returns the variable \a m_type in the derived class PQLeaf. - /** - * The type of a node is either \b PNode, \b QNode or - * \b leaf (see PQNodeRoot). - * Since the type of an element of type PQLeaf is \b leaf every - * input is ignored and the return value will always be \b leaf. - */ - virtual PQNodeRoot::PQNodeType type() const { return PQNodeRoot::leaf; } - - //! Sets the variable \a m_type in the derived class PQLeaf. - virtual void type(PQNodeRoot::PQNodeType) { } - -private: - - /** - * \a m_mark is a variable, storing if the PQLeaf is - * \b QUEUEUD, \b BLOCKED or \b UNBLOCKED (see PQNode) - * during the first phase of the procedure Bubble(). - */ - PQNodeRoot::PQNodeMark m_mark; - - /** - * \a m_pointerToKey stores the adress of the corresponding - * PQLeafKey. - * This PQLeafKey can be overloaded by the - * client in order to represent different sets of elements, where - * possible permutations have to be examined by the PQ-tree. - */ - PQLeafKey* m_pointerToKey; - - /** - * \a m_status is a variable storing the status of a PQLeaf. - * A PQLeaf can be either \b FULL or \b EMPTY (see PQNode). - */ - PQNodeRoot::PQNodeStatus m_status; - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PQLeafKey.h b/ext/OGDF/ogdf/internal/planarity/PQLeafKey.h deleted file mode 100644 index 605591480..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQLeafKey.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQLeafKey. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_LEAF_KEY_H -#define OGDF_PQ_LEAF_KEY_H - - - -#include -#include - -namespace ogdf { - - -template class PQNode; - -/** - * The class template PQLeafKey is a derived class of class template - * PQBasicKey. PQLeafKey is a concrete class. - * - * The class template PQLeafKey is used for carrying the elements of - * a user defined set of any type, where permissible permutations have to be - * found. In order to use the datastructure PQ-tree as class template - * PQTree, the user has to specify a set of arbitrary elements that - * form the leaves of the PQ-tree. - * - * It has to be oberved that leaves have to be treated in almost all - * manipulations of the PQ-tree as all other nodes in the tree. Therefore - * the leaves have the same base class PQNode as the P- or Q-nodes. - * This obviously permits direct manipulation of the leaves in the tree by - * the client. Hence the client cannot overload the leaves by himself in order - * to specify the set of elements that he wants to manipulate. - * - * Therefore the class template PQLeafKey is used. The user is allowed to - * manipulate the class at his will, and he can instantiate any kind template - * class of PQLeafKey.h. - * - * Besides the specification, what kind of element of the observed set is - * carried along, PQLeafKey has a pointer to the leaf - * symbolizing this special element in the PQ-tree. On the other hand, - * a leaf has a pointer to its corresponding PQLeafKey. - * - * After instantiating a various amount of PQLeafKey's, - * the PQ-tree is initialized with this set of PQLeafKey's. Every time - * a subset of elements has to be reduced, the corresponding subset of - * PQLeafKey's is handed over to the PQTree. This enables the class template - * PQTree to identify the corresponing leaves in the tree and - * to start the reduction process. - * - * The class template PQLeafKey is treated in a different way by the - * class template PQTree than all other information - * storage classes derived from PQBasicKey. - * When initializing the PQ-tree, the - * class template PQTree sets the pointer \a m_nodePointer of PQLeafKey - * which is contained in the abstract base class PQBasicKey. - * This pointer identifies a unique leave in the tree that belongs to the information - * stored in a PQLeafKey. The maintainance - * of this pointer is not left to the user. It is managed by the - * PQ-tree but still allows the user to identify and acces leaves - * with a certain informations in constant time. - */ - -template -class PQLeafKey : public PQBasicKey -{ -public: - - /** - * The \a m_userStructKey has to be overloaded by the client. This - * element is kept public, since the user has to have the opportunity - * to manipulate the information that was stored by her algorithm at a - * node. - */ - T m_userStructKey; - - // Constructor - PQLeafKey(T element) - : PQBasicKey() { m_userStructKey = element; } - - //Destructor - virtual ~PQLeafKey() {} - - //! Returns 0. - virtual X userStructInfo() { return 0; } - - //! Returns 0; - virtual Y userStructInternal() {return 0; } - - //! Returns \a m_userStructKey. - virtual T userStructKey() { return m_userStructKey; } - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PQNode.h b/ext/OGDF/ogdf/internal/planarity/PQNode.h deleted file mode 100644 index e8e9eaede..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQNode.h +++ /dev/null @@ -1,651 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQNode. - * - * This file contains the header for the class template PQNode. The - * class template PQNode is used as an abstract base class for all - * nodes in a PQ-tree. The derived classes are a class template for - * Q- and P-nodes internalNodes (PQInternalNode) and a class template - * PQLeaf for the leaves of the tree. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_NODE_H -#define OGDF_PQ_NODE_H - - -#include -#include - - -namespace ogdf { - - -template class PQTree; -template class PQLeafKey; -template class PQNodeKey; -template class PQInternalKey; - - -template class PQNode: public PQNodeRoot -{ - /** - * All members and member function of PQNode are needed - * by the class template PQTree. Therefore the class PQTree - * was made friendof PQNode, since this prevents the use of a large - * amount of extra public functions. - */ - friend class PQTree; - -public: - - /** - * The (first) constructor combines the node with its information and - * will automatically set the \a m_nodePointer (see basicKey) of - * the element of type PQNodeKey. - */ - PQNode(int count, PQNodeKey* infoPtr); - - - /** - * The (second) constructor is called, - * if no information is available or neccessary. - */ - PQNode(int count); - - /** - * The destructor does not delete any accompanying information class as PQLeafKey, - * PQNodeKey and PQInternalKey. This has been avoided, since applications may - * need the existence of these information classes after the corresponding node - * has been deleted. If the deletion of an accompanying information class should - * be performed with the deletion of a node, either derive a new class - * with an appropriate destructor, or make use of the function - * CleanNode() of the class template PQTree. - */ - virtual ~PQNode() - { - delete fullChildren; - delete partialChildren; - } - - /** - * The function changeEndmost() replaces the old endmost child \a oldEnd - * of the node by a new child \a newEnd. - * If the node is a Q-node, then it must have two valid - * pointers to its endmost children. If one of the endmost children is - * \a oldEnd, it is replaced by \a newEnd. - * The function changeEndmost() returns 1 if it succeeded in - * replacing \a oldEnd by \a newEnd. Otherwise the function returns - * 0, leaving with an error message. - */ - bool changeEndmost(PQNode* oldEnd, PQNode* newEnd); - - /** - * The function changeSiblings() replaces the old sibling \a oldSib of the - * node by a new sibling \a newSib. - * If the node has \a oldSib as sibling, then it changes the - * sibling pointer that references to \a oldSib and places \a newSib - * at its position. - * The function changeSiblings() returns 1 if it succeeded in - * replacing \a oldSib by \a newSib. Otherwise the function returns - * 0, leaving with an error message. - */ - bool changeSiblings(PQNode* oldSib, PQNode* newSib); - - /** - * The function endmostChild() checks if a node is endmost child of - * a Q-node. This is 1 if one of the sibling pointers \a m_sibLeft - * or \a m_sibRight is 0. If the node is endmost child of a Q-node, - * then it has a valid parent pointer. - */ - bool endmostChild() { - return (m_sibLeft == 0 || m_sibRight == 0); - } - - /** - * Returns one of the endmost children of node, if node is a Q-node. - * The function getEndmost() accepts as input a pointer to a - * PQNode stored in \a other. The returned endmost child is unequal - * to the one specified in \a other. In case that an arbitrary endmost child - * should be looked up, set \a other = 0. This makes the function - * getEndmost() return an arbitrary endmost child (it returns the - * left endmost child). - */ - PQNode* getEndmost(PQNode* other) const { - if (m_leftEndmost != other) - return m_leftEndmost; - else if (m_rightEndmost != other) - return m_rightEndmost; - - return 0; - } - - /** - * Returns one of the endmost children of node, if node is a Q-node. - * The function accepts an integer denoting a direction causing the - * function to return either the left or the endmost child. - */ - PQNode* getEndmost(int side) const { - if (side == LEFT || side == 0) - return m_leftEndmost; - else if(side == RIGHT) - return m_rightEndmost; - - return 0; - } - - //! Returns the identification number of a node. - PQNodeKey* getNodeInfo() const { return m_pointerToInfo; } - - /** - * The function getSib() returns one of the siblings of the node. - * It accepts an integer denoting a dircetion causing the - * function to return either the left or the right sibling. - */ - PQNode* getSib(int side) const { - if (side == LEFT) - return m_sibLeft; - else if (side == RIGHT) - return m_sibRight; - - return 0; - } - - /** - * The function getNextSib() returns one of the siblings of the node. - * The function getNextSib() accepts as input a pointer to a - * PQNode stored in \a other. The returned sibling is unequal to the - * one specified in \a other. In case - * that no sibling has been looked up before, set \a other = 0. - * This makes the function getNextSib() return an arbitrary sibling - * (it returns the left sibling). - */ - PQNode* getNextSib(PQNode* other) const { - if (m_sibLeft != other) - return m_sibLeft; - else if (m_sibRight != other) - return m_sibRight; - - return 0; - } - - - //! Returns the identification number of a node. - int identificationNumber() const { return m_identificationNumber; } - - //! Returns the number of children of a node. - int childCount() const { return m_childCount; } - - //! Sets the number of children of a node. - void childCount(int count) { m_childCount = count; } - - /** - * The function parent() returns a pointer to the parent of a node. - * - * \warning After reducing the PQ-tree, some nodes may not have - * valid parent pointers anymore. This is no fault, the datastructur - * was designed this way. See also Booth and Lueker. - */ - PQNode* parent() const { return m_parent; } - - /** - * Sets the parent pointer of a node. This function - * is needed in more ellaborated algorithms implemented as derivation of - * the class template PQTree. Here, the parent pointer probably is - * always needed and therefore has to be set within special functions, - * used in a pre-run before applying the bubble Phase of the PQTree. - */ - PQNode* parent(PQNode* newParent) - { - return m_parent = newParent; - } - - //! Returns the type of the parent of a node. - int parentType() const { return m_parentType; } - - /** - * Sets the type of the parent of a node. - * This does not change the type of the parent! - */ - void parentType(int newParentType) { m_parentType = newParentType; } - - //! Returs the number of pertinent children of a node. - int pertChildCount() const { return m_pertChildCount; } - - //! Sets the number of pertinent children of a node. - void pertChildCount(int count) { m_pertChildCount = count; } - - /** - * The default function putSibling() - * stores a new sibling at a free sibling pointer - * of the node. This is only possible, if the node has at most one sibling. - * The function then detects a non used sibling pointer and places \a newSib - * onto it. putSibling() returns 0 if there have been two siblings - * detected, occupying the two possible pointers. In this case the new sibling - * \a newSib cannot be stored. If there was at a maximum one sibling stored, - * the function will place \a newSib on the free pointer and return either - * \a LEFT or \a RIGHT, depending wich pointer has been used. - * - * This function will always scan the pointer to the left brother first. - */ - SibDirection putSibling(PQNode* newSib) - { - if (m_sibLeft == 0) { - m_sibLeft = newSib; - return LEFT; - } - - OGDF_ASSERT(m_sibRight == 0); - m_sibRight = newSib; - return RIGHT; - } - - /** - * The function putSibling() - * with preference stores a new sibling at a free sibling pointer - * of the node. This is only possible, if the node has at most one sibling. - * The function then detects a non used sibling pointer and places \a newSib - * onto it. putSibling() returns 0 if there have been two siblings - * detected, occupying the two possible pointers. In this case the new sibling - * \a newSib could not be stored. If there was at a maximum one sibling - * stored, the function will place \a newSib on the free pointer and - * return either \a LEFT or \a RIGHT, depending wich pointer has been used. - * - * This function scans the brother first, which has been specified in the - * preference. If the preference has value \a LEFT, it scans the pointer - * to the left brother first. If the value is \a RIGHT, it scans the pointer - * to the right brother first. - */ - SibDirection putSibling(PQNode* newSib, int preference) - { - if (preference == LEFT) - return putSibling(newSib); - - OGDF_ASSERT(preference == RIGHT); - - if (m_sibRight == 0) - { - m_sibRight = newSib; - return RIGHT; - } - - OGDF_ASSERT(m_sibLeft == 0); - m_sibLeft = newSib; - return LEFT; - } - - //! Returns a pointer to the reference child if node is a P-node. - PQNode* referenceChild() const { return m_referenceChild; } - - //! Returns the pointer to the parent if node is a reference child. - PQNode* referenceParent() const { return m_referenceParent; } - - //! Sets the pointer \a m_pointerToInfo to the specified adress of \a pointerToInfo. - bool setNodeInfo(PQNodeKey* pointerToInfo) { - m_pointerToInfo = pointerToInfo; - if (pointerToInfo != 0) - { - m_pointerToInfo->setNodePointer(this); - return true; - } - - return false; - } - - /** - * getKey() returns a pointer to the PQLeafKeyof a node, in case that - * the node is supposed to have a key, such as elements of the derived - * class template PQLeaf. - * The key contains information and is of type PQLeafKey. - */ - virtual PQLeafKey* getKey() const = 0; - - //! Sets a specified pointer variable in a derived class to the specified adress of \a pointerToKey that is of type PQLeafKey. - /** - * If a derived class, such as PQInternalNode, is not supposed to store - * informations of type PQLeafKey, setKey() ignores the informations as long as - * \a pointerToKey = 0. The return value then is 1. - * In case that \a pointerToKey != 0, the return value is 0. - * - * If a derived class, such as PQLeaf is supposed to - * store informations of type PQLeafKey, \a pointerToKey - * has to be instantiated by the client. The function setKey() does - * not instantiate the corresponding variable in the derived class. - * The return value is always 1 unless \a pointerKey was equal to 0. - */ - virtual bool setKey(PQLeafKey* pointerToKey) = 0; - - /** - * getInternal() returns a pointer to the PQInternalKey - * information of a node, in case that - * the node is supposed to have PQInternalKey information, - * such as elements of the derived class template PQInternalNode. - * The internal information is of type PQInternalKey. - */ - virtual PQInternalKey* getInternal() const = 0; - - /* - * setInternal() sets a specified pointer variable in a derived class - * to the specified adress of \a pointerToInternal that is of type - * PQInternalKey. - * - * If a derived class, such as PQLeaf, - * is not supposed to store informations of type PQInternalKey, - * setInternal() ignores the informations as long as - * \a pointerToInternal = 0. The return value then is 1. - * In case that \a pointerToInternal != 0, the return value is 0. - * - * If a derived class, such as PQInternalNode is - * supposed to store informations of type PQInternalKey, - * \a pointerToInternal has to be instantiated by the client. The - * function setInternal() does - * not instantiate the corresponding variable in the derived class. - * The return value is always 1 unless \a pointerInternal was - * equal to 0. - */ - virtual bool setInternal(PQInternalKey* pointerToInternal) = 0; - - /** - * mark() returns the variable \a m_mark in the - * derived class PQLeaf and PQInternalNode. - * In a derived class this function has to return the designation used in - * the first pass of Booth and Luekers algorithm called Bubble(). A - * node then is either marked \a BLOCKED, \a UNBLOCKED or \a QUEUED (see PQNode). - */ - virtual PQNodeMark mark() const = 0; - - //! mark() sets the variable \a m_mark in the derived class PQLeaf and PQInternalNode. - virtual void mark(PQNodeMark) = 0; - - //! Returns the variable \a m_status in the derived class PQLeaf and PQInternalNode. - /** - * Its objective is to manage - * status of a node in the PQ-tree. A status is - * any kind of information of the current situation in the frontier of - * a node (the frontier of a node are all descendant leaves of the - * node). A status is anything such as \a EMPTY, \a FULL or - * \a PARTIAL (see PQNode). Since there might be more than those three possibilities, - * (e.g. in computing planar subgraphs this - * function probably has to be overloaded by the client. - */ - virtual PQNodeStatus status() const = 0; - - //! Sets the variable \a m_status in the derived class PQLeaf and PQInternalNode. - virtual void status(PQNodeStatus) = 0; - - //! Returns the variable \a m_type in the derived class PQLeaf and PQInternalNode. - /** - * Its objective it to manage the type of a node. - * node the current node is. The type of a node in the class template - * PQTree is either \a PNode, \a QNode or \a leaf (see PQNode). - * There may be of course more types such as sequence indicators. - * - * Observe that the derived class template PQLeaf does - * not have a variable \a m_type, since it obviously is of type \a leaf. - */ - virtual PQNodeType type() const = 0; - - //! Sets the variable \a m_type in the derived class PQLeaf and PQInternalNode. - virtual void type(PQNodeType) = 0; - - -protected: - - - // Stores the number of children of the node. - int m_childCount; - - /** - * Needed for debuging - * purposes. The PQ-trees can be visualized with the help of the Tree - * Interface and the \a m_debugTreeNumber is needed to print out the - * tree in the correct file format. - */ - int m_debugTreeNumber; - - /** - * Each node that has been introduced once into - * the tree gets a unique number. If the node is removed from the - * tree during a reduction or with the help of one of the functions - * that is provided by the class template PQtree, its number is not reused. - * This always allows exact identification of nodes - * during any process that is envoked on the PQ-tree. We strongly - * recommend users who construct the tree with the help of the - * construction functions and who instantiate the nodes by them selves - * to do the same. - */ - int m_identificationNumber; - - //! Stores the type of the parent which can be either a P- or Q-node. - int m_parentType; - - //! Stores the number of pertinent children of the node. - int m_pertChildCount; - - //! Stores the number of pertinent leaves in the frontier of the node. - int m_pertLeafCount; - - //! Stores a pointer to the first full child of a Q-node. - PQNode *m_firstFull; - - PQNode *m_leftEndmost; - - /** - * Is a pointer to the parent. Observe that this - * pointer may not be up to date after a few applications of the - * reduction. - */ - PQNode *m_parent; - - /** - * Stores a pointer to one child, the reference child of the - * doubly linked cirkular list of children of a - * P-node. With the help of this pointer, it is possible to access - * the children of the P-node - */ - PQNode *m_referenceChild; - - /** - * Is a pointer to the parent, in case that the - * parent is a P-node and the node itself is its reference child. - * The pointer is needed in order to identify the reference child - * among all children of a P-node. - */ - PQNode *m_referenceParent; - - //! Stores the right endmost child of a Q-node. - PQNode *m_rightEndmost; - - /** - * Stores a pointer ot the left sibling of PQNode. - * If PQNode is child of a Q-node and has no left sibling, - * \a m_sibLeft is set to 0. If PQNode is child of a P-node, - * all children of the P-node are linked in a cirkular list. In the - * latter case, \a m_sibLeft is never 0. - */ - PQNode *m_sibLeft; - - /** - * Stores a pointer ot the right sibling of PQNode. - * If PQNode is child of a Q-node and has no right sibling, - * \ m_sibRight is set to 0. If PQNode is child of a P-node, - * all children of the P-node are linked in a cirkular list. In the - * latter case, \a m_sibRight is never 0. - */ - PQNode *m_sibRight; - - //! Stores a pointer to the corresponding information of the node. - PQNodeKey *m_pointerToInfo; - - - //! Stores all full children of a node during a reduction. - List*> *fullChildren; - - //! Stores all partial children of a node during a reduction. - List*> *partialChildren; - -}; - - -/* -The function [[changeEndmost]] replaces the old endmost child [[oldEnd]] of -the node by a new child [[newEnd]]. -If the node is a $Q$-node, then it must have two valid -pointers to its endmost children. If one of the endmost children is [[oldEnd]], -it is replaced by [[newEnd]]. -The function [[changeEndmost]] returns [[1]] if it succeeded in -replacing [[oldEnd]] by [[newEnd]]. Otherwise the function returns -[[0]], leaving with an error message. -*/ -template -bool PQNode::changeEndmost(PQNode* oldEnd, PQNode* newEnd) -{ - if (m_leftEndmost == oldEnd) - { - m_leftEndmost = newEnd; - return true; - } - else if (m_rightEndmost == oldEnd) - { - m_rightEndmost = newEnd; - return true; - } - return false; -} - -/* -The function [[changeSiblings]] replaces the old sibling [[oldSib]] of the -node by a new sibling [[newSib]]. - -If the node has [[oldSib]] as sibling, then it changes the -sibling pointer that references to [[oldSib]] and places [[newSib]] -at its position. - -The function [[changeSiblings]] returns [[1]] if it succeeded in replacing -[[oldSib]] by [[newSib]]. Otherwise the function returns -[[0]], leaving with an error message. -*/ -template -bool PQNode::changeSiblings(PQNode* oldSib, PQNode* newSib) -{ - if (m_sibLeft == oldSib) - { - m_sibLeft = newSib; - return true; - } - else if (m_sibRight == oldSib) - { - m_sibRight = newSib; - return true; - } - return false; -} - - -/* -The (first) constructor combines the node with its information and -will automatically set the [[m_nodePointer]] (see \ref{basicKey}) of -the element of type [[PQNodeKey]] (see \ref{PQNodeKey}). -*/ -template -PQNode::PQNode(int count,PQNodeKey* infoPtr) -{ - m_identificationNumber = count; - m_childCount = 0; - m_pertChildCount = 0; - m_pertLeafCount = 0; - m_debugTreeNumber = 0; - m_parentType = 0; - - m_parent = 0; - m_firstFull = 0; - m_sibLeft = 0; - m_sibRight = 0; - m_referenceChild = 0; - m_referenceParent = 0; - m_leftEndmost = 0; - m_rightEndmost = 0; - - fullChildren = OGDF_NEW List*>; - partialChildren = OGDF_NEW List*>; - - m_pointerToInfo = infoPtr; - infoPtr->setNodePointer(this); -} - - -/* -The (second) constructor is called, -if no information is available or neccessary. -*/ -template -PQNode::PQNode(int count) -{ - m_identificationNumber = count; - m_childCount = 0; - m_pertChildCount = 0; - m_pertLeafCount = 0; - m_debugTreeNumber = 0; - m_parentType = 0; - - m_parent = 0; - m_firstFull = 0; - m_sibLeft = 0; - m_sibRight = 0; - m_referenceChild = 0; - m_referenceParent = 0; - m_leftEndmost = 0; - m_rightEndmost = 0; - - fullChildren = OGDF_NEW List*>; - partialChildren = OGDF_NEW List*>; - - m_pointerToInfo = 0; -} - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/planarity/PQNodeKey.h b/ext/OGDF/ogdf/internal/planarity/PQNodeKey.h deleted file mode 100644 index 32116c835..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQNodeKey.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQNodeKey. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_NODE_KEY_H -#define OGDF_PQ_NODE_KEY_H - - - -#include -#include - -namespace ogdf { - - -template class PQNode; - -/** - * The class template PQNodeKey is a derived class of class template - * PQBasicKey. PQNodeKey is a concrete class. - * It is constructed to store any kind of information of nodes of the - * PQ-tree. It may be used for both internal nodes as well as leaves. - * - * The information is stored in \a m_userStructInfo and - * is assigned to a unique node in the PQ-tree. This - * unique node can be identified with the \a m_nodePointer of the - * astract base class PQBasicKey. The - * maintainance of this pointer is left to the user. By keeping the - * responsibillity by the user, nodes with certain informations can - * be identified and accessed by her in constant time. This makes - * the adaption of algorithms fast and easy. - */ - -template -class PQNodeKey : public PQBasicKey -{ -public: - - //! Stores the information. Has to be overloaded by the client. - X m_userStructInfo; - - // Constructor - PQNodeKey(X info):PQBasicKey() { m_userStructInfo = info; } - - // Destructor - virtual ~PQNodeKey() { } - - //! Returns 0. - virtual T userStructKey() { return 0; } - - //! Returns \a m_userStructInfo. - virtual X userStructInfo() { return m_userStructInfo; } - - //! Returns 0. - virtual Y userStructInternal() { return 0; } -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PQNodeRoot.h b/ext/OGDF/ogdf/internal/planarity/PQNodeRoot.h deleted file mode 100644 index 18955d22c..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQNodeRoot.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQNodeRoot. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_NODE_ROOT_H -#define OGDF_PQ_NODE_ROOT_H - - - -namespace ogdf { - - -/** - * The class PQNodeRoot is used as a base class of the class - * PQNode. Using the class PQNodeRoot, a user may - * refer to a node without the class structure. - */ - -class PQNodeRoot { - -public: - enum PQNodeType { PNode = 1, QNode = 2, leaf = 3 }; - - enum SibDirection { NODIR, LEFT, RIGHT }; - - // Status Definitions - enum PQNodeStatus { - EMPTY = 1, - PARTIAL = 2, - FULL = 3, - PERTINENT = 4, - TO_BE_DELETED = 5, - - // Extra node status defines - INDICATOR = 6, - ELIMINATED = 6, //!< Nodes removed durign the template reduction are marked as - //!< as ELIMINATED. Their memory is not freed. They are kept - //!< for parent pointer update. - WHA_DELETE = 7, //!< Nodes that need to be removed in order to obtain a - //!< maximal pertinent sequence are marked WHA_DELETE. - PERTROOT = 8 //!< The pertinent Root is marked PERTROOTduring the clean up - //!< after a reduction. Technical. - }; - - // Mark Definitions for Bubble Phase - enum PQNodeMark { UNMARKED = 0, QUEUED = 1, BLOCKED = 2, UNBLOCKED = 3 }; - - - PQNodeRoot() { } - virtual ~PQNodeRoot() { } - - OGDF_NEW_DELETE -}; - -} - -#endif - diff --git a/ext/OGDF/ogdf/internal/planarity/PQTree.h b/ext/OGDF/ogdf/internal/planarity/PQTree.h deleted file mode 100644 index d271675e2..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PQTree.h +++ /dev/null @@ -1,3968 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the class PQTree. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PQ_TREE_H -#define OGDF_PQ_TREE_H - - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -template - -class PQTree -{ -public: - - PQTree(); - - /** - * The function shown here is the destructor of the class template PQTree. - * In order to free allocated memory, all nodes of the - * tree have to be deleted, hence their destructors have to be called. - * This is done in the function Cleanup(). - * Furthermore all other initialized memory has to be freed which is - * done as well in the function Cleanup(). - */ - virtual ~PQTree() { Cleanup(); } - - bool addNewLeavesToTree( - PQInternalNode *father, - SListPure*> &leafKeys); - - void emptyNode(PQNode* nodePtr); - - virtual void front( - PQNode* nodePtr, - SListPure*> &leafKeys); - - virtual void CleanNode(PQNode* /* nodePtr */) { } - - virtual void Cleanup(); - - /** - * If the user wishes to use different flags in a derived class of PQTree - * that are not available in this implementation, he can overload the function - * clientDefinedEmptyNode() in order to make a valid cleanup of the nodes. - * It will be called per default by the function emptyAllPertinentNodes(). - */ - virtual void clientDefinedEmptyNode(PQNode* nodePtr) { - emptyNode(nodePtr); - } - - virtual void emptyAllPertinentNodes(); - - virtual int Initialize(SListPure*> &leafKeys); - - virtual bool Reduction(SListPure*> &leafKeys); - - /** - * The function root() returns a pointer of the root node of the PQTree. - */ - PQNode* root() const { - return m_root; - } - - void writeGML(const char *fileName); - void writeGML(ostream &os); - - -protected: - - - //! is a pointer to the root of the $PQ$-tree. - PQNode* m_root; - - //! is a pointer to the root of the pertinent subtree. - PQNode* m_pertinentRoot; - - //! is a pointer to the virtual root of the pertinent subtree, in case that the pertinent root cannot be detected. - PQNode* m_pseudoRoot; - - //! Stores the total number of nodes that have been allocated. - /** - * Gives every node that has been used once in the - * PQ-tree a unique identification number. - */ - int m_identificationNumber; - - //! Stores the number of leaves. - int m_numberOfLeaves; - - /** - * Stores all nodes that have been marked \b FULL or - * \b PARTIAL during a reduction. After the reduction has been - * finished succesfully, all pertinent nodes are reinitialized and - * prepared for the next reduction. This list also contains pertinent - * nodes that have been removed during a reduction. When detected in - * the stack, their memory is freed. - */ - List*> *m_pertinentNodes; - - - virtual bool Bubble(SListPure*> &leafKeys); - - virtual bool Reduce(SListPure*> &leafKeys); - - virtual bool templateL1(PQNode *nodePtr, bool isRoot); - - virtual bool templateP1(PQNode *nodePtr, bool isRoot); - - virtual bool templateP2(PQNode **nodePtr); - - virtual bool templateP3(PQNode *nodePtr); - - virtual bool templateP4(PQNode **nodePtr); - - virtual bool templateP5(PQNode *nodePtr); - - virtual bool templateP6(PQNode **nodePtr); - - virtual bool templateQ1(PQNode *nodePtr, bool isRoot); - - virtual bool templateQ2(PQNode *nodePtr, bool isRoot); - - virtual bool templateQ3(PQNode *nodePtr); - - - - virtual bool addNodeToNewParent( - PQNode* parent, - PQNode* child); - - virtual bool addNodeToNewParent( - PQNode* parent, - PQNode* child, - PQNode* leftBrother, - PQNode* rightBrother); - - virtual bool checkIfOnlyChild( - PQNode *child, - PQNode *parent); - - /** - * The function destroyNode() marks a node as TO_BE_DELETED. This - * enables the function emptyAllPertinentNodes() - * to remove the node and free its memory. - */ - virtual void destroyNode(PQNode *nodePtr) { - nodePtr->status(PQNodeRoot::TO_BE_DELETED); - } - - virtual void exchangeNodes( - PQNode *oldNode, - PQNode *newNode); - - virtual void linkChildrenOfQnode( - PQNode *installed, - PQNode *newChild); - - virtual void removeChildFromSiblings(PQNode* nodePtr); - - virtual int removeNodeFromTree( - PQNode* parent, - PQNode* child); - - - List*>* fullChildren(PQNode* nodePtr) { - return nodePtr->fullChildren; - } - - - List*>* partialChildren(PQNode* nodePtr) { - return nodePtr->partialChildren; - } - - virtual PQNode* clientLeftEndmost(PQNode* nodePtr) const { - return nodePtr->m_leftEndmost; - } - - virtual PQNode* clientRightEndmost(PQNode* nodePtr) const { - return nodePtr->m_rightEndmost; - } - - virtual PQNode* clientNextSib(PQNode* nodePtr, - PQNode* other) const { - return nodePtr->getNextSib(other); - } - - virtual PQNode* clientSibLeft(PQNode* nodePtr) const { - return nodePtr->m_sibLeft; - } - - virtual PQNode* clientSibRight(PQNode* nodePtr) const { - return nodePtr->m_sibRight; - } - - virtual int clientPrintNodeCategorie(PQNode* nodePtr); - - virtual const char* clientPrintStatus(PQNode* nodePtr); - - virtual const char* clientPrintType(PQNode* nodePtr); - -private: - - bool checkChain( - PQNode *nodePtr, - PQNode *firstFull, - PQNode **seqStart, - PQNode **seqEnd); - - void copyFullChildrenToPartial( - PQNode *nodePtr, - PQNode *partialChild); - - PQNode* createNodeAndCopyFullChildren(List*> *fullNodes); - - void printNode( - char *filename, - int number, - PQNode* father, - PQNode* son); - - void removeBlock(PQNode *nodePtr, bool isRoot); - - void sortExceptions(int Exceptions[], int arraySize); -}; - - - -/************************************************************************ - addNewLeavesToTree -************************************************************************/ - -/** - * The function addNewLeavesToTree() adds a set of elements to the already - * existing set of elements of a PQ-tree. - * These elements have to be of type PQLeafKey - * and are handed to the function in an array leafKeys. - * The father of the new elements that has to be an existing P- or Q-node, - * has to be specified and is not allowed to have children. - * - * The above mentioned facts - * are checked by the function addNodeToNewParent() and the process - * of adding a child to parent is interrupted with an error message - * returning 0 as soon none of the facts is fullfilled. - * The function addNewLeavesToTree() returns 1 if it - * succeeded in adding the leaves to parent. - */ - -template -bool PQTree::addNewLeavesToTree( - PQInternalNode *father, - SListPure*> &leafKeys) -{ - if (!leafKeys.empty()) - { - OGDF_ASSERT(!father->m_childCount) - // Father has children. Brothers expected - - /// Enter the first element as PQLeaf to the [[parent]]. - SListIterator*> it = leafKeys.begin(); - PQLeafKey* newKey = *it; //leafKeys[0]; - - PQNode* aktualSon = OGDF_NEW PQLeaf(m_identificationNumber++,PQNodeRoot::EMPTY,newKey); - PQNode* firstSon = aktualSon; - firstSon->m_parent = father; - firstSon->m_parentType = father->type(); - father->m_childCount++; - PQNode* oldSon = firstSon; - - /// Enter all other elements as leaves to [[parent]]. - for (++it; it.valid(); ++it) - { - newKey = *it; //leafKeys[i]; - aktualSon = OGDF_NEW PQLeaf(m_identificationNumber++, - PQNodeRoot::EMPTY,newKey); - aktualSon->m_parent = father; - aktualSon->m_parentType = father->type(); - father->m_childCount++; - oldSon->m_sibRight = aktualSon; - aktualSon->m_sibLeft = oldSon; - oldSon = aktualSon; - } - if (father->type() == PQNodeRoot::PNode) - /// Set the reference pointers if [[parent]] is a $P$-node. - { - firstSon->m_sibLeft = oldSon; - oldSon->m_sibRight = firstSon; - father->m_referenceChild = firstSon; - firstSon->m_referenceParent = father; - } - else if (father->type() == PQNodeRoot::QNode) - /// Set the endmost children if [[parent is a $Q$-node. - { - father->m_leftEndmost = firstSon; - father->m_rightEndmost = oldSon; - } - return true; - } - - return false; -} - - - -/************************************************************************ - addNodeToNewParent -************************************************************************/ - -/** - * The function addNodeToNewParent() adds a node \a child as a child - * to another node specified in \a parent. - * The \a parent of the new node has to be an existing P- or Q-node and - * is \b not allowed to have children. - * In the case, that \a parent has children, addNewNodeToParent() - * returns 0 printing an error-message. - * In this case, use the function addNodeToParent() while specifying the future - * siblings of \a child. See addNodeToNewParent2() for more - * details. - * - * After successfully inserting \a child to \a parent the function - * addNewNodeToParent() returns 1. Otherwise it returns - * 0. - */ - -template -bool PQTree::addNodeToNewParent( - PQNode* parent, - PQNode* child) -{ - OGDF_ASSERT(parent->type() == PQNodeRoot::PNode && parent->type() == PQNodeRoot::QNode) - //parent type not valid. - - if (child != 0) - { - OGDF_ASSERT(parent->m_childCount == 0) - //when adding new nodes: Brothers expected. - child->m_parent = parent; - child->m_parentType = parent->type(); - parent->m_childCount++; - - /* - Set the reference pointers in case that [[parent]] is a $P$-node. - If [[parent]] is a $Q$-node, this chunk sets the endmost children - of [[parent]]. Since [[child]] is the only child of [[parent]] - both endmost pointers are set to [[child]]. - */ - if (parent->type() == PQNodeRoot::PNode) - { - child->m_sibLeft = child; - child->m_sibRight = child; - parent->m_referenceChild = child; - child->m_referenceParent = parent; - } - else if (parent->type() == PQNodeRoot::QNode) - { - parent->m_leftEndmost = child; - parent->m_rightEndmost = child; - } - - return true; - } - - return false; -} - - -/************************************************************************ - addNodeToNewParent -************************************************************************/ - -/** - * The function addNodeToNewParent() adds a node \a child to the children - * of another node specified in \a parent. - * The \a parent of the new node has to be an existing P- or Q-node and - * is allowed to have children. In case that \a parent has children, - * the siblings of the new introduced child must be specified. - * If no siblings are specified, the function addNodeToNewParent(PQNode*,PQNode*) - * is called by default. - * If the \a parent is not specified, the function assumes that - * \a child is added as interior child to a Q-node. - * - * The client of this function should observe the following facts: - * - If \a parent is a P-node, than only one sibling is needed in order - * to enter the \a child. If the client specifies two siblings in \a leftBrother - * and \a rightBrother, then an arbitrary one is choosen to be a sibling. - * - If \a parent is a Q-node, two siblings must be specified if - * \a child has to become an interior child of the Q-node. If just - * one sibling is specified, this implies that \a child is about to become - * a new endmost child of \a parent. So either \a leftBrother or - * \a rightBrother must store an existing endmost child of \a parent. - * - If \a parent is a zero pointer, addNodeToNewParents() assumes - * that \a child is added as interior child to a Q-node. In this - * case \b both siblings of \a child have to be specified. Observe - * however, that it is also legal to specify the parent in this case. - * - * The above mentioned facts - * are checked by the function addNodeToNewParent() and the process - * of adding a child to \a parent is interrupted with an error message - * returning 0 as soon - * none of the facts is fullfilled. - * The function addNodeToNewParent() returns 1 if it - * succeeded in adding the \a child to \a parent. -*/ - -template -bool PQTree::addNodeToNewParent( - PQNode* parent, - PQNode* child, - PQNode* leftBrother, - PQNode* rightBrother) -{ - - if (parent != 0) - { - OGDF_ASSERT(parent->type() == PQNodeRoot::PNode || parent->type() == PQNodeRoot::QNode) - //parent type not valid - if ((leftBrother == 0) && (rightBrother == 0)) - return addNodeToNewParent(parent,child); - else if (child != 0) - { - child->m_parent = parent; - child->m_parentType = parent->type(); - parent->m_childCount++; - - if (parent->type() == PQNodeRoot::PNode) - { - /* - The parent is a $P$-node with children. - Either [[leftBrother]] or [[rightBrother]] stores - a pointer to an existing child of [[parent]] and [[parent]] - is a $P$-node. In case that two brothers are stored, an - arbitrary one is choosen to be the next sibling of [[child]]. - This brother is stored in [[brother]]. The pointer [[sister]] - denotes a pointer to an arbitrary sibling of [[brother]]. - */ - PQNode* brother = (leftBrother != 0) ? leftBrother : rightBrother; - PQNode* sister = brother->m_sibRight; - child->m_sibLeft = brother; - child->m_sibRight = sister; - brother->m_sibRight = child; - sister->m_sibLeft = child; - return true; - } - - else if (leftBrother == 0) - { - /* - The parent is a $Q$-node with children. - The [[leftBrother]] is a [[0]]-pointer while the - [[rightBrother]] denotes an existing child of [[parent]]. - The node [[rightBrother]] {\bf must be} one of the two endmost - children of [[parent]]. If this is not the case, the chunk - detects this, halts the procedure [[addNewLeavesToTree]] - printing an error message and returning [[0]]. - If [[rightBrother]] is endmost child of [[parent]], then - this chunk adds [[child]] at the one end where - [[rightBrother]] hides. The node [[child]] is then made the - new endmost child of [[parent]] on the corresponding side. - */ - if (rightBrother == parent->m_leftEndmost) - { - parent->m_leftEndmost = child; - child->m_sibRight = rightBrother; - rightBrother->putSibling(child,PQNodeRoot::LEFT); - return true; - } - - // missing second brother? - OGDF_ASSERT(rightBrother == parent->m_rightEndmost); - parent->m_rightEndmost = child; - child->m_sibLeft = rightBrother; - rightBrother->putSibling(child,PQNodeRoot::LEFT); - return true; - } - - else if (rightBrother == 0) - { - /* - The parent is a $Q$-node with children. - The [[rightBrother]] is a [[0]]-pointer while the - [[leftBrother]] denotes an existing child of [[parent]]. The - node [[leftBrother]] {\bf must be} one of the two endmost - children of [[parent]]. If this is not the case, the chunk - detects this, halts the procedure [[addNodeToNewParent]] - printing an error message and returning [[0]]. - If [[leftBrother]] is endmost child of [[parent]], then this - chunk adds [[child]] at the one end where [[leftBrother]] - hides. The node [[child]] is then made new endmost child of - [[parent]] on the corresponding side. - */ - if (leftBrother == parent->m_rightEndmost) - { - parent->m_rightEndmost = child; - child->m_sibLeft = leftBrother; - leftBrother->putSibling(child,PQNodeRoot::RIGHT); - return true; - } - - // missing second brother? - OGDF_ASSERT(leftBrother == parent->m_leftEndmost); - parent->m_leftEndmost = child; - child->m_sibRight = leftBrother; - leftBrother->putSibling(child,PQNodeRoot::RIGHT); - return true; - } - - else - { - /* - The parent is a $Q$-node with children. - Both the [[rightBrother]] and the [[leftBrother]] denote - existing children of [[parent]]. In this case, [[leftBrother]] - and [[rightBrother]] must be immideate siblings. If this is - not the case, this will be detected during the function call - [[changeSiblings]] of the class [[PQNode.h]] (see - \ref{PQNode.changeSiblings}) in the first two lines of this - chunk. If the chunk recognizes the failure of - [[changeSiblings]] it halts the procedure - [[addNewLeavesToTree]], printing an error message and - returning [[0]]. - If the two brothers are immediate siblings, this chunk - adds [[child]] between the two brothers as interior child of - the $Q$-node [[parent]]. - */ -#ifdef OGDF_DEBUG - bool ok = -#endif - rightBrother->changeSiblings(leftBrother,child) && leftBrother->changeSiblings(rightBrother,child); - - // brothers are not siblings? - OGDF_ASSERT(ok); - - if (leftBrother->m_sibRight == child) - { - child->m_sibLeft = leftBrother; - child->m_sibRight = rightBrother; - } - else - { - child->m_sibLeft = rightBrother; - child->m_sibRight = leftBrother; - } - return true; - } - } - else - return false; - } - else if (leftBrother != 0 && rightBrother != 0) - { - /* - The parent is a $Q$-node with children. - Both the [[rightBrother]] and the [[leftBrother]] denote - existing children of [[parent]]. In this case, [[leftBrother]] - and [[rightBrother]] must be immideate siblings. If this is - not the case, this will be detected during the function call - [[changeSiblings]] of the class [[PQNode.h]] (see - \ref{PQNode.changeSiblings}) in the first two lines of this - chunk. If the chunk recognizes the failure of - [[changeSiblings]] it halts the procedure - [[addNewLeavesToTree]], printing an error message and - returning [[0]]. - If the two brothers are immediate siblings, this chunk - adds [[child]] between the two brothers as interior child of - the $Q$-node [[parent]]. - */ -#ifdef OGDF_DEBUG - bool ok = -#endif - rightBrother->changeSiblings(leftBrother,child) && leftBrother->changeSiblings(rightBrother,child); - - // brothers are not siblings? - OGDF_ASSERT(ok); - - if (leftBrother->m_sibRight == child) - { - child->m_sibLeft = leftBrother; - child->m_sibRight = rightBrother; - } - else - { - child->m_sibLeft = rightBrother; - child->m_sibRight = leftBrother; - } - return true; - } - - return true; -} - - - -/************************************************************************ - Bubble -************************************************************************/ - -/** - * The function Bubble() realizes a function described in [Booth]. - * It bubbles up from the pertinent leaves to the pertinent root - * in order to make sure that every pertinent node in the pertinent subtree - * has a valid pointer to its parent. If Bubble() does not succed in doing so, - * then the set of elements, stored in the \a leafKeys cannot form - * a consecutive sequence. - * - * The function Bubble() uses a wide variaty of variables, explained - * in detail below. - * - \a blockcount is the number of blocks of blocked nodes during - * the bubbling up phase. - * - \a numBlocked is the number of blocked nodes during the - * bubbling up phase. - * - \a blockedSiblings counts the number of blocked siblings that - * are adjacent to \a checkNode. A node has 0, 1 or 2 blocked siblings. - * A child of a P-node has no blocked siblings. Endmost children of - * Q-nodes have at most 1 blocked sibling. The interior children of - * a Q-Node have at most 2 blocked siblings. - * - \a checkLeaf is a pointer used for finding the pertinent leaves. - * - \a checkNode is a pointer to the actual node. - * - \a checkSib is a pointer used to examin the siblings of [[checkNode]]. - * - \a offTheTop is a variable which is either 0 (that is its - * initial value) or 1 in case that the root of the tree has been - * process during the first phase. - * - \a parent is a pointer to the parent of \a checkNode, if \a checkNode - * has a valid parent pointer. - * - \a processNodes is a first-in first-out list that is used for - * sequencing the order in which the nodes are processed. - * - \a blockedNodes is a stack storing all nodes that have been - * once blocked. In case that the [[m_pseudoRoot]] has to be - * introduced, the stack contains the blocked nodes. - */ - -template -bool PQTree::Bubble(SListPure*> &leafKeys) -{ - Queue*> processNodes; - - /* - Enter the [[Full]] leaves into the queue [[processNodes]]. - In a first step the pertinent leaves have to be identified in the tree - and entered on to the queue [[processNodes]]. The identification of - the leaves can be done with the help of a pointer stored in every - [[PQLeafKey]] (see \ref{PQLeafKey}) in constant time for every element. - */ - SListIterator*> it; - for (it = leafKeys.begin(); it.valid(); ++it) - { - PQNode* checkLeaf = (*it)->nodePointer(); //leafKeys[i]->nodePointer(); - checkLeaf->mark(PQNodeRoot::QUEUED); - processNodes.append(checkLeaf); - m_pertinentNodes->pushFront(checkLeaf); - } - - int blockCount = 0; - int numBlocked = 0; - int offTheTop = 0; - int blockedSiblings = 0; - PQNode* checkSib = 0; - Stack*> blockedNodes; - - while ((processNodes.size() + blockCount + offTheTop) > 1) - { - if (processNodes.size() == 0) - /* - No consecutive sequence possible. - The queue [[processNodes]] does not contain any nodes for - processing and the sum of [[blockCount]] and [[offTheTop]] is - greater than 1. If the queue is empty, the root of the pertinent - subtree was already processed. Nevertheless, there are blocked - nodes since [[offTheTop]] is either be [[0]] or [[1]], hence - [[blockCount]] must be at least [[1]]. Such blocked nodes cannot - form a consecutive sequence with all nodes in the set - [[leafKeys]]. Observe that this chunk finishes the function - [[Bubble]]. Hence every memory allocated by the function [[Bubble]] - has to be deleted here as well. - */ - return false; - /* - If there are still nodes to be processed in which case the queue - [[processNodes]] is not empty, we get the next node from the queue. - By default this node has to be marked as blocked. - */ - PQNode* checkNode = processNodes.pop(); - blockedNodes.push(checkNode); - checkNode->mark(PQNodeRoot::BLOCKED); - blockedSiblings = 0; - - /* - Check if node is adjacent to an unblocked node. - After getting the node [[checkNode]] from the queue, its siblings are - checked, whether they are unblocked. If they are, then they have a - valid pointer to their parent and the parent pointer of [[checkNode]] - is updated. - */ - if ((checkNode->m_parentType != PQNodeRoot::PNode) && (checkNode != m_root)) - // checkNode is son of a QNode. - // Check if it is blocked. - { - if (clientSibLeft(checkNode) == 0) - // checkNode is endmost child of - // a QNode. It has a valid pointer - // to its parent. - { - checkNode->mark(PQNodeRoot::UNBLOCKED); - if (clientSibRight(checkNode) && - clientSibRight(checkNode)->mark() == PQNodeRoot::BLOCKED) - blockedSiblings++; - } - - else if (clientSibRight(checkNode) == 0) - // checkNode is endmost child of - // a QNode. It has a valid pointer - // to its parent. - { - checkNode->mark(PQNodeRoot::UNBLOCKED); - if (clientSibLeft(checkNode) && - clientSibLeft(checkNode)->mark() == PQNodeRoot::BLOCKED) - blockedSiblings++; - } - - - else - // checkNode is not endmost child of - // a QNode. It has not a valid - // pointer to its parent. - { - if (clientSibLeft(checkNode)->mark() == PQNodeRoot::UNBLOCKED) - // checkNode is adjacent to an - // unblocked node. Take its parent. - { - checkNode->mark(PQNodeRoot::UNBLOCKED); - checkNode->m_parent = clientSibLeft(checkNode)->m_parent; - } - else if (clientSibLeft(checkNode)->mark() == PQNodeRoot::BLOCKED) - blockedSiblings++; - - if (clientSibRight(checkNode)->mark() == PQNodeRoot::UNBLOCKED) - // checkNode is adjacent to an - // unblocked node. Take its parent. - { - checkNode->mark(PQNodeRoot::UNBLOCKED); - checkNode->m_parent = clientSibRight(checkNode)->m_parent; - } - else if (clientSibRight(checkNode)->mark() == PQNodeRoot::BLOCKED) - blockedSiblings++; - } - } - - else - // checkNode is son of a PNode - // and children of P_NODEs - // cannot be blocked. - checkNode->mark(PQNodeRoot::UNBLOCKED); - - if (checkNode->mark() == PQNodeRoot::UNBLOCKED) - { - PQNode* parent = checkNode->m_parent; - - /* - Get maximal consecutive set of blocked siblings. - This chunk belongs to the procedure [[bubble]]. - The node [[checkNode]] is [[UNBLOCKED]]. - If the parent of [[checkNode]] is a $Q$-Node, then we check the - siblings [[checkSib]] of [[checkNode]] whether they are - [[BLOCKED]]. If they are blocked, they have to be marked - [[UNBLOCKED]] since they are adjacent to the [[UNBLOCKED]] node - [[checkNode]]. We then have to proceed with the siblings of - [[checkSib]] in order to find [[BLOCKED]] nodes - adjacent to [[checkSib]]. This is repeated until no [[BLOCKED]] - nodes are found any more. - - Observe that while running through the children of the $Q$-Node - (referred by the pointer [[parent]]), their parent pointers, - as well as the [[pertChildCount]] of [[parent]] are updated. - Furthermore we reduce simultaneously the count [[numBlocked]]. - */ - if (blockedSiblings > 0) - { - if (clientSibLeft(checkNode) != 0) - { - checkSib = clientSibLeft(checkNode); - PQNode* oldSib = checkNode; - while (checkSib->mark() == PQNodeRoot::BLOCKED) - { - checkSib->mark(PQNodeRoot::UNBLOCKED); - checkSib->m_parent = parent; - numBlocked--; - parent->m_pertChildCount++; - PQNode* holdSib = clientNextSib(checkSib,oldSib); - oldSib = checkSib; - checkSib = holdSib; - //Blocked node as endmost child of a QNode. - } - } - - if (clientSibRight(checkNode) != 0) - { - checkSib = clientSibRight(checkNode); - PQNode* oldSib = checkNode; - while (checkSib->mark() == PQNodeRoot::BLOCKED) - { - checkSib->mark(PQNodeRoot::UNBLOCKED); - checkSib->m_parent = parent; - numBlocked--; - parent->m_pertChildCount++; - PQNode* holdSib = clientNextSib(checkSib,oldSib); - oldSib = checkSib; - checkSib = holdSib; - //Blocked node as endmost child of a QNode. - } - } - }// if (blockedSiblings > 0) - - - /* - Process parent of [[checkNode]] - After processing the siblings of the [[UNBLOCKED]] [[checkNode]] - the parent has to be processed. If [[checkNode]] is the root - of the tree we do nothing except setting the flag [[offTheTop]]. - If it is not the root and [[parent]] has not been placed onto the - queue [[processNodes]], the [[parent]] is placed on to - [[processNodes]]. - - Observe that the number [[blockCount]] is updated. Since - [[checkNode]] was [[UNBLOCKED]] all perinent nodes adjacent - to that node became [[UNBLOCKED]] as well. Therefore the number - of blocks is reduced by the number of [[BLOCKED]] siblings of - [[checkNode]]. - */ - if (parent == 0) - // checkNode is root of the tree. - offTheTop = 1; - else - // checkNode is not the root. - { - parent->m_pertChildCount++; - if (parent->mark() == PQNodeRoot::UNMARKED) - { - processNodes.append(parent); - m_pertinentNodes->pushFront(parent); - parent->mark(PQNodeRoot::QUEUED); - } - } - - blockCount -= blockedSiblings; - blockedSiblings = 0; - - }//if (checkNode->mark() == UNBLOCKED) - - else - { - /* - Process blocked [[checkNode]] - Since [[checkNode]] is [[BLOCKED]], we cannot continue - processing at this point in the Tree. We have to wait until - this node becomes unblocked. So only the variables - [[blockCount]] and [[numBlocked]] are updated. - */ - blockCount += 1 - blockedSiblings; - numBlocked++; - } - - }//while ((processNodes.size() + blockCount + offTheTop) > 1) - - if (blockCount == 1) - { - /* - If [[blockCount]] $= 1$ enter [[m_pseudoRoot]] to the tree - In case that the root of the pertinent subtree is a $Q$-node - with empty children on both sides and the pertinent children - in the middle, it is possible that the $PQ$-tree is reducible. - But since the sequence of pertinent children of the $Q$-node is - blocked, the procedure is not able to find the parent of its - pertinent children. This is due to the fact that the interior - children of a $Q$-node do not have a valid parent pointer. - - So the root of the pertinent subtree is not known, hence cannot be - entered into the processing queue used in the function call [[Reduce]] - (see \ref{Reduce}). To solve this problem a special node only designed - for this cases is used: [[m_pseudoRoot]]. It simulates the root of the - pertinent subtree. This works out well, since for this node the only - possible template maching is [[templateQ3]] (see \ref{templateQ3}), - where no pointers to the endmost children of a $Q$-node are used. - */ - while (!blockedNodes.empty()) - { - PQNode* checkNode = blockedNodes.pop(); - if (checkNode->mark() == PQNodeRoot::BLOCKED) - { - checkNode->mark(PQNodeRoot::UNBLOCKED); - checkNode->m_parent = m_pseudoRoot; - m_pseudoRoot->m_pertChildCount++; - OGDF_ASSERT(!checkNode->endmostChild()) - //Blocked node as endmost child of a QNode. - } - } - } - - return true; -} - - -/************************************************************************ - checkChain -************************************************************************/ - -/** - * The function checkChain() is used by the function templateQ2() - * and templateQ3(). - * It checks whether all full children of a Q-node - * \a nodePtr form a consecutive sequence. If the full nodes do so, - * the procedure returns 1 as a result, otherwise 0. - * - * The pointer \a firstFull denotes just an arbirtary full child. Starting - * from this position, checkChain sweeps through the consecutive - * sequence, halting as soon as a nonfull child is detected. - * The two pointers \a seqStart and \a seqEnd are set within the - * function \a checkChain. They denote the first and last node of the consecutive - * sequence. - * - * The client should observe that it is not possible to avoid the use - * of such a function. According to the procedure Bubble() children of - * Q-nodes get unblocked as soon as they are adjacent to any pertinent - * sibling. This includes that chains of more than two partial children - * are regarded as unblocked as well. - * Such chains are of course not reducible and therefore - * have to be detected by the function checkChain(). - * - * Following we give an overview of the variables used in - * checkChain(). - * - \a fullCount counts the number of children that are - * discovered by the function checkChain(). This is necessary, since - * checkChain() is used by two template matching functions - * templateQ2() and templateQ3() where in the latter case the - * pointer \a firstFull may point to any full child in the front of the Q-node - * \a nodePtr. - * - \a notFull is set 1 when an empty child is encountered. - * - \a checkNode is the actual node that is examined. - * - \a leftNext is the next node that has to be examined on the - * left side of \a firstFull. - * - \a leftOld is the node that has been examined right before - * \a checkNode on the left side of \a firstFull. - * - \a rightNext is the next node that has to be examined on the - * right side of \a firstFull. Not needed when checkChain() was - * called by templateQ2(). - * - \a rightOld is the node that has been examined right before - * \a checkNode on the right side of \a firstFull. - * Not needed when checkChain() was called by templateQ2(). -*/ - -template -bool PQTree::checkChain( - PQNode *nodePtr, - PQNode *firstFull, - PQNode **seqStart, - PQNode **seqEnd) -{ - bool notFull = false; - int fullCount = nodePtr->fullChildren->size(); - fullCount--; // firstFull does have a FULL label. - - /* - Start at the [[firstFull]] child sweeping through the full children on - the left side of [[firstfull]]. It stops as soon as a nonfull child is - detected. The last found full child is stored in [[seqEnd]]. - */ - PQNode *leftNext = clientSibLeft(firstFull); - (*seqEnd) = firstFull; - if (leftNext != 0) - { - if (leftNext->status() == PQNodeRoot::FULL) { - fullCount--; - - PQNode *leftOld = firstFull; - PQNode *checkNode = leftNext; - - while (fullCount > 0 && !notFull) - // There are still full children to be - // counted, and no empty child has been - // encountered on this side. - { - leftNext = clientNextSib(checkNode,leftOld); - if (leftNext != 0 && leftNext->status() == PQNodeRoot::FULL) - fullCount--; - else - notFull = true; - leftOld = checkNode; - checkNode = leftNext; - } - - if (checkNode != 0 && checkNode->status() == PQNodeRoot::FULL) - (*seqEnd) = checkNode; - - else { - //searching consecutive sequence in Q2 or Q3. - OGDF_ASSERT(leftOld != 0 && leftOld->status() == PQNodeRoot::FULL); - (*seqEnd) = leftOld; - } - - } else { - (*seqEnd) = firstFull; - } - } - - /* - Start at the [[firstFull]] child sweeping through the full children on - the right side of [[firstfull]]. It stops as soon as a nonfull child is - detected. - */ - notFull = false; - PQNode *rightNext = clientSibRight(firstFull); - (*seqStart) = firstFull; - if(rightNext != 0) - { - if (rightNext->status() == PQNodeRoot::FULL) { - fullCount--; - - PQNode *rightOld = firstFull; - PQNode *checkNode = rightNext; - - while (fullCount > 0 && !notFull) - // There are still full children to be - // counted, and no empty child has been - // encountered on this side. - { - rightNext = clientNextSib(checkNode,rightOld); - if (rightNext != 0 && rightNext->status() == PQNodeRoot::FULL) - fullCount--; - else - notFull = true; - rightOld = checkNode; - checkNode = rightNext; - } - if (checkNode != 0 && checkNode->status() == PQNodeRoot::FULL) - (*seqStart) = checkNode; - - else { - OGDF_ASSERT(rightOld != 0 && rightOld->status() == PQNodeRoot::FULL); - (*seqStart) = rightOld; - //searching consecutive seqeuence in Q2 or Q3. - } - - } else { - (*seqStart) = firstFull; - } - } - - - - if (firstFull == (*seqEnd)) - { - PQNode *checkNode = (*seqEnd); - (*seqEnd) = (*seqStart); - (*seqStart) = checkNode; - } - - if (fullCount == 0) - // All full children occupy a consecutive - // sequence. - return true; - else - return false; -} - - -/************************************************************************ - checkIfOnlyChild -************************************************************************/ - -/** - * The function checkIfOnlyChild() checks if \a child is the only - * child of \a parent. If so, \a child is connected to its - * grandparent, as long as parent is not the root of the tree. In case - * that \a parent is the root of the tree and \a child is its only - * child, the node \a child becomes the new root of the tree. The parent then - * is completely removed from the tree and destroyd. The return value of - * the method checkIfOnlyChild() is 1, if \a child was the only - * child of parent. Otherwise the return value is 0. - * Before applying the function exchangeNodes(), the function removeChildFromSiblings() - * is applied. This is usefull in case - * the node \a parent has some ignored children and has to be reused - * within some extra algorithmic context. - */ - -template -bool PQTree::checkIfOnlyChild( - PQNode *child, - PQNode *parent) - -{ - if ((parent->type() == PQNodeRoot::PNode && parent->m_childCount == 1) - || (parent->type() == PQNodeRoot::QNode && parent->m_leftEndmost == child - && parent->m_rightEndmost == child)) - { - removeChildFromSiblings(child); - child->m_parent = parent->m_parent; - if (parent->m_parent != 0) // parent is not the root. - exchangeNodes(parent,child); - else - { - exchangeNodes(parent,child); - m_root = child; - } - destroyNode(parent); - return true; - } - else - return false; -} - - -/************************************************************************ - Cleanup -************************************************************************/ - -/** - * The function Cleanup() removes the entire PQ-tree, stored in the - * class template PQTree. The function Cleanup() is called by the - * destructor of the class template PQTree. - * It scans all nodes of the tree and frees the - * memory used by the tree. Cleanup() includes the removal of the memory - * allocated by the following datastructures: - * - \a m_root, - * - \a m_pseudoRoot, - * - \a m_pertinentNodes. - * The function Cleanup() enables the client to reuse the function - * Initialize(). - * - * In order to free the allocated memory, all nodes of the - * tree have to be deleted, hence there destructors are called. - * In order to achieve this, we start at the root of the tree and go down the - * tree to the leaves for reaching every node. When a node is processed, - * (besides the \a m_root, this will always be the node \a checkNode) - * the pointers of all its children are stored in a queue \a helpqueue and - * then the processed node is deleted. - * - * The use of a queue \a helpqueue is a must, since the nodes do not - * have pointers to all of their children, as the children mostly do - * not have a pointer to their parent. - * - * It might look weird at the first glance that the function Cleanup() - * calls the function emptyAllPertinentNodes(), but if some nodes were removed - * during a reduction, they were stored in the stack \a m_pertinentNodes. - * These nodes have to be deleted as well - * which is provided by the function emptyAllPertinentNodes(). - */ - -template -void PQTree::Cleanup() -{ - PQNode* nextSon = 0; - PQNode* lastSon = 0; - PQNode* oldSib = 0; - - Queue*> helpqueue; - - if (m_root != 0) - { - emptyAllPertinentNodes(); - - /* - Process the [[m_root]] of the [[PQTree]]. Before deleting [[m_root]], - pointers to all its children are stored in the queue [[helpqueue]]. - */ - if (m_root->type() == PQNodeRoot::PNode) - { - if (m_root->m_referenceChild != 0) - { - PQNode* firstSon = m_root->m_referenceChild; - helpqueue.append(firstSon); - - if (firstSon->m_sibRight != 0) - nextSon = firstSon->m_sibRight; - while (nextSon != firstSon) - { - helpqueue.append(nextSon); - nextSon = nextSon->m_sibRight; - } - } - } - else if (m_root->type() == PQNodeRoot::QNode) - { - PQNode* firstSon = m_root->m_leftEndmost; - helpqueue.append(firstSon); - - lastSon = m_root->m_rightEndmost; - helpqueue.append(lastSon); - - nextSon = lastSon->getNextSib(oldSib); - oldSib = lastSon; - while (nextSon != firstSon) - { - helpqueue.append(nextSon); - PQNode* holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - } - - - CleanNode(m_root); - delete m_root; - - while (!helpqueue.empty()) - { - PQNode* checkNode = helpqueue.pop(); - - /* - Process an arbitrary node [[checkNode]] of the [[PQTree]]. - Before deleting [[checkNode]], - pointers to all its children are stored in the queue [[helpqueue]]. - */ - if (checkNode->type() == PQNodeRoot::PNode) - { - if (checkNode->m_referenceChild != 0) - { - PQNode* firstSon = checkNode->m_referenceChild; - helpqueue.append(firstSon); - - if (firstSon->m_sibRight != 0) - nextSon = firstSon->m_sibRight; - while (nextSon != firstSon) - { - helpqueue.append(nextSon); - nextSon = nextSon->m_sibRight; - } - } - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - oldSib = 0; - - PQNode*firstSon = checkNode->m_leftEndmost; - helpqueue.append(firstSon); - - lastSon = checkNode->m_rightEndmost; - helpqueue.append(lastSon); - - nextSon = lastSon->getNextSib(oldSib); - oldSib = lastSon; - while (nextSon != firstSon) - { - helpqueue.append(nextSon); - PQNode* holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - } - - CleanNode(checkNode); - delete checkNode; - } - } - - CleanNode(m_pseudoRoot); - delete m_pseudoRoot; - - delete m_pertinentNodes; - - m_root = 0; - m_pertinentRoot = 0; - m_pseudoRoot = 0; - m_pertinentNodes = 0; - - m_numberOfLeaves = 0; - m_identificationNumber = 0; -} - - -/************************************************************************ - clientPrintNodeCategorie -************************************************************************/ - -/** - * If the user wishes to use different flags in a derived class of PQTree - * that are not available in this implementation, he can overload the function - * clientPrintNodeCategorie(). This function is called per default by the functions - * printOutCurrentTree() and printNode(). - * With the help of this function it is possible to influence the layout of the nodes - * by using new, different lables depicting node categories - * in the Tree Interface. - */ - -template -int PQTree::clientPrintNodeCategorie(PQNode* nodePtr) -{ - return (nodePtr != 0) ? 1 : 0; - // 1 is the standard node categrie in the Tree Interface. -} - - -/************************************************************************ - clientPrintStatus -************************************************************************/ - -/** - * If the user wishes to use different status in a derived class of PQTree - * that are not available in this implementation, he can overload the function - * clientPrintStatus(). This function is called per default by the functions - * printOutCurrentTree() and printNode(). - * With the help of this function it is possible to influence the information stored - * at nodes in the Tree Interface that concern the - * status of a node. - */ - -template -const char* PQTree::clientPrintStatus(PQNode* nodePtr) -{ - return (nodePtr != 0) ? "ERROR" : "ERROR: clientPrintStatus: NO NODE ACCESSED"; -} - - -/************************************************************************ - clientPrintType -************************************************************************/ - -/** - * If the user wishes to use different types in a derived class of PQTree - * that are not available in this implementation, he can overload the function - * clientPrintType(). This function is called per default by the functions - * printOutCurrentTree() and printNode(). - * With the help of this function it is possible to influence the information stored - * at nodes in the Tree Interface that concern the - * type of a node. - */ - -template -const char* PQTree::clientPrintType(PQNode* nodePtr) -{ - return (nodePtr != 0) ? "ERROR" : "ERROR: clientPrintType: NO NODE ACCESSED"; -} - - -/************************************************************************ - Constructor -************************************************************************/ - - -template PQTree::PQTree() -{ - m_root = 0; - m_pertinentRoot = 0; - m_pseudoRoot = 0; - - m_numberOfLeaves = 0; - m_identificationNumber = 0; - - m_pertinentNodes = 0; -} - - - -/************************************************************************ - copyFullChildrenToPartial -************************************************************************/ - -/** - * The function copyFullChildrenToPartial() - * copies all full children of \a nodePtr to a new P-node - * The node \a nodePtr has to be a P-node. The new P-node - * is added to \a partialChild as an endmost child of \a partialChild. - * The node \a partialChild has to be a Q-node and the new P-node is added - * to the side of \a partialChild where the pertinent children are. - * - * The new P-node is allocated by this function and referenced by the - * variable \a newNode. - * - * The function copyFullChildrenToPartial() is used by the functions - * templateP4(), templateP5(), and templateP6(). - */ - -template -void PQTree::copyFullChildrenToPartial( - PQNode *nodePtr, - PQNode *partialChild) -{ - if (nodePtr->fullChildren->size() > 0) - // There are some full children to - // be copied. - { - nodePtr->m_childCount = nodePtr->m_childCount - - nodePtr->fullChildren->size(); - - PQNode *newNode = createNodeAndCopyFullChildren(nodePtr->fullChildren); - - // Introduce newNode as endmost - // child of the partial Q-node. - partialChild->m_childCount++; - partialChild->fullChildren->pushFront(newNode); - - if (clientLeftEndmost(partialChild)->status() == PQNodeRoot::FULL) - { - PQNode *checkNode = partialChild->m_leftEndmost; - partialChild->m_leftEndmost = newNode; - linkChildrenOfQnode(checkNode,newNode); - - } - else { - // ERROR: Endmostchild not found? - OGDF_ASSERT(clientRightEndmost(partialChild)->status() == PQNodeRoot::FULL); - - PQNode *checkNode = partialChild->m_rightEndmost; - partialChild->m_rightEndmost = newNode; - linkChildrenOfQnode(checkNode,newNode); - } - - newNode->m_parent = partialChild; - newNode->m_parentType = PQNodeRoot::QNode; - } -} - - -/************************************************************************ - createNodeAndCopyFullChildren -************************************************************************/ - -/** - * The function createNodeAndCopyFullChildren() copies the full children of a - * P-node that are stored in the stack \a fullNodes to a new P-node. - * This new P-node - * is created by the function and stored in \a newNode if there is more than one full child. - * If there is just one full child, it is not necessary to construct a new - * P-node and the full child is stored in \a newNode. - * The \a newNode is the return value of the procedure. - * - * The function createNodeAndCopyFullChildren() is used by - * templateP2() templateP3() and the function copyFullChildrenToPartial(). - * The function createNodeAndCopyFullChildren() uses the following - * variables. - * - \a newNode stores the adress of the new allocated P-node or - * the adress of the only full child. - * - \a oldSon is a variable used for adding the full nodes as - * children to the new P-node. - * - \a firstSon stores the adress of the first detected full - * child. It is needed for adding the full nodes as - * children to the new P-node. - * - \a checkSon is a variable used for adding the full nodes as - * children to the new P-node. - * - \a newPQnode is used for proper allocation of the new P-node. - */ - -template -PQNode* PQTree::createNodeAndCopyFullChildren( - List*> *fullNodes) -{ - PQNode *newNode = 0; - - if (fullNodes->size() == 1) - { - /* - There is just one full child. So no new $P$-node is created. The - full child is copied as child to the [[partialChild]]. - */ - newNode = fullNodes->popFrontRet(); - removeChildFromSiblings(newNode); - } - - else - { - /* - This chunk belongs to the function [[createNodeAndCopyFullChildren]]. - There is more than one full child, so a new $P$-node is created. - This chunk first allocates the memory for the new $P$-node that will - be stored in [[newNode]]. Then it pops the nodes out of the stack - [[fullNodes]] and introduces them as sons of [[newNode]]. - Popping the nodes out of the stack implies at the same time - that they are removed from the [[fullChildren]] stack of the - $P$-node of their parent. - */ - newNode = OGDF_NEW PQInternalNode(m_identificationNumber++,PQNodeRoot::PNode,PQNodeRoot::FULL); - m_pertinentNodes->pushFront(newNode); - newNode->m_pertChildCount = fullNodes->size(); - newNode->m_childCount = fullNodes->size(); - - /* - The first node is copied separately, since we need the pointer to it - for setting the pointers to the siblings of the next full nodes. - */ - PQNode *firstSon = fullNodes->popFrontRet(); - removeChildFromSiblings(firstSon); - newNode->fullChildren->pushFront(firstSon); - firstSon->m_parent = newNode; - firstSon->m_parentType = newNode->type(); - PQNode *oldSon = firstSon; - - - /* - All remaining nodes that are stored in the stack [[fullNodes]] are - introduced as children of the new $P$-node [[newNode]]. Observe - that the children of a $P$-node must form a doubly linked list. - Hence the last node and the [[firstSon]] must be linked via their - siblings pointers. - */ - while (!fullNodes->empty()) - { - PQNode *checkSon = fullNodes->popFrontRet(); - removeChildFromSiblings(checkSon); - newNode->fullChildren->pushFront(checkSon); - oldSon->m_sibRight = checkSon; - checkSon->m_sibLeft = oldSon; - checkSon->m_parent = newNode; - checkSon->m_parentType = newNode->type(); - oldSon = checkSon; - } - firstSon->m_sibLeft = oldSon; - oldSon->m_sibRight = firstSon; - newNode->m_referenceChild = firstSon; - firstSon->m_referenceParent = newNode; - } - - return newNode; -} - - -/************************************************************************ - emptyAllPertinetNodes -************************************************************************/ - -/** - * The function emptyAllPertinentNodes() has to be called after a reduction - * has been processed. In cleans up all flags that have been set in the - * pertinent nodes during the reduction process. All pertinent nodes have been - * stored in the private member stack \a m_pertinentNodes of the class template - * PQTree during the Bubble()-phase - * or when processing one of the templates (see templateL1() to templateQ3()). - */ - -template -void PQTree::emptyAllPertinentNodes() -{ - PQNode *nodePtr; - - while(!m_pertinentNodes->empty()) - { - nodePtr = m_pertinentNodes->popFrontRet(); - switch (nodePtr->status()) - { - case PQNodeRoot::TO_BE_DELETED: - if (nodePtr == m_root) - m_root = 0; - CleanNode(nodePtr); - //if (nodePtr) - delete nodePtr; - break; - - case PQNodeRoot::FULL: - emptyNode(nodePtr); - break; - - case PQNodeRoot::PARTIAL: - emptyNode(nodePtr); - break; - - default: - clientDefinedEmptyNode(nodePtr); - break; - } - } - m_pseudoRoot->m_pertChildCount = 0; - m_pseudoRoot->m_pertLeafCount = 0; - m_pseudoRoot->fullChildren->clear(); - m_pseudoRoot->partialChildren->clear(); - m_pseudoRoot->status(PQNodeRoot::EMPTY); - m_pseudoRoot->mark(PQNodeRoot::UNMARKED); -} - - -/************************************************************************ - emptyNode -************************************************************************/ - -/** - * The funtion emptyNode() cleans up all stacks, flags and pointers of a - * pertinent node that has been visited during the reduction process. - */ - -template -void PQTree::emptyNode(PQNode *nodePtr) -{ - nodePtr->status(PQNodeRoot::EMPTY); - nodePtr->m_pertChildCount = 0; - nodePtr->m_pertLeafCount = 0; - nodePtr->fullChildren->clear(); - nodePtr->partialChildren->clear(); - nodePtr->mark(PQNodeRoot::UNMARKED); -} - - -/************************************************************************ - exchangeNodes -************************************************************************/ - -/** - * The function exchangeNodes() replaces the \a oldNode by the \a newNode - * in the tree. This is a function used very often in the template matchings, - * normally in combination with the construction of a new node which has to - * conquer the place of an existing node in the tree. - * - * This function can be used in all cases, so the parent of \a oldNode - * is allowed to be either a Q-node or a P-node and \a oldNode may be - * any child of its parent. - * - * The client should observe, that this function does \b not reset - * the pointer \a m_root. If necessary, this has to be done explicitly by - * the client himself. - */ - -template -void PQTree::exchangeNodes( - PQNode *oldNode, - PQNode *newNode) -{ - if (oldNode->m_referenceParent != 0) - { - /* - The node [[oldNode]] is connected to its parent - via the reference pointer of the doubly linked list. The [[newNode]] - will be the new reference child and is linked via the reference - pointers to the $P$-node. - */ - oldNode->m_referenceParent->m_referenceChild = newNode; - newNode->m_referenceParent = oldNode->m_referenceParent; - oldNode->m_referenceParent = 0; - } - - else if (oldNode->endmostChild()) - { - /* - The [[oldNode]] is endmost child of a Q-node. So its parent - contains an extra pointer to [[oldNode]]. Link the parent of - [[oldNode]] to [[newNode]] via this pointer and make [[newNode]] - endmost child of its new parent. - */ - if (oldNode->m_parent->m_leftEndmost == oldNode) - oldNode->m_parent->m_leftEndmost = newNode; - else if (oldNode->m_parent->m_rightEndmost == oldNode) - oldNode->m_parent->m_rightEndmost = newNode; - } - - if ((oldNode->m_sibLeft == oldNode) && (oldNode->m_sibRight == oldNode)) - { - /* - Two possible cases are occured. - \begin{enumerate} - \item [[oldNode]] is the only child of a $P$-node. In order to - implement the doubly linked list of children of the $P$-node, the sibling - pointers of [[newNode]] are set to [[newNode]]. - \item [[oldNode]] is the [[m_root]] of the $PQ$-tree. Since - by our definition of the $PQ$-tree the sibling pointers of the - [[m_root]] point to the root itself, (i.e. to make sure that - checking for the endmost child property is also valid for the root) - the sibling pointers of [[newNode]] are set to [[newNode]] as well. - \end{enumerate} - */ - oldNode->m_sibLeft = 0; - oldNode->m_sibRight = 0; - if (oldNode->m_parent == 0) - { - newNode->m_sibLeft = newNode; - newNode->m_sibRight = newNode; - } - else - { - newNode->m_sibLeft = newNode; - newNode->m_sibRight = newNode; - } - } - else - { - OGDF_ASSERT(!(oldNode->m_sibLeft == oldNode)) - //sibling pointers of old node are not compatible - OGDF_ASSERT(!(oldNode->m_sibRight == oldNode)) - //sibling pointers of old node are not compatible. - } - /* - Manage the exchange of [[oldNode]] and [[newNode]] according to - [[oldNode]]'s siblings. The chunk checks both siblings of - [[oldNode]] and resets the sibling pointers of [[oldNode]]'s siblings - as well as the sibling pointers of [[newNode]]. - */ - if (oldNode->m_sibLeft != 0) - { - if (oldNode->m_sibLeft->m_sibRight == oldNode) - oldNode->m_sibLeft->m_sibRight = newNode; - else { - // Sibling was not connected to child? - OGDF_ASSERT(oldNode->m_sibLeft->m_sibLeft == oldNode); - oldNode->m_sibLeft->m_sibLeft = newNode; - } - newNode->m_sibLeft = oldNode->m_sibLeft; - oldNode->m_sibLeft = 0; - } - - if (oldNode->m_sibRight != 0) - { - if (oldNode->m_sibRight->m_sibLeft == oldNode) - oldNode->m_sibRight->m_sibLeft = newNode; - else { - // Sibling was not connected to child? - OGDF_ASSERT(oldNode->m_sibRight->m_sibRight == oldNode); - oldNode->m_sibRight->m_sibRight = newNode; - } - newNode->m_sibRight = oldNode->m_sibRight; - oldNode->m_sibRight = 0; - } - - newNode->m_parentType = oldNode->m_parentType; - newNode->m_parent = oldNode->m_parent; -} - - -/************************************************************************ - front -************************************************************************/ - -/** - * The function front() - * returns the keys stored in the leaves of the front of - * \a nodePtr. A specified node \a nodePtr of the PQ-tree is - * handed to the function and front() detects the leaves in the front - * of this node returning the elements represented by the leaves. These - * elements are - * stored in an array of keys named \a leafKeys. - * The return value is the numbers of leaves that have been detected. - * Observe that front() uses \a leafKeys[0] to store the - * first key. - */ - -template -void PQTree::front( - PQNode* nodePtr, - SListPure*> &leafKeys) -{ - Queue*> helpqueue; - helpqueue.append(nodePtr); - - while (!helpqueue.empty()) - { - PQNode* checkNode = helpqueue.pop(); - - if (checkNode->type() == PQNodeRoot::leaf) - leafKeys.pushBack(checkNode->getKey()); - else - { - PQNode* firstSon = 0; - PQNode* nextSon = 0; - PQNode* oldSib = 0; - PQNode* holdSib = 0; - - if (checkNode->type() == PQNodeRoot::PNode) - { - OGDF_ASSERT(checkNode->m_referenceChild) - firstSon = checkNode->m_referenceChild; - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - OGDF_ASSERT(checkNode->m_leftEndmost) - firstSon = checkNode->m_leftEndmost; - } - helpqueue.append(firstSon); - nextSon = firstSon->getNextSib(oldSib); - oldSib = firstSon; - while (nextSon && nextSon != firstSon) - { - helpqueue.append(nextSon); - holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - } - } -} - - -/************************************************************************ - Initialize -************************************************************************/ - -/** - * The function Initialize() initializes the PQ-tree with a set of elements. - * These elements have to be template classes of the class template PQLeafKey - * and are handed to the function in an array \a leafKeys. - * The function constructs the universal PQ-tree. If the - * \a numberOfElements > 1, the universal PQ-tree consists of one P-node - * as root (stored in \a m_root) and all leaves gathered underneath the P-node, - * symbolizing all kinds of permutations. If \a numberOfElements = 1, - * the universal PQ-tree consists of a single PQLeaf, being the root of - * the tree. - * - * Observe that the first element has to be stored in - * \a leafKeys[0] and the last one in - * \a leafKeys[\a numberOfElements-1]. - * The function Initialize() returns 1, if the initialization of - * the PQ-tree was successful. - */ - -template -int PQTree::Initialize(SListPure*> &leafKeys) -{ - m_pertinentNodes = OGDF_NEW List*>; - - if (!leafKeys.empty()) - { - PQInternalNode *newNode2 = OGDF_NEW PQInternalNode(-1,PQNodeRoot::QNode,PQNodeRoot::PARTIAL); - m_pseudoRoot = newNode2; - - if (leafKeys.begin() != leafKeys.end()) // at least two elements - { - PQInternalNode *newNode = OGDF_NEW PQInternalNode(m_identificationNumber++,PQNodeRoot::PNode,PQNodeRoot::EMPTY); - m_root = newNode; - m_root->m_sibLeft = m_root; - m_root->m_sibRight = m_root; - return addNewLeavesToTree(newNode,leafKeys); - } - PQLeaf *newLeaf = OGDF_NEW PQLeaf(m_identificationNumber++,PQNodeRoot::EMPTY,*leafKeys.begin()); - m_root = newLeaf; - m_root->m_sibLeft = m_root; - m_root->m_sibRight = m_root; - return 1; - } - - return 0; -} - - -/************************************************************************ - linkChildrenOfQnode -************************************************************************/ - -/** - * The function linkChildrenOfQnode() links the two endmost children - * of two \b different Q-nodes via their sibling pointers together. - * The purpose of doing this is to combine the children of two Q-nodes - * as children of only one Q-node. This function does not reset the - * pointers to the endmost children of the Q-node. This has to be done - * by the client of the function. - */ - -template -void PQTree::linkChildrenOfQnode( - PQNode *installed, - PQNode *newChild) -{ - if ((installed != 0) && (newChild != 0)) - { - if (installed->m_sibLeft == 0) - { - installed->m_sibLeft = newChild; - if (newChild->m_sibRight == 0) - newChild->m_sibRight = installed; - else - newChild->m_sibLeft = installed; - } - else { - // endmost child with 2 siblings encountered? - OGDF_ASSERT(installed->m_sibRight == 0); - - installed->m_sibRight = newChild; - if (newChild->m_sibLeft == 0) - newChild->m_sibLeft = installed; - else - newChild->m_sibRight = installed; - } - } -} - - - -/************************************************************************ - writeGML -************************************************************************/ - -/** - * The function writeGML() prints the PQ-tree in the GML - * fileformat. The filename is ended by a ".gml" and can be read - * eg. by the AGD. - */ - -template -void PQTree::writeGML(const char *fileName) -{ - ofstream os(fileName); - writeGML(os); -} - -template -void PQTree::writeGML(ostream &os) -{ - Array id(0,m_identificationNumber,0); - int nextId = 0; - - SListPure*> helpQueue; - SListPure*> secondTrace; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::PQTree::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - PQNode* checkNode = m_root; - PQNode* firstSon = 0; - PQNode* nextSon = 0; - PQNode* lastSon = 0; - PQNode* oldSib = 0; - PQNode* holdSib = 0; - - if (checkNode->type() != PQNodeRoot::leaf) - secondTrace.pushBack(checkNode); - - while (checkNode) - { - os << " node [\n"; - - os << " id " << (id[checkNode->m_identificationNumber] = nextId++) << "\n"; - - os << " label \"" << checkNode->m_identificationNumber; - if (checkNode->getKey() != 0) - checkNode->getKey()->print(os); - os << "\"\n"; - - os << " graphics [\n"; - if (m_root->status() == PQNodeRoot::FULL) - { - if (checkNode->type() == PQNodeRoot::PNode) - os << " fill \"#FF0000\"\n"; - else if (checkNode->type() == PQNodeRoot::QNode) - os << " fill \"#0000A0\"\n"; - else if (checkNode->type() == PQNodeRoot::leaf) - os << "fill \"#FFFFE6\"\n"; - } - else if (m_root->status() == PQNodeRoot::EMPTY) - { - if (checkNode->type() == PQNodeRoot::PNode) - os << " fill \"#FF0000\"\n"; - else if (checkNode->type() == PQNodeRoot::QNode) - os << " fill \"#0000A0\"\n"; - else if (checkNode->type() == PQNodeRoot::leaf) - os << " fill \"#00FF00\"\n"; - } - else if (m_root->status() == PQNodeRoot::PARTIAL) - { - if (checkNode->type() == PQNodeRoot::PNode) - os << " fill \"#FF0000\"\n"; - else if (checkNode->type() == PQNodeRoot::QNode) - os << " fill \"#0000A0\"\n"; - else if (checkNode->type() == PQNodeRoot::leaf) - os << " fill \"#FFFFE6\"\n"; - } - else if (m_root->status() == PQNodeRoot::PERTINENT) - { - if (checkNode->type() == PQNodeRoot::PNode) - os << " fill \"#FF0000\"\n"; - else if (checkNode->type() == PQNodeRoot::QNode) - os << " fill \"#0000A0\"\n"; - else if (checkNode->type() == PQNodeRoot::leaf) - os << " fill \"#FFFFE6\"\n"; - } - - os << " ]\n"; // graphics - os << " ]\n"; // node - - if (checkNode->type() == PQNodeRoot::PNode) - { - if (checkNode->m_referenceChild != 0) - { - firstSon = checkNode->m_referenceChild; - helpQueue.pushBack(firstSon); - - if (firstSon->m_sibRight != 0) - nextSon = firstSon->m_sibRight; - while (nextSon != firstSon) - { - helpQueue.pushBack(nextSon); - nextSon = nextSon->m_sibRight; - } - } - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - oldSib = 0; - holdSib = 0; - - firstSon = checkNode->m_leftEndmost; - helpQueue.pushBack(firstSon); - - lastSon = checkNode->m_rightEndmost; - if ( firstSon != lastSon) - { - helpQueue.pushBack(lastSon); - nextSon = lastSon->getNextSib(oldSib); - oldSib = lastSon; - while (nextSon != firstSon) - { - helpQueue.pushBack(nextSon); - holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - } - } - if (!helpQueue.empty()) - { - checkNode = helpQueue.popFrontRet(); - if (checkNode->type() != PQNodeRoot::leaf) - secondTrace.pushBack(checkNode); - } - else - checkNode = 0; - } - - - SListIterator*> it; - - for (it = secondTrace.begin(); it.valid(); it++) - { - checkNode = *it; - if (checkNode->type() == PQNodeRoot::PNode) - { - if (checkNode->m_referenceChild != 0) - { - firstSon = checkNode->m_referenceChild; - os << " edge [\n"; - os << " source " << id[checkNode->m_identificationNumber] << "\n"; - os << " target " << id[firstSon->m_identificationNumber] << "\n"; - os << " ]\n"; // edge - - if (firstSon->m_sibRight != 0) - nextSon = firstSon->m_sibRight; - while (nextSon != firstSon) - { - os << " edge [\n"; - os << " source " << id[checkNode->m_identificationNumber] << "\n"; - os << " target " << id[nextSon->m_identificationNumber] << "\n"; - os << " ]\n"; // edge - nextSon = nextSon->m_sibRight; - } - } - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - oldSib = 0; - holdSib = 0; - - firstSon = checkNode->m_leftEndmost; - lastSon = checkNode->m_rightEndmost; - - os << " edge [\n"; - os << " source " << id[checkNode->m_identificationNumber] << "\n"; - os << " target " << id[lastSon->m_identificationNumber] << "\n"; - os << " ]\n"; // edge - if ( firstSon != lastSon) - { - nextSon = lastSon->getNextSib(oldSib); - os << " edge [\n"; - os << " source " << id[checkNode->m_identificationNumber] << "\n"; - os << " target " << id[nextSon->m_identificationNumber] << "\n"; - os << " ]\n"; // edge - - oldSib = lastSon; - while (nextSon != firstSon) - { - holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - os << " edge [\n"; - os << " source " << id[checkNode->m_identificationNumber] << "\n"; - os << " target " << id[nextSon->m_identificationNumber] << "\n"; - os << " ]\n"; // edge - } - } - } - } - os << "]\n"; // graph -} - - - -/************************************************************************ - Reduce -************************************************************************/ - -/** - * The function Reduce() does the reduction of the pertinent leaves - * with the help of the template matchings, designed by Booth and Lueker. - * The reader should observe that this function can only be called after - * every pertinent node in the pertinent subtree has gotten a valid parent - * pointer. If this is not the case, the programm will be interrupted - * by run-time errors such as seqmentation faults. The pertinent nodes - * can get valid parent pointers by using the function Bubble(). - * If the function Bubble() returns 1, then it was succesful in - * giving each pertinent node in the pertinent subtree a valid parent pointer. - * If the function returns 0, then some nodes do not have a valid - * parent pointer and the pertinent leaves are not reducable. - * - * The function Reduce() starts with the pertinent leaves and stores - * them in - * a queue \a processNodes. Every time a node is processed, its parent is - * checked whether all its pertinent children are already processed. - * If this is the case, the parent is allowed to be processed as well - * and stored in the queue. - * - * Processing a node means that the function Reduce() tries to apply - * one of the template matchings. In case that one template matching was - * successful, the node was reduced and Reduce() tries to reduce the - * next node. - * In case that no template matching was successfully applied, the tree is - * is irreducible. This causes the reduction process to be halted - * returning 0. - * - * The folllowing variables are used by the function Reduce(). - * - \a checkLeaf is a pointer to a various PQLeaf of the set of - * elements that has to be reduced. - * - \a checkNode is a pointer to a various node of the pertinent - * subtree. - * - \a pertLeafCount counts the number of pertinent leaves in the - * PQ-tree. Since Reduce() takes care that every node knows the - * number of pertinent leaves in its frontier, the root of the - * pertinent subtree can be identified with the help of \a pertLeafCount. - * - \a processNodes is a queue storing nodes of the pertinent - * subtree that are considered to be reduced next. A node may be - * reduced (and therefore is pushed on to \a processNodes) as soon as - * all its pertinent children have been reduced. - */ - -template -bool PQTree::Reduce(SListPure*> &leafKeys) -{ - int pertLeafCount = 0; - Queue*> processNodes; - - /* - In a first step the pertinent leaves have to be identified in the tree - and are entered on to the queue [[processNodes]]. The identification of - the leaves can be done with the help of a pointer stored in every - [[PQLeafKey]] in constant time for every element. - */ - SListIterator*> it; - for (it = leafKeys.begin(); it.valid(); ++it) - { - PQNode* checkLeaf = (*it)->nodePointer(); - checkLeaf->status(PQNodeRoot::FULL); - checkLeaf->m_pertLeafCount = 1; - processNodes.append(checkLeaf); - pertLeafCount++; - } - - PQNode* checkNode = processNodes.top(); - while ((checkNode != 0) && (processNodes.size() > 0)) - { - checkNode = processNodes.pop(); - - if (checkNode->m_pertLeafCount < pertLeafCount) - { - /* - Application of the template matchings to a pointer [[checkNode]] - storing the adress of a node that is {\bf not the root} of the - pertinent subtree. Before applying the template matchings to - [[checkNode]], some values of the parent of [[checkNode]] are - updated. The number of the parents pertinent children stored in - [[pertChildCount]] is count down by one. In case that - [[checkNode->m_parent->m_pertChildCount == 0]], we know that all - pertinent children of the parent have been processed. Since the - parent then is allowed to be processed as well, - [[checkNode->m_parent]] is stored in the queue [[processNodes]]. - */ - checkNode->m_parent->m_pertLeafCount = - checkNode->m_parent->m_pertLeafCount - + checkNode->m_pertLeafCount; - - checkNode->m_parent->m_pertChildCount--; - if (!checkNode->m_parent->m_pertChildCount) - processNodes.append(checkNode->m_parent); - if (!templateL1(checkNode,0)) - if (!templateP1(checkNode,0)) - if (!templateP3(checkNode)) - if (!templateP5(checkNode)) - if (!templateQ1(checkNode,0)) - if (!templateQ2(checkNode,0)) - checkNode= 0; - } - else - { - /* - application of the template matchings to a pointer [[checkNode]] - that stores the adress of a node that {\bf is the root} of the - pertinent subtree. In a case that a template matching was - successfully applied, the pointer [[checkNode]] stores after the - application the adress of the root of pertinent subtree. This - includes nodes that have been newly introduced as root of the - perinent subtree during the application. If no template matching - was successfully applied [[checkNode]] is a [[0]] pointer. - */ - if (!templateL1(checkNode,1)) - if (!templateP1(checkNode,1)) - if (!templateP2(&checkNode)) - if (!templateP4(&checkNode)) - if (!templateP6(&checkNode)) - if (!templateQ1(checkNode,1)) - if (!templateQ2(checkNode,1)) - if (!templateQ3(checkNode)) - checkNode = 0; - } - } - - m_pertinentRoot = checkNode; - return (m_pertinentRoot != 0); -} - - - -/************************************************************************ - Reduction -************************************************************************/ - -/** - * The function Reduction() tests whether permissible permutations of the - * elements of U exist such that the elements of a subset S of U, - * stored in \a leafKeys, form a consecutive sequence. If there exists - * such a permutation, the PQ-tree is reduced and Reduction() - * returns 1. - * - * The function Reduction() gets a list \a leafKeys - * of pointers to elements of type PQLeafKey, - * representing all elements of S. - * - * Reduction() calls the procedure Bubble() and if Bubble() was - * successful, Reduction() calls the function Reduce(). - */ - -template -bool PQTree::Reduction(SListPure*> &leafKeys) -{ - bool success = Bubble(leafKeys); - - if (!success) - return false; - else - return Reduce(leafKeys); - -} - - -/************************************************************************ - removeBlock -************************************************************************/ - -/** - * This chunk contains the procedure removeBlock. It is used by the functions - * templateQ2() and templateQ3(). The node \a nodePtr is expected to be a - * Q-node with no, one or at most two partial children, such that - * the partial and full children of \a nodePtr form a legal consecutive - * sequence, hence can be reduced. - * - * The function removeBlock() does the - * following: Of every partial node that is found in the sequence of children of - * \a nodePtr, all children are removed from that partial node and included - * as children of \a nodePtr, occupying the place of the partial node in - * the sequence of children of \a nodePtr. Thereby, removeBlock() takes - * care, that the newly included full children of \a nodePtr form - * a consecutive sequence with the already existing pertinent children of - * \a nodePtr. The partial node itself is deleted afterwards. - */ - -template -void PQTree::removeBlock(PQNode *nodePtr,bool isRoot) - -{ - /* - For every - partial child we keep a set of pointers. Since there are at most - two partial children, we initialize two sets. Every set contains - besides a pointer to the partial child four pointers to its endmost - children, sorted according to their full or empty labels and pointers - to the immediate siblings of the partial child, also sorted according - to their full or empty labels. - */ - ///Pointer to the first partial child - PQNode *partial_1 = 0; - - /* - Pointer to the full endmost child (more - precisely: to the endmost child appearing on the full side) of - [[partial_1]]. In case that ignored nodes are used, this [[endfull_1]] - may store the adress of an ignored node. - */ - PQNode *endfull_1 = 0; - - /* - Pointer to the empty endmost child (more - precisely: to the endmost child appearing on the empty side) of - [[partial_1]]. In case that ignored nodes are used, this [[endempty_1]] - may store the adress of an ignored node. - */ - PQNode *endempty_1 = 0; - - /* - Pointer to the first {\it non ignored} node - with full status. [[realfull_1]] is identical to [[endfull_1]] if no - ignored nodes appear at the full end of the first partial child. - */ - PQNode *realfull_1 = 0; - - /* - Pointer to the first {\it non ignored} node - with empty status. [[realempty_1]] is identical to [[endempty_1]] if no - ignored nodes appear at the empty end of the first partial child. - */ - PQNode *realempty_1 = 0; - - // Pointer to the second partial child. - PQNode *partial_2 = 0; - - /* - Pointer to the full endmost child (more - precisely: to the endmost child appearing on the full side) of - [[partial_2]]. In case that ignored nodes are used, this [[endfull_2]] - may store the adress of an ignored node. - */ - PQNode *endfull_2 = 0; - - /* - Pointer to the empty endmost child (more - precisely: to the endmost child appearing on the empty side) of - [[partial_2]]. In case that ignored nodes are used, this [[endempty_2]] - may store the adress of an ignored node. - */ - PQNode *endempty_2 = 0; - - /* - Pointer to the first {\it non ignored} node - with empty status. [[realempty_2]] is identical to [[endempty_2]] if no - ignored nodes appear at the empty end of the first partial child. - */ - PQNode *realempty_2 = 0; - - /* - Pointer to a full sibling of - [[partial_1]], if it exists. In case that ignored nodes are used - this [[sibfull_1]] stores the direct sibling of [[partial_1]] - on the side where the full siblings are. Hence [[sibfull_1]] may - store an ignored node. - */ - PQNode *sibfull_1 = 0; - - /* - Pointer to a partial sibling of - [[partial_1]], if it exists. In case that ignored nodes are used - this [[sibpartial_1]] stores the direct sibling of [[partial_1]] - on the side where a partial sibling is. Hence [[sibpartial_1]] may - store an ignored node. - */ - PQNode *sibpartial_1 = 0; - - /* - Pointer to an empty sibling of - [[parial_1]], if it exists. In case that ignored nodes are used - this [[sibempty_1]] stores the direct sibling of [[partial_1]] - on the side where the empty siblings are. Hence [[sibempty_1]] may - store an ignored node. - */ - PQNode *sibempty_1 = 0; - - /* - Pointer only used in case that [[partial_1]] has - no non-ignored siblings on one side. [[partial_1]] then is endmost child - of [[nodePtr]], but ignored children may appear between [[partial_1]] - and the end of sequence of children of [[nodePtr]]. The - [[nonstatussib_1]] then stores the adress of the endmost ignored child. - Observe that it is not valid for a $Q$-node to have only one - non-ignored child and several ignored children. Hence this situation - is only allowed to appear {\bf once} on one side of [[partial_1]]. - Every other situation results in an error message. - */ - PQNode *nonstatussib_1 = 0; - - /* - Pointer to a full sibling of - [[partial_2]], if it exists. In case that ignored nodes are used - this [[sibfull_2]] stores the direct sibling of [[partial_2]] - on the side where the full siblings are. Hence [[sibfull_2]] may - store an ignored node. - */ - PQNode *sibfull_2 = 0; - - /* - Pointer to a partial sibling of - [[partial_2]], if it exists. In case that ignored nodes are used - this [[sibpartial_2]] stores the direct sibling of [[partial_2]] - on the side where a partial sibling is. Hence [[sibpartial_2]] may - store an ignored node. - */ - PQNode *sibpartial_2 = 0; - - /* - Pointer to an empty sibling of - [[parial_2]], if it exists. In case that ignored nodes are used - this [[sibempty_2]] stores the direct sibling of [[partial_2]] - on the side where the empty siblings are. Hence [[sibempty_2]] may - store an ignored node. - */ - PQNode *sibempty_2 = 0; - - /* - Pointer only used in case that [[partial_2]] has - no non-ignored siblings on one side. [[partial_2]] then is endmost child - of [[nodePtr]], but ignored children may appear between [[partial_2]] - and the end of sequence of children of [[nodePtr]]. The - [[nonstatussib_2]] then stores the adress of the endmost ignored child. - Observe that it is not valid for a $Q$-node to have only one - non-ignored child and several ignored children. Hence this situation - is only allowed to appear {\bf once} on one side of [[partial_2]]. - Every other situation results in an error message. - */ - PQNode *nonstatussib_2 = 0; - - PQNode *helpptr = 0; - - PQNode *checkVarLeft = 0; - - PQNode *checkVarRight = 0; - - /* - [[endmostcheck]] is [[1]], if [[partial_1]] is the endmost - child of [[nodePtr]]. Per default, [[endmostcheck]] is [[0]]. - */ - int endmostcheck = 0; - - - nodePtr->status(PQNodeRoot::PARTIAL); - if (!isRoot) - nodePtr->m_parent->partialChildren->pushFront(nodePtr); - - if (!nodePtr->partialChildren->empty()) - // Get a partial child. - { - partial_1 = nodePtr->partialChildren->popFrontRet(); - - // Get the full and empty - // endmost children of the - // partial child [[partial_1]]. - checkVarLeft = clientLeftEndmost(partial_1); - checkVarRight = clientRightEndmost(partial_1); - if (checkVarLeft->status() == PQNodeRoot::FULL) - { - endfull_1 = partial_1->m_leftEndmost; - realfull_1 = checkVarLeft; - } - else { - // partial child with no full endmost child detected? - OGDF_ASSERT(checkVarRight->status() == PQNodeRoot::FULL); - - endfull_1 = partial_1->m_rightEndmost; - realfull_1 = checkVarRight; - } - - if (checkVarLeft->status() == PQNodeRoot::EMPTY) - { - endempty_1 = partial_1->m_leftEndmost; - realempty_1 = checkVarLeft; - } - else { - // partial child with no empty endmost child detected? - OGDF_ASSERT(checkVarRight->status() == PQNodeRoot::EMPTY); - - endempty_1 = partial_1->m_rightEndmost; - realempty_1 = checkVarRight; - } - - // Get the immediate - // siblings of the partial - // child [[partial_1]]. - if (clientSibLeft(partial_1) != 0) - { - if (clientSibLeft(partial_1)->status() == PQNodeRoot::FULL) - sibfull_1 = partial_1->m_sibLeft; - else if (clientSibLeft(partial_1)->status() == PQNodeRoot::EMPTY) - sibempty_1 = partial_1->m_sibLeft; - else if (clientSibLeft(partial_1)->status() == PQNodeRoot::PARTIAL) - sibpartial_1 = partial_1->m_sibLeft; - } - else - nonstatussib_1 = partial_1->m_sibLeft; - - if (clientSibRight(partial_1) != 0) - { - if (clientSibRight(partial_1)->status() == PQNodeRoot::FULL) - sibfull_1 = partial_1->m_sibRight; - else if (clientSibRight(partial_1)->status() == PQNodeRoot::EMPTY) - sibempty_1 = partial_1->m_sibRight; - else if (clientSibRight(partial_1)->status() == PQNodeRoot::PARTIAL) - sibpartial_1 = partial_1->m_sibRight; - } - else { - // partial child detected with no siblings of valid status? - OGDF_ASSERT(nonstatussib_1 == 0); - nonstatussib_1 = partial_1->m_sibRight; - } - } - - - if (!nodePtr->partialChildren->empty()) - // There is a second partial child. - { - partial_2 = nodePtr->partialChildren->popFrontRet(); - // Get the full and empty endmost - // children of the partial - // child [[partial_2]]. - - checkVarLeft = clientLeftEndmost(partial_2); - checkVarRight = clientRightEndmost(partial_2); - if (checkVarLeft->status() == PQNodeRoot::FULL) - { - endfull_2 = partial_2->m_leftEndmost; - } - else { - // partial child with no full endmost child detected? - OGDF_ASSERT(checkVarRight->status() == PQNodeRoot::FULL); - - endfull_2 = partial_2->m_rightEndmost; - } - - if (checkVarLeft->status() == PQNodeRoot::EMPTY) - { - endempty_2 = partial_2->m_leftEndmost; - realempty_2 = checkVarLeft; - } - else { - // partial child with no empty endmost child detected? - OGDF_ASSERT(checkVarRight->status() == PQNodeRoot::EMPTY); - - endempty_2 = partial_2->m_rightEndmost; - realempty_2 = checkVarRight; - } - // Get the immediate siblings - // of the partial child - // [[partial_2]]. - if (clientSibLeft(partial_2) != 0) - { - if (clientSibLeft(partial_2)->status() == PQNodeRoot::FULL) - sibfull_2 = partial_2->m_sibLeft; - else if (clientSibLeft(partial_2)->status() == PQNodeRoot::EMPTY) - sibempty_2 = partial_2->m_sibLeft; - else if (clientSibLeft(partial_2)->status() == PQNodeRoot::PARTIAL) - sibpartial_2 = partial_2->m_sibLeft; - } - else - nonstatussib_2 = partial_2->m_sibLeft; - - - if (clientSibRight(partial_2) != 0) - { - if (clientSibRight(partial_2)->status() == PQNodeRoot::FULL) - sibfull_2 = partial_2->m_sibRight; - else if (clientSibRight(partial_2)->status() == PQNodeRoot::EMPTY) - sibempty_2 = partial_2->m_sibRight; - else if (clientSibRight(partial_2)->status() == PQNodeRoot::PARTIAL) - sibpartial_2 = partial_2->m_sibRight; - } - else { - OGDF_ASSERT(nonstatussib_2 == 0); - nonstatussib_2 = partial_2->m_sibRight; - } - } - - - if (partial_1 != 0 && partial_2 != 0) - - /* - Connect the endmost - children of the partial children [[partial_1]] and [[partial_2]] correctly - with their new siblings. In doing this, all children of the partial - children become children of [[nodePtr]]. The reader should observe that - the parent pointers of the interior children of [[partial_1]] and - [[partial_2]] are not updated in order to hit the linear time complexity. - - When including the children of the partial children to the children - of [[nodePtr]], it is taken care that all full children - form a consecutive sequence afterwards. If neccessary the pointers to the - endmost children of [[nodePtr]] are updated. - */ - { - if (sibfull_1 != 0 && sibfull_2 != 0) - // There are full children between - // the 2 partial nodes. - // Connect the full children - // between the 2 partial children - // with the full endmost children - // of the 2 partial nodes. - { - sibfull_1->changeSiblings(partial_1,endfull_1); - endfull_1->putSibling(sibfull_1); - sibfull_2->changeSiblings(partial_2,endfull_2); - endfull_2->putSibling(sibfull_2); - } - - else if (sibpartial_1 != 0 && sibpartial_2 != 0) - // There are no full children between - // the 2 partial nodes. Connect the - // full endmost children of the - // partial nodes as siblings. - { - if (partial_1 == sibpartial_2 && partial_2 == sibpartial_1) - // Regular Case. - { - endfull_1->putSibling(endfull_2); - endfull_2->putSibling(endfull_1); - } - // Only ignored children between - // partial_1 and partial_2. - else - { - endfull_1->putSibling(sibpartial_1); - sibpartial_1->changeSiblings(partial_1,endfull_1); - endfull_2->putSibling(sibpartial_2); - sibpartial_2->changeSiblings(partial_2,endfull_2); - } - - } - // Include the children of the - // partial children with their - // full nodes inbetween into - // the sequence of the children of - // Q-node nodePtr. - if (sibempty_1 == 0) - // partial_1 is endmost child of - // nodePtr. Make the empty endmost - // child of partial_1 be the new - // endmost child of nodePtr. - { - if (nonstatussib_1 == 0) - // Regular case. - { - nodePtr->changeEndmost(partial_1,endempty_1); - } - else - // Only ignored children between - // partial_1 and one end of nodePtr. - { - nonstatussib_1->changeSiblings(partial_1,endempty_1); - endempty_1->putSibling(nonstatussib_1); - } - endempty_1->m_parent = nodePtr; - realempty_1->m_parent = nodePtr; - } - - else - // partial_1 is not endmost child. - { - sibempty_1->changeSiblings(partial_1,endempty_1); - endempty_1->putSibling(sibempty_1); - } - - - if (sibempty_2 == 0) - // partial_2 is endmost child of - // nodePtr. Make the empty endmost - // child of partial_2 be the new - // endmost child of nodePtr. - { - if (nonstatussib_2 == 0) - // Regular case. - { - nodePtr->changeEndmost(partial_2,endempty_2); - } - else - // Only ignored children between - // partial_1 and one end of - // nodePtr. - { - nonstatussib_2->changeSiblings(partial_2,endempty_2); - endempty_2->putSibling(nonstatussib_2); - } - endempty_2->m_parent = nodePtr; - realempty_2->m_parent = nodePtr; - } - - else - // partial_2 is not endmost child. - { - sibempty_2->changeSiblings(partial_2,endempty_2); - endempty_2->putSibling(sibempty_2); - } - - // Copy the full children of - // partial_1 and partial_2 to - // nodePtr. - while (!partial_2->fullChildren->empty()) - { - helpptr = partial_2->fullChildren->popFrontRet(); - nodePtr->fullChildren->pushFront(helpptr); - } - nodePtr->m_childCount = nodePtr->m_childCount +partial_2->m_childCount - 1; - - destroyNode(partial_2); - - while (!partial_1->fullChildren->empty()) - { - helpptr = partial_1->fullChildren->popFrontRet(); - nodePtr->fullChildren->pushFront(helpptr); - } - nodePtr->m_childCount = nodePtr->m_childCount +partial_1->m_childCount - 1; - - destroyNode(partial_1); - } - - - else if (partial_1 != 0) - - /* - Connect the endmost - children of the partial child [[partial_1]] correctly - with their new siblings. In doing this, all children of the partial - child become children of [[nodePtr]]. The reader should observe that - the parent pointers of the interior children of [[partial_1]] - are not updated in order to hit the linear time complexity. - - When including the children of [[partial_1]] to the children - of [[nodePtr]], it is taken care that all full children - form a consecutive sequence afterwards. If necessary the pointers to the - endmost children of [[nodePtr]] are updated. - */ - - { - if ((clientLeftEndmost(nodePtr) == partial_1) || - (clientRightEndmost(nodePtr) == partial_1)) - // partial_1 is endmost child. - endmostcheck = 1; - - if (sibfull_1 != 0) - // There are full children on one - // side of the partial node. - // Connect the full children with - // the full endmost child of - // partial_1. - { - sibfull_1->changeSiblings(partial_1,endfull_1); - endfull_1->putSibling(sibfull_1); - } - - else if (!endmostcheck) - // There are not any full children - // and partial_1 is not endmost. - // So get the 2nd empty sibling - // of partial_1 and connect it - // to the full endmost child - // of partial_1. - { - if (partial_1->m_sibLeft != sibempty_1) - sibempty_2 = partial_1->m_sibLeft; - else - sibempty_2 = partial_1->m_sibRight; - - sibempty_2->changeSiblings(partial_1,endfull_1); - endfull_1->putSibling(sibempty_2); - } - - else - // partial_1 is endmost child - // and there are no full children. - // Make the full endmost child of - // partial_1 be the endmostchild - // of nodePtr. - { - - if (nonstatussib_1 == 0) - // Regular case. - { - nodePtr->changeEndmost(partial_1,endfull_1); - } - else - // Only ignored children between - // partial_1 and one end of - // nodePtr. - { - nonstatussib_1->changeSiblings(partial_1,endfull_1); - endfull_1->putSibling(nonstatussib_1); - } - endfull_1->m_parent = nodePtr; - realfull_1->m_parent = nodePtr; - - } - - if (sibempty_1 == 0) - // There are no empty children. - // partial_1 is endmost child of - // nodePtr. Make the empty endmost - // child of partial_1 be the new - // endmost child of nodePtr. - { - if (nonstatussib_1 == 0) - // Regular case. - { - nodePtr->changeEndmost(partial_1,endempty_1); - } - else - // Only ignored children between - // partial_1 and one end of - // nodePtr. - { - nonstatussib_1->changeSiblings(partial_1,endempty_1); - endempty_1->putSibling(nonstatussib_1); - } - endempty_1->m_parent = nodePtr; - realempty_1->m_parent = nodePtr; - } - - else - // There are empty children. So - // connect the empty endmost child - // of partial_1 with sibempty_1. - { - sibempty_1->changeSiblings(partial_1,endempty_1); - endempty_1->putSibling(sibempty_1); - } - - while (!partial_1->fullChildren->empty()) - { - helpptr = partial_1->fullChildren->popFrontRet(); - nodePtr->fullChildren->pushFront(helpptr); - } - - nodePtr->m_childCount = nodePtr->m_childCount + partial_1->m_childCount - 1; - destroyNode(partial_1); - - } - // else nodePtr does not have partial children. Then nothing is to do. -} - - -/************************************************************************ - removeChildFromSiblings -************************************************************************/ - -/** - * The function removeChildFromSiblings() removes the node \a nodePtr from - * the doubly linked list of its parent. In case that \a nodePtr is endmost - * child of an Q-node or child of a P-node equiped with a valid - * reference pointer \a referenceParent to its parent (see PQNode), - * these pointers are considered as - * well and the adjacent siblings of \a nodePtr have to cover - * \a nodePtr's task. - */ - -template -void PQTree::removeChildFromSiblings(PQNode* nodePtr) -{ - if (nodePtr->m_referenceParent != 0) - { - /* - Checksif [[nodePtr]] is connected with its parent via the reference - pointers (see \ref{PQNode}). If so, the next sibling of [[nodePtr]] - will be the the new reference child. - */ - nodePtr->m_referenceParent->m_referenceChild = nodePtr->m_sibRight; - nodePtr->m_sibRight->m_referenceParent = nodePtr->m_referenceParent; - if (nodePtr->m_referenceParent->m_referenceChild == nodePtr) - nodePtr->m_referenceParent->m_referenceChild = 0; - nodePtr->m_referenceParent = 0; - } - else if (nodePtr->endmostChild()) - { - /* - Check if [[nodePtr]] is the endmost child of a $Q$-node. - If so, the next sibling of [[nodePtr]] will be the the new endmost - child of the $Q$-node. Observe that the sibling then gets a valid - pointer to its parent. - */ - PQNode *sibling = nodePtr->getNextSib(0); - if (nodePtr->m_parent->m_leftEndmost == nodePtr) - nodePtr->m_parent->m_leftEndmost = sibling; - else if (nodePtr->m_parent->m_rightEndmost == nodePtr) - nodePtr->m_parent->m_rightEndmost = sibling; - if (sibling != 0) - sibling->m_parent = nodePtr->m_parent; - } - - /* - Remove [[nodePtr]] from its immediate siblings and links the - siblings via the [[sibRight]] and [[sibLeft]] pointers. - */ - if ((nodePtr->m_sibRight != 0) && (nodePtr->m_sibRight != nodePtr)) - { - if (nodePtr->m_sibRight->m_sibLeft == nodePtr) - nodePtr->m_sibRight->m_sibLeft = nodePtr->m_sibLeft; - else { - // Sibling was not connected to child? - OGDF_ASSERT(nodePtr->m_sibRight->m_sibRight == nodePtr); - nodePtr->m_sibRight->m_sibRight = nodePtr->m_sibLeft; - } - } - if ((nodePtr->m_sibLeft != 0) && (nodePtr->m_sibLeft != nodePtr)) - { - if (nodePtr->m_sibLeft->m_sibRight == nodePtr) - nodePtr->m_sibLeft->m_sibRight = nodePtr->m_sibRight; - else { - // Sibling was not connected to child? - OGDF_ASSERT(nodePtr->m_sibLeft->m_sibLeft == nodePtr); - nodePtr->m_sibLeft->m_sibLeft = nodePtr->m_sibRight; - } - } - - nodePtr->m_sibRight = 0; - nodePtr->m_sibLeft = 0; -} - - -/************************************************************************ - removeNodeFromTree -************************************************************************/ - -/** - * The function removeNodeFromTree() has to be handled with great care by - * the user. This function is not used in any of the functions of - * the class template PQTree and can only be accessed by inheritance. - * - * Its objective is to remove a node \a child from the PQ-tree. To do so, - * the \a parent of the node \a child has to be known by the user. - * To indicate this, the parent has to be handed over by her. - * - * This function does not check if \a parent is the parent node of - * \a child. This has to be guaranteed by the user. The reason for - * this riscfull approach lies in the details of the powerful data structure - * PQ-tree. In order to reach linear runtime, the internal children - * of a Q-node normally do not have valid parent pointers. So forcing - * this function to search the parent would cost in worst case - * linear runtime for one call of the function removeNodeFromTree(). - * Its up to the user to do better. - * - * Calling removeNodeFromTree() with a 0-pointer for \a parent, - * will always terminate this function with an ERROR-message and returning - * -1 as value. - * - * The return value is an integer value used to indicate how many children - * the \a parent after the removal of \a child still has. The client should - * observe that internal nodes in the PQ-tree which have just one or - * no children at all do not make sense. However, the function - * removeNodeFromTree() does not check if \a parent has less than - * two children after the removal of \< child. - * So in case that \a parent has less than two children, the user has to check - * this by herself and remove the \a parent, probably using the function - * checkIfOnlyChild(). - * - * There are two reasons why the function removeNodeFromTree() does - * not check if \a parent has less than two children after the removal - * of \a child: - * -# The user might keep the node in the tree in order to add new nodes - * as children to it. - * -# Again, the parent of \a parent might not be known to \a parent, - * hence removeNodeTree() would have to search, at the cost of linear time - * consumption, for the parent of \a parent first before removing - * \a parent from the tree. - * - * Observe that removeNodeFromTree() does not free the allocated - * memory of \a child. This has to be done by the user \b after calling - * removeNodeFromTree(). It also offers the opportunity to reuse - * deleted nodes. Observe that the identification number of a node - * \a m_identificationNumber (see PQNode) cannot be changed. - */ - -template -int PQTree::removeNodeFromTree(PQNode* parent,PQNode* child) -{ - if (parent !=0) - { - removeChildFromSiblings(child); - parent->m_childCount--; - if ((child->status() == PQNodeRoot::FULL) || (child->status() == PQNodeRoot::PARTIAL)) - parent->m_pertChildCount--; - return parent->m_childCount; - } - else - { - //parent is invalid 0-pointer. - return -1; - } -} - - -/************************************************************************ - sortExceptions -************************************************************************/ - -/** - * The function sortExceptions() is only called by the function frontExcept(). - * It sorts the exceptions before frontExcept() - * scans the frontier. - */ - -template -void PQTree::sortExceptions(int Exceptions[],int arraySize) -{ - bool changed = true; - while (changed) - { - changed = false; - for (int i = 0; i < (arraySize-1); i++) - { - if (Exceptions[i] > Exceptions[i+1]) - { - swap(Exceptions[i],Exceptions[i+1]); - changed = true; - } - } - } -} - - -/************************************************************************ - templateL1 -************************************************************************/ - -/** - * The function templateL1() implements the template matching for - * leaves. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a PQLeaf, - * templateL1() considers itself responsible for the node and will - * apply the template matching for pertinent leaves to \a nodePtr. - * If the flag \a isRoot is set to 1, it signalizes - * templateL1() that \a nodePtr is the root of - * the pertinent subtree. In any other case the flag has to be 0. - * - * If templateL1() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * The function updates the \a fullChildren stack of its parent, as long as - * \a nodePtr is not the root of the pertinent subtree. - * Observe that \a nodePtr needs a valid pointer to its parent. This - * can be achieved by using the function Bubble() or any other - * appropriate, user defined function. - */ - -template -bool PQTree::templateL1(PQNode *nodePtr, bool isRoot) -{ - if ((nodePtr->type() == PQNodeRoot::leaf) && (nodePtr->status() == PQNodeRoot::FULL)) - { - if (!isRoot) - nodePtr->m_parent->fullChildren->pushFront(nodePtr); - return true; - } - - return false; -} - - -/************************************************************************ - templateP1 -************************************************************************/ - -/** - * The function templateP1() implements the template matching for - * P-nodes with only full children. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a P-node with - * only full children, - * templateP1() considers itself responsible for the node and will - * apply the template matching for full P-nodes to \a nodePtr. - * If the flag \a isRoot is set to 1, it signalizes - * templateP1() that \a nodePtr is the root of - * the pertinent subtree. In any other case the flag has to be 0. - * - * If templateP1() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * If the P-node is not the root of the pertinent subtree, - * the \a fullChildren stack of the parent of \a nodePtr is updated. - * If the P-node is the root of the pertinent subtree, nothing has to - * be done. - */ - -template -bool PQTree::templateP1(PQNode *nodePtr, bool isRoot) -{ - if (nodePtr->type() != PQNodeRoot::PNode || - nodePtr->fullChildren->size() != nodePtr->m_childCount) - return false; - else - { - nodePtr->status(PQNodeRoot::FULL); - if (!isRoot) - nodePtr->m_parent->fullChildren->pushFront(nodePtr); - - return true; - } -} - - -/************************************************************************ - templateP2 -************************************************************************/ - -/** - * The function templateP2() implements the template matching for a - * P-node with full \b and empty children that is the root of - * the pertinent subtree. - * The function requires as input any pointer to a node stored in - * \ nodePtr. If the node stored in \a nodePtr is a P-node with - * no partial children, - * templateP2() considers itself responsible for the node and will - * apply the template matching \b P2 to \a nodePtr. - * Observe that the user calling this function has to make sure that - * \a nodePtr is partial and is the root of the pertinent subtree. - * - * If templateP2() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * The function templateP2() creates a new full P-node that - * will be the new root of the pertinent subtree. It then copies all full - * children from \a nodePtr to the new root of the pertinent subtree. - */ - -template -bool PQTree::templateP2(PQNode **nodePtr) -{ - if ((*nodePtr)->type() != PQNodeRoot::PNode || - (*nodePtr)->partialChildren->size() > 0) - return false; - - (*nodePtr)->m_childCount = - (*nodePtr)->m_childCount - (*nodePtr)->fullChildren->size() + 1; - // Gather all full children of nodePtr - // as children of the new P-node. - // Delete them from nodePtr. - - PQNode *newNode = createNodeAndCopyFullChildren((*nodePtr)->fullChildren); - // Correct parent-pointer and - // sibling-pointers of the new P-node. - - newNode->m_parent = (*nodePtr); - newNode->m_sibRight = (*nodePtr)->m_referenceChild->m_sibRight; - newNode->m_sibLeft = newNode->m_sibRight->m_sibLeft; - newNode->m_sibLeft->m_sibRight = newNode; - newNode->m_sibRight->m_sibLeft = newNode; - newNode->m_parentType = PQNodeRoot::PNode; - // The new P-node now is the root of - // the pertinent subtree. - (*nodePtr) = newNode; - - return true; -} - - -/************************************************************************ - templateP3 -************************************************************************/ - -/* - * The function templateP3() implements the template matching for a - * P-node with full \b and empty children that is \b not the root of - * the pertinent subtree. - * The function requires as input any pointer to a node stored in - * \ nodePtr. If the node stored in \a nodePtr is a P-node with - * no partial children, - * templateP3() considers itself responsible for the node and will - * apply the template matching \b P3 to \a nodePtr. - * Observe that the user calling this function has to make sure that - * \a nodePtr is partial and is not the root of the pertinent subtree. - * - * If templateP3() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * The function templateP3() creates - * a new full P-node, stored in \a newPnode and copies the full children - * of \a nodePtr to \a newPnode. \a nodePtr keeps all empty children - * and will be labeled empty. A new partial Q-node will be created and stored - * in \a newQnode. \a newQnode is placed at the position of \a nodePtr - * in the tree and gets two children: \a nodePtr itself and the newly - * created \a newPnode. - * - * The function templateP3() uses a few variables. - * - \a newPnode is the pointer to the new P-node, or, in case - * that \a nodePtr has only one full child, is the pointer of this child. - * - \a newQnode is the pointer to the new Q-node. - * - \a newNode is used for the proper allocation of the new - * Q-node. - * - \a emptyNode is a pointer to any empty child of nodePtr. - */ - -template -bool PQTree::templateP3(PQNode *nodePtr) -{ - if (nodePtr->type() != PQNodeRoot::PNode || nodePtr->partialChildren->size() > 0) - return false; - - /* - Create a new partial $Q$-node stored in [[newQnode]]. - It replaces [[nodePtr]] by the Q-node [[newQnode]] in the $PQ$-tree - and makes [[nodePtr]] endmost child of [[newQnode]]. - This is done by updating parent-pointers and sibling-pointers. - */ - PQInternalNode *newNode = OGDF_NEW PQInternalNode(m_identificationNumber++,PQNodeRoot::QNode,PQNodeRoot::PARTIAL); - PQNode *newQnode = newNode; - m_pertinentNodes->pushFront(newQnode); - - exchangeNodes(nodePtr,newQnode); - nodePtr->m_parent = newQnode; - nodePtr->m_parentType = PQNodeRoot::QNode; - - newQnode->m_leftEndmost = (nodePtr); - newQnode->m_childCount = 1; - - /* - Create a new full $P$-node stored in [[newPnode]]. - It copies the full children of [[nodePtr]] to [[newPnode]]. - The new $P$-node will then be included into the tree as child of - the new $Q$-node [[newQnode]]. - */ - if (nodePtr->fullChildren->size() > 0) - { - nodePtr->m_childCount = nodePtr->m_childCount - - nodePtr->fullChildren->size(); - - PQNode *newPnode = createNodeAndCopyFullChildren(nodePtr->fullChildren); - newPnode->m_parentType = PQNodeRoot::QNode; - - // Update newQnode. - newQnode->m_childCount++; - newQnode->fullChildren->pushFront(newPnode); - // Update sibling pointers. - nodePtr->m_sibRight = newPnode; - newPnode->m_sibLeft = nodePtr; - newQnode->m_rightEndmost = newPnode; - newPnode->m_parent = newQnode; - } - - // Check if nodePtr contains - // only one son. If so, nodePtr - // will be deleted from the tree. - PQNode *emptyNode = nodePtr->m_referenceChild; - checkIfOnlyChild(emptyNode,nodePtr); - // Update partialchildren stack of - // the parent of the new Q-node. - newQnode->m_parent->partialChildren->pushFront(newQnode); - - return true; -} - - -/************************************************************************ - templateP4 -************************************************************************/ - -/** - * The function templateP4() implements the template matching for a - * P-node with full, empty and exactly one partial children. The - * P-node has to be the root of the pertinent subtree. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a P-node with - * one partial child, - * templateP4() considers itself responsible for the node and will - * apply the template matching \b P4 to \a nodePtr. - * Observe that the user calling this function has to make sure that - * \a nodePtr is the root of the pertinent subtree. - * - * If templateP4() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * The function templateP4() creates a new full P-node, if neccessary, - * and copies the full children of \a nodePtr to this P-node. - * The new P-node then is made endmost child of \a partialChild. - * The node \a partialChild is used to store the adress of the partial - * child of \a nodePtr. - * The \a partialChild itself stays child of \a nodePtr. - * Most of the here described action is done in the function - * copyFullChildrenToPartial(). - */ - -template -bool PQTree::templateP4(PQNode **nodePtr) -{ - if ((*nodePtr)->type() != PQNodeRoot::PNode || - (*nodePtr)->partialChildren->size() != 1) - return false; - - PQNode *partialChild = (*nodePtr)->partialChildren->popFrontRet(); - copyFullChildrenToPartial(*nodePtr,partialChild); - // If nodePtr does not have any - // empty children, then it has to - // be deleted and the partial node - // is occupying its place in the tree. - checkIfOnlyChild(partialChild,*nodePtr); - // The partial child now is - // root of the pertinent subtree. - *nodePtr = partialChild; - - return true; -} - - -/************************************************************************ - templateP5 -************************************************************************/ - -/** - * The function templateP5() implements the template matching for a - * P-node with full, empty children and exactly one partial child. The - * P-node is not allowed to be the root of the pertinent subtree. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a P-node with - * one partial child, - * templateP5() considers itself responsible for the node and will - * apply the template matching \b P5 to \a nodePtr. - * Observe that the user calling this function has to make sure that - * \a nodePtr is not the root of the pertinent subtree. - * - * If templateP5() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * The function templateP5() uses a few variables. - * - \a partialChild is a pointer to the partial child of - * \a nodePtr. - * - \a checkNode is a pointer to the endmost empty child of - * \a partialChild. - * - \a emptyNode is a pointer to the empty node that is copied as - * endmost child to \a partialChild. - * - \a emptyChildCount stores the number of empty children of - * \a nodePtr. - * - * If neccessary, the function templateP5() creates a new full P-node - * and copies all full children of \a nodePtr to this new full P-node. - * All empty children of \a nodePtr stay empty children of \a nodePtr. - * - * The new full P-node and \a nodePtr will be the new endmost children of - * \a partialChild. The \a partialChild then occupies the position - * of \a nodePtr in the PQ-tree. - */ - -template -bool PQTree::templateP5(PQNode *nodePtr) -{ - if ((nodePtr->type() != PQNodeRoot::PNode) || - (nodePtr->partialChildren->size() != 1)) - return false; - - /* - Remove [[partialChild]] from the children of [[nodePtr]]. The node - [[partialChild]] then occupies the position of [[nodePtr]] in the - $PQ$-tree which is done in the function call [[exchangeNodes]] - (\ref{exchangeNodes}). The chunk then removes all full children from - [[nodePtr]] and adds them as children of a new $P$-node as endmost - child of [[partialChild]]. This is done in the function call - [[copyFullChildrenToPartial]] (\ref{copyFullChildrenToPartial}). - When this chunk has finished, [[nodePtr]] has only empty children. - */ - int emptyChildCount = nodePtr->m_childCount - - nodePtr->fullChildren->size() - 1; - PQNode *partialChild = nodePtr->partialChildren->popFrontRet(); - nodePtr->m_parent->partialChildren->pushFront(partialChild); - removeChildFromSiblings(partialChild); - exchangeNodes(nodePtr,partialChild); - copyFullChildrenToPartial(nodePtr,partialChild); - - if (emptyChildCount > 0) - { - /* - Check if [[nodePtr]] has just one empty child. If so, the child - is stored in [[emptyNode]] in order to be added to the empty - side of the partial $Q$-node [[partialChild]]. If [[nodePtr]] - has more than one empty child, [[nodePtr]] is stored in - [[emptyNode]] in order to be added to the empty - side of the partial $Q$-node [[partialChild]]. - */ - PQNode *emptyNode; - if (emptyChildCount == 1) - { - emptyNode = nodePtr->m_referenceChild; - removeChildFromSiblings(emptyNode); - - } else { - emptyNode = nodePtr; - emptyNode->m_childCount = emptyChildCount; - } - - /* - Check at which side of [[partialChild]] - the empty children hide. [[emptyNode]] stores the empty node - that is added to the empty side of [[partialChild]]. - */ - PQNode *checkNode; - if (clientLeftEndmost(partialChild)->status() == PQNodeRoot::EMPTY) - { - checkNode = partialChild->m_leftEndmost; - partialChild->m_leftEndmost = emptyNode; - } - else { - // Endmostchild not found? - OGDF_ASSERT(clientRightEndmost(partialChild)->status() == PQNodeRoot::EMPTY); - - checkNode = partialChild->m_rightEndmost; - partialChild->m_rightEndmost = emptyNode; - } - - linkChildrenOfQnode(checkNode,emptyNode); - emptyNode->m_parent = partialChild; - emptyNode->m_parentType = PQNodeRoot::QNode; - partialChild->m_childCount++; - } - // If nodePtr did not have any empty - // children it has to be deleted. - if (emptyChildCount <= 1) - destroyNode(nodePtr); - - return true; -} - - -/************************************************************************ - templateP6 -************************************************************************/ - -/** - * The function templateP6() implements the template matching for a - * P-node with full, empty and exactly two partial children. The - * P-node must be the root of the pertinent subtree. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a P-node with - * two partial children, - * templateP6() considers itself responsible for the node and will - * apply the template matching \b P6 to \a nodePtr. - * Observe that the user calling this function has to make sure that - * \a nodePtr is the root of the pertinent subtree. - * - * If templateP6() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * The function templateP6() creates, if neccessary, - * a new full P-node and copies all the full children of \a nodePtr - * to the new full P-node, whereas all empty children stay children of - * \a nodePtr. The new P-node will be copied to one of the partial children - * as endmost child of this partial node. The children of the second - * partial node are copied to the first one, such that the pertinent nodes - * form a consecutive sequence. - * - * The following variables are used in the function templateP6(). - * - \a partial_1 is a pointer to the first partial child of - * \a nodePtr. - * - \a partial_2 is a pointer to the second partial child of - * \a nodePtr. - * - \a fullEnd_1 is a pointer to a full endmost child of \a partial_1. - * - \a fullEnd_2 is a pointer to a full endmost child of \a partial_2. - * - \a emptyEnd_2 is a pointer to the empty endmost child (more - * precisely: to the endmost child appearing on the empty side) of - * \a partial_2. In case that ignored nodes are used, this - * \a emptyEnd_2 may store the adress of an ignored node. - * - \a realEmptyEnd_2 is a pointer to the first non ignored - * node with empty status on the empty side of \a partial_2. In case - * that no ignored nodes are used, \a realEmpty_2 is identical to - * \a endEmpty_2. -*/ - -template -bool PQTree::templateP6(PQNode **nodePtr) -{ - //PQNode *partial_1 = 0; - //PQNode *partial_2 = 0; - //PQNode *fullEnd_1 = 0; - //PQNode *fullEnd_2 = 0; - //PQNode *emptyEnd_2 = 0; - //PQNode *realEmptyEnd_2 = 0; - - if ((*nodePtr)->type() != PQNodeRoot::PNode || - (*nodePtr)->partialChildren->size() != 2) - return false; - - /* - Get the partial children of [[nodePtr]] and removes the second - partial child stored in [[partial_2]] from the children of - [[nodePtr]]. If there are any full children of [[nodePtr]], the - chunk removes them from the children of [[nodePtr]] and copies them - as children to a new $P$-node. This new $P$-node is then made - endmost child of [[partial_1]]. - */ - PQNode *partial_1 = (*nodePtr)->partialChildren->popFrontRet(); - PQNode *partial_2 = (*nodePtr)->partialChildren->popFrontRet(); - - removeChildFromSiblings(partial_2); - (*nodePtr)->m_childCount--; - copyFullChildrenToPartial(*nodePtr,partial_1); - - /* - Check the endmost children of the two partial children of [[nodePtr]] - and stores them at approriate places, remembering what kind of type - the endmost children are. - */ - PQNode *fullEnd_1; - if (clientLeftEndmost(partial_1)->status() == PQNodeRoot::FULL) - fullEnd_1 = partial_1->m_leftEndmost; - else { - // partial child with no FULL endmost child detected? - OGDF_ASSERT(clientRightEndmost(partial_1)->status() == PQNodeRoot::FULL); - fullEnd_1 = partial_1->m_rightEndmost; - } - - PQNode *fullEnd_2 = 0; - PQNode *emptyEnd_2 = 0; - PQNode *realEmptyEnd_2 = 0; - if (clientLeftEndmost(partial_2)->status() == PQNodeRoot::FULL) - fullEnd_2 = partial_2->m_leftEndmost; - else { - // partial child with no FULL or EMPTY endmost child detected? - OGDF_ASSERT(clientLeftEndmost(partial_2)->status() == PQNodeRoot::EMPTY); - - emptyEnd_2 = partial_2->m_leftEndmost; - realEmptyEnd_2 = clientLeftEndmost(partial_2); - } - - if (clientRightEndmost(partial_2)->status() == PQNodeRoot::FULL) - fullEnd_2 = partial_2->m_rightEndmost; - else { - // partial child with no FULL or EMPTY endmost child detected? - OGDF_ASSERT(clientRightEndmost(partial_2)->status() == PQNodeRoot::EMPTY); - - emptyEnd_2 = partial_2->m_rightEndmost; - realEmptyEnd_2 = clientRightEndmost(partial_2); - } - - OGDF_ASSERT(fullEnd_2 != emptyEnd_2) - //partial child with same type of endmost child detected - - /* - The children of [[partial_2]] are removed from their parent and - added as children to [[partial_1]]. This is done by resetting the - sibling pointers of the two endmost children of [[partial_1]] and - [[partial_2]] and the endmost child pointers of [[partial_1]]. - Observe that the parent pointers are not updated. The node - [[partial_2]] is deleted. - */ - while (!partial_2->fullChildren->empty()) - partial_1->fullChildren->pushFront(partial_2->fullChildren->popFrontRet()); - linkChildrenOfQnode(fullEnd_1,fullEnd_2); - if (partial_1->m_leftEndmost == fullEnd_1) - partial_1->m_leftEndmost = emptyEnd_2; - else - partial_1->m_rightEndmost = emptyEnd_2; - - emptyEnd_2->m_parent = partial_1; - emptyEnd_2->m_parentType = PQNodeRoot::QNode; - - realEmptyEnd_2->m_parent = partial_1; - realEmptyEnd_2->m_parentType = PQNodeRoot::QNode; - - partial_1->m_childCount = partial_1->m_childCount + - partial_2->m_childCount; - destroyNode(partial_2); - - - - // If nodePtr does not have any - // empty children, then it has to - // be deleted and the partial node - // is occupying its place in the tree. - checkIfOnlyChild(partial_1,*nodePtr); - // partial_1 is now root of the - // pertinent subtree. - *nodePtr = partial_1; - - return true; -} - - -/************************************************************************ - templateQ1 -************************************************************************/ - -/** - * The function templateQ1() implements the template matching for - * Q-nodes with only full children. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a Q-node with - * only full children, - * templateQ1() considers itself responsible for the node and will - * apply the template matching for full Q-nodes to \a nodePtr. - * If the flag \a isRoot is set to 1, it signalizes - * templateQ1() that \a nodePtr is the root of - * the pertinent subtree. In any other case the flag has to be 0. - * - * If templateQ1() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * Different to the templateP1() for P-nodes, - * this function is not able to check if Q-node is full by comparing - * the number of children with the number of full children. The reason - * is the application of the \a m_pseudoRoot at certain steps in the - * matching algorithm. This \a m_pseudoRoot is used instead of the real - * root of the pertinent subtree in case that no parent pointer was - * found. But this implies that changing the number of the children of - * the pertinent root is not registered by the pertinent root. Hence we - * are not allowed to use the \a childCount of Q-nodes. - */ - -template -bool PQTree::templateQ1(PQNode *nodePtr, bool isRoot) -{ - if (nodePtr->type() == PQNodeRoot::QNode && - nodePtr != m_pseudoRoot && - clientLeftEndmost(nodePtr)->status() == PQNodeRoot::FULL && - clientRightEndmost(nodePtr)->status() == PQNodeRoot::FULL) - { - PQNode* seqStart = 0; - PQNode* seqEnd = 0; - if (checkChain(nodePtr,clientLeftEndmost(nodePtr),&seqStart,&seqEnd)) - { - nodePtr->status(PQNodeRoot::FULL); - if (!isRoot) - nodePtr->m_parent->fullChildren->pushFront(nodePtr); - return true; - } - } - - return false; -} - - -/************************************************************************ - templateQ2 -************************************************************************/ - -/** - * The function templateQ2() implements the template matching for - * Q-nodes with a pertinent - * sequence of children on one side of the Q-node. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a Q-node with - * a pertinent - * sequence of children on one side of the Q-node, - * templateQ2() considers itself responsible for the node and will - * apply the template matching \b Q2 to \a nodePtr. - * If the flag \a isRoot is set to 1, it signalizes - * templateQ2() that \a nodePtr is the root of - * the pertinent subtree. In any other case the flag has to be 0. - * - * If templateQ2() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * Below a short description is given of all different cases that - * may occure and that are handled by the function templateQ2(), \b regardless - * whether the Q-node \a nodePtr is root of the pertinent subtree or not. - * The description is somewhat trunkated and should be understood as a - * stenographic description of the labels of the children of \a nodePtr - * when running through the children from one side to the other. Of course - * we leave the mirror-images out. - * - full, empty - * - full, partial, empty - * - full, partial - * - partial, empty. - * - * templateQ2() uses the following variables. - * - \a fullNode is a pointer to the full endmost child of \a nodePtr. - * - \a sequenceBegin is a pointer to the first node of the - * sequence of full children. Identical to the node fullNode and - * mainly needed by the function checkChain(). - * - \a sequenceEnd is a pointer to the last node of the sequence - * of full children. Is set by the function checkChain(). - * - \a partialChild is a pointer to the partial child of \a nodePtr. - * - \a sequenceCons is 1 if all full children of - * \a nodePtr form a consecutive sequence with one full child beeing - * an endmost child of \a nodePtr \b and the partial child is - * adjacent to the sequence. - * - * templateQ2() first checks if one of the above mentioned cases - * occures and - * then applies the necessary template matching. - * No special action has to be performed for the full nodes. If there exists - * a partial child that will be stored in \a partialChild, its children - * are made children of \a nodePtr. So to say, \a partialChild is lifted - * up to the Q-node \a nodePtr and the occurance of the children - * of \a partialChild is fixed within the children of \a nodePtr. - * (Remember that a partial child is also a Q-node). - */ - -template -bool PQTree::templateQ2(PQNode *nodePtr,bool isRoot) -{ - if (nodePtr->type() != PQNodeRoot::QNode || - nodePtr->partialChildren->size() > 1) - return false; - - bool sequenceCons = false; - if (nodePtr->fullChildren->size() > 0) - { - /* - Get a full endmost child of - the $Q$-node [[nodePtr]] if there exists one. - */ - PQNode *fullNode = 0; - if (nodePtr->m_leftEndmost != 0) - { - fullNode = clientLeftEndmost(nodePtr); - if (fullNode->status() != PQNodeRoot::FULL) - fullNode = 0; - } - if (nodePtr->m_rightEndmost != 0 && fullNode == 0) - { - fullNode = clientRightEndmost(nodePtr); - if (fullNode->status() != PQNodeRoot::FULL) - fullNode = 0; - } - - /* - In case that a full endmost child of [[nodePtr]] exists, this - child has been stored in [[fullNode]] and the chunk checks by - calling the function [[checkChain]] (\ref{checkChain}), if all - full children of [[nodePtr]] form a consecutive sequence. - In case that the full children - of [[nodePtr]] form a consecutive sequence the - return value of [[checkChain]] is [[1]]. If a partial child - stored in [[partialChild]] exists, the chunk checks if - [[partialChild]] is adjacent to the sequence of full children. - If the latter case is [[1]], the flag [[sequenceCons]] is - set to [[1]] and the function [[templateQ2]] is allowed to - reduce the pertient children of [[nodePtr]]. - */ - PQNode *sequenceBegin = 0; - PQNode *sequenceEnd = 0; - if (fullNode != 0) - sequenceCons = checkChain(nodePtr,fullNode,&sequenceBegin,&sequenceEnd); - - if (sequenceCons && (nodePtr->partialChildren->size() == 1)) - { - PQNode *partialChild = nodePtr->partialChildren->front(); - sequenceCons = false; - - if (clientSibLeft(sequenceEnd) == partialChild || - clientSibRight(sequenceEnd) == partialChild) - sequenceCons = true; - } - } - else - { - if (!nodePtr->partialChildren->empty()) - { - /* - If the $Q$-node [[nodePtr]] has no full children but one - partial child this chunk checks, if the partial child is - endmost child of the [[nodePtr]]. If this is not the case, - [[nodePtr]] cannot be reduced by the template matching - {\bf Q2}. - */ - //nodePtr->partialChildren->startAtBottom(); - //partialChild = nodePtr->partialChildren->readNext(); - PQNode *partialChild = nodePtr->partialChildren->front(); - if ((clientLeftEndmost(nodePtr) == partialChild) || - (clientRightEndmost(nodePtr) == partialChild)) - sequenceCons = true; - } - } - - if (sequenceCons) - removeBlock(nodePtr,isRoot); - - return sequenceCons; -} - - -/************************************************************************ - templateQ3 -************************************************************************/ - -/* - * The function templateQ3() implements the template matching for - * Q-nodes with empty and/or partial children at both ends and a sequence - * of full and/or partial children in the middle. The Q-node must be the - * root of the pertinent subtree. - * The function requires as input any pointer to a node stored in - * \a nodePtr. If the node stored in \a nodePtr is a Q-node - * with empty and/or partial children at both ends and a sequence - * full or partial children in the middle, - * templateQ3() considers itself responsible for the node and will - * apply the template matching \b Q3 to \a nodePtr. - * Observe that the user calling this function has to make sure that - * \a nodePtr is the root of the pertinent subtree. - * - * If templateQ3() was responsible for \a nodePtr and the - * reduction was successful, the return value is 1. Otherwise - * the return value is 0. - * - * Below a short description is given of all different cases that - * may occure and are handled by the function templateQ3(), \b regardless - * whether the Q-node \a nodePtr is the root of the pertinent subtree or not. - * The description is somewhat trunkated and should be understood as a - * stenographic description of the labels of the children of \a nodePtr - * when running through the children from one side to the other. Of course - * we leave the mirror-images out. - * - empty, full, empty - * - empty, partial, full, partial, empty - * - empty, partial, full, empty - * - empty, partial, full, partial - * - partial, full, partial - * - empty, partial, partial, empty - * - empty, partial, partial - * - partial, partial - * - * The function templateQ3() uses the following variables. - * - \a fullChild is a pointer to an arbitrary full child of \a nodePtr. - * - \a fullStart is a pointer to the first full child of a - * consecutive sequence of full children. - * - \a fullEnd is a pointer to the last full child of a - * consecutive sequence of full children. - * - \a partial_1 is a pointer to the first partial child of \a nodePtr. - * - \a partial_2 is a pointer to the second partial child of \a nodePtr. - * - \a conssequence is 1 if the pertinent children of - * \a nodePtr form a consecutive sequence with at most one partial - * child at every end of the sequence. - * - \a found is a help variable. - * - * templateQ3() first checks if one of the above mentioned cases - * occures and then applies the neccessary template matching. - * No special action has to be performed for the full nodes. If there exist - * one or two partial children which will be stored in \a partial_1 - * or \a partial_2, their children - * are made children of \a nodePtr. So to say, \a partial_1 and - * partial_2 are lifted up to the Q-node \a nodePtr - * and the occurance of their children - * is fixed within the children of \a nodePtr. - */ - -template -bool PQTree::templateQ3(PQNode *nodePtr) -{ - if (nodePtr->type() != PQNodeRoot::QNode || nodePtr->partialChildren->size() >= 3) - return false; - - bool conssequence = false; - bool found = false; - - /* - Check ifthe - pertinent children of [[nodePtr]] form a consecutive sequence. We - differ between two cases: - \begin{enumerate} - \item There exist full children of [[nodePtr]]. First check with - the function [[checkChain]] (\ref{checkChain}) if the full children - form a consecutive sequence. In case that the check was - successful, check if each partial child is adjacent to a full child. - If both checks were successful, the pertient children form a - consecutive sequence. - \item There do not exist full children. Check if the partial - children (there are at most two of them) form a consecutive sequence. - If the test was successful, the pertinent children form a - consecutive sequence. - */ - - if (!nodePtr->fullChildren->empty()) - { - /* - A consecutive - sequence of full children has been detected, containing all full - children of [[nodePtr]]. The chunk checks if each partial child - of [[nodePtr]] is adjacent to a full child. Observe that the - function [[templateQ3]] only reaches this chunk when [[nodePtr]] - has less than three partial children. - */ - PQNode *fullChild = nodePtr->fullChildren->front(); - PQNode *fullStart = 0; - PQNode *fullEnd = 0; - conssequence = checkChain(nodePtr,fullChild,&fullStart,&fullEnd); - if (conssequence) - { - ListIterator*> it; - for (it = nodePtr->partialChildren->begin(); it.valid(); ++it) - { - PQNode *partial_1 = *it; - found = false; - if ((clientSibLeft(fullStart) == partial_1) || - (clientSibRight(fullStart) == partial_1) || - (clientSibLeft(fullEnd) == partial_1) || - (clientSibRight(fullEnd) == partial_1) ) - found = true; - if (!found) - conssequence = found; - } - } - } - - else if (nodePtr->partialChildren->size() == 2) - { - /* - In case that the node [[nodePtr]] does not have any full children, - this chunk checks if the partial children are adjacent. - */ - PQNode *partial_1 = nodePtr->partialChildren->front(); - PQNode *partial_2 = nodePtr->partialChildren->back(); - if ((clientSibLeft(partial_1) == partial_2) || - (clientSibRight(partial_1) == partial_2) ) - found = true; - conssequence = found; - } - - if (conssequence) - removeBlock(nodePtr,true); - - return conssequence; -} - - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PlanarLeafKey.h b/ext/OGDF/ogdf/internal/planarity/PlanarLeafKey.h deleted file mode 100644 index 5c086c6c7..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PlanarLeafKey.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarLeafKey. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLANAR_LEAFKEY_H -#define OGDF_PLANAR_LEAFKEY_H - - - -#include -#include -#include - - - - -namespace ogdf { - - -template -class PlanarLeafKey : public PQLeafKey -{ -public: - - PlanarLeafKey(edge e) : PQLeafKey(e) { } - - virtual ~PlanarLeafKey() { } - - ostream &print(ostream &os) - { - int sId = this->m_userStructKey->source()->index(); - int tId = this->m_userStructKey->target()->index(); - - os << " (" << sId << "," << tId << ")"; - - return os; - } - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PlanarPQTree.h b/ext/OGDF/ogdf/internal/planarity/PlanarPQTree.h deleted file mode 100644 index 206cb3963..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PlanarPQTree.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarPQTree. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLANAR_PQTREE_H -#define OGDF_PLANAR_PQTREE_H - - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -class PlanarPQTree: public PQTree { - -public: - - PlanarPQTree() : PQTree() { } - - virtual ~PlanarPQTree() { } - - //! Does a clean up after a reduction. - virtual void emptyAllPertinentNodes(); - - //! Initializes a new PQ-tree with a set of leaves. - virtual int Initialize(SListPure*> &leafKeys); - - //! Replaces the pertinent subtree by a set of new leaves. - void ReplaceRoot(SListPure*> &leafKeys); - - //! Reduces a set of leaves. - virtual bool Reduction(SListPure*> &leafKeys); - -private: - - //! Replaces a pertinet subtree by a set of new leaves if the root is full. - void ReplaceFullRoot(SListPure*> &leafKeys); - - //! Replaces a pertinet subtree by a set of new leaves if the root is partial. - void ReplacePartialRoot(SListPure*> &leafKeys); - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/PlanarSubgraphPQTree.h b/ext/OGDF/ogdf/internal/planarity/PlanarSubgraphPQTree.h deleted file mode 100644 index 336ad8cb1..000000000 --- a/ext/OGDF/ogdf/internal/planarity/PlanarSubgraphPQTree.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarSubgraphPQTree. - * - * Datastructure used by the planarization module FastPlanarSubgraph. - * Derived class of MaxSequencePQTree. Implements an Interface - * of MaxSequencePQTree for the planarization module FastPlanarSubgraph. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLANAR_SUBGRAPH_PQTREE_H -#define OGDF_PLANAR_SUBGRAPH_PQTREE_H - - - -#include -#include -#include -#include -#include - -namespace ogdf { - -// Overriding the function doDestruction (see basic.h) -// Allows deallocation of lists of PlanarLeafKey -// and PQLeafKey in constant time using OGDF -// memory management. - - -typedef PQLeafKey *PtrPQLeafKeyEWB; - -template<> -inline bool doDestruction(const PtrPQLeafKeyEWB*) { return false; } - -typedef PlanarLeafKey *PtrPlanarLeafKeyW; - -template<> -inline bool doDestruction(const PtrPlanarLeafKeyW*) { return false; } - - - -class PlanarSubgraphPQTree: public MaxSequencePQTree { - -public: - - PlanarSubgraphPQTree() : MaxSequencePQTree() { } - - virtual ~PlanarSubgraphPQTree() { } - - //! Initializes a new PQ-tree with a set of leaves. - virtual int Initialize(SListPure*> &leafKeys); - - //! Replaces the pertinent subtree by a set of new leaves. - void ReplaceRoot(SListPure*> &leafKeys); - - //! Reduces a set of leaves. - virtual bool Reduction( - SListPure*> &leafKeys, - SList*> &eliminatedKeys); - -private: - - //! Replaces a pertinet subtree by a set of new leaves if the root is full. - void ReplaceFullRoot(SListPure*> &leafKeys); - - //! Replaces a pertinet subtree by a set of new leaves if the root is partial. - void ReplacePartialRoot(SListPure*> &leafKeys); - - //! Removes the leaves that have been marked for elimination from the PQ-tree. - void removeEliminatedLeaves(SList*> &eliminatedKeys); - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/planarity/whaInfo.h b/ext/OGDF/ogdf/internal/planarity/whaInfo.h deleted file mode 100644 index 835be10a3..000000000 --- a/ext/OGDF/ogdf/internal/planarity/whaInfo.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * $Revision: 2555 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 12:12:10 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class whaInfo. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_WHA_INFO_H -#define OGDF_WHA_INFO_H - - -#include - - -namespace ogdf{ - -/** -The definitions for W_TYPE, B_TYPE, H_TYPE and A_TYPE -describe the type of a node during the computation of the -maximal pertinent sequence. A pertinent node X in the PQ-tree will be -either of type B, W, A or H. Together -with some other information stored at every node the pertinent leaves -in the frontier of X that have to be deleted. For further -description of the types see Jayakumar, Thulasiraman and Swamy 1989. -*/ - -enum whaType { - W_TYPE, B_TYPE, H_TYPE, A_TYPE -}; - - - -class whaInfo -{ - template friend class MaxSequencePQTree; - -public: - - //The deleteType is set to type b (= keep all leaves in the frontier). - whaInfo() { - m_a = 0; - m_h = 0; - m_w = 0; - m_deleteType = B_TYPE; - m_pertLeafCount = 0; - m_notVisitedCount = 0; - m_aChild = 0; - m_hChild1 = 0; - m_hChild2 = 0; - m_hChild2Sib = 0; - } - - - ~whaInfo() {} - - - void defaultValues() { - m_a = 0; - m_h = 0; - m_w = 0; - m_deleteType = B_TYPE; - m_pertLeafCount = 0; - m_notVisitedCount = 0; - } - - -private: - - - // number of pertinent leaves in the frontier of the node respectively the - // number of leaves that have to be deleted in the frontier of the node to - // make it an empty node. - int m_h; - - // number of pertinent leaves in the frontier of the node that have to be - // deleted in order to create a node of type h, that is a node, where a - // permutation of the leaves of the node exist such that the remaining - // pertinent leaves form a consecutive sequence on one end of the permutation. - int m_w; - - // number of pertinent leaves in the frontier of the node that have to be - // deleted in order to create a node of type $a$, that is a node, where a - // permutation of the leaves of the node exist such that the remaining - // pertinent leaves form a consecutive somewhere within the permutation. - int m_a; - - // deleteType is type of the node being either - // W_TYPE, B_TYPE, H_TYPE or A_TYPE. - whaType m_deleteType; - - //the number of pertinent leaves in the frontier of a node. - int m_pertLeafCount; - - //counts the number of pertinent children, that have not been - // processed yet during the computation of the w,h,a-numbering. - int m_notVisitedCount; - - // a pointer to the child of node that has to be of type a if the - // node itself has been determined to be of type a. - PQNodeRoot *m_aChild; - - // a pointer to the child of node that has to be of type h if the - // node itself has been determined to be of type h. - PQNodeRoot *m_hChild1; - - // a pointer to the child of node that has to be of type h if the - // node itself has been determined to be of type a and m_aChild does - // contain the empty pointer. - PQNodeRoot *m_hChild2; - - - // m_hChild2Sib is a pointer to the pertinent sibling of m_hChild2. This - // pointer is necessary if the sequence of pertinent children is not unique. - PQNodeRoot *m_hChild2Sib; - - OGDF_NEW_DELETE -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraph.h b/ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraph.h deleted file mode 100644 index acc30f61f..000000000 --- a/ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraph.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class WeightedGraph - * - * \author Matthias Woste - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_WEIGHTED_GRAPH_H_ -#define OGDF_EDGE_WEIGHTED_GRAPH_H_ - -#include - -namespace ogdf { - -template -class EdgeWeightedGraph: public Graph { -public: - EdgeWeightedGraph(); - EdgeWeightedGraph(GraphCopy &gC); - virtual ~EdgeWeightedGraph(); - edge newEdge(node v, node w, T weight); - node newNode(); - T weight(edge e) const; - EdgeArray edgeWeights() const; - -protected: - EdgeArray m_edgeWeight; -}; - -} - -//Implementation - -namespace ogdf { - -template -EdgeWeightedGraph::EdgeWeightedGraph() : - Graph() { - m_edgeWeight = EdgeArray(*this); -} - -template -EdgeWeightedGraph::~EdgeWeightedGraph() { -} - -template -edge EdgeWeightedGraph::newEdge(node v, node w, T weight) { - edge e = Graph::newEdge(v, w); - m_edgeWeight[e] = weight; - return e; -} - -template -node EdgeWeightedGraph::newNode() { - node u = Graph::newNode(); - return u; -} - -template -T EdgeWeightedGraph::weight(edge e) const { - return m_edgeWeight[e]; -} - -template -EdgeArray EdgeWeightedGraph::edgeWeights() const { - return m_edgeWeight; -} - -} - -#endif /* OGDF_EDGE_WEIGHTED_GRAPH_H_ */ diff --git a/ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraphCopy.h b/ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraphCopy.h deleted file mode 100644 index b849844e2..000000000 --- a/ext/OGDF/ogdf/internal/steinertree/EdgeWeightedGraphCopy.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Extends the GraphCopy concept to weighted graphs - * - * \author Matthias Woste - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_WEIGHTED_GRAPH_COPY_H_ -#define OGDF_EDGE_WEIGHTED_GRAPH_COPY_H_ - -#include -#include - -namespace ogdf { - -template -class EdgeWeightedGraphCopy: public GraphCopy { -public: - EdgeWeightedGraphCopy() : - GraphCopy() { - } - EdgeWeightedGraphCopy(const EdgeWeightedGraph &wC); - EdgeWeightedGraphCopy(const EdgeWeightedGraphCopy &wGC); - EdgeWeightedGraphCopy &operator=(const EdgeWeightedGraphCopy &wGC); - virtual ~EdgeWeightedGraphCopy() { - } - ; - void createEmpty(const EdgeWeightedGraph &wG); - edge newEdge(node u, node v, T weight); - T weight(edge e) const { - return m_edgeWeight[e]; - } - void setWeight(edge e, T v) { - m_edgeWeight[e] = v; - } - EdgeArray edgeWeights() const { - return m_edgeWeight; - } - -protected: - EdgeArray m_edgeWeight; - -private: - void initWGC(const EdgeWeightedGraphCopy &wGC, NodeArray &vCopy, EdgeArray &eCopy); -}; - -} - -// Implementation - -namespace ogdf { - -template -void EdgeWeightedGraphCopy::initWGC(const EdgeWeightedGraphCopy &wGC, NodeArray &vCopy, EdgeArray &eCopy) { - m_pGraph = wGC.m_pGraph; - - m_vOrig.init(*this, 0); - m_eOrig.init(*this, 0); - m_vCopy.init(*m_pGraph, 0); - m_eCopy.init(*m_pGraph); - m_eIterator.init(*this, 0); - - node v, w; - forall_nodes(v, wGC) - m_vOrig[vCopy[v]] = wGC.original(v); - - edge e; - forall_edges(e, wGC) - m_eOrig[eCopy[e]] = wGC.original(e); - - forall_nodes(v, *this) - if ((w = m_vOrig[v]) != 0) - m_vCopy[w] = v; - - forall_edges(e, *m_pGraph) - { - ListConstIterator it; - for (it = wGC.m_eCopy[e].begin(); it.valid(); ++it) - m_eIterator[eCopy[*it]] = m_eCopy[e].pushBack(eCopy[*it]); - } - - m_edgeWeight = EdgeArray((*this)); - - forall_edges(e, wGC) - { - m_edgeWeight[eCopy[e]] = wGC.weight(e); - } -} - -template -EdgeWeightedGraphCopy &EdgeWeightedGraphCopy::operator=(const EdgeWeightedGraphCopy &wGC) { - - GraphCopy::operator =(wGC); - - m_edgeWeight = EdgeArray((*this)); - - edge e, f; - forall_edges(e, wGC) - { - f = wGC.original(e); - m_edgeWeight[copy(f)] = wGC.weight(e); - } - -} - -template -EdgeWeightedGraphCopy::EdgeWeightedGraphCopy(const EdgeWeightedGraphCopy &wGC) : - GraphCopy(wGC) { - m_edgeWeight = EdgeArray((*this)); - - edge e, f; - forall_edges(e, wGC) - { - f = wGC.original(e); - m_edgeWeight[copy(f)] = wGC.weight(e); - } -} - -template -EdgeWeightedGraphCopy::EdgeWeightedGraphCopy(const EdgeWeightedGraph &wG) : - GraphCopy(wG) { - m_edgeWeight = EdgeArray((*this)); - - edge e; - forall_edges(e, (*this)) - { - m_edgeWeight[e] = wG.weight(original(e)); - } -} - -template -void EdgeWeightedGraphCopy::createEmpty(const EdgeWeightedGraph &wG) { - GraphCopy::createEmpty(wG); - m_pGraph = &wG; - m_edgeWeight = EdgeArray(*this); -} - -template -edge EdgeWeightedGraphCopy::newEdge(node u, node v, T weight) { - edge e = GraphCopy::newEdge(u, v); - m_edgeWeight[e] = weight; - return e; -} - -} - -#endif /* OGDF_EDGE_WEIGHTED_GRAPH_COPY_H_ */ diff --git a/ext/OGDF/ogdf/labeling/ELabelInterface.h b/ext/OGDF/ogdf/labeling/ELabelInterface.h deleted file mode 100644 index f25aa1ee4..000000000 --- a/ext/OGDF/ogdf/labeling/ELabelInterface.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Provide an interface for edge label information - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_E_LABEL_INTERFACE_H -#define OGDF_E_LABEL_INTERFACE_H - -#include -#include -#include -#include - - -namespace ogdf { - -//******************************************************** -// the available labels -// the five basic labels are not allowed to be changed, -// cause they have a special meaning/position, insert -// other labels between mult1/End2 - -enum eLabelType { - elEnd1 = 0, - elMult1, - elName, - elEnd2, - elMult2, - elNumLabels //!< the number of available labels at an edge -}; - -enum eUsedLabels { - lEnd1 = (1 << elEnd1), // 1 - lMult1 = (1 << elMult1), // 2 - lName = (1 << elName), // 4 - lEnd2 = (1 << elEnd2), // 8 - lMult2 = (1 << elMult2), // 16 - lAll = (1 << elNumLabels) -1, // 31 -}; - - -//************************************* -// the basic single label defining class -// holds info about all labels for one edge -template -class OGDF_EXPORT EdgeLabel -{ -public: - - //construction and destruction - EdgeLabel() { m_edge = 0; m_usedLabels = 0; } - - //bit pattern 2^labelenumpos bitwise - EdgeLabel(edge e, int usedLabels = lAll) : m_usedLabels(usedLabels), m_edge(e) - { - for(int i = 0; i < elNumLabels; i++) - { - //zu testzwecken randoms - m_xSize[i] = double(randomNumber(5,13))/50.0; //1 - m_ySize[i] = double(randomNumber(3,7))/50.0; //1 - - m_xPos[i] = 0; - m_yPos[i] = 0; - } - } - - // Construction with specification of label sizes in arrays of length labelnum - EdgeLabel(edge e, coordType w[], coordType h[], int usedLabels = lAll) : m_usedLabels(usedLabels), m_edge(e) - { - for(int i = 0; i < elNumLabels; i++) - { - m_xSize[i] = w[i]; - m_ySize[i] = h[i]; - m_xPos[i] = 0; - m_yPos[i] = 0; - } - } - - EdgeLabel(edge e, coordType w, coordType h, int usedLabels) : m_usedLabels(usedLabels), m_edge(e) - { - for (int i = 0; i < elNumLabels; i++) - if (m_usedLabels & (1 << i)) { - m_xPos[i] = 0.0; - m_yPos[i] = 0.0; - m_xSize[i] = w; - m_ySize[i] = h; - } - } - - //copy constructor - EdgeLabel(const EdgeLabel& rhs) : m_usedLabels(rhs.m_usedLabels), m_edge(rhs.m_edge) - { - for(int i = 0; i < elNumLabels; i++) - { - m_xPos[i] = rhs.m_xPos[i]; - m_yPos[i] = rhs.m_yPos[i]; - m_xSize[i] = rhs.m_xSize[i]; - m_ySize[i] = rhs.m_ySize[i]; - } - }//copy con - - ~EdgeLabel() { } - - //assignment - EdgeLabel& operator=(const EdgeLabel& rhs) - { - if (this != &rhs) - { - m_usedLabels = rhs.m_usedLabels; - m_edge = rhs.m_edge; - int i; - for(i = 0; i < elNumLabels; i++) - { - m_xPos[i] = rhs.m_xPos[i]; - m_yPos[i] = rhs.m_yPos[i]; - m_xSize[i] = rhs.m_xSize[i]; - m_ySize[i] = rhs.m_ySize[i]; - } - } - return *this; - }//assignment - - EdgeLabel& operator|=(const EdgeLabel& rhs) - { - if (m_edge) { - OGDF_ASSERT(m_edge == rhs.m_edge); - } - else - m_edge = rhs.m_edge; - if (this != &rhs) - { - m_usedLabels |= rhs.m_usedLabels; - for (int i = 0; i < elNumLabels; i++) - if (rhs.m_usedLabels & (1 << i)) { - m_xPos[i] = rhs.m_xPos[i]; - m_yPos[i] = rhs.m_yPos[i]; - m_xSize[i] = rhs.m_xSize[i]; - m_ySize[i] = rhs.m_ySize[i]; - } - } - return *this; - } - - - //set - void setX(eLabelType elt, coordType x) { m_xPos[elt] = x; } - void setY(eLabelType elt, coordType y) { m_yPos[elt] = y; } - void setHeight(eLabelType elt, coordType h) { m_ySize[elt] = h; } - void setWidth(eLabelType elt, coordType w) { m_xSize[elt] = w; } - void setEdge(edge e) { m_edge = e; } - void addType(eLabelType elt) { m_usedLabels |= (1< 0 ); - } - - int &usedLabel() { return m_usedLabels; } - - -private: - - //the positions of the labels - coordType m_xPos[elNumLabels]; - coordType m_yPos[elNumLabels]; - - //the input label sizes - coordType m_xSize[elNumLabels]; - coordType m_ySize[elNumLabels]; - - //which labels have to be placed bit pattern 2^labelenumpos bitwise - int m_usedLabels; //1 = only name, 5 = name and end2, ... - - //the edge of heaven - edge m_edge; - - //the label text - //String m_string; - - -};//edgelabel - - -//********************* -//Interface to algorithm -template -class ELabelInterface -{ -public: - //constructor - ELabelInterface(PlanRepUML& pru) - { - //the PRU should not work with real world data but with - //normalized integer values - m_distDefault = 2; - m_minFeatDist = 1; - m_labels.init(pru.original()); - m_ug = 0; - - //temporary - edge e; - forall_edges(e, pru.original()) - setLabel(e, EdgeLabel(e, 0)); - } - - //constructor on GraphAttributes - ELabelInterface(GraphAttributes& uml) : m_ug(¨) - { - //the GraphAttributes should work on real world data, - //which can be floats or ints - m_distDefault = 0.002; - m_minFeatDist = 0.003; - m_labels.init(uml.constGraph()); - - //temporary - edge e; - forall_edges(e, uml.constGraph()) - setLabel(e, EdgeLabel(e, 0)); - } - - GraphAttributes& graph() { return *m_ug; } - - //set new EdgeLabel - void setLabel(const edge &e, const EdgeLabel& el) { - m_labels[e] = el; - } - - void addLabel(const edge &e, const EdgeLabel& el) { - m_labels[e] |= el; - } - - //get info about current EdgeLabel - EdgeLabel& getLabel(edge e) { return m_labels[e]; } - - coordType getWidth(edge e, eLabelType elt) { - return m_labels[e].getWidth(elt); - } - coordType getHeight(edge e, eLabelType elt) { - return m_labels[e].getHeight(elt); - } - - //get general information - coordType& minFeatDist() { return m_minFeatDist; } - coordType& distDefault() { return m_distDefault; } - -private: - - EdgeArray > m_labels; //holds all labels for original edges - //the base graph - GraphAttributes* m_ug; - - coordType m_distDefault; //default distance label/edge for positioner - coordType m_minFeatDist; //min Distance label/feature in candidate posit. -};//ELabelInterface - - -}//end namespace - -#endif diff --git a/ext/OGDF/ogdf/labeling/ELabelPosSimple.h b/ext/OGDF/ogdf/labeling/ELabelPosSimple.h deleted file mode 100644 index 7c2e5d21d..000000000 --- a/ext/OGDF/ogdf/labeling/ELabelPosSimple.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class ELabelPosSimple which represents - * a simple labeling algorithm. - * - * \author Joachim Kupke - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_E_LABEL_POS_SIMPLE_H -#define OGDF_E_LABEL_POS_SIMPLE_H - -#include - - -namespace ogdf { - -class OGDF_EXPORT ELabelPosSimple { - -public: - - ELabelPosSimple(); - ~ELabelPosSimple(); - - void call(GraphAttributes& ug, ELabelInterface& eli); //double - - bool m_absolut; - double m_marginDistance; - double m_edgeDistance; - - bool m_midOnEdge; - -private: - - -}; - - -} - -#endif diff --git a/ext/OGDF/ogdf/labeling/EdgeLabel.h b/ext/OGDF/ogdf/labeling/EdgeLabel.h deleted file mode 100644 index bb8f35a16..000000000 --- a/ext/OGDF/ogdf/labeling/EdgeLabel.h +++ /dev/null @@ -1,451 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of EdgeLabelPositioner classes used in EdgeLabel placement. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_LABEL_H -#define OGDF_EDGE_LABEL_H - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -//debug -//#define foutput - -namespace ogdf { - -//******************************************************* -//all label types are declared in ELabelInterface - -//every edge has a number of labels associated with it -//current status: - -//two end labels -//two end multiplicities -//a name - -//each label has two coordinates and its input size -//******************************************************* - - -//******************************************************* -//there are some discrete phases: -// *compute(UML)Candidates: -// assign candidate positions to all input labels -// *test(UML)FeatureIntersect: -// test intersection of graph features by position candidates -// currently, only nodes are considered -// *test(UML)AllIntersect: -// test label position intersection against each other -// and save the resulting information -// *Assignment of "good" candidates -// different heuristics can be applied -//******************************************************* - - -//parameter values for write(UML)GML - output function -enum OutputParameter {opStandard, opOmitIntersect, opOmitFIntersect, opResult}; - -//the candidate status values have the following meaning -//csActive: candidate can be assigned -//csAssigned: another candidate was assigned for that label -//csFIntersect: label would intersect Graph node -//csUsed: this candidate was used for the label - -//csActive and csUsed are both counted as active candidates -//in PosInfo structure, cause they can have influence on the number -//of necessary intersections -enum candStatus {csAssigned, csFIntersect, csActive, csUsed}; - - - -//class ELabelPos is responsible for computation of edge label positions - -//this should NOT be a template class -//UG call is for double only, PRU call for int, PRU call maybe be considered obsolete -//and is no longer maintained (but works) -template -class ELabelPos { - -public: - //construction and destruction - ELabelPos(); - - ~ELabelPos() {} - - //we can call the positioner on a given PlanRepUML (grid)drawing or - //just with given (double)positions for all graph features and label sizes - virtual void call(PlanRepUML& pru, GridLayoutMapped& L, ELabelInterface& eli); //int - - virtual void call(GraphAttributes& ug, ELabelInterface& eli); //double - - //set the edge-label distance - void setDefaultDistance(coordType dist) { m_defaultDistance = dist; } - - void setDistance(edge e, eLabelType elt, coordType dist) { (m_distance[elt])[e] = dist; } - - //switch if all label types should be distributed evenly on the edge length - void setEndLabelPlacement(bool b) { m_endLabelPlacement = b; } - - void writeGML(const char *filename="labelgraph.gml", OutputParameter sectOmit = opStandard); - void writeUMLGML(const char *filename="labelgraphUML.gml", OutputParameter sectOmit = opStandard); - -protected: - - //********************************************************** - //needed structures - - struct SegmentInfo { - //SegmentInfo() {length = 0; number = 0; direction = odNorth;} - - coordType length; - int number; - coordType min_x, max_x, min_y, max_y; - OrthoDir direction; - };//Segmentinfo - - - struct FeatureInfo { - coordType min_x, max_x, min_y, max_y, size_x, size_y; - };//FeatureInfo - - //Candidate positions have the following properties: - //*active/passive (if intersection) - //*pointer list, pointers to all intersecting candidates - //*Number of intersections with status active (=> if number == 0, this - //candidate can be assigned,fuer andere Kandidaten deren Ueberlappungspartner --Anzahl - //sowie die aktiven Ueberlappungen vorlaeufig sperren - struct PosInfo { - GenericPoint m_coord; //position of middle - List< PosInfo* > m_intersect; - int m_numActive; //active label intersections - int m_numFeatures; //number of intersected features - int m_posIndex; //holds the relative position of candidates - - edge m_edge; - eLabelType m_typ; - candStatus m_active; //csAssigned assigned, csFIntersect node, csActive - - double m_cost; //costs for intersections, placement - - PosInfo() {m_edge = 0; m_active = csActive; m_posIndex = 0; m_numActive = 0; - m_typ = elName; - m_cost = 0.0; - } - PosInfo(edge e, eLabelType elt, GenericPoint gp, int posIndex = -1) - { - m_edge = e; - m_typ = elt; - m_coord = gp; - m_numActive = 0; - m_numFeatures = 0; - m_posIndex = posIndex; - m_active = csActive; - m_cost = 0.0; - } - PosInfo(edge e, eLabelType elt) - { - m_edge = e; - m_typ = elt; - m_numActive = 0; - m_numFeatures = 0; - m_posIndex = 0; - m_active = csActive; - m_cost = 0.0; - } - - bool active() {return (m_active == csActive) || (m_active == csUsed);} - //deactivate candidate - void deactivate() {} - - };//PosInfo - - - //used for sorting and intersection graph buildup - struct FeatureLink { - FeatureInfo m_fi; - edge m_edge; - eLabelType m_elt; - int m_index; //index of label position entry in list - node m_node; //representant in intersection graph - PosInfo* m_posInfo; - - FeatureLink() {m_edge = 0; m_elt = (eLabelType)0; m_index = 0; m_node = 0; m_posInfo = 0;} - FeatureLink(edge e, eLabelType elt, node v, FeatureInfo& fi, int index) - { - m_edge = e; - m_elt = elt; - m_node = v; - m_fi = fi; - m_index = index; - m_posInfo = 0; - } - FeatureLink(edge e, eLabelType elt, node v, FeatureInfo& fi, int index, PosInfo& pi) - { - m_edge = e; - m_elt = elt; - m_node = v; - m_fi = fi; - m_index = index; - m_posInfo = π - } - };//FeatureLink - - struct LabelInfo { - edge m_e; - int m_labelTyp; - - int m_index; //index in der PosListe - - LabelInfo() {m_e = 0; m_labelTyp = m_index = 0;} - LabelInfo(edge e, int l, int i) {m_e = e; m_labelTyp = l; m_index = i;} - };//LabelInfo - - - //********************************************************** - //modification - - //******** - //settings - //cost for feature (node?) intersection - double costFI() {return m_posNum*5.0;} - //cost for label intersection - double costLI() {return 0.9;}//2.0;} - //cost for edge intersection - double costEI() {return 0.7;} - //cost for distance from standard position, - double costPos() {return 0.6;} //e.g. edge start for start label - //cost for non-symmetry at start/end label pairs - double costSym() {return 1.3;} - - coordType segmentMargin() {return m_segMargin;} //defining the size of the rectangle - //around a segment for intersection testing - - bool usePosCost() {return m_posCost;} - bool useSymCost() {return m_symCost;} - - //********************************************************** - //main parts of the algorithm - //check edges for segment structure - void initSegments(); - void initUMLSegments(); - - //build rectangle structures for all graph features - void initFeatureRectangles(); - void initUMLFeatureRectangles(); - - //computes the candidate positions, fills the lists - void computeCandidates(); - void computeUMLCandidates(); - - //build up data structure to decide feasible solutions - //only needed if labeltree not already build - void initStructure(); - - //check label candidates for feature intersection, delete from list - void testFeatureIntersect(); - void testUMLFeatureIntersect(); - - //assign special candidate to avoid empty list after featuretest - void saveRecovery(EdgeArray< GenericPoint > (&saveCandidate)[elNumLabels]); - void saveUMLRecovery(EdgeArray< GenericPoint > (&saveCandidate)[elNumLabels]); - - //check label candidates for label intersection - void testAllIntersect(); - void testUMLAllIntersect(); - - - //return the list of all label position candidates (PlanRepUML) - List< GenericPoint >& posList(edge e, int lnum) {return (m_candPosList[lnum])[e];} - //return the list of all label position candidates - List< PosInfo >& candList(edge e, int lnum) {return (m_candList[lnum])[e];} - - - //**************************** - //information about the segments - //return number of segments for original edge e - int segNumber(edge e) {return m_poly[e].size() - 1;} - //return direction (?ver/hor?) of edge segments, dynamic version - //of SegInfo.dir - OrthoDir segDir(edge e, int segNum) - { - OrthoDir od; - if (segNum > segNumber(e)) OGDF_THROW(Exception); - - IPoint ip1 = (*m_poly[e].get(segNum - 1)); - IPoint ip2 = (*m_poly[e].get(segNum)); - bool isHor = (ip1.m_y == ip2.m_y); //may still be same place - if (isHor) - { - if (ip1.m_x > ip2.m_x) od = odWest; - else od = odEast; - }//if isHor - else - { - //check m_x == m_x - if (ip1.m_y < ip2.m_y) od = odNorth; - else od = odSouth; - }//else - - return od; - }//segDir - - -private: - - //settings - int m_numAssignment; //number of necessary assignments - - int m_candStyle; //defines the style how pos cands are computed - int m_placeHeuristic; //defines how candidates are chosen - bool m_endInsertion; //should candidates nearest to endnode be chosen - - bool m_endLabelPlacement; //are endlabels candidates computed near the nodes - - bool m_posCost; //should end label distance to end give a cost for candidates - bool m_symCost; //should non-symmetric assignment for end label pairs -"- - - //number of candidates for every label - //end pos. candidates get double the number , cause a position - //on both sides of the edge is possible for these values - int m_posNum; //number of pos. cand. for candstyle 1, like ppinch - - //only internally used option: dont stop after first feature intersection, - //allows weighting over number of feature intersections - bool m_countFeatureIntersect; - - coordType m_segMargin; - - //pointers to the PlanRepUML input instances - PlanRepUML* m_prup; - GridLayoutMapped* m_gl; //the existing drawing - - //pointers to the AttributedGraph input instances - GraphAttributes* m_ug; - - //pointers to the generic input instances - ELabelInterface* m_eli;//the input/output interface - - //maybe this should be a parameter, reference - //forall label types the cand. pos. - EdgeArray< List > > m_candPosList[elNumLabels]; - //wird ersetzt durch: Liste von PosInfos - EdgeArray< List < PosInfo > > m_candList[elNumLabels]; - //structure holding all intersection free labels - List< PosInfo* > m_freeLabels; - //structure holding all intersecting labels (should be PQ) - List< PosInfo* > m_sectLabels; - //structure holding candidates sorted by associated costs - BinaryHeap2 m_candidateHeap; - - //the bends and crossings, in the UML call use AttributedGraph::bends - EdgeArray< List > > m_poly; - - //list of segment info - EdgeArray< List > m_segInfo; - EdgeArray m_edgeLength; - - //list of graph feature(nodes,...) info - NodeArray m_featureInfo; //on prup-original - - //save the intersections - EdgeArray< List< List > > m_intersect[elNumLabels]; - - EdgeArray m_assigned[elNumLabels]; //edges with already assigned labels? - - //allow specific edge to label distance, there is a default value - EdgeArray m_distance[elNumLabels]; - coordType m_defaultDistance; - - Graph m_intersectGraph; - - void init(PlanRepUML& pru, GridLayoutMapped& L, ELabelInterface& eli); //int - - void initUML(GraphAttributes& ug, ELabelInterface& eli); //double - - //intersection test section - //we have to sort the features and therefore define a special method - class FeatureComparer; - friend class FeatureComparer; - class FeatureComparer - { - public: - //we sort from lower (bottom side) to upper and from left to right side - static int compare(const FeatureLink &f1, const FeatureLink &f2) { - coordType d1 = f1.m_fi.min_y; - coordType d2 = f2.m_fi.min_y; - - if (DIsLess(d1, d2)) return -1; - else if (DIsGreater(d1, d2)) return 1; - else - { - if (DIsLess(f1.m_fi.min_x, f2.m_fi.min_x)) return -1; - else if (DIsGreater(f1.m_fi.min_x, f2.m_fi.min_x)) return 1; - - return 0; - } - } - OGDF_AUGMENT_STATICCOMPARER(FeatureLink) - }; - - -};//ELabelPos - -}//namespace - -//#if defined(_MSC_VER) || defined(__BORLANDC__) -#include -//#endif - -#endif diff --git a/ext/OGDF/ogdf/layered/BarycenterHeuristic.h b/ext/OGDF/ogdf/layered/BarycenterHeuristic.h deleted file mode 100644 index e889cbfa6..000000000 --- a/ext/OGDF/ogdf/layered/BarycenterHeuristic.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class BarycenterHeuristic - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BARYCENTER_HEURISTIC_H -#define OGDF_BARYCENTER_HEURISTIC_H - - - -#include - - -namespace ogdf { - - -//! The barycenter heuristic for 2-layer crossing minimization. -class OGDF_EXPORT BarycenterHeuristic : public TwoLayerCrossMin -{ -public: - //! Initializes crossing minimization for hierarchy \a H. - void init (const Hierarchy &H) { m_weight.init(H); } - - //! Calls the barycenter heuristic for level \a L. - void call (Level &L); - - //! Does some clean-up after calls. - void cleanup () { m_weight.init(); } - -private: - NodeArray m_weight; //!< The barycenter weight of the nodes. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/CoffmanGrahamRanking.h b/ext/OGDF/ogdf/layered/CoffmanGrahamRanking.h deleted file mode 100644 index c809793b6..000000000 --- a/ext/OGDF/ogdf/layered/CoffmanGrahamRanking.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * $Revision: 2526 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 22:32:03 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of coffman graham ranking algorithm for Sugiyama - * algorithm. - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_COFFMAN_GRAHAM_RANKING_H -#define OGDF_COFFMAN_GRAHAM_RANKING_H - - -#include -#include -#include -#include -#include -#include - -namespace ogdf { - -//! The coffman graham ranking algorithm. -/** - * The class CoffmanGrahamRanking implements a node ranking algorithmn based on - * the coffman graham scheduling algorithm, which can be used as first phase - * in SugiyamaLayout. The aim of the algorithm is to ensure that the height of - * the ranking (the number of layers) is kept small. - */ -class OGDF_EXPORT CoffmanGrahamRanking : public RankingModule { - -public: - //! Creates an instance of coffman graham ranking. - CoffmanGrahamRanking(); - - - /** - * @name Algorithm call - * @{ - */ - - //! Computes a node ranking of \a G in \a rank. - void call(const Graph &G, NodeArray &rank); - - - /** @} - * @name Module options - * @{ - */ - - //! Sets the module for the computation of the acyclic subgraph. - void setSubgraph(AcyclicSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - //! @} - - //! Get for the with - int width() const { - return m_w; - } - - //! Set for the with - void width (int w) { - m_w = w; - } - - -private: - // CoffmanGraham data structures - class _int_set { - int *A, l, p; - public: - _int_set() : A(NULL), l(0), p(0) { } - _int_set(int len) : A(NULL), l(len), p(len) { - if (len > 0) - A = new int[l]; - } - ~_int_set() { delete[] A; } - - void init(int len) { - delete A; - if ((l = len) == 0) - A = NULL; - else - A = new int[l]; - p = len; - } - - int length() const { - return l; - } - - int operator[](int i) const { - return A[i]; - } - - void insert(int x) { - A[--p] = x; - } - - bool ready() const { - return (p == 0); - } - }; - - // CoffmanGraham members - ModuleOption m_subgraph; - int m_w; - NodeArray<_int_set> m_s; - - // dfs members - NodeArray mark; - StackPure *visited; - - // CoffmanGraham funktions - void insert (node u, List > &ready_nodes); - void insert (node u, List &ready, const NodeArray &pi); - - // dfs funktions - void removeTransitiveEdges (Graph& G); - void dfs(node v); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/CrossingsMatrix.h b/ext/OGDF/ogdf/layered/CrossingsMatrix.h deleted file mode 100644 index 0ecb12054..000000000 --- a/ext/OGDF/ogdf/layered/CrossingsMatrix.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class CrossingsMatrix. - * - * \author Andrea Wagner - * Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CROSSINGS_MATRIX_H -#define OGDF_CROSSINGS_MATRIX_H - -#include -#include -#include - -namespace ogdf -{ - -//--------------------------------------------------------- -// CrossingsMatrix -// implements crossings matrix which is used by some -// TwoLayerCrossingMinimization heuristics (e.g. split) -//--------------------------------------------------------- -class OGDF_EXPORT CrossingsMatrix -{ -public: - CrossingsMatrix() : matrix(0,0,0,0) { - m_bigM = 10000; - } - - CrossingsMatrix(const Hierarchy &H); - - ~CrossingsMatrix() { } - - int operator()(int i, int j) const - { - return matrix(map[i],map[j]); - } - - void swap(int i, int j) - { - map.swap(i,j); - } - - //! ordinary init - void init(Level &L); - - //! SimDraw init - void init(Level &L, const EdgeArray *edgeSubGraph); - -private: - Array map; - Array2D matrix; - //! need this for SimDraw to grant epsilon-crossings instead of zero-crossings - int m_bigM; // is set to some big number in both constructors -}; - -}// end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/layered/DfsAcyclicSubgraph.h b/ext/OGDF/ogdf/layered/DfsAcyclicSubgraph.h deleted file mode 100644 index cbec3d443..000000000 --- a/ext/OGDF/ogdf/layered/DfsAcyclicSubgraph.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class DfsAcyclicSubgraph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DFS_ACYCLIC_SUBGRAPH_H -#define OGDF_DFS_ACYCLIC_SUBGRAPH_H - - - -#include - - -namespace ogdf { - -class GraphAttributes; - - - -//! DFS-based algorithm for computing a maximal acyclic subgraph. -/** - * The algorithm simply removes all DFS-backedges and works in linear-time. - */ -class OGDF_EXPORT DfsAcyclicSubgraph : public AcyclicSubgraphModule { -public: - //! Computes the set of edges \a arcSet, which have to be deleted in the acyclic subgraph. - void call (const Graph &G, List &arcSet); - - //! Call for UML graph. - /** - * Computes the set of edges \a arcSet, which have to be deleted - * in the acyclic subgraph. - */ - void callUML (const GraphAttributes &AG, List &arcSet); - -private: - int dfsFindHierarchies( - const GraphAttributes &AG, - NodeArray &hierarchy, - int i, - node v); - - void dfsBackedgesHierarchies( - const GraphAttributes &AG, - node v, - NodeArray &number, - NodeArray &completion, - int &nNumber, - int &nCompletion); - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/ExtendedNestingGraph.h b/ext/OGDF/ogdf/layered/ExtendedNestingGraph.h deleted file mode 100644 index 5b06d5077..000000000 --- a/ext/OGDF/ogdf/layered/ExtendedNestingGraph.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of ExtendedNestingGraph - * - * Manages access on copy of an attributed graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EXTENDED_NESTING_GRAPH_H -#define OGDF_EXTENDED_NESTING_GRAPH_H - - - -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// RCCrossings -//--------------------------------------------------------- -struct OGDF_EXPORT RCCrossings -{ - RCCrossings() { - m_cnClusters = 0; - m_cnEdges = 0; - } - - RCCrossings(int cnClusters, int cnEdges) { - m_cnClusters = cnClusters; - m_cnEdges = cnEdges; - } - - void incEdges(int cn) { - m_cnEdges += cn; - } - - void incClusters() { - ++m_cnClusters; - } - - RCCrossings &operator+=(const RCCrossings &cr) { - m_cnClusters += cr.m_cnClusters; - m_cnEdges += cr.m_cnEdges; - return *this; - } - - RCCrossings operator+(const RCCrossings &cr) const { - return RCCrossings(m_cnClusters+cr.m_cnClusters, m_cnEdges+cr.m_cnEdges); - } - - RCCrossings operator-(const RCCrossings &cr) const { - return RCCrossings(m_cnClusters-cr.m_cnClusters, m_cnEdges-cr.m_cnEdges); - } - - bool operator<=(const RCCrossings &cr) const { - if(m_cnClusters == cr.m_cnClusters) - return (m_cnEdges <= cr.m_cnEdges); - else - return (m_cnClusters <= cr.m_cnClusters); - } - - bool operator<(const RCCrossings &cr) const { - if(m_cnClusters == cr.m_cnClusters) - return (m_cnEdges < cr.m_cnEdges); - else - return (m_cnClusters < cr.m_cnClusters); - } - - bool isZero() const { - return m_cnClusters == 0 && m_cnEdges == 0; - } - - RCCrossings &setInfinity() { - m_cnClusters = m_cnEdges = INT_MAX; - return *this; - } - - static int compare(const RCCrossings &x, const RCCrossings &y) - { - int dc = y.m_cnClusters - x.m_cnClusters; - if(dc != 0) - return dc; - return y.m_cnEdges - x.m_cnEdges; - } - - int m_cnClusters; - int m_cnEdges; -}; - -OGDF_EXPORT ostream& operator<<(ostream &os, const RCCrossings &cr); - - -//--------------------------------------------------------- -// LHTreeNode -//--------------------------------------------------------- -class OGDF_EXPORT LHTreeNode -{ -public: - enum Type { Compound, Node, AuxNode }; - - struct Adjacency - { - Adjacency() { m_u = 0; m_v = 0; m_weight = 0; } - Adjacency(node u, LHTreeNode *vNode, int weight = 1) { - m_u = u; - m_v = vNode; - m_weight = weight; - } - - node m_u; - LHTreeNode *m_v; - int m_weight; - - OGDF_NEW_DELETE - }; - - struct ClusterCrossing - { - ClusterCrossing() { m_uc = 0; m_u = 0; m_cNode = 0; m_uNode = 0; } - ClusterCrossing(node uc, LHTreeNode *cNode, node u, LHTreeNode *uNode, edge e) { - m_uc = uc; - m_u = u; - m_cNode = cNode; - m_uNode = uNode; - - m_edge = e; - } - - node m_uc; - node m_u; - LHTreeNode *m_cNode; - LHTreeNode *m_uNode; - - edge m_edge; - }; - - // Construction - LHTreeNode(cluster c, LHTreeNode *up) { - m_parent = 0; - m_origCluster = c; - m_node = 0; - m_type = Compound; - m_down = 0; - - m_up = up; - if(up) - up->m_down = this; - } - - LHTreeNode(LHTreeNode *parent, node v, Type t = Node) { - m_parent = parent; - m_origCluster = 0; - m_node = v; - m_type = t; - m_up = 0; - m_down = 0; - } - - // Access functions - bool isCompound() const { return m_type == Compound; } - - int numberOfChildren() const { return m_child.size(); } - - const LHTreeNode *parent() const { return m_parent; } - const LHTreeNode *child(int i) const { return m_child[i]; } - - cluster originalCluster() const { return m_origCluster; } - node getNode() const { return m_node; } - - const LHTreeNode *up () const { return m_up; } - const LHTreeNode *down() const { return m_down; } - - int pos() const { return m_pos; } - - - // Modification functions - LHTreeNode *parent() { return m_parent; } - void setParent(LHTreeNode *p) { m_parent = p; } - - LHTreeNode *child(int i) { return m_child[i]; } - void initChild(int n) { m_child.init(n); } - void setChild(int i, LHTreeNode *p) { m_child[i] = p; } - - void setPos(); - - void store() { m_storedChild = m_child; } - void restore() { m_child = m_storedChild; } - void permute() { m_child.permute(); } - - void removeAuxChildren(); - - List m_upperAdj; - List m_lowerAdj; - List m_upperClusterCrossing; - List m_lowerClusterCrossing; - -private: - LHTreeNode *m_parent; - - cluster m_origCluster; - node m_node; - Type m_type; - - Array m_child; - Array m_storedChild; - - LHTreeNode *m_up; - LHTreeNode *m_down; - int m_pos; - - OGDF_NEW_DELETE -}; - - -//--------------------------------------------------------- -// ENGLayer -//--------------------------------------------------------- -class OGDF_EXPORT ENGLayer -{ -public: - ENGLayer() { m_root = 0; } - ~ENGLayer(); - - const LHTreeNode *root() const { return m_root; } - LHTreeNode *root() { return m_root; } - - void setRoot(LHTreeNode *r) { m_root = r; } - - void store(); - void restore(); - void permute(); - - void simplifyAdjacencies(); - void removeAuxNodes(); - -private: - void simplifyAdjacencies(List &adjs); - - LHTreeNode *m_root; -}; - - -//--------------------------------------------------------- -// ClusterGraphCopy -//--------------------------------------------------------- -class OGDF_EXPORT ExtendedNestingGraph; - -class OGDF_EXPORT ClusterGraphCopy : public ClusterGraph -{ -public: - - ClusterGraphCopy(); - ClusterGraphCopy(const ExtendedNestingGraph &H, const ClusterGraph &CG); - - void init(const ExtendedNestingGraph &H, const ClusterGraph &CG); - - const ClusterGraph &getOriginalClusterGraph() const { return *m_pCG; } - - cluster copy(cluster cOrig) const { return m_copy[cOrig]; } - cluster original(cluster cCopy) const { return m_original[cCopy]; } - - void setParent(node v, cluster c); - -private: - void createClusterTree(cluster cOrig); - - const ClusterGraph *m_pCG; - const ExtendedNestingGraph *m_pH; - - ClusterArray m_copy; - ClusterArray m_original; -}; - - -//--------------------------------------------------------- -// ExtendedNestingGraph -//--------------------------------------------------------- -class OGDF_EXPORT ExtendedNestingGraph : public Graph -{ -public: - // the type of a node in this copy - enum NodeType { ntNode, ntClusterTop, ntClusterBottom, ntDummy, ntClusterTopBottom }; - - ExtendedNestingGraph(const ClusterGraph &CG); - - const ClusterGraphCopy &getClusterGraph() const { return m_CGC; } - const ClusterGraph &getOriginalClusterGraph() const { return m_CGC.getOriginalClusterGraph(); } - - node copy (node v) const { return m_copy[v]; } - node top (cluster cOrig) const { return m_topNode[cOrig]; } - node bottom(cluster cOrig) const { return m_bottomNode[cOrig]; } - - int topRank (cluster c) const { return m_topRank[c]; } - int bottomRank(cluster c) const { return m_bottomRank[c]; } - - - NodeType type(node v) const { return m_type[v]; } - node origNode (node v) const { return m_origNode[v]; } - edge origEdge (edge e) const { return m_origEdge[e]; } - - cluster originalCluster(node v) const { return m_CGC.original(m_CGC.clusterOf(v)); } - cluster parent(node v) const { return m_CGC.clusterOf(v); } - cluster parent(cluster c) const { return c->parent(); } - bool isVirtual(cluster c) const { return m_CGC.original(c) == 0; } - - const List &chain(edge e) const { return m_copyEdge[e]; } - - // is edge e reversed ? - bool isReversed (edge e) const { - return e->source() != origNode(chain(e).front()->source()); - } - - bool isLongEdgeDummy(node v) const { - return (type(v) == ntDummy && v->outdeg() == 1); - } - - bool verticalSegment(edge e) const { return m_vertical[e]; } - - int numberOfLayers() const { return m_numLayers; } - int rank(node v) const { return m_rank[v]; } - int pos(node v) const { return m_pos[v]; } - const LHTreeNode *layerHierarchyTree(int i) const { return m_layer[i].root(); } - const ENGLayer &layer(int i) const { return m_layer[i]; } - - RCCrossings reduceCrossings(int i, bool dirTopDown); - void storeCurrentPos(); - void restorePos(); - void permute(); - - void removeTopBottomEdges(); - - int aeLevel(node v) const { return m_aeLevel[v]; } - -protected: - cluster lca(node u, node v) const; - LHTreeNode *lca( - LHTreeNode *uNode, - LHTreeNode *vNode, - LHTreeNode **uChild, - LHTreeNode **vChild) const; - - edge addEdge(node u, node v, bool addAlways = false); - void assignAeLevel(cluster c, int &count); - bool reachable(node v, node u, SListPure &successors); - void moveDown(node v, const SListPure &successors, NodeArray &level); - bool tryEdge(node u, node v, Graph &G, NodeArray &level); - - RCCrossings reduceCrossings(LHTreeNode *cNode, bool dirTopDown); - void assignPos(const LHTreeNode *vNode, int &count); - -private: - void computeRanking(); - void createDummyNodes(); - void createVirtualClusters(); - void createVirtualClusters( - cluster c, - NodeArray &vCopy, - ClusterArray &cCopy); - void buildLayers(); - void removeAuxNodes(); - - // original graph - //const ClusterGraph &m_CG; - ClusterGraphCopy m_CGC; - - // mapping: nodes in CG <-> nodes in this copy - NodeArray m_copy; - NodeArray m_origNode; - - // mapping: clusters in CG <-> nodes in this copy - ClusterArray m_topNode; // the node representing top-most part of cluster (min. rank) - ClusterArray m_bottomNode; // the node representing bottom-most part of cluster (max. rank) - ClusterArray m_topRank; - ClusterArray m_bottomRank; - - // the type of a node in this copy - NodeArray m_type; - - // mapping: edges in CG <-> edges in this copy - EdgeArray > m_copyEdge; - EdgeArray m_origEdge; - - // level of each node - NodeArray m_rank; - int m_numLayers; - - // the layers - Array m_layer; - // positions within a layer - NodeArray m_pos; - - // can an edge segment be drawn vertically? - EdgeArray m_vertical; - - // temporary data for "addEdge()" - NodeArray m_aeLevel; - NodeArray m_aeVisited; - NodeArray m_auxDeg; - - // temporary data for "lca()" - mutable ClusterArray m_mark; - mutable SListPure m_markedClusters; - mutable cluster m_secondPath; - mutable node m_secondPathTo; - mutable SListPure m_markedClustersTree; - mutable ClusterArray m_markTree; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/FastHierarchyLayout.h b/ext/OGDF/ogdf/layered/FastHierarchyLayout.h deleted file mode 100644 index 71194a484..000000000 --- a/ext/OGDF/ogdf/layered/FastHierarchyLayout.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration and implementation of the third phase of sugiyama - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FAST_HIERARCHY_LAYOUT_H -#define OGDF_FAST_HIERARCHY_LAYOUT_H - - - -#include -#include - - -namespace ogdf { - - -/** - * \brief Coordinate assignment phase for the Sugiyama algorithm by Buchheim et al.. - * - * This class implements a hierarchy layout algorithm, i.e., it layouts - * hierarchies with a given order of nodes on each layer. It is used as a third - * phase of the Sugiyama algorithm. - * - * All edges of the layout will have at most two bends. Additionally, - * for each edge having exactly two bends, the segment between them is - * drawn vertically. This applies in particular to the long edges - * arising in the first phase of the Sugiyama algorithm. - * - * The implementation is based on: - * - * Christoph Buchheim, Michael Jünger, Sebastian Leipert: A Fast %Layout - * Algorithm for k-Level Graphs. LNCS 1984 (Proc. %Graph Drawing 2000), - * pp. 229-240, 2001. - * - *

    Optional Parameters

    - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription
    node distancedouble3.0the minimal horizontal distance between two nodes on the same layer
    layer distancedouble3.0the minimal vertical distance between two nodes on neighbored layers
    fixed layer distanceboolfalseif true, the distance between neighbored layers is fixed, otherwise variable
    - */ -class OGDF_EXPORT FastHierarchyLayout : public HierarchyLayoutModule -{ -protected: - - void doCall(const Hierarchy& H,GraphCopyAttributes &AGC); - -public: - //! Creates an instance of fast hierarchy layout. - FastHierarchyLayout(); - - //! Copy constructor. - FastHierarchyLayout(const FastHierarchyLayout &); - - // destructor - virtual ~FastHierarchyLayout() { } - - - //! Assignment operator - FastHierarchyLayout &operator=(const FastHierarchyLayout &); - - - //! Returns the option node distance. - double nodeDistance() const { - return m_minNodeDist; - } - - //! Sets the option node distance to \a dist. - void nodeDistance(double dist) { - m_minNodeDist = dist; - } - - //! Returns the option layer distance. - double layerDistance() const { - return m_minLayerDist; - } - - //! Sets the option layer distance to \a dist. - void layerDistance(double dist) { - m_minLayerDist = dist; - } - - //! Returns the option fixed layer distance. - bool fixedLayerDistance() const { - return m_fixedLayerDist; - } - - //! Sets the option fixed layer distance to \a b. - void fixedLayerDistance(bool b) { - m_fixedLayerDist = b; - } - - -private: - - int n; //!< The number of nodes including virtual nodes. - int m; //!< The number edge sections. - int k; //!< The number of layers. - int *layer; //!< Stores for every node its layer. - int *first; //!< Stores for every layer the index of the first node. - - - // nodes are numbered top down and from left to right. - // Is called "internal numbering". - // Nodes and Layeras are number 0 to n-1 and 0 to k-1, respectively. - // For thechnical reasons we set first[k] to n. - - /** - * \brief The list of neighbors in previous / next layer. - * - * for every node : adj[0][node] list of neighbors in previous layer; - * for every node : adj[1][node] list of neighbors in next layer - */ - List *adj[2]; - - /** - * \brief The nodes belonging to a long edge. - * - * for every node : longEdge[node] is a pointer to a list containing all - * nodes that belong to the same long edge as node. - */ - List **longEdge; - - double m_minNodeDist; //!< The minimal node distance on a layer. - double m_minLayerDist;//!< The minimal distance between layers. - double *breadth; //!< for every node : breadth[node] = width of the node. - double *height; //!< for every layer : height[layer] = height of max{height of node on layer}. - double *y; //!< for every layer : y coordinate of layer. - double *x; //!< for every node : x coordinate of node. - /** - * for every node : minimal possible distance between the center of a node - * and first[layer[node]]. - */ - double *totalB; - - double *mDist; //!< Similar to totalB, used for temporary storage. - - bool m_fixedLayerDist; //!< 0 if distance between layers should be variable, 1 otherwise. - bool *virt; //!< for every node : virt[node] = 1 if node is virtual, 0 otherwise. - - void incrTo(double& d, double t) { - if(d < t) d = t; - } - - void decrTo(double& d, double t) { - if(d > t) d = t; - } - - bool sameLayer(int n1, int n2) const { - return (n1 >= 0 && - n1 < n && - n2 >=0 && - n2 < n && - layer[n1] == layer[n2]); - } - - bool isFirst(int actNode) const { - return (actNode < 0 || - actNode >= n || - actNode == first[layer[actNode]]); - } - - bool isLast(int actNode) const { - return (actNode < 0 || - actNode >= n || - actNode == first[layer[actNode] + 1] -1); - } - - void sortLongEdges(int,int,double*,bool&,double&,int*,bool*); - bool placeSingleNode(int,int,int,double&,int); - void placeNodes(int,int,int,int,int); - void moveLongEdge(int,int,bool*); - void straightenEdge(int,bool*); - void findPlacement(); -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/FastSimpleHierarchyLayout.h b/ext/OGDF/ogdf/layered/FastSimpleHierarchyLayout.h deleted file mode 100644 index 2019faecb..000000000 --- a/ext/OGDF/ogdf/layered/FastSimpleHierarchyLayout.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration of the FastSimpleHierarchyLayout - * (third phase of sugiyama) - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FAST_SIMPLE_LAYOUT_H -#define OGDF_FAST_SIMPLE_LAYOUT_H - - -#include -#include -#include - -namespace ogdf { - -/** - * \brief Coordinate assignment phase for the Sugiyama algorithm by Ulrik Brandes and Boris Köpf - * - * This class implements a hierarchy layout algorithm, i.e., it layouts - * hierarchies with a given order of nodes on each layer. It is used as a third - * phase of the Sugiyama algorithm. - * - * The Algorithm runs in three phases.
    - * - Alignment (4x)
    - * - Horizontal Compactation (4x)
    - * - Balancing - * - * The Alignment and Horzontal Compactation phase are calculated downward, upward, - * leftToRight and rightToLeft. The four resulting layouts are combined in a balancing step. - * - * Warning: The implementation is known to not always produce a correct layout. - * Therefore this Algorithm is for testing purpose only. - * - * The implementation is based on: - * - * Ulrik Brandes, Boris Köpf: Fast and Simple Horizontal Coordinate Assignment. - * LNCS 2002, Volume 2265/2002, pp. 33-36 - * - *

    Optional Parameters

    - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription
    minimal x separationint150the minimal horizontal distance between two nodes on the same layer
    layer distanceint75the minimal vertical distance between two nodes on adjacent layers
    - */ -class OGDF_EXPORT FastSimpleHierarchyLayout : public HierarchyLayoutModule -{ -private: - int m_minXSep; - int m_ySep; - bool m_balanced; - bool m_downward; - bool m_leftToRight; - -protected: - void doCall(const Hierarchy& H, GraphCopyAttributes &AGC); - -public: - /** - * Constructor for balanced layout. This is usually the best choice! - * - * @param minXSep Mimimum separation between each node in x-direction. - * @param ySep Distance between adjacent layers in y-direction. - */ - FastSimpleHierarchyLayout(int minXSep = 150, int ySep = 75); - - /** - * Constructor for specific unbalanced layout. - * This is for scientific purpose and debugging. If you are not sure then use the other Constructor - * - * @param downward The level direction - * @param leftToRight The node direction on each level - * @param ySep Distance between adjacent layers in y-direction. - * @param minXSep Mimimum separation between nodes in x-direction. - */ - FastSimpleHierarchyLayout(bool downward, bool leftToRight, int minXSep = 150, int ySep = 75); - - //! Copy constructor. - FastSimpleHierarchyLayout(const FastSimpleHierarchyLayout &); - - // destructor - virtual ~FastSimpleHierarchyLayout(); - - - //! Assignment operator - FastSimpleHierarchyLayout &operator=(const FastSimpleHierarchyLayout &); - - -private: - /** - * Preprocessing step to find all type1 conflicts. - * A type1 conflict is a crossing of a inner segment with a non-inner segment. - * - * This is for preferring straight inner segments. - * - * @param H The Hierarchy - * @param downward The level direction - * @return (type1Conflicts[v])[u]=true means (u,v) is marked, u is the upper node - */ - NodeArray > markType1Conflicts(const Hierarchy& H, bool downward); - - /** - * Align each node to a node on the next higher level. The result is a blockgraph where each - * node is in a block whith a nother node when they have the same root. - * - * @param H The Hierarchy - * @param root The root for each node (calculated by this method) - * @param align The alignment to the next level node (align(v)=u <=> u is aligned to v) (calculated by this method) - * @param type1Conflicts Type1 conflicts to prefer straight inner segments - * @param downward The level direction - * @param leftToRight The node direction on each level - */ - void verticalAlignment( - const Hierarchy &H, - NodeArray &root, - NodeArray &align, - const NodeArray > &type1Conflicts, - const bool downward, - const bool leftToRight); - - /** - * Calculate the coordinates for each node - * - * @param align The alignment to the next level node (align(v)=u <=> u is aligned to v) - * @param H The Hierarchy - * @param root The root for each node - * @param x The x-coordinates for each node (calculated by this method) - * @param leftToRight The node direction on each level - * @param downward The level direction - */ - void horizontalCompactation( - const NodeArray &align, - const Hierarchy &H, - const NodeArray root, - NodeArray &x, - const bool leftToRight, - bool downward); - - /** - * Calculate the coordinate for root nodes (placing) - * - * @param v The root node to place - * @param sink The Sink for each node. A sink identifies each block class (calculated by this method) - * @param shift The shift for each class (calculated by this method) - * @param x The class relative x-coordinate for each node (calculated by this method) - * @param align The alignment to the next level node (align(v)=u <=> u is aligned to v) - * @param H The Hierarchy - * @param root The root for each node - * @param leftToRight The node direction on each level - */ - void placeBlock(node v, NodeArray &sink, NodeArray &shift, - NodeArray &x, const NodeArray &align, - const Hierarchy &H, const NodeArray &root, const bool leftToRight); - - /** - * The twin of an inner Segment - * - * @return Parent node which is connected by an inner segment. - * NULL if there is no parent segment or if the segment is not an inner segment. - */ - node virtualTwinNode(const Hierarchy &H, const node v, const Hierarchy::TraversingDir dir) const; - - /** - * Predecessor of v on the same level, - * - * @param v The node for which the predecessor should be calculated. - * @param H The Hierarchy - * @param leftToRight If true the left predecessor is choosen. Otherwise the right predecessor. - * @return Predescessor on the same level. NULL if there is no predecessor. - */ - node pred(const node v, const Hierarchy &H, const bool leftToRight); -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/GreedyCycleRemoval.h b/ext/OGDF/ogdf/layered/GreedyCycleRemoval.h deleted file mode 100644 index f934f3c10..000000000 --- a/ext/OGDF/ogdf/layered/GreedyCycleRemoval.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GeedyCycleRemoval. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GREEDY_CYCLE_REMOVAL_H -#define OGDF_GREEDY_CYCLE_REMOVAL_H - - - -#include -#include - - -namespace ogdf { - - -//! Greedy algorithm for computing a maximal acyclic subgraph. -/** - * The algorithm applies a greedy heuristic to compute a maximal - * acyclic subgraph and works in linear-time. - */ -class OGDF_EXPORT GreedyCycleRemoval : public AcyclicSubgraphModule { -public: - //! Computes the set of edges \a arcSet, which have to be deleted in the acyclic subgraph. - void call (const Graph &G, List &arcSet); - -private: - void dfs (node v, const Graph &G); - - int m_min, m_max, m_counter; - - NodeArray m_in, m_out, m_index; - Array > m_B; - NodeArray > m_item; - NodeArray m_visited; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/GreedyInsertHeuristic.h b/ext/OGDF/ogdf/layered/GreedyInsertHeuristic.h deleted file mode 100644 index f4a6d798b..000000000 --- a/ext/OGDF/ogdf/layered/GreedyInsertHeuristic.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Revision: 2526 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 22:32:03 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GreedyInsertHeuristic - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GREEDY_INSERT_HEURISTIC_H -#define OGDF_GREEDY_INSERT_HEURISTIC_H - - -#include -#include -#include - - -namespace ogdf -{ - - -//! The greedy-insert heuristic for 2-layer crossing minimization. -class OGDF_EXPORT GreedyInsertHeuristic : public TwoLayerCrossMin -{ -public: - //! Initializes weights and crossing minimization for hierarchy \a H. - void init (const Hierarchy &H); - - //! Calls the greedy insert heuristic for level \a L. - void call (Level &L); - - //! Does some clean-up after calls. - void cleanup (); - -private: - CrossingsMatrix *m_crossingMatrix; - NodeArray m_weight; -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/layered/GreedySwitchHeuristic.h b/ext/OGDF/ogdf/layered/GreedySwitchHeuristic.h deleted file mode 100644 index 26766137e..000000000 --- a/ext/OGDF/ogdf/layered/GreedySwitchHeuristic.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $Revision: 2526 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 22:32:03 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GreedySwitchHeuristic - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GREEDY_SWITCH_HEURISTIC_H -#define OGDF_GREEDY_SWITCH_HEURISTIC_H - - -#include -#include - - -namespace ogdf -{ - - -//! The greedy-switch heuristic for 2-layer crossing minimization. -class OGDF_EXPORT GreedySwitchHeuristic : public TwoLayerCrossMin -{ -public: - //! Initializes crossing minimization for hierarchy \a H. - void init (const Hierarchy &H); - - //! Calls the greedy switch heuristic for level \a L. - void call (Level &L); - - //! Does some clean-up after calls. - void cleanup (); - -private: - CrossingsMatrix *m_crossingMatrix; -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/layered/Hierarchy.h b/ext/OGDF/ogdf/layered/Hierarchy.h deleted file mode 100644 index 69c6f14d9..000000000 --- a/ext/OGDF/ogdf/layered/Hierarchy.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Hierarchy class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HIERARCHY_H -#define OGDF_HIERARCHY_H - - -#include -#include -#include - - -namespace ogdf { - - -//! Representation of proper hierarchies used by Sugiyama-layout. -/** - * \see Level, SugiyamaLayout - */ -class OGDF_EXPORT Hierarchy { -public: - friend class Level; - - friend class LayerBasedUPRLayout; - friend class HierarchyLayoutModule; - - //! The traversing direction of the layer-by-layer sweep. - enum TraversingDir { downward, upward }; - -private: - Array m_pLevel; //!< The array of all levels. - GraphCopy m_GC; //!< The graph copy representing the topology of the proper hierarchy. - NodeArray m_pos; //!< The position of a node on its level. - NodeArray m_rank; //!< The rank (level) of a node. - //! (Sorted) adjacent nodes on lower level. - NodeArray > m_lowerAdjNodes; - //! (Sorted) adjacent nodes on upper level. - NodeArray > m_upperAdjNodes; - - NodeArray m_nSet; //!< (Only used by buildAdjNodes().) - - //! (Only used by calculateCrossingsPlaneSweep().) - NodeArray > m_lastOcc; - - TraversingDir m_direction; //!< The current direction of layer-by-layer sweep. - - bool getMarkedNodes(NodeArray &markedNodes, int r, List &result, List &positions) { - result.clear(); - positions.clear(); - bool allDummies = true; - - if (r > high() || r < 0) - return false; - - Level &lvl = *m_pLevel[r]; - - for(int i = 0; i <= lvl.high(); i++) { - node v = lvl[i]; - if (markedNodes[v]) { - result.pushBack(v); - positions.pushBack(pos(v)); - if (!isLongEdgeDummy(v)) - allDummies = false; - } - } - positions.quicksort(); - return allDummies; - } - - -public: - //! Creates an empty hierarchy. - Hierarchy() { } - //! Creates an hierarchy of graph \a G with node ranks \a rank. - Hierarchy(const Graph &G, const NodeArray &rank); - - // destruction - ~Hierarchy(); - - void createEmpty(const Graph &G); - void initByNodes(const List &nodes, - EdgeArray &eCopy, - const NodeArray &rank); - - //! Conversion to const GraphCopy reference. - operator const GraphCopy &() const { return m_GC; } - - //! Returns the current direction of layer-by-layer sweep. - TraversingDir direction() const { - return m_direction; - } - - //! Sets the current direction of layer-by-layer sweep. - void direction (TraversingDir dir) { - m_direction = dir; - } - - //! Returns the number of levels. - int size() const { return m_pLevel.size(); } - - //! Returns the maximal array index of a level (= size()-1). - int high() const { return m_pLevel.high(); } - - //! Returns the rank (level) of node \a v. - int rank(node v) const { return m_rank[v]; } - - //! Returns the position of node \a v on its level. - int pos(node v) const { return m_pos[v]; } - - //! Returns the adjacent nodes of \a v (according to direction()). - const Array &adjNodes(node v) { - return (m_direction == downward) ? m_lowerAdjNodes[v] : - m_upperAdjNodes[v]; - } - - //! Returns the adjacent nodes of \a v. - const Array &adjNodes(node v, TraversingDir dir) const { - return (dir == downward) ? m_lowerAdjNodes[v] : - m_upperAdjNodes[v]; - } - - //! Returns the adjacent level of level \a i (according to direction()). - const Level &adjLevel(int i) const { - return (m_direction == downward) ? *m_pLevel[i-1] : *m_pLevel[i+1]; - - } - - bool isLongEdgeDummy(node v) const { - return (m_GC.isDummy(v) && v->outdeg() == 1); - } - - //! Returns the i-th level. - const Level &operator[](int i) const { return *m_pLevel[i]; } - - //! Returns the i-th level. - Level &operator[](int i) { return *m_pLevel[i]; } - - - //! Computes the number of crossings between level \a i and \a i+1. - int calculateCrossings(int i); - //! Computes the total number of crossings. - int calculateCrossings(); - - //! Old version of counting crossings using plane-seep algorithm (only for testing purposes). - int calculateCrossingsPlaneSweep(int i); - //! Old version of counting crossings using plane-seep algorithm (only for testing purposes). - int calculateCrossingsPlaneSweep(); - - //! Computes the number of crossings between level \a i and \a i+1 (for simultaneous drawing). - int calculateCrossingsSimDraw(int i, const EdgeArray *edgeSubGraph); - //! Computes the total number of crossings (for simultaneous drawing). - int calculateCrossingsSimDraw(const EdgeArray *edgeSubGraph); - - - //! Stores the position of nodes in \a oldPos. - void storePos (NodeArray &oldPos); - //! Restores the position of nodes from \a newPos. - void restorePos (const NodeArray &newPos); - - //! Permutes the order of nodes on each level. - void permute(); - - //! Adjusts node positions such that nodes are ordered according to components numbers. - void separateCCs(int numCC, NodeArray &component); - - bool transpose(node v); - - void print(ostream &os); - - void buildAdjNodes(int i); - void buildAdjNodes(); - - void check(); - -private: - void doInit(const NodeArray &rank); - - int transposePart(const Array &adjV, const Array &adjW); - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/Level.h b/ext/OGDF/ogdf/layered/Level.h deleted file mode 100644 index 633f6d924..000000000 --- a/ext/OGDF/ogdf/layered/Level.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of Level class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LEVEL_H -#define OGDF_LEVEL_H - - - -#include -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT Hierarchy; - -class LayerBasedUPRLayout; - - -template -class WeightComparer { - const NodeArray *m_pWeight; - -public: - WeightComparer(const NodeArray *pWeight) : m_pWeight(pWeight) { } - - bool less(node v, node w) const { return (*m_pWeight)[v] < (*m_pWeight)[w]; } - bool operator()(node v, node w) const { return (*m_pWeight)[v] < (*m_pWeight)[w]; } -}; - - -//! Representation of levels in hierarchies. -/** - * \see Hierarchy, SugiyamaLayout - */ -class OGDF_EXPORT Level { - - friend class Hierarchy; - friend class LayerBasedUPRLayout; - friend class HierarchyLayoutModule; - - Array m_nodes; //!< The nodes on this level. - Hierarchy *m_pHierarchy; //!< The hierarchy to which this level belongs. - int m_index; //!< The index of this level. - -public: - //! Creates a level with index \a index in hierarchy \a pHierarchy. - /** - * @param pHierarchy is a pointer to the hierarchy to which the created - * level will belong. - * @param index is the index of the level. - * @param num is the number of nodes on this level. - */ - Level(Hierarchy *pHierarchy, int index, int num) : - m_nodes(num), m_pHierarchy(pHierarchy), m_index(index) { } - - // destruction - ~Level() { } - - //! Returns the node at position \a i. - const node &operator[](int i) const { return m_nodes[i]; } - //! Returns the node at position \a i. - node &operator[](int i) { return m_nodes[i]; } - - //! Returns the number of nodes on this level. - int size() const { return m_nodes.size(); } - //! Returns the maximal array index (= size()-1). - int high() const { return m_nodes.high(); } - - //! Returns the array index of this level in the hierarchy. - int index() const { return m_index; } - - //! Returns the (sorted) array of adjacent nodes of \a v (according to direction()). - const Array &adjNodes(node v); - - //! Returns the hierarchy to which this level belongs. - const Hierarchy &hierarchy() const { return *m_pHierarchy; } - - //! Exchanges nodes at position \a i and \a j. - void swap(int i, int j); - - //! Sorts the nodes according to \a weight using quicksort. - void sort(NodeArray &weight); - - //! Sorts the nodes according to \a weight using bucket sort. - void sort(NodeArray &weight, int minBucket, int maxBucket); - - //! Sorts the nodes according to \a weight (without special placement for "isolated" nodes). - void sortByWeightOnly(NodeArray &weight); - - //!Sorts the nodes according to \a orderComparer - template - void sortOrder(C &orderComparer) { - m_nodes.quicksort(orderComparer); - recalcPos(); - } - - void recalcPos(); - - friend ostream &operator<<(ostream &os, const Level &L) { - os << L.m_nodes; - return os; - } - -private: - void getIsolatedNodes(SListPure > &isolated); - void setIsolatedNodes(SListPure > &isolated); - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/LongestPathRanking.h b/ext/OGDF/ogdf/layered/LongestPathRanking.h deleted file mode 100644 index 9eaf494dd..000000000 --- a/ext/OGDF/ogdf/layered/LongestPathRanking.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of hierachrical ranking algorithm - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LONGEST_PATH_RANKING_H -#define OGDF_LONGEST_PATH_RANKING_H - - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - class GraphCopySimple; - class GraphAttributes; - - -//! The longest-path ranking algorithm. -/** - * The class LongestPathRanking implements the well-known longest-path - * ranking algorithm, which can be used as first phase in SugiyamaLayout. - * The implementation contains a special optimization for reducing - * edge lengths, as well as special treatment of mixed-upward graphs - * (e.g., UML class diagrams). - * - *

    Optional parameters

    - * The following options affect the crossing minimization step - * of the algorithm: - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    separateDeg0Layerbooltrue - * If set to true, isolated nodes are placed on a separate layer. - *
    separateMultiEdgesbooltrue - * If set to true, multi-edges will span at least two layers. - *
    optimizeEdgeLengthbooltrue - * If set to true the ranking algorithm tries to reduce edge length - * even if this might increase the height of the layout. Choose - * false if the longest-path ranking known from the literature - * shall be used. - *
    alignBaseClassesboolfalse - * If set to true, base classes (in UML class diagrams) are aligned - * on the same layer (callUML only). - *
    alignSiblingsboolfalse - * If set to true, siblings in inheritance trees are aligned on the - * same layer (callUML only). - *
    - * - *

    %Module options

    - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    subgraphAcyclicSubgraphModuleDfsAcyclicSubgraph - * The module for the computation of the acyclic subgraph. - *
    - */ -class OGDF_EXPORT LongestPathRanking : public RankingModule { - - ModuleOption m_subgraph; //!< The acyclic sugraph module. - bool m_sepDeg0; //!< Put isolated nodes on a separate layer? - bool m_separateMultiEdges; //!< Separate multi-edges? - bool m_optimizeEdgeLength; //!< Optimize for short edges. - bool m_alignBaseClasses; //!< Align base classes (callUML only). - bool m_alignSiblings; //!< Align siblings (callUML only). - - int m_offset, m_maxN; - - NodeArray m_isSource, m_finished; - NodeArray > > m_adjacent; - NodeArray m_ingoing; - -public: - //! Creates an instance of longest-path ranking. - LongestPathRanking(); - - - /** - * @name Algorithm call - * @{ - */ - - //! Computes a node ranking of \a G in \a rank. - void call(const Graph &G, NodeArray &rank); - - //! Computes a node ranking of \a G with given minimal edge length in \a rank. - /** - * @param G is the input graph. - * @param length specifies the minimal length of each edge. - * @param rank is assigned the rank (layer) of each node. - */ - void call(const Graph &G, const EdgeArray &length, NodeArray &rank); - - //! Call for UML graphs with special treatement of inheritance hierarchies. - void callUML(const GraphAttributes &AG, NodeArray &rank); - - - /** @} - * @name Optional parameters - * @{ - */ - - //! Returns the current setting of option separateDeg0Layer. - /** - * If set to true, isolated nodes are placed on a separate layer. - */ - bool separateDeg0Layer() const { return m_sepDeg0; } - - //! Sets the option separateDeg0Layer to \a sdl. - void separateDeg0Layer (bool sdl) { m_sepDeg0 = sdl; } - - //! Returns the current setting of option separateMultiEdges. - /** - * If set to true, multi-edges will span at least two layers. Since - * each such edge will have at least one dummy node, the edges will - * automaticall be separated in a Sugiyama drawing. - */ - bool separateMultiEdges() const { return m_separateMultiEdges; } - - //! Sets the option separateMultiEdges to \a b. - void separateMultiEdges(bool b) { m_separateMultiEdges = b; } - - //! Returns the current setting of option optimizeEdgeLength. - /** - * If set to true the ranking algorithm tries to reduce edge length - * even if this might increase the height of the layout. Choose - * false if the longest-path ranking known from the literature - * shall be used. - */ - bool optimizeEdgeLength() const { return m_optimizeEdgeLength; } - - //! Sets the option optimizeEdgeLength to \a b. - void optimizeEdgeLength(bool b) { m_optimizeEdgeLength = b; } - - //! Returns the current setting of alignment of base classes (callUML only). - bool alignBaseClasses() const { return m_alignBaseClasses; } - - //! Sets the option for alignment of base classes to \a b. - void alignBaseClasses(bool b) { m_alignBaseClasses = b; } - - //! Returns the current setting of option for alignment of siblings. - bool alignSiblings() const { return m_alignSiblings; } - - //! Sets the option for alignment of siblings to \a b. - void alignSiblings(bool b) { m_alignSiblings = b; } - - - /** @} - * @name Module options - * @{ - */ - - //! Sets the module for the computation of the acyclic subgraph. - void setSubgraph(AcyclicSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - //! @} - -private: - //! Implements the algorithm call. - void doCall(const Graph& G, - NodeArray &rank, - EdgeArray &reversed, - const EdgeArray &length); - - void join( - GraphCopySimple &GC, - NodeArray &superNode, - NodeArray > &joinedNodes, - node v, node w); - - void dfs(node v); - void getTmpRank(node v, NodeArray &rank); - void dfsAdd(node v, NodeArray &rank); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/MedianHeuristic.h b/ext/OGDF/ogdf/layered/MedianHeuristic.h deleted file mode 100644 index f7ff28b9d..000000000 --- a/ext/OGDF/ogdf/layered/MedianHeuristic.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MedianHeuristic - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MEDIAN_HEURISTIC_H -#define OGDF_MEDIAN_HEURISTIC_H - - - -#include - - -namespace ogdf { - - -//! The median heuristic for 2-layer crossing minimization. -class OGDF_EXPORT MedianHeuristic : public TwoLayerCrossMin -{ -public: - //! Initializes crossing minimization for hierarchy \a H. - void init (const Hierarchy &H) { m_weight.init(H); } - - //! Calls the median heuristic for level \a L. - void call (Level &L); - - //! Does some clean-up after calls. - void cleanup () { m_weight.init(); } - -private: - NodeArray m_weight; //!< The median weight of a node. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/OptimalHierarchyClusterLayout.h b/ext/OGDF/ogdf/layered/OptimalHierarchyClusterLayout.h deleted file mode 100644 index aee93db5a..000000000 --- a/ext/OGDF/ogdf/layered/OptimalHierarchyClusterLayout.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the optimal third phase of the sugiyama - * algorithm for clusters. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_OPTIMAL_HIERARCHY_CLUSTER_LAYOUT_H -#define OGDF_OPTIMAL_HIERARCHY_CLUSTER_LAYOUT_H - - - -#include -#include - - -namespace ogdf { - - -//! The LP-based hierarchy cluster layout algorithm. -/** - * OptimalHierarchyClusterLayout implements a hierarchy layout algorithm - * fpr cluster graphs that is based on an LP-formulation. It is only - * available if OGDF is compiled with LP-solver support (e.g., Coin). - * - * The used model avoids Spaghetti-effect like routing of edges by using - * long vertical segments as in FastHierarchyLayout. An additional balancing - * can be used which balances the successors below a node. - * - *

    Optional parameters

    - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    nodeDistancedouble3.0 - * The minimal allowed x-distance between nodes on a layer. - *
    layerDistancedouble3.0 - * The minimal allowed y-distance between layers. - *
    fixedLayerDistanceboolfalse - * If set to true, the distance between neighboured layers is always - * layerDistance; otherwise the distance is adjusted (increased) to improve readability. - *
    weightSegmentsdouble2.0 - * The weight of edge segments connecting to vertical segments. - *
    weightBalancingdouble0.1 - * The weight for balancing successors below a node; 0.0 means no balancing. - *
    weightClustersdouble0.05 - * The weight for cluster boundary variables. - *
    - */ -class OGDF_EXPORT OptimalHierarchyClusterLayout : public HierarchyClusterLayoutModule -{ -#ifndef OGDF_LP_SOLVER -protected: - void doCall(const ExtendedNestingGraph& H,ClusterGraphCopyAttributes &ACGC) { - OGDF_THROW_PARAM(LibraryNotSupportedException, lnscCoin); - } - -#else - -public: - //! Creates an instance of optimal hierarchy layout for clusters. - OptimalHierarchyClusterLayout(); - - //! Copy constructor. - OptimalHierarchyClusterLayout(const OptimalHierarchyClusterLayout &); - - // destructor - ~OptimalHierarchyClusterLayout() { } - - - //! Assignment operator. - OptimalHierarchyClusterLayout &operator=(const OptimalHierarchyClusterLayout &); - - - /** - * @name Optional parameters - * @{ - */ - - //! Returns the minimal allowed x-distance between nodes on a layer. - double nodeDistance() const { - return m_nodeDistance; - } - - //! Sets the minimal allowed x-distance between nodes on a layer to \a x. - void nodeDistance(double x) { - if(x >= 0) - m_nodeDistance = x; - } - - //! Returns the minimal allowed y-distance between layers. - double layerDistance() const { - return m_layerDistance; - } - - //! Sets the minimal allowed y-distance between layers to \a x. - void layerDistance(double x) { - if(x >= 0) - m_layerDistance = x; - } - - //! Returns the current setting of option fixedLayerDistance. - /** - * If set to true, the distance is always layerDistance; otherwise - * the distance is adjusted (increased) to improve readability. - */ - bool fixedLayerDistance() const { - return m_fixedLayerDistance; - } - - //! Sets the option fixedLayerDistance to \a b. - void fixedLayerDistance(bool b) { - m_fixedLayerDistance = b; - } - - //! Returns the weight of edge segments connecting to vertical segments. - double weightSegments() const { - return m_weightSegments; - } - - //! Sets the weight of edge segments connecting to vertical segments to \a w. - void weightSegments(double w) { - if(w > 0.0 && w <= 100.0) - m_weightSegments = w; - } - - //! Returns the weight for balancing successors below a node; 0.0 means no balancing. - double weightBalancing() const { - return m_weightBalancing; - } - - //! Sets the weight for balancing successors below a node to \a w; 0.0 means no balancing. - void weightBalancing(double w) { - if(w >= 0.0 && w <= 100.0) - m_weightBalancing = w; - } - - //! Returns the weight for cluster boundary variables. - double weightClusters() const { - return m_weightClusters; - } - - //! Sets the weight for cluster boundary variables to \a w. - void weightClusters(double w) { - if(w > 0.0 && w <= 100.0) - m_weightClusters = w; - } - - //! @} - -protected: - //! Implements the algorithm call. - void doCall(const ExtendedNestingGraph& H,ClusterGraphCopyAttributes &ACGC); - -private: - void buildLayerList( - const LHTreeNode *vNode, - List > &L); - - void computeXCoordinates( - const ExtendedNestingGraph& H, - ClusterGraphCopyAttributes &AGC); - void computeYCoordinates( - const ExtendedNestingGraph& H, - ClusterGraphCopyAttributes &AGC); - - // options - double m_nodeDistance; //!< The minimal distance between nodes. - double m_layerDistance; //!< The minimal distance between layers. - bool m_fixedLayerDistance; //!< Use fixed layer distances? - - double m_weightSegments; //!< The weight of edge segments. - double m_weightBalancing; //!< The weight for balancing. - double m_weightClusters; //!< The weight for cluster boundary variables. - - // auxiliary data - ClusterGraphCopyAttributes *m_pACGC; - const ExtendedNestingGraph *m_pH; - - int m_vertexOffset; - int m_segmentOffset; - int m_clusterLeftOffset; - int m_clusterRightOffset; - - NodeArray m_isVirtual; - NodeArray m_vIndex; - ClusterArray m_cIndex; - -#endif -}; - -} - - -#endif diff --git a/ext/OGDF/ogdf/layered/OptimalHierarchyLayout.h b/ext/OGDF/ogdf/layered/OptimalHierarchyLayout.h deleted file mode 100644 index 34e8b5235..000000000 --- a/ext/OGDF/ogdf/layered/OptimalHierarchyLayout.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the optimal third - * phase of the Sugiyama algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_OPTIMAL_HIERARCHY_LAYOUT_H -#define OGDF_OPTIMAL_HIERARCHY_LAYOUT_H - - - -#include - - -namespace ogdf { - - -//! The LP-based hierarchy layout algorithm. -/** - * OptimalHierarchyLayout implements a hierarchy layout algorithm that is based - * on an LP-formulation. It is only available if OGDF is compiled with LP-solver - * support (e.g., Coin). - * - * The used model avoids Spaghetti-effect like routing of edges by using - * long vertical segments as in FastHierarchyLayout. An additional balancing - * can be used which balances the successors below a node. - * - *

    Optional parameters

    - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    nodeDistancedouble3.0 - * The minimal allowed x-distance between nodes on a layer. - *
    layerDistancedouble3.0 - * The minimal allowed y-distance between layers. - *
    fixedLayerDistanceboolfalse - * If set to true, the distance between neighboured layers is always - * layerDistance; otherwise the distance is adjusted (increased) to improve readability. - *
    weightSegmentsdouble2.0 - * The weight of edge segments connecting to vertical segments. - *
    weightBalancingdouble0.1 - * The weight for balancing successors below a node; 0.0 means no balancing. - *
    - */ -class OGDF_EXPORT OptimalHierarchyLayout : public HierarchyLayoutModule -{ -#ifndef OGDF_LP_SOLVER -protected: - void doCall(const Hierarchy& /*H*/, GraphCopyAttributes & /*AGC*/) { - OGDF_THROW_PARAM(LibraryNotSupportedException, lnscCoin); - } - -#else - -public: - //! Creates an instance of optimal hierarchy layout. - OptimalHierarchyLayout(); - - //! Copy constructor. - OptimalHierarchyLayout(const OptimalHierarchyLayout &); - - // destructor - ~OptimalHierarchyLayout() { } - - - //! Assignment operator. - OptimalHierarchyLayout &operator=(const OptimalHierarchyLayout &); - - - /** - * @name Optional parameters - * @{ - */ - - //! Returns the minimal allowed x-distance between nodes on a layer. - double nodeDistance() const { - return m_nodeDistance; - } - - //! Sets the minimal allowed x-distance between nodes on a layer to \a x. - void nodeDistance(double x) { - if(x >= 0) - m_nodeDistance = x; - } - - //! Returns the minimal allowed y-distance between layers. - double layerDistance() const { - return m_layerDistance; - } - - //! Sets the minimal allowed y-distance between layers to \a x. - void layerDistance(double x) { - if(x >= 0) - m_layerDistance = x; - } - - //! Returns the current setting of option fixedLayerDistance. - /** - * If set to true, the distance is always layerDistance; otherwise - * the distance is adjusted (increased) to improve readability. - */ - bool fixedLayerDistance() const { - return m_fixedLayerDistance; - } - - //! Sets the option fixedLayerDistance to \a b. - void fixedLayerDistance(bool b) { - m_fixedLayerDistance = b; - } - - //! Returns the weight of edge segments connecting to vertical segments. - double weightSegments() const { - return m_weightSegments; - } - - //! Sets the weight of edge segments connecting to vertical segments to \a w. - void weightSegments(double w) { - if(w > 0.0 && w <= 100.0) - m_weightSegments = w; - } - - //! Returns the weight for balancing successors below a node; 0.0 means no balancing. - double weightBalancing() const { - return m_weightBalancing; - } - - //! Sets the weight for balancing successors below a node to \a w; 0.0 means no balancing. - void weightBalancing(double w) { - if(w >= 0.0 && w <= 100.0) - m_weightBalancing = w; - } - - //! @} - -protected: - //! Implements the algorithm call. - void doCall(const Hierarchy& H,GraphCopyAttributes &AGC); - -private: - void computeXCoordinates( - const Hierarchy& H, - GraphCopyAttributes &AGC); - void computeYCoordinates( - const Hierarchy& H, - GraphCopyAttributes &AGC); - - // options - double m_nodeDistance; //!< The minimal distance between nodes. - double m_layerDistance; //!< The minimal distance between layers. - bool m_fixedLayerDistance; //!< Use fixed layer distances? - - double m_weightSegments; //!< The weight of edge segments. - double m_weightBalancing; //!< The weight for balancing. - -#endif -}; - -} - - -#endif diff --git a/ext/OGDF/ogdf/layered/OptimalRanking.h b/ext/OGDF/ogdf/layered/OptimalRanking.h deleted file mode 100644 index b111eb335..000000000 --- a/ext/OGDF/ogdf/layered/OptimalRanking.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of optimal ranking algorithm for Sugiyama - * algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_OPTIMAL_RANKING_H -#define OGDF_OPTIMAL_RANKING_H - - - -#include -#include -#include -#include - - -namespace ogdf { - -//! The optimal ranking algorithm. -/** - * The class OptimalRanking implements the LP-based algorithm for computing - * a node ranking with minimal edge lengths, which can be used as first phase - * in SugiyamaLayout. - * - *

    Optional parameters

    - * The following options affect the crossing minimization step - * of the algorithm: - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    separateMultiEdgesbooltrue - * If set to true, multi-edges will span at least two layers. - *
    - * - *

    %Module options

    - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    subgraphAcyclicSubgraphModuleDfsAcyclicSubgraph - * The module for the computation of the acyclic subgraph. - *
    - */ -class OGDF_EXPORT OptimalRanking : public RankingModule { - - ModuleOption m_subgraph; // option for acyclic sugraph - bool m_separateMultiEdges; - -public: - //! Creates an instance of optimal ranking. - OptimalRanking(); - - - /** - * @name Algorithm call - * @{ - */ - - //! Computes a node ranking of \a G in \a rank. - void call(const Graph &G, NodeArray &rank); - - //! Computes a node ranking of \a G with given minimal edge length in \a rank. - /** - * @param G is the input graph. - * @param length specifies the minimal length of each edge. - * @param rank is assigned the rank (layer) of each node. - */ - void call(const Graph &G, const EdgeArray &length, NodeArray &rank); - - //! Computes a cost-minimal node ranking of \a G for given edge costs and minimal edge lengths in \a rank. - /** - * @param G is the input graph. - * @param length specifies the minimal length of each edge. - * @param cost specifies the cost of each edge. - * @param rank is assigned the rank (layer) of each node. - */ - void call( - const Graph &G, - const EdgeArray &length, - const EdgeArray &cost, - NodeArray &rank); - - - /** @} - * @name Optional parameters - * @{ - */ - - //! Returns the current setting of option separateMultiEdges. - /** - * If set to true, multi-edges will span at least two layers. Since - * each such edge will have at least one dummy node, the edges will - * automaticall be separated in a Sugiyama drawing. - */ - bool separateMultiEdges() const { return m_separateMultiEdges; } - - //! Sets the option separateMultiEdges to \a b. - void separateMultiEdges(bool b) { m_separateMultiEdges = b; } - - - /** @} - * @name Module options - * @{ - */ - - //! Sets the module for the computation of the acyclic subgraph. - void setSubgraph(AcyclicSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - //! @} - -private: - //! Implements the algorithm call. - void doCall(const Graph& G, - NodeArray &rank, - EdgeArray &reversed, - const EdgeArray &length, - const EdgeArray &cost); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/layered/SiftingHeuristic.h b/ext/OGDF/ogdf/layered/SiftingHeuristic.h deleted file mode 100644 index dc9330a9d..000000000 --- a/ext/OGDF/ogdf/layered/SiftingHeuristic.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2526 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 22:32:03 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class SiftingHeuristic - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SIFTING_HEURISTIC_H -#define OGDF_SIFTING_HEURISTIC_H - - -#include -#include - - -namespace ogdf -{ - - -//! The sifting heuristic for 2-layer crossing minimization. -class OGDF_EXPORT SiftingHeuristic : public TwoLayerCrossMin -{ -public: - //! Enumerates the different sifting strategies - enum Strategy { left_to_right, desc_degree, random }; - - //! Initializes crossing minimization for hierarchy \a H. - void init (const Hierarchy &H); - - //! Calls the sifting heuristic for level \a L. - void call (Level &L); - - //! Does some clean-up after calls. - void cleanup (); - - //! Get for \a Strategy. - Strategy strategy() const { - return m_strategy; - } - - /** - * \brief Set for \a Strategy. - * - * @param strategy is the \a Strategy to be set - */ - void strategy (Strategy strategy) { - m_strategy = strategy; - } - -private: - CrossingsMatrix *m_crossingMatrix; - Strategy m_strategy; -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/layered/SplitHeuristic.h b/ext/OGDF/ogdf/layered/SplitHeuristic.h deleted file mode 100644 index ce4de3639..000000000 --- a/ext/OGDF/ogdf/layered/SplitHeuristic.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class SplitHeuristic. - * - * \author Andrea Wagner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SPLIT_HEURISTIC_H -#define OGDF_SPLIT_HEURISTIC_H - - -#include -#include -#include - -namespace ogdf { - - -//! The split heuristic for 2-layer crossing minimization. -class OGDF_EXPORT SplitHeuristic : public TwoLayerCrossMinSimDraw -{ -public: - //! Initializes crossing minimization for hierarchy \a H. - void init (const Hierarchy &H); - - //! Calls the split heuristic for level \a L. - void call (Level &L); - - //! Calls the median heuristic for level \a L (simultaneous drawing). - void call (Level &L, const EdgeArray *edgeSubGraph); - - //! Does some clean-up after calls. - void cleanup (); - -private: - CrossingsMatrix *m_cm; - Array buffer; - - void recCall(Level&, int low, int high); -}; - -}// end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/layered/SugiyamaLayout.h b/ext/OGDF/ogdf/layered/SugiyamaLayout.h deleted file mode 100644 index 2c99e6bab..000000000 --- a/ext/OGDF/ogdf/layered/SugiyamaLayout.h +++ /dev/null @@ -1,484 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Sugiyama algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SUGIYAMA_LAYOUT_H -#define OGDF_SUGIYAMA_LAYOUT_H - - - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - class ExtendedNestingGraph; - -/** - * \brief Sugiyama's layout algorithm. - * - * The class SugiyamaLayout represents a customizable implementation - * of Sugiyama's layout algorithm. The class provides three different - * algorithm calls: - * - Calling the algorithm for a usual graph; this is the well-known - * Sugiyama algorithm. - * - Calling the algorithm for a cluster graph. - * - Calling the algorithm for mixed-upward graphs (e.g., UML class - * diagrams), where only some edges are directed and shall point - * in the same direction. - * - * If the Sugiyama algorithm shall be used for simultaneous drawing, - * you need to define the different subgraphs by setting the subgraphs - * option. - * - * The implementation used in SugiyamaLayout is based on the following - * publications: - * - * Emden R. Gansner, Eleftherios Koutsofios, Stephen C. North, - * Kiem-Phong Vo: A technique for drawing directed graphs. - * IEEE Trans. Software Eng. 19(3), pp. 214-230, 1993. - * - * Georg Sander: %Layout of compound directed graphs. - * Technical Report, Universität des Saarlandes, 1996. - * - *

    Optional parameters

    - * The following options affect the crossing minimization step - * of the algorithm: - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    runsint15 - * Determines, how many times the crossing minimization is repeated. - * Each repetition (except for the first) starts with randomly - * permuted nodes on each layer. Deterministic behaviour can be achieved - * by setting runs to 1. - *
    transposebooltrue - * Determines whether the transpose step is - * performed after each 2-layer crossing minimization; this step - * tries to reduce the number of crossings by switching neighbored - * nodes on a layer. - *
    failsint4 - * The number of times that the number of crossings - * may not decrease after a complete top-down bottom-up traversal, - * before a run is terminated. - *
    arrangeCCsbooltrue - * If set to true connected components are - * laid out separately and the resulting layouts are arranged afterwards - * using the packer module. - *
    minDistCCdouble20.0 - * Specifies the spacing between connected components of the graph. - * Other spacing parameters have to be set in the used hierarchy layout - * module. - *
    alignBaseClassesboolfalse - * Determines if base classes of inheritance hierarchies shall be - * aligned (only callUML()). - *
    alignSiblingsboolfalse - * Determines if siblings in an inheritance tree shall be aligned - * (only callUML()). - *
    - * - * The crossing minimization step of the algorithm is affected by the - * options runs, transpose, and fails. The options - * alignBaseClasses and alignSiblings are only relevant for - * laying out mixed-upward graphs, where directed edges are interpreted - * as generlizations and undirected egdes as associations - * in a UML class diagram. - * - *

    %Module options

    - * The various phases of the algorithm can be exchanged by setting - * module options allowing flexible customization. The algorithm provides - * the following module options: - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    rankingRankingModuleLongestPathRanking - * The ranking module determines the layering of the graph. - *
    crossMinTwoLayerCrossMinBarycenterHeuristic - * The crossMin module performs two-layer crossing - * minimization and is applied during the top-down bottom-up traversals. - *
    crossMinSimDrawTwoLayerCrossMinSimDrawSplitHeuristic - * The crossMin module used with simultaneous drawing. - *
    layoutHierarchyLayoutModuleFastHierarchyLayout - * The hierarchy layout module that computes the final layout - * (call for graph). - *
    clusterLayoutHierarchyClusterLayoutModuleOptimalHierarchyClusterLayout - * The hierarchy layout module that computes the final - * layout (call for cluster graph). - *
    packerCCLayoutPackModuleTileToRowsCCPacker - * The packer module used for arranging connected components. - *
    - */ -class OGDF_EXPORT SugiyamaLayout : public LayoutModule { - -protected: - - //! the ranking module (level assignment) - ModuleOption m_ranking; - - //! the module for two-layer crossing minimization - ModuleOption m_crossMin; - - ModuleOption m_crossMinSimDraw; - - //! the hierarchy layout module (final coordinate assignment) - ModuleOption m_layout; - - //! the hierarchy cluster layout module (final coordinate assignment for clustered graphs) - ModuleOption m_clusterLayout; - - //! The module for arranging connected components. - ModuleOption m_packer; - - int m_fails; //!< Option for maximal number of fails. - int m_runs; //!< Option for number of runs. - bool m_transpose; //!< Option for switching on transposal heuristic. - bool m_arrangeCCs; //!< Option for laying out components separately. - double m_minDistCC; //!< Option for distance between connected components. - double m_pageRatio; //!< Option for desired page ratio. - bool m_permuteFirst; - - int m_nCrossings; //!< Number of crossings in computed layout. - RCCrossings m_nCrossingsCluster; - Array m_levelChanged; - - bool m_alignBaseClasses; //!< Option for aligning base classes. - bool m_alignSiblings; //!< Option for aligning siblings in inheritance trees. - - EdgeArray *m_subgraphs; //!< Defines the subgraphs for simultaneous drawing. - -public: - - //! Creates an instance of SugiyamaLayout and sets options to default values. - SugiyamaLayout(); - - // destructor - ~SugiyamaLayout() { } - - - /** - * @name Algorithm call - * @{ - */ - - /** - * \brief Calls the layout algorithm for graph \a AG. - * - * Returns the computed layout in \a AG. - */ - void call(GraphAttributes &AG); - - /** - * \brief Calls the layout algorithm for clustered graph \a AG. - * - * Returns the computed layout in \a AG. - */ - void call(ClusterGraphAttributes &AG); - - /** - * \brief Calls the layout algorithm for graph \a AG with a given level assignment. - * - * Returns the computed layout in \a AG. - * @param AG is the input graph (with node size information) and is assigned - * the computed layout. - * @param rank defines the level of each node. - */ - void call(GraphAttributes &AG, NodeArray &rank); - - // special call for UML graphs - void callUML(GraphAttributes &AG); - - - /** @} - * @name Optional parameters - * @{ - */ - - /** - * \brief Returns the current setting of option fails. - * - * This option determines, how many times the total number of crossings - * after a complete top down or bottom up traversal may not decrease before - * one repetition is stopped. - */ - int fails() const { return m_fails; } - - //! Sets the option fails to \a nFails. - void fails(int nFails) { m_fails = nFails; } - - /** - * \brief Returns the current setting of option runs. - * - * This option determines, how many times the crossing minimization is - * repeated. Each repetition (except for the first) starts with randomly - * permuted nodes on each layer. Deterministic behaviour can be achieved - * by setting runs to 1. - */ - int runs() const { return m_runs; } - - //! Sets the option runs to \a nRuns. - void runs(int nRuns) { m_runs = nRuns; } - - /** - * \brief Returns the current setting of option transpose. - * - * If this option is set to true an additional fine tuning step is - * performed after each traversal, which tries to reduce the total number - * of crossings by switching adjacent vertices on the same layer. - */ - bool transpose() const { return m_transpose; } - - //! Sets the option transpose to \a bTranspose. - void transpose(bool bTranspose) { m_transpose = bTranspose; } - - /** - * \brief Returns the current setting of option arrangeCCs. - * - * If this option is set to true, connected components are laid out - * separately and arranged using a packing module. - */ - bool arrangeCCs() const { return m_arrangeCCs; } - - //! Sets the options arrangeCCs to \a bArrange. - void arrangeCCs(bool bArrange) { m_arrangeCCs = bArrange; } - - /** - * \brief Returns the current setting of option minDistCC (distance between components). - * - * This options defines the minimum distance between connected - * components of the graph. - */ - double minDistCC() const { return m_minDistCC; } - - //! Sets the option minDistCC to \a x. - void minDistCC(double x) { m_minDistCC = x; } - - /** - * \brief Returns the current setting of option pageRation. - * - * This option defines the desired page ratio of the layout and - * is used by the packing algorithms used for laying out - * connected components. - */ - double pageRatio() const { return m_pageRatio; } - - //! Sets the option pageRatio to \a x. - void pageRatio(double x) { m_pageRatio = x; } - - /** - * \brief Returns the current setting of option alignBaseClasses. - * - * This option defines whether base classes in inheritance hierarchies - * shall be aligned. - */ - bool alignBaseClasses() const { return m_alignBaseClasses; } - - //! Sets the option alignBaseClasses to \a b. - void alignBaseClasses(bool b) { m_alignBaseClasses = b; } - - /** - * \brief Returns the current setting of option alignSiblings. - * - * This option defines whether siblings in inheritance trees - * shall be aligned. - */ - bool alignSiblings() const { return m_alignSiblings; } - - //! Sets the option alignSiblings to \a b. - void alignSiblings(bool b) { m_alignSiblings = b; } - - //! Sets the subgraphs for simultaneous drawing. - void setSubgraphs(EdgeArray *esg) { m_subgraphs = esg; } - - //! Returns true iff subgraphs for simultaneous drawing are set. - bool useSubgraphs() const { return (m_subgraphs == 0) ? 0 : 1; } - - - bool permuteFirst() const { return m_permuteFirst; } - void permuteFirst(bool b) { m_permuteFirst = b; } - - - /** @} - * @name Module options - * @{ - */ - - /** - * \brief Sets the module option for the node ranking (layer assignment). - * - * The layer assignment is the first step of the Sugiyama algorithm - * and distributes the nodes onto layers. The layer assignment usually - * respects edge directions; if the graph is not acyclic, the ranking - * module computes an acyclic subgraph. The ranking module specifies - * which method is used and usually provides a module option for - * the acyclic subgraph. - */ - void setRanking(RankingModule *pRanking) { - m_ranking.set(pRanking); - } - - /** - * \brief Sets the module option for the two-layer crossing minimization. - * - * This module is called within the top-down and bottom-up traversal - * of the Sugiyama crossing minimization procedure. - */ - void setCrossMin(TwoLayerCrossMin *pCrossMin) { - m_crossMin.set(pCrossMin); - } - - /** - * \brief Sets the module option for the computation of the final layout. - * - * This module receives as input the computed layer assignment and - * and order of nodes on each layer, and computes the final coordinates - * of nodes and bend points. - */ - void setLayout(HierarchyLayoutModule *pLayout) { - m_layout.set(pLayout); - } - - /** - * \brief Sets the module option for the computation of the final layout for clustered graphs. - * - * This module receives as input the computed layer assignment and - * and order of nodes on each layer, and computes the final coordinates - * of nodes and bend points. - */ - void setClusterLayout(HierarchyClusterLayoutModule *pLayout) { - m_clusterLayout.set(pLayout); - } - - /** - * \brief Sets the module option for the arrangement of connected components. - * - * If arrangeCCs is set to true, the Sugiyama layout algorithm draws each - * connected component of the input graph seperately, and then arranges the - * resulting drawings using this packing module. - */ - void setPacker(CCLayoutPackModule *pPacker) { - m_packer.set(pPacker); - } - - /** @} - * @name Information after call - * The following information can be accessed after calling the algorithm. - * @{ - */ - - //! Returns the number of crossings in the computed layout (usual graph). - int numberOfCrossings() const { return m_nCrossings; } - - //! Returns the number of crossings in the computed layout (cluster graph). - RCCrossings numberOfCrossingsCluster() const { return m_nCrossingsCluster; } - - //! Return the number of layers/levels} - int numberOfLevels() { return m_numLevels; } - - //! Return the max. number of elements on a layer - int maxLevelSize() { return m_maxLevelSize; } - - double timeReduceCrossings() { return m_timeReduceCrossings; } - -protected: - - void reduceCrossings(Hierarchy &H); - //void reduceCrossings2(Hierarchy &H); - void reduceCrossings(ExtendedNestingGraph &H); - -private: - int m_numCC; - NodeArray m_compGC; - - void doCall(GraphAttributes &AG, bool umlCall); - void doCall(GraphAttributes &AG, bool umlCall, NodeArray &rank); - - int traverseTopDown (Hierarchy &H); - int traverseBottomUp(Hierarchy &H); - //int traverseTopDown2 (Hierarchy &H); - //int traverseBottomUp2(Hierarchy &H); - - bool transposeLevel(int i, Hierarchy &H); - void doTranspose(Hierarchy &H); - void doTransposeRev(Hierarchy &H); - - int m_numLevels; - int m_maxLevelSize; - double m_timeReduceCrossings; - - RCCrossings traverseTopDown (ExtendedNestingGraph &H); - RCCrossings traverseBottomUp(ExtendedNestingGraph &H); - - //NodeArray m_weight; -}; - - -} - -#endif diff --git a/ext/OGDF/ogdf/lpsolver/LPSolver.h b/ext/OGDF/ogdf/lpsolver/LPSolver.h deleted file mode 100644 index 007ff5626..000000000 --- a/ext/OGDF/ogdf/lpsolver/LPSolver.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class LPSolver which is the front-end - * for the LP solver - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_LP_SOLVER_H -#define OGDF_LP_SOLVER_H - -#if defined(OGDF_OWN_LPSOLVER) -#include - -#elif defined(USE_COIN) -#include -#endif - - -#endif diff --git a/ext/OGDF/ogdf/misclayout/BalloonLayout.h b/ext/OGDF/ogdf/misclayout/BalloonLayout.h deleted file mode 100644 index 51d2d366e..000000000 --- a/ext/OGDF/ogdf/misclayout/BalloonLayout.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class BalloonLayout. Computes - * a radial (balloon) layout based on a spanning tree. - * The algorithm is partially based on the paper - * "On Balloon Drawings of Rooted Trees" by Lin and Yen - * and on - * "Interacting with Huge Hierarchies: Beyond Cone Trees" - * by Carriere and Kazman - * - * \author Karsten Klein; - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ -/* - * The layout is computed by first computing a spanning tree - * of the graph that is then used to derive the vertices' coordinates. - * First, the radii at each vertex are computed. - * Then, depending on the embedding option, the order of the - * edges around each vertex is optimized to maximize angular - * resolution and to minimize the aspect ratio. - * - * Finally, the layout is shifted into the positive quadrant - * of the cartesian plane - * */ -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BALLOON_LAYOUT_H_ -#define OGDF_BALLOON_LAYOUT_H_ - -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT BalloonLayout : public LayoutModule -{ -public: - //Root may be defined by center of the graph - //Directed cases: source/sink - enum RootSelection {rootCenter, rootHighestDegree}; - //either keep the given embedding or optimize - //the order wrto angular resolution and minimum aspect ratio - enum ChildOrder {orderFixed, orderOptimized}; - //compute tree by different methods - enum TreeComputation {treeBfs, treeDfs, treeBfsRandom}; - //! Constructor, sets options to default values. - BalloonLayout(); - virtual ~BalloonLayout(); - //! Assignmentoperator. - BalloonLayout &operator=(const BalloonLayout &bl); - - //! Standard call using the stored parameter settings. - virtual void call(GraphAttributes & AG); - - /** Call using special parameter settings for fractal model - * takes radius ratio < 0.5 as parameter. - */ - virtual void callFractal(GraphAttributes & AG, double ratio = 0.3) - { - bool even = getEvenAngles(); - setEvenAngles(true); - call(AG); - setEvenAngles(even); - } - - /// Subtrees may be assigned even angles or angles depending on their size. - void setEvenAngles(bool b) {m_evenAngles = b;} - /// returns how the angles are assigned to subtrees. - bool getEvenAngles() {return m_evenAngles;} - - - protected: - //! Computes the spanning tree that is used for the - //! layout computation, the non-tree edges are - //! simply added into the layout. - void computeTree(const Graph &G); - //! Computes tree by BFS, fills m_parent and m_childCount. - void computeBFSTree(const Graph &G, node v); - //! Selects the root of the spanning tree that - //! is placed in the layout center. - void selectRoot(const Graph &G); - //------------------------------------------------ - //! Computes a radius for each of the vertices in G. - //! fractal model: same radius on same level, such - //! that r(m) = gamma* r(m-1) where gamma is predefined - //! SNS model: different radii possible - //! Optimal: unordered tree, order of children is optimized. - #ifdef OGDF_DEBUG - void computeRadii(GraphAttributes &AG); - #else - void computeRadii(const GraphAttributes &AG); - #endif - //! Computes the angle distribution: assigns m_angle each node. - void computeAngles(const Graph &G); - //! Computes coordinates from angles and radii. - void computeCoordinates(GraphAttributes &AG); - -private: - NodeArray m_radius; //! Radius at node center. - NodeArray m_oRadius; //!< Outer radius enclosing all children. - NodeArray m_maxChildRadius; //!< Outer radius of largest child. - NodeArray m_parent; //!< Parent in spanning tree. - NodeArray m_childCount; //!< Number of children in spanning tree. - NodeArray m_angle; //!< Angle assigned to nodes. - NodeArray m_estimate; //!< Rough estimate of circumference of subtrees. - NodeArray m_size; //!< Radius of circle around node box. - - NodeArray< List > m_childList; -#ifdef OGDF_DEBUG - //! Consistency check for the tree. - void checkTree(const Graph &G, bool treeRoot = true); - EdgeArray *m_treeEdge; //!< Holds info about tree edges. -#endif - - //----------------------- - //optimization parameters - RootSelection m_rootSelection; //!< Defines how the tree root is selected - node m_treeRoot; //!< Root of tree after computation. - node m_root; //!< Root of tree by selection method. - - double m_estimateFactor; //!< Weight of value (largestchild / number of children) added to - // estimate to compute radius. - double m_fractalRatio; //!< Ratio of neighbor radii in fractal model. - - ChildOrder m_childOrder; //!< How to arrange the children. - TreeComputation m_treeComputation; //!< How to derive the spanning tree. - bool m_evenAngles; //! Use even angles independent of subtree size. - - void check(Graph &G); - - OGDF_NEW_DELETE -}; //class BalloonLayout - -}//end namespace ogdf -#endif /*BALLOONLAYOUT_H_*/ diff --git a/ext/OGDF/ogdf/misclayout/CircularLayout.h b/ext/OGDF/ogdf/misclayout/CircularLayout.h deleted file mode 100644 index c21b4a172..000000000 --- a/ext/OGDF/ogdf/misclayout/CircularLayout.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class CircularLayout - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_CIRCULAR_LAYOUT_H -#define OGDF_CIRCULAR_LAYOUT_H - - -#include - - -namespace ogdf { - -class OGDF_EXPORT GraphCopyAttributes; -struct ClusterStructure; - -//! The circular layout algorithm. -/** - * The implementation used in CircularLayout is based on - * the following publication: - * - * Ugur Dogrusöz, Brendan Madden, Patrick Madden: Circular %Layout in the - * %Graph %Layout Toolkit. Proc. %Graph Drawing 1996, LNCS 1190, pp. 92-100, 1997. - * - *

    Optional parameters

    - * Circular layout provides the following optional parameters. - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    minDistCircledouble20.0 - * The minimal distance between nodes on a circle. - *
    minDistLeveldouble20.0 - * The minimal distance between father and child circle. - *
    minDistSiblingdouble10.0 - * The minimal distance between circles on same level. - *
    minDistCCdouble20.0 - * The minimal distance between connected components. - *
    pageRatiodouble1.0 - * The page ratio used for packing connected components. - *
    - */ -class OGDF_EXPORT CircularLayout : public LayoutModule -{ -public: - //! Creates an instance of circular layout. - CircularLayout(); - - // destructor - ~CircularLayout() { } - - - /** - * @name The algorithm call - * @{ - */ - - //! Computes a circular layout for graph attributes \a GA. - void call(GraphAttributes &GA); - - - /** @} - * @name Optional parameters - * @{ - */ - - //! Returns the option minDistCircle. - double minDistCircle() const { return m_minDistCircle; } - - //! Sets the option minDistCircle to \a x. - void minDistCircle(double x) { m_minDistCircle = x; } - - //! Returns the option minDistLevel. - double minDistLevel() const { return m_minDistLevel; } - - //! Sets the option minDistLevel to \a x. - void minDistLevel(double x) { m_minDistLevel = x; } - - //! Returns the option minDistSibling. - double minDistSibling() const { return m_minDistSibling; } - - //! Sets the option minDistSibling to \a x. - void minDistSibling(double x) { m_minDistSibling = x; } - - //! Returns the option minDistCC. - double minDistCC() const { return m_minDistCC; } - - //! Sets the option minDistCC to \a x. - void minDistCC(double x) { m_minDistCC = x; } - - //! Returns the option pageRatio. - double pageRatio() const { return m_pageRatio; } - - //! Sets the option pageRatio to \a x. - void pageRatio(double x) { m_pageRatio = x; } - - //! @} - -private: - double m_minDistCircle; //!< The minimal distance between nodes on a circle. - double m_minDistLevel; //!< The minimal distance between father and child circle. - double m_minDistSibling; //!< The minimal distance between circles on same level. - double m_minDistCC; //!< The minimal distance between connected components. - double m_pageRatio; //!< The page ratio used for packing connected components. - - void doCall(GraphCopyAttributes &AG, ClusterStructure &C); - - void assignClustersByBiconnectedComponents(ClusterStructure &C); - - int sizeBC(node vB); - - void computePreferedAngles( - ClusterStructure &C, - const Array &outerRadius, - Array &preferedAngle); - - void assignPrefAngle(ClusterStructure &C, - const Array &outerRadius, - Array &preferedAngle, - int c, - int l, - double r1); - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/misclayout/ProcrustesSubLayout.h b/ext/OGDF/ogdf/misclayout/ProcrustesSubLayout.h deleted file mode 100644 index ba59989ff..000000000 --- a/ext/OGDF/ogdf/misclayout/ProcrustesSubLayout.h +++ /dev/null @@ -1,197 +0,0 @@ -/** \file - * \brief Declares class ProcrustesSubLayout - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PROCRUSTES_SUB_LAYOUT_H -#define OGDF_PROCRUSTES_SUB_LAYOUT_H - - -#include - - -namespace ogdf { - - class ProcrustesPointSet - { - public: - //! Constructor for allocating mem for numPoints points - ProcrustesPointSet(int numPoints); - - //! Destructor which frees mem - ~ProcrustesPointSet(); - - //! translates and scales the set such that the avg center is 0, 0 and the avg size is 1.0 - void normalize(bool flip = false); - - //! rotates the point set so it fits somehow on other - void rotateTo(const ProcrustesPointSet& other); - - //! calculates a value how good the two point sets match - double compare(const ProcrustesPointSet& other) const; - - //! sets ith coordinate - void set(int i, double x, double y) - { - m_x[i] = x; - m_y[i] = y; - } - - //! returns ith x-coordinate - double getX(int i) const - { - return m_x[i]; - } - - //! returns ith y-coordinate - double getY(int i) const - { - return m_y[i]; - } - - //! returns the origins x - double originX() const - { - return m_originX; - } - - //! returns the origins y - double originY() const - { - return m_originY; - } - - //! returns the scale factor - double scale() const - { - return m_scale; - } - - //! returns the rotation angle - double angle() const - { - return m_angle; - } - - //! returns true if the point set is flipped by y coord - bool isFlipped() const - { - return m_flipped; - } - - private: - //! The number of points - int m_numPoints; - - //! x coordinates - double* m_x; - - //! y coordinates - double* m_y; - - //! the original avg center's x when normalized - double m_originX; - - //! the original avg center's y when normalized - double m_originY; - - //! the scale factor - double m_scale; - - //! if rotated, the angle - double m_angle; - - //! if flipped then this is true - bool m_flipped; - }; - - //! A simple procrustes analysis implementation - /*! - */ - class OGDF_EXPORT ProcrustesSubLayout : public LayoutModule - { - public: - //! Creates an instance of circular layout. - ProcrustesSubLayout(LayoutModule* pSubLayout); - - // destructor - ~ProcrustesSubLayout() { } - - //! Computes a circular layout for graph attributes \a GA. - void call(GraphAttributes &GA); - - //! Should the new layout scale be used or the initial scale? Default: inital - void setScaleToInitialLayout(bool flag) - { - m_scaleToInitialLayout = flag; - } - - //! Should the new layout scale be used or the initial scale? - bool scaleToInitialLayout() const - { - return m_scaleToInitialLayout; - } - - private: - //! Does a reverse transform of graph attributes by using the origin, scale and angle in pointset - void reverseTransform(GraphAttributes& graphAttributes, const ProcrustesPointSet& pointSet); - - //! Moves all coords in graphAttributes by dx, dy - void translate(GraphAttributes& graphAttributes, double dx, double dy); - - //! Rotates all coords in graphAttributes by angle - void rotate(GraphAttributes& graphAttributes, double angle); - - //! Scales all coords in graphAttributes by scale - void scale(GraphAttributes& graphAttributes, double scale); - - //! Flips all y coordinates - void flipY(GraphAttributes& graphAttributes); - - //! copysthe coords in graph attributes to the point set - void copyFromGraphAttributes(const GraphAttributes& graphAttributes, ProcrustesPointSet& pointSet); - - //! The layout module to call for a new layout - LayoutModule* m_pSubLayout; - - //! option for enabling/disabling scaling to initial layout scale - bool m_scaleToInitialLayout; - }; - -} // end of namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/AcyclicSubgraphModule.h b/ext/OGDF/ogdf/module/AcyclicSubgraphModule.h deleted file mode 100644 index 12d997ba0..000000000 --- a/ext/OGDF/ogdf/module/AcyclicSubgraphModule.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for acyclic subgraph algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_ACYCLIC_SUBGRAPH_MODULE_H -#define OGDF_ACYCLIC_SUBGRAPH_MODULE_H - - - -#include - -namespace ogdf { - -/** - * \brief Base class of algorithms for computing a maximal acyclic subgraph. - * - * \see SugiyamaLayout - */ -class OGDF_EXPORT AcyclicSubgraphModule { -public: - //! Initializes an acyclic subgraph module. - AcyclicSubgraphModule() { } - - // destruction - virtual ~AcyclicSubgraphModule() { } - - /** - * \brief Computes the set of edges \a arcSet which have to be removed - * for obtaining an acyclic subgraph of \a G. - * - * This is the actual algorithm call and must be implemented by derived classes. - * @param G is the input graph. - * @param arcSet is assigned the list of edges that have to be removed in \a G. - */ - virtual void call(const Graph &G, List &arcSet) = 0; - - /** - * \brief Computes the set of edges \a arcSet which have to be removed - * for obtaining an acyclic subgraph of \a G. - * @param G is the input graph. - * @param arcSet is assigned the list of edges that have to be removed in \a G. - */ - void operator()(const Graph &G, List &arcSet) { - call(G,arcSet); - } - - /** - * \brief Makes \a G acyclic by reversing edges. - * - * This method will ignore self-loops in the input graph \a G; thus self-loops - * are neither reversed or removed nor added to \a reversed. - * @param G is the input graph. - * @param reversed is assigned the list of edges that have been reversed in \a G. - */ - void callAndReverse(Graph &G, List &reversed); - - // makes G acyclic (except for self-loops!) by reversing edges - /** - * \brief Makes \a G acyclic by reversing edges. - * - * This method will ignore self-loops in the input graph \a G; thus self-loops - * are neither reversed nor removed. This is the simplified version of callAndDelete() - * that does not return the list of reversed edges. - * @param G is the input graph. - */ - void callAndReverse(Graph &G); - - // makes G acyclic by deleting edges - /** - * \brief Makes \a G acyclic by removing edges. - * - * This method will also remove self-loops in the input graph \a G. - * @param G is the input graph. - */ - void callAndDelete(Graph &G); - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/AugmentationModule.h b/ext/OGDF/ogdf/module/AugmentationModule.h deleted file mode 100644 index d80bfcebd..000000000 --- a/ext/OGDF/ogdf/module/AugmentationModule.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for graph augmentation algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_AUGMENTATION_MODULE_H -#define OGDF_AUGMENTATION_MODULE_H - - - -#include - -namespace ogdf { - -/** - * \brief The base class for graph augmentation algorithms. - * - * The class \a AugmentationModule is the base class for augmentation modules. - * An augmentation module transforms an input graph \a G into an output - * graph \a G' by adding edges, such that \a G' has a certain - * property, e.g., biconnected. - * - *

    Implementation of Augmentation Algorithms

    - * An implementation of an augmentation module must override - * the protected method doCall(G,L), which gets as - * input a graph reference \a G. It then adds the augmented edges - * to \a G and returns the list of added edges in \a L. - */ - -class OGDF_EXPORT AugmentationModule { -public: - //! Initializes an augmentation module. - AugmentationModule() { } - // destruction - virtual ~AugmentationModule() { } - - //! Calls the augmentation module for graph \a G. - void call(Graph& G) { - List L; - call(G,L); - } - - //! Calls the augmentation module for graph \a G. - void operator()(Graph& G) { call(G); } - - /** - * \brief Calls the augmentation module for graph \a G. - * - * Returns the list of added edges in \a L. - */ - void call(Graph& G, List &L) { - doCall(G,L); - m_nAddedEdges = L.size(); - } - - /** - * \brief Calls the augmentation module for graph \a G. - * - * Returns the list of added edges in \a L. - */ - void operator()(Graph& G, List &L) { call(G,L); } - - //! Returns the number of added edges. - int numberOfAddedEdges() const { - return m_nAddedEdges; - } - -protected: - /** - * \brief Implements the augmentation algorithm for graph \a G. - * - * Returns the list of added edges in \a L. - */ - virtual void doCall(Graph& G, List &L) = 0; - -private: - int m_nAddedEdges; - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/CCLayoutPackModule.h b/ext/OGDF/ogdf/module/CCLayoutPackModule.h deleted file mode 100644 index fe7df5231..000000000 --- a/ext/OGDF/ogdf/module/CCLayoutPackModule.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for algorithms that arrange/pack - * layouts of connected components. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CC_LAYOUT_PACK_MODULE_H -#define OGDF_CC_LAYOUT_PACK_MODULE_H - - - -#include - - - -namespace ogdf { - - -/** - * \brief Base class of algorithms that arrange/pack layouts of connected - * components. - * - * \see PlanarizationLayout
    PlanarizationGridLayout - */ -class OGDF_EXPORT CCLayoutPackModule { -public: - //! Initializes a layout packing module. - CCLayoutPackModule() { } - - virtual ~CCLayoutPackModule() { } - - /** - * \brief Arranges the rectangles given by \a box. - * - * The algorithm call takes an input an array \a box of rectangles with - * real coordinates and computes in \a offset the offset to (0,0) of each - * rectangle in the layout. - * - * This method is the actual algorithm call and must be overridden by derived - * classes. - * @param box is the array of input rectangles. - * @param offset is assigned the offset of each rectangle to the origin (0,0). - * The offset of a rectangle is its lower left point in the layout. - * @param pageRatio is the desired page ratio (width / height) of the - * resulting layout. - */ - virtual void call(Array &box, - Array &offset, - double pageRatio = 1.0) = 0; - - /** - * \brief Arranges the rectangles given by \a box. - * - * The algorithm call takes an input an array \a box of rectangles with - * real coordinates and computes in \a offset the offset to (0,0) of each - * rectangle in the layout. - * @param box is the array of input rectangles. - * @param offset is assigned the offset of each rectangle to the origin (0,0). - * The offset of a rectangle is its lower left point in the layout. - * @param pageRatio is the desired page ratio (width / height) of the - * resulting layout. - */ - void operator()(Array &box, - Array &offset, - double pageRatio = 1.0) - { - call(box,offset,pageRatio); - } - - /** - * \brief Arranges the rectangles given by \a box. - * - * The algorithm call takes an input an array \a box of rectangles with - * integer coordinates and computes in \a offset the offset to (0,0) of each - * rectangle in the layout. - * - * This method is the actual algorithm call and must be overridden by derived - * classes. - * @param box is the array of input rectangles. - * @param offset is assigned the offset of each rectangle to the origin (0,0). - * The offset of a rectangle is its lower left point in the layout. - * @param pageRatio is the desired page ratio (width / height) of the - * resulting layout. - */ - virtual void call(Array &box, - Array &offset, - double pageRatio = 1.0) = 0; - - /** - * \brief Arranges the rectangles given by \a box. - * - * The algorithm call takes an input an array \a box of rectangles with - * integer coordinates and computes in \a offset the offset to (0,0) of each - * rectangle in the layout. - * @param box is the array of input rectangles. - * @param offset is assigned the offset of each rectangle to the origin (0,0). - * The offset of a rectangle is its lower left point in the layout. - * @param pageRatio is the desired page ratio (width / height) of the - * resulting layout. - */ - void operator()(Array &box, - Array &offset, - double pageRatio = 1.0) - { - call(box,offset,pageRatio); - } - - /** - * \brief Checks if the rectangles in \a box do not overlap for given offsets. - * - * This function serves for checking if the computed offsets are correct in - * the sense that the rectangles do not overlap in the resulting layout. - * @param box is the array of rectangles. - * @param offset is the array of corresponding offsets. - */ - static bool checkOffsets(const Array &box, - const Array &offset); - - /** - * \brief Checks if the rectangles in \a box do not overlap for given offsets. - * - * This function serves for checking if the computed offsets are correct in - * the sense that the rectangles do not overlap in the resulting layout. - * @param box is the array of rectangles. - * @param offset is the array of corresponding offsets. - */ - static bool checkOffsets(const Array &box, - const Array &offset); - - - OGDF_MALLOC_NEW_DELETE - -private: - /** - * \brief Checks if the rectangles in \a box do not overlap for given offsets. - * - * This is a parameterized function for generic point types \a POINT. - * @param box is the array of rectangles. - * @param offset is the array of corresponding offsets. - */ - template - static bool checkOffsetsTP( - const Array &box, - const Array &offset); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/CPlanarSubgraphModule.h b/ext/OGDF/ogdf/module/CPlanarSubgraphModule.h deleted file mode 100644 index 39aa7cee7..000000000 --- a/ext/OGDF/ogdf/module/CPlanarSubgraphModule.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of an interface for c-planar subgraph algorithms. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CPLANAR_SUBGRAPH_MODULE_H -#define OGDF_CPLANAR_SUBGRAPH_MODULE_H - -#include -#include - -#include -//#include - -namespace ogdf { - -//-------------------------------------------------------------------------- -//CPlanarSubgraphModule -//base class of algorithms for the computation of c-planar subgraphs -//-------------------------------------------------------------------------- -/** - * - * \brief Interface of algorithms for the computation of c-planar subgraphs. - */ -class CPlanarSubgraphModule : public Module, public Timeouter -{ - -public: - //! Constructs a cplanar subgraph module - CPlanarSubgraphModule() {} - //! Destruction - virtual ~CPlanarSubgraphModule() {} - - /** - * \brief Computes set of edges delEdges, which have to be deleted - * in order to get a c-planar subgraph. - * - * Must be implemented by derived classes. - * @param G is the clustergraph. - * @param delEdges holds the edges not in the subgraph on return. - * - */ - ReturnType call(const ClusterGraph &G, List &delEdges) { - return doCall(G, delEdges); - } - - -protected: - - /** - * \brief Computes a maximum c-planar subgraph. - * - * If delEdges is empty on return, the clustered graph G is c-planar- - * The actual algorithm call that must be implemented by derived classes! - * - * @param CG is the given cluster graph. - * @param delEdges holds the set of edges that have to be deleted. - */ - virtual ReturnType doCall(const ClusterGraph &CG, - List &delEdges) = 0; - - OGDF_MALLOC_NEW_DELETE -}; - -} //end namespace ogdf - - -#endif // OGDF_CPLANAR_SUBGRAPH_MODULE_H diff --git a/ext/OGDF/ogdf/module/ClustererModule.h b/ext/OGDF/ogdf/module/ClustererModule.h deleted file mode 100644 index 6ef846467..000000000 --- a/ext/OGDF/ogdf/module/ClustererModule.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for clustering algorithms that - * compute a clustering for a given graph based on some - * structural or semantical properties. - * - * Precondition: - * Input graph has to be connected - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_CLUSTERER_MODULE_H -#define OGDF_CLUSTERER_MODULE_H - -#include -#include -#include - - -#include - -namespace ogdf { - - //Helper classes to code a clustering, used as an interface to applications that - //need to build the clustergraph structure themselves - class SimpleCluster - { - public: - SimpleCluster(SimpleCluster* parent = 0) : m_size(0), m_parent(parent), m_index(-1) { } - - //insert vertices and children - void pushBackVertex(node v) {m_nodes.pushBack(v);} - void pushBackChild(SimpleCluster* s) {m_children.pushBack(s);} - - void setParent(SimpleCluster* parent) {m_parent = parent;} - SimpleCluster* getParent() {return m_parent;} - - void setIndex(int index) {m_index = index;} - int getIndex() {return m_index;} - - SList &nodes() {return m_nodes;} - SList &children() {return m_children;} - - int m_size; //preliminary: allowed to be inconsistent with real vertex number to - //allow lazy vertex addition (should therefore be local Array?) - - private: - SList m_nodes; - SList m_children; - SimpleCluster* m_parent; - int m_index; //index of the constructed cluster - - };//class SimpleCluster - - /** - * \brief Interface for algorithms that compute a clustering for a - * given graph - * - * The class ClustererModule is the base class for clustering - * classes that allow to compute some hierarchical clustering - */ - class OGDF_EXPORT ClustererModule - { - - public: - //Constructor taking a graph G to be clustered - explicit ClustererModule(const Graph &G) : m_pGraph(&G) {OGDF_ASSERT(isConnected(G));} - //! Default constructor, initializes a clustering module. - // Allows to cluster multiple - // graphs with the same instance of the Clusterer - ClustererModule() {} - - /** - * \brief Sets the graph to be clustered - * - * @param G is the input graph - * - */ - void setGraph(const Graph &G) {OGDF_ASSERT(isConnected(G));m_pGraph = &G;} - //! Returns the graph to be clustered - const Graph& getGraph() const {return *m_pGraph;} - - /** - * \brief compute some kind of clustering on the graph m_pGraph - * - * This is the algorithm call that has to be implemented by derived classes - * - * @param sl is the resulting list of clusters - */ - virtual void computeClustering(SList &sl) = 0; - - //! translate computed clustering into cluster hierarchy in cluster graph C - virtual void createClusterGraph(ClusterGraph &C) = 0; - - //! compute a clustering index for each vertex - virtual double computeCIndex(const Graph & G, node v) = 0; - //! compute a clustering index for each vertex - virtual double computeCIndex(node v) = 0; - //! compute the average clustering index for the given graph - virtual double averageCIndex() - { - return averageCIndex(*m_pGraph); - } - virtual double averageCIndex(const Graph &G) - { - node v; - double ciSum = 0.0; - forall_nodes(v, G) - { - ciSum += computeCIndex(G, v); - } - return ciSum / (G.numberOfNodes()); - } - - - protected: - const Graph* m_pGraph; //the graph to be clustered - - OGDF_MALLOC_NEW_DELETE - - };//class ClustererModule - - - -} //end namespace ogdf - - -#endif /*CLUSTERERMODULE_H_*/ diff --git a/ext/OGDF/ogdf/module/CrossingMinimizationModule.h b/ext/OGDF/ogdf/module/CrossingMinimizationModule.h deleted file mode 100644 index da53c0af2..000000000 --- a/ext/OGDF/ogdf/module/CrossingMinimizationModule.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of CrossingMinimization Module, an interface for crossing minimization algorithms - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_CROSSING_MINIMIZATION_MODULE_H -#define OGDF_CROSSING_MINIMIZATION_MODULE_H - - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -/** - * \brief Interface for crossing minimization algorithms. - * - */ -class OGDF_EXPORT CrossingMinimizationModule : public Module, public Timeouter -{ -public: - //! Initializes a crossing minimization module. - CrossingMinimizationModule() { } - - // destruction - virtual ~CrossingMinimizationModule() { } - - /** - * \brief Computes a planarized representation of the input graph. - * - * @param PG represents the input graph as well as the computed planarized - * representation after the call. \a PG has to be initialzed as a - * PlanRep of the input graph and is modified to obatain the planarized - * representation (crossings are replaced by dummy vertices with degree - * four. - * @param cc is the number of the connected component in \a PG that is considered. - * @param crossingNumber is assigned the number of crossings. - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. If forbid = 0, no edges are - * forbidden. - * @param cost points to an edge array that gives the cost of each edge. If cost - * = 0, all edges have cost 1. - * @param subgraphs - * \return the status of the result. - */ - ReturnType call(PlanRep &PG, - int cc, - int& crossingNumber, - const EdgeArray * cost = 0, - const EdgeArray * forbid = 0, - const EdgeArray * subgraphs = 0) - { - m_useCost = (cost != 0); - m_useForbid = (forbid != 0); - m_useSubgraphs = (subgraphs != 0); - - if(!useCost()) cost = OGDF_NEW EdgeArray (PG.original(), 1); - if(!useForbid()) forbid = OGDF_NEW EdgeArray (PG.original(), 0); - if(!useSubgraphs()) subgraphs = OGDF_NEW EdgeArray (PG.original(), 1); - - ReturnType R = doCall(PG, cc, *cost, *forbid, *subgraphs, crossingNumber); - - if(!useCost()) delete cost; - if(!useForbid()) delete forbid; - if(!useSubgraphs()) delete subgraphs; - return R; - }; - - //! Computes a planarized representation of the input graph (shorthand for call) - ReturnType operator()(PlanRep &PG, - int cc, - int& crossingNumber, - const EdgeArray * cost = 0, - const EdgeArray * forbid = 0, - const EdgeArray * const subgraphs = 0) { - return call(PG, cc, crossingNumber, cost, forbid, subgraphs); - }; - - //! Returns true iff edge costs are given. - bool useCost() const { return m_useCost; } - - //! Returns true iff forbidden edges are given. - bool useForbid() const { return m_useForbid; } - - bool useSubgraphs() const { return m_useSubgraphs; } - -protected: - /** - * \brief Actual algorithm call that needs to be implemented by derived classed. - * - * @param PG represents the input graph as well as the computed planarized - * representation after the call. \a PG is initialzed as a - * PlanRep of the input graph and has to be modified so that it represents - * the planarized representation (crossings are replaced by dummy vertices - * with degree four). - * @param cc is the number of the connected component in \a PG that is considered. - * @param crossingNumber is assigned the number of crossings. - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. - * @param cost points to an edge array that gives the cost of each edge. - * @param subgraphs - * \return the status of the result. - */ - virtual ReturnType doCall(PlanRep &PG, - int cc, - const EdgeArray &cost, - const EdgeArray &forbid, - const EdgeArray &subgraphs, - int& crossingNumber) = 0; - - OGDF_MALLOC_NEW_DELETE - -private: - bool m_useCost; //!< True iff edge costs are given. - bool m_useForbid; //!< True iff forbidden edges are given. - bool m_useSubgraphs; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/EdgeInsertionModule.h b/ext/OGDF/ogdf/module/EdgeInsertionModule.h deleted file mode 100644 index 0333730fd..000000000 --- a/ext/OGDF/ogdf/module/EdgeInsertionModule.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for edge insertion algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_INSERTION_MODULE_H -#define OGDF_EDGE_INSERTION_MODULE_H - - -#include -#include -#include -#include - - -namespace ogdf { - -/** - * \brief Interface for edge insertion algorithms - * - * \see SubgraphPlanarizer - */ -class OGDF_EXPORT EdgeInsertionModule : public Module, public Timeouter { -public: - //! The postprocessing method. - enum RemoveReinsertType { - rrNone, //!< No postprocessing. - rrInserted, //!< Postprocessing only with the edges that have to be inserted. - rrMostCrossed, //!< Postprocessing with the edges involved in the most crossings. - rrAll, //!< Postproceesing with all edges. - rrIncremental, //!< Full postprocessing after each edge insertion. - rrIncInserted //!< Postprocessing for (so far) inserted edges after each edge insertion. - }; - - //! Initializes an edge insertion module. - EdgeInsertionModule() { } - // destruction - virtual ~EdgeInsertionModule() { } - - /** - * \brief Inserts all edges in \a origEdges into \a PG. - * - * @param PG is the input planarized representation and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(PlanRep &PG, const List &origEdges) { - return doCall(PG, origEdges, false, 0, 0, 0); - } - - /** - * \brief Inserts all edges in \a origEdges with given costs into \a PG. - * - * @param PG is the input planarized representation and will also receive the result. - * @param costOrig is an edge array containing the costs of original edges; edges in - * \a PG without an original edge have zero costs. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(PlanRep &PG, - const EdgeArray &costOrig, - const List &origEdges) - { - return doCall(PG, origEdges, false, &costOrig, 0, 0); - } - - /** - * \brief Inserts all edges in \a origEdges with given costs into \a PG, considering the Simultaneous Drawing Setting. - * - * @param PG is the input planarized representation and will also receive the result. - * @param costOrig is an edge array containing the costs of original edges; edges in - * \a PG without an original edge have zero costs. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * @param edgeSubGraph is an edge array specifying to which subgraph the edge belongs - * \return the status of the result. - */ - ReturnType call(PlanRep &PG, - const EdgeArray &costOrig, - const List &origEdges, - const EdgeArray &edgeSubGraph) - { - return doCall(PG, origEdges, false, &costOrig, 0, &edgeSubGraph); - } - - /** - * \brief Inserts all edges in \a origEdges with given forbidden edges into \a PG. - * - * \pre No forbidden edge may be in \a origEdges. - * - * @param PG is the input planarized representation and will also receive the result. - * @param forbidOriginal is an edge array indicating if an original edge is - * forbidden to be crossed. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(PlanRep &PG, - const EdgeArray &forbidOriginal, - const List &origEdges) - { - return doCall(PG, origEdges, false, 0, &forbidOriginal, 0); - } - - /** - * \brief Inserts all edges in \a origEdges with given costs and forbidden edges into \a PG. - * - * \pre No forbidden edge may be in \a origEdges. - * - * @param PG is the input planarized representation and will also receive the result. - * @param costOrig is an edge array containing the costs of original edges; edges in - * \a PG without an original edge have zero costs. - * @param forbidOriginal is an edge array indicating if an original edge is - * forbidden to be crossed. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(PlanRep &PG, - const EdgeArray &costOrig, - const EdgeArray &forbidOriginal, - const List &origEdges) - { - return doCall(PG, origEdges, false, &costOrig, &forbidOriginal, 0); - } - - // inserts all edges in origEdges into PG using edge costs given by costOrig and edgeSubGraph; - // explicitly forbids crossing of those original edges for which - // forbidOriginal[eG] == true; no such edge may be in the list origEdges! - ReturnType call(PlanRep &PG, - const EdgeArray &costOrig, - const EdgeArray &forbidOriginal, - const List &origEdges, - const EdgeArray &edgeSubGraph) - { - return doCall(PG, origEdges, false, &costOrig, &forbidOriginal, &edgeSubGraph); - } - - /** - * \brief Inserts all edges in \a origEdges into \a PG while avoiding crossings - * between generalizations. - * - * @param PG is the input planarized representation and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType callForbidCrossingGens(PlanRepUML &PG, - const List &origEdges) - { - return doCall(PG, origEdges, true, 0, 0, 0); - } - - /** - * \brief Inserts all edges in \a origEdges with given costs into \a PG while - * avoiding crossings between generalizations. - * - * @param PG is the input planarized representation and will also receive the result. - * @param costOrig is an edge array containing the costs of original edges; edges in - * \a PG without an original edge have zero costs. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType callForbidCrossingGens(PlanRepUML &PG, - const EdgeArray &costOrig, - const List &origEdges) - { - return doCall(PG, origEdges, true, &costOrig, 0, 0); - } - - //! Returns the number of postprocessing runs after the algorithm has been called. - virtual int runsPostprocessing() const { - return 0; - } - - -#ifdef OGDF_DEBUG - bool checkCrossingGens(const PlanRepUML &PG); -#endif - -protected: - /** - * \brief Actual algorithm call that has to be implemented by derived classes. - * - * @param PG is the input planarized representation and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * @param forbidCrossingGens is true if generalizations are not allowed to cross each other. - * @param costOrig points to an edge array containing the costs of original edges; edges in - * \a PG without an original edge have zero costs. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - * @param edgeSubGraph is used for simultaneous embedding and specifies for each edge - * to which subgraphs it belongs. - */ - virtual ReturnType doCall(PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig, - const EdgeArray *edgeSubGraph) = 0; - - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/EmbedderModule.h b/ext/OGDF/ogdf/module/EmbedderModule.h deleted file mode 100644 index 6f2b9c5f1..000000000 --- a/ext/OGDF/ogdf/module/EmbedderModule.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * $Revision: 2546 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 21:16:17 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for embedder for - * graphs. - * - * \author Thorsten Kerkhof (thorsten.kerkhof@udo.edu) - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MODULE_H -#define OGDF_EMBEDDER_MODULE_H - -#include -#include -#include - -namespace ogdf { - -/** - * \brief Base class for embedder algorithms. - * - * An embedder algorithm computes a planar embedding of a planar - * graph. - * - * \see PlanarizationLayout, PlanarizationGridLayout - */ -class OGDF_EXPORT EmbedderModule : public Module, public Timeouter { -public: - //! Initializes an embedder module. - EmbedderModule() { } - - virtual ~EmbedderModule() { } - - /** - * \brief Calls the embedder algorithm for graph \a G. - * \param G is the graph that shall be embedded. - * \param adjExternal is set (by the algorithm) to an adjacency entry on the - * external face of \a G. - */ - virtual void call(Graph& G, adjEntry& adjExternal) = 0; - - //! Calls the embedder algorithm for planarized representation \a PG. - void operator()(Graph& G, adjEntry& adjExternal) { call(G, adjExternal); } - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/FUPSModule.h b/ext/OGDF/ogdf/module/FUPSModule.h deleted file mode 100644 index 11d2c95a9..000000000 --- a/ext/OGDF/ogdf/module/FUPSModule.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Feasible Upward Planar Subgraph (FUPS) Module, an interface for subgraph computation. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_FUPS_MODULE_H -#define OGDF_FUPS_MODULE_H - -#include -#include - -namespace ogdf { - -/** - * \brief Interface for feasible upward planar subgraph algorithms. - * - */ -class OGDF_EXPORT FUPSModule : public Module -{ - -public: - - //! Initializes a feasible upward planar subgraph module. - FUPSModule() { } - - // destruction - virtual ~FUPSModule() { } - - /** - * \brief Computes a feasible upward planar subgraph of the input graph. - * - * @param UPR represents the feasible upward planar subgraph after the call. \a UPR has to be initialzed as a - * UpwardPlanRep of the input graph \a G and is modified. - * The subgraph is represented as an upward planar representation. - * @param delEdges is the list of deleted edges which are deleted from the input graph in order to obtain the subgraph. - * The edges are edges of the original graph of UPR. - * \return the status of the result. - */ - ReturnType call(UpwardPlanRep &UPR, - List &delEdges) - { - return doCall(UPR, delEdges); - } - - //! Computes a upward planarized representation of the input graph (shorthand for call) - ReturnType operator()(UpwardPlanRep &UPR, - List &delEdges) - { - return call(UPR, delEdges); - } - - -protected: - /** - * \brief Computes a feasible upward planar subgraph of the input graph. - * - * @param UPR represents the feasible upward planar subgraph after the call. \a UPR has to be initialzed as a - * UpwardPlanRep of the input graph \a G and is modified. - * The subgraph is represented as an upward planar representation. - * @param delEdges is the list of deleted edges which are deleted from the input graph in order to obtain the subgraph. - * The edges are edges of the original graph G. - * \return the status of the result. - */ - virtual ReturnType doCall(UpwardPlanRep &UPR, - List &delEdges) = 0; - - OGDF_MALLOC_NEW_DELETE - -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/ForceLayoutModule.h b/ext/OGDF/ogdf/module/ForceLayoutModule.h deleted file mode 100644 index 40ae98cbf..000000000 --- a/ext/OGDF/ogdf/module/ForceLayoutModule.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for energy-based layout algorithms - * (class ForceLayoutModule) - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FORCE_LAYOUT_MODULE_H -#define OGDF_FORCE_LAYOUT_MODULE_H - - - -#include -#include -#include - -namespace ogdf { - - -/** - * \brief Interface of general layout algorithms. - * - */ -class OGDF_EXPORT ForceLayoutModule : public LayoutModule -{ - // holds index of the current level in multilevel hierarchy - int m_currentLevel; - -public: - //! Initializes a force layout module. - ForceLayoutModule() { } - - virtual ~ForceLayoutModule() { } - - virtual void call(GraphAttributes &GA) = 0; - - /** - * \brief Computes a layout of graph \a MLG. - * - * This method can be implemented optionally to allow a LayoutModule to modify the Graph. - * This allows some Layout Algorithms to save Memory, compared to a normal call(GA) - * DO NOT implement this if you are not sure whether this would save you Memory! - * This Method only helps if the Graph is already in the MultiLevelGraph Format - * (or can be converted without creating a copy) AND the Layout would need a copy otherwise. - * All incremental Layouts (especially energy based) CAN be called by ModularMultilevelMixer. - * The standard implementation converts the MLG to GA and uses call(GA). - * - * If implemented, the following Implementation of call(GA) is advised - * to ensure consistent behaviour of the two call Methods: - * void YourLayout::call(GraphAttributes &GA) - * { - * MultilevelGraph MLG(GA); - * call(MLG); - * MLG.exportAttributes(GA); - * } - * - * @param MLG is the input graph and will also be assigned the layout information. - */ - virtual void call(MultilevelGraph &MLG) { - m_currentLevel = MLG.getLevel(); - GraphAttributes GA(MLG.getGraph()); - MLG.exportAttributesSimple(GA); - call(GA); - MLG.importAttributesSimple(GA); - }; - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/GridLayoutModule.h b/ext/OGDF/ogdf/module/GridLayoutModule.h deleted file mode 100644 index a3f134206..000000000 --- a/ext/OGDF/ogdf/module/GridLayoutModule.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for grid layout algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GRID_LAYOUT_MODULE_H -#define OGDF_GRID_LAYOUT_MODULE_H - - - -#include -#include -#include - - -namespace ogdf { - - -/** - * \brief Base class for grid layout algorithms. - * - * A grid layout algorithm computes a grid layout of a graph. - * Such a grid layout does not take real node sizes into account - * and places a node simply on a grid point; edges may be routed - * via bend points on grid points. - * - * The class GridLayoutModule provides the infrastructure - * to transform a grid layout into a (usual) layout of a graph, - * turning a grid layout algorithm automatically into a - * LayoutModule. - */ -class OGDF_EXPORT GridLayoutModule : public LayoutModule -{ - friend class GridLayoutPlanRepModule; - friend class PlanarGridLayoutModule; - -public: - //! Initializes a grid layout module. - GridLayoutModule() : LayoutModule(), m_separation(40) { } - - virtual ~GridLayoutModule() { } - - /** - * \brief Calls the grid layout algorithm (general call). - * - * This method implements the call function of the base class LayoutModule. - * A derived algorithm implements the call by implementing doCall(). - * - * @param AG is the input graph; the new layout is also stored in \a AG. - */ - void call(GraphAttributes &AG); - - /** - * \brief Calls the grid layout algorithm (call for GridLayout). - * - * A derived algorithm implements the call by implementing doCall(). - * - * @param G is the input graph. - * @param gridLayout is assigned the computed grid layout. - */ - void callGrid(const Graph &G, GridLayout &gridLayout); - - - //! Returns the current setting of the minimum distance between nodes. - /** - * This minimum distance is used for mapping grid coordinates to double coordinates as stored - * in GraphAttributes. This mapping occurs automatically when the grid layout algorithm is - * called with LayoutModule's call method. - */ - double separation() const { return m_separation; } - - //! Sets the minimum distance between nodes. - /** - * This minimum distance is used for mapping grid coordinates to double coordinates as stored - * in GraphAttributes. This mapping occurs automatically when the grid layout algorithm is - * called with LayoutModule's call method. - */ - void separation(double sep) { m_separation = sep; } - - const IPoint &gridBoundingBox() const { return m_gridBoundingBox; } - -protected: - /** - * \brief Implements the algorithm call. - * - * A derived algorithm must implement this method and return the computed grid - * layout in \a gridLayout. - * - * @param G is the input graph. - * @param gridLayout is assigned the computed grid layout. - * @param boundingBox returns the bounding box of the grid layout. The lower left - * corner of the bounding box is always (0,0), thus this IPoint defines the - * upper right corner as well as the width and height of the grid layout. - */ - virtual void doCall(const Graph &G, GridLayout &gridLayout, IPoint &boundingBox) = 0; - -private: - double m_separation; //!< The minimum distance between nodes. - IPoint m_gridBoundingBox; //!< The computed bounding box of the grid layout. - - //! Internal transformation of grid coordinates to real coordinates. - void mapGridLayout(const Graph &G, - GridLayout &gridLayout, - GraphAttributes &AG); -}; - - -/** - * \brief Base class for planar grid layout algorithms. - * - * A planar grid layout algorithm is a grid layout algorithm - * that produces a crossing-free grid layout of a planar - * graph. It provides an additional call method for producing - * a planar layout with a predefined planar embedding. - */ -class OGDF_EXPORT PlanarGridLayoutModule : public GridLayoutModule -{ -public: - //! Initializes a planar grid layout module. - PlanarGridLayoutModule() : GridLayoutModule() { } - - virtual ~PlanarGridLayoutModule() { } - - /** - * \brief Calls the grid layout algorithm with a fixed planar embedding (general call). - * - * A derived algorithm implements the call by implementing doCall(). - * - * @param AG is the input graph; the new layout is also stored in \a AG. - * @param adjExternal specifies an adjacency entry on the external face, - * or is set to 0 if no particular external face shall be specified. - */ - void callFixEmbed(GraphAttributes &AG, adjEntry adjExternal = 0); - - /** - * \brief Calls the grid layout algorithm with a fixed planar embedding (call for GridLayout). - * - * A derived algorithm implements the call by implementing doCall(). - * - * @param G is the input graph. - * @param gridLayout is assigned the computed grid layout. - * @param adjExternal specifies an adjacency entry (of \a G) on the external face, - * or is set to 0 if no particular external face shall be specified. - */ - void callGridFixEmbed(const Graph &G, GridLayout &gridLayout, adjEntry adjExternal = 0); - -protected: - /** - * \brief Implements the algorithm call. - * - * @param G is the input graph. - * @param gridLayout is assigned the computed grid layout. - * @param boundingBox returns the bounding box of the grid layout. The lower left - * corner of the bounding box is always (0,0), thus this IPoint defines the - * upper right corner as well as the width and height of the grid layout. - */ - virtual void doCall( - const Graph &G, - GridLayout &gridLayout, - IPoint &boundingBox) - { - doCall(G,0,gridLayout,boundingBox,false); - } - - /** - * \brief Implements the algorithm call. - * - * A derived algorithm must implement this method and return the computed grid - * layout in \a gridLayout. - * - * @param G is the input graph. - * @param adjExternal is an adjacency entry on the external face, or 0 if no external - * face is specified. - * @param gridLayout is assigned the computed grid layout. - * @param boundingBox returns the bounding box of the grid layout. The lower left - * corner of the bounding box is always (0,0), thus this IPoint defines the - * upper right corner as well as the width and height of the grid layout. - * @param fixEmbedding determines if the input graph is embedded and that embedding - * has to be preserved (true), or if an embedding needs to be computed (false). - */ - virtual void doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) = 0; -}; - - -/** - * \brief Base class for grid layout algorithms operating on a PlanRep. - * - * A GridLayoutPlanRepModule is a special class of a grid layout module - * that produces a planar layout of a planar graph, and that has a - * special call method (taking a PlanRep as input) for using the - * layout module within the planarization approach. - * - * \see PlanarizationGridLayout - */ -class OGDF_EXPORT GridLayoutPlanRepModule : public PlanarGridLayoutModule -{ -public: - //! Initializes a plan-rep grid layout module. - GridLayoutPlanRepModule() : PlanarGridLayoutModule() { } - - virtual ~GridLayoutPlanRepModule() { } - - /** - * \brief Calls the grid layout algorithm (call for GridLayout). - * - * The implementation of this call method temporarily constructs a - * PlanRep and copies the resulting grid layout to the grid layout for - * the input graph. - * - * @param G is the input graph. - * @param gridLayout is assigned the computed grid layout. - */ - void callGrid(const Graph &G, GridLayout &gridLayout) { - PlanarGridLayoutModule::callGrid(G,gridLayout); - } - - /** - * \brief Calls the grid layout algorithm (call for GridLayout of a PlanRep). - * - * @param PG is the input graph which may be modified by the algorithm. - * @param gridLayout is assigned the computed grid layout of \a PG. - */ - void callGrid(PlanRep &PG, GridLayout &gridLayout); - - /** - * \brief Calls the grid layout algorithm with a fixed planar embedding (call for GridLayout). - * - * A derived algorithm implements the call by implementing doCall(). - * - * @param G is the input graph. - * @param gridLayout is assigned the computed grid layout. - * @param adjExternal specifies an adjacency entry (of \a G) on the external face, - * or is set to 0 if no particular external face shall be specified. - */ - void callGridFixEmbed(const Graph &G, GridLayout &gridLayout, adjEntry adjExternal = 0) { - PlanarGridLayoutModule::callGridFixEmbed(G,gridLayout,adjExternal); - } - - /** - * \brief Calls the grid layout algorithm with a fixed planar embedding (call for GridLayout of a PlanRep). - * - * A derived algorithm implements the call by implementing doCall(). - * - * @param PG is the input graph which may be modified by the algorithm. - * @param gridLayout is assigned the computed grid layout. - * @param adjExternal specifies an adjacency entry (of \a PG) on the external face, - * or is set to 0 if no particular external face shall be specified. - */ - void callGridFixEmbed(PlanRep &PG, GridLayout &gridLayout, adjEntry adjExternal = 0); - -protected: - /** - * \brief Implements the algorithm call. - * - * A derived algorithm must implement this method and return the computed grid - * layout of \a PG in \a gridLayout. - * - * @param PG is the input graph which may be modified by the algorithm. - * @param adjExternal is an adjacency entry on the external face, or 0 if no external - * face is specified. - * @param gridLayout is assigned the computed grid layout. - * @param boundingBox is assigned the bounding box of the computed layout. - * @param fixEmbedding determines if the input graph is embedded and that embedding - * has to be preserved (true), or if an embedding needs to be computed (false). - */ - virtual void doCall( - PlanRep &PG, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) = 0; - -private: - //! Implements PlanarGridLayoutModule::doCall(). - void doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/HierarchyClusterLayoutModule.h b/ext/OGDF/ogdf/module/HierarchyClusterLayoutModule.h deleted file mode 100644 index 478b5429a..000000000 --- a/ext/OGDF/ogdf/module/HierarchyClusterLayoutModule.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for hierarchy layout algorithms - * (3. phase of Sugiyama) for cluster graphs. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HIER_CLUSTER_LAYOUT_MODULE_H -#define OGDF_HIER_CLUSTER_LAYOUT_MODULE_H - - - -#include - - -namespace ogdf { - - -/** - * \brief Interface of hierarchy layout algorithms for cluster graphs. - * - * \see SugiyamaLayout - */ -class OGDF_EXPORT HierarchyClusterLayoutModule { -public: - //! Initializes a hierarchy cluster layout module. - HierarchyClusterLayoutModule() { } - - virtual ~HierarchyClusterLayoutModule() { } - - /** - * \brief Computes a hierarchy layout of a clustered hierarchy \a H in \a ACG. - * @param H is the input clustered hierarchy. - * @param ACG is assigned the cluster hierarchy layout. - */ - void callCluster(const ExtendedNestingGraph& H, ClusterGraphAttributes &ACG) { - ClusterGraphCopyAttributes ACGC(H,ACG); - doCall(H,ACGC); - ACGC.transform(); - } - -protected: - /** - * \brief Implements the actual algorithm call. - * - * Must be implemented by derived classes. - * - * @param H is the input clustered hierarchy. - * @param ACGC has to be assigned the cluster hierarchy layout. - */ - virtual void doCall( - const ExtendedNestingGraph& H, - ClusterGraphCopyAttributes &ACGC) = 0; - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/HierarchyLayoutModule.h b/ext/OGDF/ogdf/module/HierarchyLayoutModule.h deleted file mode 100644 index 1ad53ae28..000000000 --- a/ext/OGDF/ogdf/module/HierarchyLayoutModule.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface hierarchy layout algorithms - * (3. phase of Sugiyama). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_HIER_LAYOUT_MODULE_H -#define OGDF_HIER_LAYOUT_MODULE_H - - - -#include -#include - - -namespace ogdf { - - -/** - * \brief Interface of hierarchy layout algorithms. - * - * \see SugiyamaLayout - */ -class OGDF_EXPORT HierarchyLayoutModule { -public: - //! Initializes a hierarchy layout module. - HierarchyLayoutModule() { } - - virtual ~HierarchyLayoutModule() { } - - /** - * \brief Computes a hierarchy layout of \a H in \a AGA - * @param H is the input hierarchy. - * @param GA is assigned the hierarchy layout. - */ - void call(const Hierarchy& H, GraphAttributes &GA) { - GraphCopyAttributes AGC(H,GA); - doCall(H,AGC); - AGC.transform(); - } - - // - // * \brief Computes a hierarchy layout of \a H in \a AG. - // * @param H is the input hierarchy. - // * @param AG is assigned the hierarchy layout. - // */ - //void call(Hierarchy& H, GraphAttributes &AG) { - // GraphCopyAttributes AGC(H,AG); - // doCall(H,AGC); - // HierarchyLayoutModule::dynLayerDistance(AGC, H); - // HierarchyLayoutModule::addBends(AGC, H); - // AGC.transform(); - //} - - - // - // * \brief Computes a hierarchy layout of \a H in \a AG. - // * @param H is the input hierarchy. - // * @param AG is assigned the hierarchy layout. - // * @param AGC is GraphCopyAttribute init. with H and AG - // */ - //void call(const Hierarchy& H, GraphAttributes &, GraphCopyAttributes &AGC) { - // doCall(H,AGC); - //} - - - //! Adds bends to edges for avoiding crossings with nodes. - static void addBends(GraphCopyAttributes &AGC, Hierarchy &H); - - static void dynLayerDistance(GraphCopyAttributes &AGC, Hierarchy &H); - -private: - - //! after calling, ci (cj) contains the number of nodes of level i (j=i-1) which overlap the edge (s,t) - static void overlap(GraphCopyAttributes &AGC, Hierarchy &H, node s, node t, int i, int &ci, int &cj); - -protected: - /** - * \brief Implements the actual algorithm call. - * - * Must be implemented by derived classes. - * - * @param H is the input hierarchy. - * @param AGC has to be assigned the hierarchy layout. - */ - virtual void doCall(const Hierarchy& H, GraphCopyAttributes &AGC) = 0; - - OGDF_MALLOC_NEW_DELETE - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/LayoutClusterPlanRepModule.h b/ext/OGDF/ogdf/module/LayoutClusterPlanRepModule.h deleted file mode 100644 index 71a58b7d3..000000000 --- a/ext/OGDF/ogdf/module/LayoutClusterPlanRepModule.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for planar layout algorithms for - * UML diagrams (used in planarization approach). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LAYOUT_CLUSTER_PLAN_REP_MODULE_H -#define OGDF_LAYOUT_CLUSTER_PLAN_REP_MODULE_H - - - -#include -#include - - - -namespace ogdf { - - class NodePair; - -/** - * \brief Interface for planar cluster layout algorithms. - * - * \warning This interface is likely to change in future releases. - * \see ClusterPlanarizationLayout - */ -class OGDF_EXPORT LayoutClusterPlanRepModule { -public: - //! Initializes a cluster planar layout module. - LayoutClusterPlanRepModule() { } - - virtual ~LayoutClusterPlanRepModule() { } - - /** \brief Computes a layout of \a PG in \a drawing. - * - * Must be overridden by derived classes. - * @param PG is the input cluster planarized representation which may be modified. - * @param adjExternal is an adjacenty entry on the external face. - * @param drawing is the computed layout of \a PG. - * @param npEdges are pairs of nodes in the original graph that shall be connected. - * @param newEdges are assigned the inserted edges. - * @param originalGraph must be the original graph of \a PG. - */ - virtual void call( - ClusterPlanRep &PG, - adjEntry adjExternal, - Layout &drawing, - List& npEdges, - List& newEdges, - Graph& originalGraph) = 0; - - - //! Returns the bounding box of the computed layout. - const DPoint &getBoundingBox() const { - return m_boundingBox; - } - - //! Sets the (generic) options; derived classes have to cope with the interpretation) - virtual void setOptions(int /* optionField */) { } //don't make it abstract - - //! Returns the (generic) options. - virtual int getOptions() { return 0; } //don't make it abstract - - //! Returns the minimal allowed distance between edges and vertices. - virtual double separation() const = 0; - - //! Sets the minimal allowed distance between edges and vertices to \a sep. - virtual void separation(double sep) = 0; - -protected: - /** - * \brief Stores the bounding box of the computed layout. - * Must be set by derived algorithms! - */ - DPoint m_boundingBox; - - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/LayoutModule.h b/ext/OGDF/ogdf/module/LayoutModule.h deleted file mode 100644 index 506856c0f..000000000 --- a/ext/OGDF/ogdf/module/LayoutModule.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for layout algorithms (class - * LayoutModule) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LAYOUT_MODULE_H -#define OGDF_LAYOUT_MODULE_H - - - -#include -#include -#include - -namespace ogdf { - - -/** - * \brief Interface of general layout algorithms. - * - */ -class OGDF_EXPORT LayoutModule { -public: - //! Initializes a layout module. - LayoutModule() { } - - virtual ~LayoutModule() { } - - /** - * \brief Computes a layout of graph \a GA. - * - * This method is the actual algorithm call and must be implemented by - * derived classes. - * @param GA is the input graph and will also be assigned the layout information. - */ - virtual void call(GraphAttributes &GA) = 0; - - /** - * \brief Computes a layout of graph \a GA wrt the constraints in \a GC - * (if applicable). - */ - virtual void call(GraphAttributes &GA, GraphConstraints & GC) { call(GA); } - - /** - * \brief Computes a layout of graph \a GA. - * - * @param GA is the input graph and will also be assigned the layout information. - */ - void operator()(GraphAttributes &GA) { call(GA); } - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/LayoutPlanRepModule.h b/ext/OGDF/ogdf/module/LayoutPlanRepModule.h deleted file mode 100644 index ccb7aa3d0..000000000 --- a/ext/OGDF/ogdf/module/LayoutPlanRepModule.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for planar layout algorithms for - * UML diagrams (used in planarization approach). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UML_PLANAR_LAYOUT_MODULE_H -#define OGDF_UML_PLANAR_LAYOUT_MODULE_H - - - -#include -#include - - - -namespace ogdf { - - -enum UMLOpt {umlOpAlign = 0x0001, umlOpScale = 0x0002, umlOpProg = 0x0004}; - - -/** - * \brief Interface for planar UML layout algorithms. - * - * \see PlanarizationLayout - */ -class OGDF_EXPORT LayoutPlanRepModule { -public: - //! Initializes a UML planar layout module. - LayoutPlanRepModule() { } - - virtual ~LayoutPlanRepModule() { } - - /** \brief Computes a planar layout of \a PG in \a drawing. - * - * Must be overridden by derived classes. - * @param PG is the input planarized representation which may be modified. - * @param adjExternal is an adjacenty entry on the external face. - * @param drawing is the computed layout of \a PG. - */ - virtual void call(PlanRepUML &PG, - adjEntry adjExternal, - Layout &drawing) = 0; - - //! Computes a planar layout of \a PG in \a drawing. - void operator()(PlanRepUML &PG, adjEntry adjExternal, Layout &drawing) { - call(PG,adjExternal,drawing); - } - - //! Returns the bounding box of the computed layout. - const DPoint &getBoundingBox() const { - return m_boundingBox; - } - - //! Sets the (generic) options; derived classes have to cope with the interpretation) - virtual void setOptions(int /* optionField */) { } //don't make it abstract - - //! Returns the (generic) options. - virtual int getOptions() { return 0; } //don't make it abstract - - //! Returns the minimal allowed distance between edges and vertices. - virtual double separation() const = 0; - - //! Sets the minimal allowed distance between edges and vertices to \a sep. - virtual void separation(double sep) = 0; - -protected: - /** - * \brief Stores the bounding box of the computed layout. - * Must be set by derived algorithms! - */ - DPoint m_boundingBox; - - /** - * \brief Computes and sets the bounding box variable \a m_boundingBox. - * An algorithm can call setBoundingBox() for setting the - * m_boundingBox variable if no faster implementation is available. - */ - void setBoundingBox(PlanRepUML &PG, Layout &drawing); - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/MMCrossingMinimizationModule.h b/ext/OGDF/ogdf/module/MMCrossingMinimizationModule.h deleted file mode 100644 index dc3fe57e2..000000000 --- a/ext/OGDF/ogdf/module/MMCrossingMinimizationModule.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of MMCrossingMinimization Module, an interface - * for minor-monotone crossing minimization algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_MM_CROSSING_MINIMIZATION_MODULE_H -#define OGDF_MM_CROSSING_MINIMIZATION_MODULE_H - - - -#include -#include -#include - - -namespace ogdf { - -/** - * \brief Interface for minor-monotone crossing minimization algorithms. - * - */ -class OGDF_EXPORT MMCrossingMinimizationModule : public Module -{ -public: - //! Initializes a minor-monotone crossing minimization module. - MMCrossingMinimizationModule() { m_nodeSplits = 0; } - - // destruction - virtual ~MMCrossingMinimizationModule() { } - - /** - * \brief Computes a planarized representation of an expansion of the input graph. - * - * @param PG represents the input graph as well as the computed planarized - * expansion after the call. \a PG has to be initialzed as a - * PlanRepExpansion of the input graph and is modified to obatain the planarized - * representation (nodes are eventually expanded by splitting the node and - * crossings are replaced by dummy vertices with degree four). - * @param cc is the number of the connected component in \a PG that is considered. - * @param crossingNumber is assigned the number of crossings. - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. If forbid = 0, no edges are - * forbidden. - * \return the status of the result. - */ - ReturnType call(PlanRepExpansion &PG, - int cc, - int& crossingNumber, - const EdgeArray *forbid = 0) - { - return doCall(PG, cc, forbid, crossingNumber, m_nodeSplits, m_splittedNodes); - }; - - /** - * \brief Performs minor-monotone crossing minimization on \a G. - * - * @param G is the input graph. - * @param cr is assigned the number of crossings. - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. If forbid = 0, no edges are - * forbidden. - * \return the status of the result. - */ - ReturnType call(const Graph &G, int &cr, const EdgeArray *forbid = 0); - - /** - * \brief Performs minor-monotone crossing minimization on \a G for given splittable nodes. - * - * @param G is the input graph. - * @param splittableNodes is the list of nodes that are allowed to be split. - * @param cr is assigned the number of crossings. - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. If forbid = 0, no edges are - * forbidden. - * \return the status of the result. - */ - ReturnType call(const Graph &G, - const List &splittableNodes, - int &cr, - const EdgeArray *forbid = 0); - - /** - * \brief Returns the number of required node splits after the call. - */ - int numberOfNodeSplits() const { return m_nodeSplits; } - - int numberOfSplittedNodes() const { return m_splittedNodes; } - -protected: - /** - * \brief Actual algorithm call that needs to be implemented by derived classed. - * - * @param PG represents the input graph as well as the computed planarized expansion - * after the call. \a PG is initialized as a PlanRepExpansion of the input - * graph and needs to be modified to obatain the planarized representation - * (crossings are replaced by dummy vertices with degree four). - * @param cc is the number of the connected component in \a PG that is considered. - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. - * @param crossingNumber needs to be assigned the number of crossings. - * @param numNS needs to be assigned the required number of node splits. - * @param numSN needs to be assigned the number of splitted nodes. - * \return the status of the result. - */ - virtual ReturnType doCall(PlanRepExpansion &PG, - int cc, - const EdgeArray *forbid, - int& crossingNumber, - int& numNS, - int& numSN) = 0; - -private: - int m_nodeSplits; //!< The number of required node splits. - int m_splittedNodes; //!< The number of nodes that are split. - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/MMEdgeInsertionModule.h b/ext/OGDF/ogdf/module/MMEdgeInsertionModule.h deleted file mode 100644 index 752a1deb9..000000000 --- a/ext/OGDF/ogdf/module/MMEdgeInsertionModule.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for minor-monotone edge - * insertion algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MM_EDGE_INSERTION_MODULE_H -#define OGDF_MM_EDGE_INSERTION_MODULE_H - - -#include -#include - - -namespace ogdf { - -/** - * \brief Interface for minor-monotone edge insertion algorithms. - * - * \see MMSubgraphPlanarizer - */ -class OGDF_EXPORT MMEdgeInsertionModule : public Module { -public: - //! The postprocessing methods. - enum RemoveReinsertType { - rrNone, //!< No postprocessing. - rrInserted, //!< Postprocessing only with the edges that have to be inserted. - rrMostCrossed, //!< Postprocessing with the edges involved in the most crossings. - rrAll, //!< Postproceesing with all edges and all node splits. - rrIncremental //!< Full postprocessing after each edge insertion. - }; - - //! Initializes a minor-monotone edge insertion module. - MMEdgeInsertionModule() { } - - // destruction - virtual ~MMEdgeInsertionModule() { } - - /** - * \brief Inserts all edges in \a origEdges into \a PG. - * - * @param PG is the input planarized expansion and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(PlanRepExpansion &PG, const List &origEdges) { - return doCall(PG, origEdges, 0); - } - - /** - * \brief Inserts all edges in \a origEdges into \a PG and forbids crossing \a forbiddenEdges. - * - * @param PG is the input planarized expansion and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * @param forbiddenEdgeOrig is an edge array indicating if an original edge is - * forbidden to be crossed. - * \return the status of the result. - */ - ReturnType call(PlanRepExpansion &PG, - const List &origEdges, - const EdgeArray &forbiddenEdgeOrig) - { - return doCall(PG, origEdges, &forbiddenEdgeOrig); - } - -protected: - /** - * \brief Actual algorithm call that has to be implemented by derived classes. - * - * @param PG is the input planarized expansion and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - */ - virtual ReturnType doCall(PlanRepExpansion &PG, - const List &origEdges, const EdgeArray *forbiddenEdgeOrig) = 0; - - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/MinCostFlowModule.h b/ext/OGDF/ogdf/module/MinCostFlowModule.h deleted file mode 100644 index 507fb7c66..000000000 --- a/ext/OGDF/ogdf/module/MinCostFlowModule.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of base class of min-cost-flow algorithms - * - * Includes some useful functions dealing with min-cost flow - * (generater, checker). - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIN_COST_FLOW_MODULE_H -#define OGDF_MIN_COST_FLOW_MODULE_H - - -#include - - -namespace ogdf { - - -/** - * \brief Interface for min-cost flow algorithms. - */ -class OGDF_EXPORT MinCostFlowModule -{ -public: - //! Initializes a min-cost flow module. - MinCostFlowModule() { } - - // destruction - virtual ~MinCostFlowModule() { } - - /** - * \brief Computes a min-cost flow in the directed graph \a G. - * - * \pre \a G must be connected, \a lowerBound[\a e] \f$\leq\f$ \a upperBound[\a e] - * for all edges \a e, and the sum over all supplies must be zero. - * - * @param G is the directed input graph. - * @param lowerBound gives the lower bound for the flow on each edge. - * @param upperBound gives the upper bound for the flow on each edge. - * @param cost gives the costs for each edge. - * @param supply gives the supply (or demand if negative) of each node. - * @param flow is assigned the computed flow on each edge. - * @param dual is assigned the computed dual variables. - * \return true iff a feasible min-cost flow exists. - */ - virtual bool call( - const Graph &G, // directed graph - const EdgeArray &lowerBound, // lower bound for flow - const EdgeArray &upperBound, // upper bound for flow - const EdgeArray &cost, // cost of an edge - const NodeArray &supply, // supply (if neg. demand) of a node - EdgeArray &flow, // computed flow - NodeArray &dual // computed dual variables - ) = 0; - - - // - // static functions - // - - /** - * \brief Generates an instance of a min-cost flow problem with \a n nodes and - * \a m+\a n edges. - */ - static void generateProblem( - Graph &G, - int n, - int m, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply); - - - /** - * \brief Checks if a given min-cost flow problem instance satisfies - * the preconditions. - * The following preconditions are checked: - * - \a lowerBound[\a e] \f$\leq\f$ \a upperBound[\a e] for all edges \a e - * - sum over all \a supply[\a v] = 0 - * - * @param G is the input graph. - * @param lowerBound gives the lower bound for the flow on each edge. - * @param upperBound gives the upper bound for the flow on each edge. - * @param supply gives the supply (or demand if negative) of each node. - * \return true iff the problem satisfies the preconditions. - */ - static bool checkProblem( - const Graph &G, - const EdgeArray &lowerBound, - const EdgeArray &upperBound, - const NodeArray &supply); - - - - /** - * \brief checks if a computed flow is a feasible solution to the given problem - * instance. - * - * Checks in particular if: - * - \a lowerBound[\a e] \f$\leq\f$ \a flow[\a e] \f$\leq\f$ \a upperBound[\a e] - * - sum \a flow[\a e], \a e is outgoing edge of \a v minus - * sum \a flow[\a e], \a e is incoming edge of \a v equals \a supply[\a v] - * for each node \a v - * - * @param G is the input graph. - * @param lowerBound gives the lower bound for the flow on each edge. - * @param upperBound gives the upper bound for the flow on each edge. - * @param cost gives the costs for each edge. - * @param supply gives the supply (or demand if negative) of each node. - * @param flow is the flow on each edge. - * @param value is assigned the value of the flow. - * \return true iff the solution is feasible. - */ - static bool checkComputedFlow( - const Graph &G, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply, - EdgeArray &flow, - int &value); - - /** - * \brief checks if a computed flow is a feasible solution to the given problem - * instance. - * - * Checks in particular if: - * - \a lowerBound[\a e] \f$\leq\f$ \a flow[\a e] \f$\leq\f$ \a upperBound[\a e] - * - sum \a flow[\a e], \a e is outgoing edge of \a v minus - * sum \a flow[\a e], \a e is incoming edge of \a v equals \a supply[\a v] - * for each node \a v - * - * @param G is the input graph. - * @param lowerBound gives the lower bound for the flow on each edge. - * @param upperBound gives the upper bound for the flow on each edge. - * @param cost gives the costs for each edge. - * @param supply gives the supply (or demand if negative) of each node. - * @param flow is the flow on each edge. - * \return true iff the solution is feasible. - */ - static bool checkComputedFlow( - const Graph &G, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply, - EdgeArray &flow) - { - int value; - return checkComputedFlow( - G,lowerBound,upperBound,cost,supply,flow,value); - } -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/MixedModelCrossingsBeautifierModule.h b/ext/OGDF/ogdf/module/MixedModelCrossingsBeautifierModule.h deleted file mode 100644 index c5093cb26..000000000 --- a/ext/OGDF/ogdf/module/MixedModelCrossingsBeautifierModule.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for mixed-model crossings - * beautifier algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIXED_MODEL_CROSSINGS_BEAUTIFIER_MODULE_H -#define OGDF_MIXED_MODEL_CROSSINGS_BEAUTIFIER_MODULE_H - - - -#include -#include - - -namespace ogdf { - -/** - * \brief The base class for Mixed-Model crossings beautifier algorithms. - * - * The class MixedModelCrossingsBeautifierModule is the base class for - * mixed model bend crossing modules. Such a module transforms an input - * graph \a G into an output graph \a G' such that crossings of edges don't - * look weird. - * - *

    Implementation of Mixed-Model Crossings Beautifier Algorithms

    - * - * An implementation of a Mixed-Model crossings beautifier module must override - * the protected method doCall(). - */ - -class OGDF_EXPORT MixedModelCrossingsBeautifierModule { -public: - //! Initializes the Mixed-Model crossings beautifier module. - MixedModelCrossingsBeautifierModule() { } - - // destruction - virtual ~MixedModelCrossingsBeautifierModule() { } - - - /* - * \brief Calls the Mixed-Model crossings beautifier module for graph \a PG and grid layout \a gl. - * - * @param PG is the input graph. - * @param gl is the grid layout of \a PG. - */ - void call(const PlanRep &PG, GridLayout &gl); - - //! Returns the number of processed crossings. - int numberOfCrossings() const { - return m_nCrossings; - } - - -protected: - /** - * \brief Implements the crossings beautifier module. - * - * @param PG is the input graph. - * @param gl is the grid layout of \a PG. - * @param L is the list of crossing nodes. - */ - virtual void doCall(const PlanRep &PG, GridLayout &gl, const List &L) = 0; - -private: - int m_nCrossings; //!< the number of processed crossings. - - OGDF_MALLOC_NEW_DELETE -}; - - -//! Dummy implementation of Mixed-Model crossings beautifier. -/** - * This implementation does no beautification at all and can thus be used - * for obtaining the original Mixed-Model layout. - */ -class MMDummyCrossingsBeautifier : public MixedModelCrossingsBeautifierModule -{ -protected: - //!< Dummy implementation. - void doCall(const PlanRep &, GridLayout &, const List &) { } -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/MultilevelLayoutModule.h b/ext/OGDF/ogdf/module/MultilevelLayoutModule.h deleted file mode 100644 index 321138f73..000000000 --- a/ext/OGDF/ogdf/module/MultilevelLayoutModule.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for layout algorithms that allow - * calls with a MultilevelGraph parameter (class MultilevelLayoutModule). - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MULTILEVEL_LAYOUT_MODULE_H -#define OGDF_MULTILEVEL_LAYOUT_MODULE_H - - - -#include -#include - -namespace ogdf { - - -/** - * \brief Interface of general layout algorithms that also allow - * a MultilevelGraph as call parameter, extending the interface - * of a simple LayoutModule. - * - */ - class OGDF_EXPORT MultilevelLayoutModule : public LayoutModule { -public: - //! Initializes a multilevel layout module. - MultilevelLayoutModule() { } - - virtual ~MultilevelLayoutModule() { } - - /** - * \brief Computes a layout of graph \a GA. - * - * This method is the actual algorithm call and must be implemented by - * derived classes. - * @param GA is the input graph and will also be assigned the layout information. - */ - virtual void call(GraphAttributes &GA) = 0; - - /** - * \brief Computes a layout of graph \a GA. - * - * @param GA is the input graph and will also be assigned the layout information. - */ - void operator()(GraphAttributes &GA) { call(GA); } - - /** - * \brief Computes a layout of graph \a MLG. - * - * This method can be implemented optionally to allow a LayoutModule to modify the Graph. - * This allows some Layout Algorithms to save Memory, compared to a normal call(GA) - * DO NOT implement this if you are not sure whether this would save you Memory! - * This method only helps if the Graph is already in the MultiLevelGraph Format - * (or can be converted without creating a copy) AND the layout would need a copy otherwise. - * All Incremental Layouts (especially energy based) CAN be called by ModularMultilevelMixer. - * The standard implementation converts the MLG to GA and uses call(GA). - * - * If implemented, the following Implementation of call(GA) is advised - * to ensure consistent behaviour of the two call Methods: - * void YourLayout::call(GraphAttributes &GA) - * { - * MultilevelGraph MLG(GA); - * call(MLG); - * MLG.exportAttributes(GA); - * } - * - * @param MLG is the input graph and will also be assigned the layout information. - */ - virtual void call(MultilevelGraph &MLG) { - GraphAttributes GA(MLG.getGraph()); - MLG.exportAttributesSimple(GA); - call(GA); - MLG.importAttributesSimple(GA); - }; - - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/PlanarSubgraphModule.h b/ext/OGDF/ogdf/module/PlanarSubgraphModule.h deleted file mode 100644 index 150fed766..000000000 --- a/ext/OGDF/ogdf/module/PlanarSubgraphModule.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for planar subgraph algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANAR_SUBGRAPH_MODULE_H -#define OGDF_PLANAR_SUBGRAPH_MODULE_H - - - -#include -#include -#include -#include - - -namespace ogdf { - -/** - * \brief Interface for planar subgraph algorithms. - * - * \see PlanarizationLayout, PlanarizationGridLayout - */ -class OGDF_EXPORT PlanarSubgraphModule : public Module, public Timeouter { -public: - //! Initializes a planar subgraph module. - PlanarSubgraphModule() { } - - // destruction - virtual ~PlanarSubgraphModule() { } - - /** - * \brief Returns the set of edges \a delEdges which have to be deleted to obtain the planar subgraph. - * @param G is the input graph. - * @param preferedEdges are edges that should be contained in the planar subgraph. - * @param delEdges is the set of edges that need to be deleted to obtain the planar subgraph. - * @param preferedImplyPlanar indicates that the edges \a preferedEdges induce a planar graph. - */ - ReturnType call(const Graph &G, - const List &preferedEdges, - List &delEdges, - bool preferedImplyPlanar = false) - { - return doCall(G,preferedEdges,delEdges,0,preferedImplyPlanar); - } - - - /** - * \brief Returns the set of edges \a delEdges which have to be deleted to obtain the planar subgraph. - * @param G is the input graph. - * @param cost are the costs of edges. - * @param delEdges is the set of edges that need to be deleted to obtain the planar subgraph. - */ - ReturnType call(const Graph &G, const EdgeArray &cost, List &delEdges) { - List preferedEdges; - return doCall(G,preferedEdges,delEdges, &cost); - } - - /** - * \brief Returns the set of edges \a delEdges which have to be deleted to obtain the planar subgraph. - * @param G is the input graph. - * @param delEdges is the set of edges that need to be deleted to obtain the planar subgraph. - */ - ReturnType call(const Graph &G, List &delEdges) { - List preferedEdges; - return doCall(G,preferedEdges,delEdges); - } - - - //! Returns the set of edges \a delEdges which have to be deleted to obtain the planar subgraph. - ReturnType operator()(const Graph &G, - const List &preferedEdges, - List &delEdges, - bool preferedImplyPlanar = false) - { - return call(G,preferedEdges,delEdges,preferedImplyPlanar); - } - - //! Returns the set of edges \a delEdges which have to be deleted to obtain the planar subgraph. - ReturnType operator()(const Graph &G, List &delEdges) { - return call(G,delEdges); - } - - - /** - * \brief Makes \a G planar by deleting edges. - * @param GC is a copy of the input graph. - * @param preferedEdges are edges in \a GC that should be contained in the planar subgraph. - * @param delOrigEdges is the set of original edges whose copy has been deleted in \a GC. - * @param preferedImplyPlanar indicates that the edges \a preferedEdges induce a planar graph. - */ - ReturnType callAndDelete(GraphCopy &GC, - const List &preferedEdges, - List &delOrigEdges, - bool preferedImplyPlanar = false); - - /** - * \brief Makes \a G planar by deleting edges. - * @param GC is a copy of the input graph. - * @param delOrigEdges is the set of original edges whose copy has been deleted in \a GC. - */ - ReturnType callAndDelete(GraphCopy &GC, List &delOrigEdges) { - List preferedEdges; - return callAndDelete(GC,preferedEdges,delOrigEdges); - } - -protected: - // computes set of edges delEdges, which have to be deleted - // in order to get a planar subgraph; edges in preferedEdges - // should be contained in planar subgraph - // must be implemented by derived classes! - /** - * \brief Computes the set of edges \a delEdges which have to be deleted to obtain the planar subgraph. - * - * This is the actual algorithm call and needs to be implemented - * by derived classes. - * @param G is the input graph. - * @param preferedEdges are edges that should be contained in the planar subgraph. - * @param delEdges is the set of edges that need to be deleted to obtain the planar subgraph. - * @param pCost is apointer to an edge array containing the edge costs; this pointer - * can be 0 if no costs are given (all edges have cost 1). - * @param preferedImplyPlanar indicates that the edges \a preferedEdges induce a planar graph. - */ - virtual ReturnType doCall(const Graph &G, - const List &preferedEdges, - List &delEdges, - const EdgeArray *pCost = 0, - bool preferedImplyPlanar = false) = 0; - - - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/PlanarityModule.h b/ext/OGDF/ogdf/module/PlanarityModule.h deleted file mode 100644 index 79969c7d9..000000000 --- a/ext/OGDF/ogdf/module/PlanarityModule.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2600 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 22:58:25 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Module for planarity testing and planar embeddings. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANARITY_MODULE_H -#define OGDF_PLANARITY_MODULE_H - -#include - -namespace ogdf { - -//! Module for planarity testing and planar embeddings. -/** - * This is a module defining functions to test planarity of graphs, and to embed planar graphs (i.e., find - * a rotation scheme of the edges around their incident vertices defining a plane graph). - * - * Use this module only if you want to be able to (later on) decide which planarity test to use. - * If you simply want to test planarity or to embed a graph, use the simpler/preferred method: - * the direct function calls in extended_graph_alg.h (ogdf::isPlanar, ogdf::planarEmbed, - * ogdf::planarEmbedPlanarGraph), which use the most efficient BoyerMyrvold algorithm. - */ -class PlanarityModule { - -public: - - PlanarityModule() { } - virtual ~PlanarityModule() { } - - //! Returns true, if G is planar, false otherwise. - virtual bool isPlanar(const Graph &G) = 0; - - //! Returns true, if G is planar, false otherwise. In the graph is non-planar, the graph may be arbitrariliy changed after the call. - /** - * This variant may be slightly faster than the default isPlanar - */ - virtual bool isPlanarDestructive(Graph &G) = 0; - - //! Returns true, if G is planar, false otherwise. If true, G contains a planar embedding. - virtual bool planarEmbed(Graph &G) = 0; - - //! Constructs a planar embedding of G. \a G \b has to be planar! - /** - * Returns true if the embedding was successful. - * Returns false, if the given graph was non-planar - * (and leaves the graph in an at least partially deleted state) - * - * This routine may be slightly faster than planarEmbed, but requires \a G to be planar. - * If \a G is not planar, the graph will be (partially) destroyed while trying to embed it! - */ - virtual bool planarEmbedPlanarGraph(Graph &G) = 0; - -}; - -} -#endif diff --git a/ext/OGDF/ogdf/module/RankingModule.h b/ext/OGDF/ogdf/module/RankingModule.h deleted file mode 100644 index 431eb275e..000000000 --- a/ext/OGDF/ogdf/module/RankingModule.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for ranking algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_RANKING_MODULE_H -#define OGDF_RANKING_MODULE_H - - - -#include - - -namespace ogdf { - - -/** - * \brief Interface of algorithms for computing a node ranking. - * - * \see SugiyamaLayout - */ -class OGDF_EXPORT RankingModule { -public: - //! Initializes a ranking module. - RankingModule() { } - - virtual ~RankingModule() { } - - /** - * \brief Computes a node ranking of the digraph \a G in \a rank. - * - * This method is the actual algorithm call and must be implemented by - * derived classes. - * - * @param G is the input digraph. - * @param rank is assigned the node ranking. - */ - virtual void call(const Graph &G, NodeArray &rank) = 0; - - virtual void call(const Graph &G, const EdgeArray & /* length */, const EdgeArray & /* cost */, NodeArray &rank) - { - call(G, rank); - } - - /** - * \brief Computes a node ranking of the digraph \a G in \a rank. - * - * @param G is the input digraph. - * @param rank is assigned the node ranking. - */ - void operator()(const Graph &G, NodeArray &rank) { - call(G,rank); - } - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/ShellingOrderModule.h b/ext/OGDF/ogdf/module/ShellingOrderModule.h deleted file mode 100644 index bfa723d12..000000000 --- a/ext/OGDF/ogdf/module/ShellingOrderModule.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares the base class ShellingOrderModule for modules - * that compute a shelling order of a graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SHELLING_ORDER_MODULE_H -#define OGDF_SHELLING_ORDER_MODULE_H - - -#include - - -namespace ogdf { - - -/** - * \brief Base class for modules that compute a shelling order of a graph. - * - */ -class OGDF_EXPORT ShellingOrderModule -{ -public: - //! Computes a shelling order of an embedded graph G such that \a adj lies on the external face. - /** - * @param G is the input graph; \a G must represent a combinatorial embedding. - * @param order is assigned the shelling order. - * @param adj is an adjacency entry on the external face; if \a adj is 0, a suitable - * external face is chosen. - */ - void call(const Graph &G, ShellingOrder &order, adjEntry adj = 0); - - //! Computes a lefmost shelling order of an embedded graph G such that \a adj lies on the external face. - /** - * @param G is the input graph; \a G must represent a combinatorial embedding. - * @param order is assigned the shelling order. - * @param adj is an adjacency entry on the external face; if \a adj is 0, a suitable - * external face is chosen. - */ - void callLeftmost(const Graph &G, ShellingOrder &order, adjEntry adj = 0); - - //! Sets the option base ratio to \a x. - void baseRatio(double x) {m_baseRatio = x;} - - //! Returns the current setting of the option base ratio. - double baseRatio() const {return m_baseRatio;} - - virtual ~ShellingOrderModule() { } - -protected: - //! This pure virtual function does the actual computation. - /** - * A derived class must implement this method. It is called with the embedded graph - * and an adjacency entry describing the external face, and must return the - * computed order in \a partition. - * @param G is the embedded input graph. - * @param adj is an adjacency entry on the external face. - * @param partition returns the coputed shelling order. - */ - virtual void doCall(const Graph &G, - adjEntry adj, - List &partition) = 0; - - double m_baseRatio; //! The option base ratio. - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/ShortestPathModule.h b/ext/OGDF/ogdf/module/ShortestPathModule.h deleted file mode 100644 index 20ce36b01..000000000 --- a/ext/OGDF/ogdf/module/ShortestPathModule.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of base class of shortest path algorithms - * including some useful functions dealing with - * shortest paths flow (generater, checker). - * - * \author Gunnar W. Klau - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SHORTEST_PATH_MODULE_H -#define OGDF_SHORTEST_PATH_MODULE_H - - -#include - - -namespace ogdf { - - -class OGDF_EXPORT ShortestPathModule -{ -public: - ShortestPathModule() { } - virtual ~ShortestPathModule() {} - - // computes shortest paths - // Precond.: - // returns true iff a feasible min-cost flow exists - virtual bool call( - const Graph &G, // directed graph - const node s, // source node - const EdgeArray &length, // length of an edge - NodeArray &d, // contains shortest path distances after call - NodeArray &pi - ) = 0; - - - -protected: - // - // static functions - // - - // generates a shortest path problem instance with n nodes and m+n edges - /* - static void generateProblem( - Graph &G, - int n, - int m, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply); - - - // checks if a given min-cost flow problem instance satisfies - // the preconditions - // - // lowerBound[e] <= upperBound[e] for all edges e - // cost[e] >= 0 for all edges e - // sum over all supply[v] = 0 - static bool checkProblem( - const Graph &G, - const EdgeArray &lowerBound, - const EdgeArray &upperBound, - const EdgeArray &cost, - const NodeArray &supply); - - - - // checks if a computed flow is a feasible solution to the given problem - // instance, i.e., checks if - // lowerBound[e] <= flow[e] <= upperBound[e] - // sum flow[e], e is outgoing edge of v - - // sum flow[e], e is incoming edge of v = supply[v] for each v - // returns true iff the solution is feasible and in value the value of - // the computed flow - static bool checkComputedFlow( - Graph &G, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply, - EdgeArray &flow, - int &value); - - static bool checkComputedFlow( - Graph &G, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply, - EdgeArray &flow) - { - int value; - return checkComputedFlow( - G,lowerBound,upperBound,cost,supply,flow,value); - } - */ -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/TwoLayerCrossMin.h b/ext/OGDF/ogdf/module/TwoLayerCrossMin.h deleted file mode 100644 index 384e97296..000000000 --- a/ext/OGDF/ogdf/module/TwoLayerCrossMin.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for two-layer crossing - * minimization algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_TWO_LAYER_CROSS_MIN_H -#define OGDF_TWO_LAYER_CROSS_MIN_H - - - -#include - - -namespace ogdf { - - -/** - * \brief Interface of two-layer crossing minimization algorithms. - * - * The interface of a two-layer crossing minimization algorithm consists of - * three methods: - * -# init(const Hierarchy & H) must be called first. This initializes the module - * for operating on hierarchy \a H. - * -# call(Level &L) (or operator()(Level &L)) performs two-layer crossing minimization, - * where \a L is the permutable level and the neighbor level of \a L (fixed - * level) is determined by the hierarchy (see documentation of class Hierarchy). - * Any number of call's may be performed once init() has been executed. - * -# cleanup() has to be called last and performs some final clean-up work. - */ -class OGDF_EXPORT TwoLayerCrossMin { -public: - //! Initializes a two-layer crossing minimization module. - TwoLayerCrossMin() { } - - virtual ~TwoLayerCrossMin() { } - - /** - * \brief Initializes the crossing minimization module for hierarchy \a H. - * - * @param H is the hierarchy on which the module shall operate. - */ - virtual void init(const Hierarchy & H) { } - - /** - * \brief Performs crossing minimization for level \a L. - * - * @param L is the level in the hierarchy on which nodes are permuted; the - * neighbor level (fixed level) is determined by the hierarchy. - */ - virtual void call(Level &L) = 0; - - /** - * \brief Performs crossing minimization for level \a L. - * - * @param L is the level in the hierarchy on which nodes are permuted; the - * neighbor level (fixed level) is determined by the hierarchy. - */ - void operator()(Level &L) { - call(L); - } - - //! Performs clean-up. - virtual void cleanup() { } - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/UMLLayoutModule.h b/ext/OGDF/ogdf/module/UMLLayoutModule.h deleted file mode 100644 index aec49d465..000000000 --- a/ext/OGDF/ogdf/module/UMLLayoutModule.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for layout algorithms for - * UML diagrams. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UML_LAYOUT_MODULE_H -#define OGDF_UML_LAYOUT_MODULE_H - - -#include -#include - - -namespace ogdf { - - -/** - * \brief Interface of UML layout algorithms. - */ -class OGDF_EXPORT UMLLayoutModule : public LayoutModule -{ -public: - //! Initializes a UML layout module. - UMLLayoutModule() { } - - virtual ~UMLLayoutModule() { } - - /** - * \brief Computes a layout of UML graph \a umlGraph - * - * Must be implemented by derived classes. - * @param umlGraph is the input UML graph and has to be assigned the UML layout. - */ - virtual void call(UMLGraph ¨Graph) = 0; - - /** - * \brief Computes a layout of UML graph \a umlGraph - * - * @param umlGraph is the input UML graph and has to be assigned the UML layout. - */ - void operator()(UMLGraph ¨Graph) { call(umlGraph); } - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/UPRLayoutModule.h b/ext/OGDF/ogdf/module/UPRLayoutModule.h deleted file mode 100644 index a9d326d0f..000000000 --- a/ext/OGDF/ogdf/module/UPRLayoutModule.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for layout algorithms for a UpwardPlanRep - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UPR_LAYOUT_MODULE_H -#define OGDF_UPR_LAYOUT_MODULE_H - - - -#include -#include - - -namespace ogdf { - - -/** - * \brief Interface of hierarchy layout algorithms. - * - * \see SugiyamaLayout - */ -class OGDF_EXPORT UPRLayoutModule { -public: - //! Initializes a upward planarized representation layout module. - UPRLayoutModule() { } - - virtual ~UPRLayoutModule() { } - - /** - * \brief Computes a upward layout of \a UPR in \a AG. - * @param UPR is the upward planarized representation of the input graph. The original graph of UPR muss be the input graph. - * @param AG is assigned the hierarchy layout. - */ - void call(const UpwardPlanRep &UPR, GraphAttributes &AG) { - doCall(UPR, AG); - } - - int numberOfLevels; - -protected: - /** - * \brief Implements the actual algorithm call. - * - * Must be implemented by derived classes. - * - * @param UPR is the upward planarized representation of the input graph. The original graph of UPR muss be the input graph. - * @param AG has to be assigned the hierarchy layout. - */ - virtual void doCall(const UpwardPlanRep &UPR, GraphAttributes &AG) = 0; - - OGDF_MALLOC_NEW_DELETE -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/module/UpwardEdgeInserterModule.h b/ext/OGDF/ogdf/module/UpwardEdgeInserterModule.h deleted file mode 100644 index ba18065d4..000000000 --- a/ext/OGDF/ogdf/module/UpwardEdgeInserterModule.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for edge insertion algorithms - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UPWARD_EDGE_INSERTER_MODULE_H -#define OGDF_UPWARD_EDGE_INSERTER_MODULE_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT UpwardEdgeInserterModule : public Module{ -public: - - - //! Initializes an edge insertion module. - UpwardEdgeInserterModule() { } - - // destruction - virtual ~UpwardEdgeInserterModule() { } - - /** - * \brief Inserts all edges in \a origEdges into \a UPR. - * - * @param UPR is the input upward planarized representation of a FUPS and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a UPR) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(UpwardPlanRep &UPR, const List &origEdges) { - return doCall(UPR, origEdges, 0, 0); - } - - /** - * \brief Inserts all edges in \a origEdges with given costs into \a UPR. - * - * @param UPR is the input upward planarized representation of a FUPS and will also receive the result. - * @param costOrig points to an edge array containing the costs of original edges; edges in - * \a UPR without an original edge have zero costs. - * @param origEdges is the list of original edges (edges in the original graph - * of \a UPR) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(UpwardPlanRep &UPR, - const EdgeArray &costOrig, - const List &origEdges) - { - return doCall(UPR, origEdges, &costOrig, 0); - } - - - /** - * \brief Inserts all edges in \a origEdges with given forbidden edges into \a UPR. - * - * @param UPR is the input upward planarized representation of a FUPS and will also receive the result. - * @param costOrig points to an edge array containing the costs of original edges; edges in - * \a UPR without an original edge have zero costs. - * @param forbidOriginal points to an edge array indicating if an original edge is - * forbidden to be crossed. - * @param origEdges is the list of original edges (edges in the original graph - * of \a UPR) that have to be inserted. - */ - ReturnType call(UpwardPlanRep &UPR, - const EdgeArray &costOrig, - const EdgeArray &forbidOriginal, - const List &origEdges) - { - return doCall(UPR, origEdges, &costOrig, &forbidOriginal); - } - - - /** - * \brief Inserts all edges in \a origEdges with given forbidden edges into \a UPR. - * - * \pre No forbidden edge may be in \a origEdges. - * - * @param UPR is the input upward planarized representation of a FUPS and will also receive the result. - * @param forbidOriginal points to an edge array indicating if an original edge is - * forbidden to be crossed. - * @param origEdges is the list of original edges (edges in the original graph - * of \a UPR) that have to be inserted. - * \return the status of the result. - */ - ReturnType call(UpwardPlanRep &UPR, - const EdgeArray &forbidOriginal, - const List &origEdges) - { - return doCall(UPR, origEdges, 0, &forbidOriginal); - } - - - - - -protected: - /** - * \brief Actual algorithm call that has to be implemented by derived classes. - * - * @param UPR is the input upward planarized representation of a FUPS and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a UPR) that have to be inserted. - * @param costOrig points to an edge array containing the costs of original edges; edges in - * \a UPR without an original edge have zero costs. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - */ - virtual ReturnType doCall(UpwardPlanRep &UPR, - const List &origEdges, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig - ) = 0; - - - OGDF_MALLOC_NEW_DELETE -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/UpwardPlanarSubgraphModule.h b/ext/OGDF/ogdf/module/UpwardPlanarSubgraphModule.h deleted file mode 100644 index 264560767..000000000 --- a/ext/OGDF/ogdf/module/UpwardPlanarSubgraphModule.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for upward planar subgraph - * algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UPWARD_PLANAR_SUBGRAPH_MODULE_H -#define OGDF_UPWARD_PLANAR_SUBGRAPH_MODULE_H - - - -#include - - -namespace ogdf { - -/** - * \brief Interface for algorithms for computing an upward planar subgraph. - */ -class OGDF_EXPORT UpwardPlanarSubgraphModule { -public: - //! Initializes an upward planar subgraph module. - UpwardPlanarSubgraphModule() { } - - // destruction - virtual ~UpwardPlanarSubgraphModule() { } - - /** - * \brief Computes set of edges \a delEdges which have to be deleted to obtain the upward planar subgraph. - * - * Must be implemented by derived classes. - * @param G is the input graph. - * @param delEdges is assigned the set of edges which have to be deleted in \a G - * to obtain the upward planar subgraph. - */ - virtual void call(const Graph &G, List &delEdges) = 0; - - - //! Computes set of edges \a delEdges which have to be deleted to obtain the upward planar subgraph. - void operator()(const Graph &G, List &delEdges) { - call(G,delEdges); - } - - - /** - * \brief Makes \a GC upward planar by deleting edges. - * @param GC is a copy of the input graph. - * @param delOrigEdges is the set of original edges whose copies have been - * deleted in \a GC. - */ - void callAndDelete(GraphCopy &GC, List &delOrigEdges); - - - - OGDF_MALLOC_NEW_DELETE -}; // class UpwardPlanarSubgraph - - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/module/UpwardPlanarizerModule.h b/ext/OGDF/ogdf/module/UpwardPlanarizerModule.h deleted file mode 100644 index f9de0c168..000000000 --- a/ext/OGDF/ogdf/module/UpwardPlanarizerModule.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of UpwardPlanarizer Module, an interface for upward planarization algorithms. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_UPWARD_PLANARIZER_MODULE_H -#define OGDF_UPWARD_PLANARIZER_MODULE_H - - -#include -#include - - -namespace ogdf { - -/** - * \brief Interface for upward planarization algorithms. - * - */ -class OGDF_EXPORT UpwardPlanarizerModule : public Module -{ - -public: - - //! Initializes an upward planarizer module. - UpwardPlanarizerModule() { } - - // destruction - virtual ~UpwardPlanarizerModule() { } - - /** - * \brief Computes a upward planarized representation (UPR) of the input graph \a G. - * - * @param UPR represents the input graph as well as the computed upward planarized - * representation after the call. The original graph of \a UPR muss be the input graph \a G. - * Crossings are replaced by dummy vertices. The UPR is finaly augmented to a st-graph. Since this augmentation, - * crossings dummies may not got an in- and outdegree of 2! - * - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. If forbid = 0, no edges are - * forbidden. - * - * @param cost points to an edge array that gives the cost of each edge. If cost - * = 0, all edges have cost 1. - * - * \return the status of the result. - * - */ - ReturnType call(UpwardPlanRep &UPR, - const EdgeArray * cost = 0, - const EdgeArray * forbid = 0) - { - m_useCost = (cost != 0); - m_useForbid = (forbid != 0); - - if(!useCost()) cost = OGDF_NEW EdgeArray (UPR.original(), 1); - if(!useForbid()) forbid = OGDF_NEW EdgeArray (UPR.original(), 0); - - - ReturnType R = doCall(UPR, *cost, *forbid); - - if(!useCost()) delete cost; - if(!useForbid()) delete forbid; - return R; - } - - - //! Computes a upward planarized representation of the input graph (shorthand for call) - ReturnType operator()(UpwardPlanRep &UPR, - const EdgeArray * cost = 0, - const EdgeArray * forbid = 0) { - return call(UPR, cost, forbid); - } - - - //! Returns true iff edge costs are given. - bool useCost() const { return m_useCost; } - - //! Returns true iff forbidden edges are given. - bool useForbid() const { return m_useForbid; } - -protected: - /** - * \brief Computes an upward planarized representation of the input graph. - * - * @param UPR represents the input graph as well as the computed upward planarized - * representation after the call. The original graph of \a UPR muss be the input graph \a G. - * Crossings are replaced by dummy vertices. The UPR is finaly augmented to a st-graph. Since this augmentation, - * crossings dummies may not got an in- and outdegree of 2! - * - * @param cost points to an edge array that gives the cost of each edge. If cost - * = 0, all edges have cost 1. - * - * @param forbid points to an edge array indicating which edges are not allowed - * to be crossed, i.e., (*forbid)[e] = true. If forbid = 0, no edges are - * forbidden. - * - * \return the status of the result. - */ - virtual ReturnType doCall( - UpwardPlanRep &UPR, - const EdgeArray &cost, - const EdgeArray &forbid) = 0; - - OGDF_MALLOC_NEW_DELETE - -private: - - bool m_useCost; //!< True iff edge costs are given. - bool m_useForbid; //!< True iff forbidden edges are given. - -}; - -} // end namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/orthogonal/CompactionConstraintGraph.h b/ext/OGDF/ogdf/orthogonal/CompactionConstraintGraph.h deleted file mode 100644 index ab8e802c8..000000000 --- a/ext/OGDF/ogdf/orthogonal/CompactionConstraintGraph.h +++ /dev/null @@ -1,1719 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares CompactionConstraintGraph. - * - * I.e. a representation of constraint graphs (dependency graphs) - * used in compaction algorithms. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_COMP_CONSTR_GRAPH_H -#define OGDF_COMP_CONSTR_GRAPH_H - - -#include -#include -#include - - -namespace ogdf { - - - // types of edges in the constraint graph - enum ConstraintEdgeType { - cetBasicArc, - cetVertexSizeArc, - cetVisibilityArc, - cetFixToZeroArc, //can be compacted to zero length, can be fixed - cetReducibleArc, //can be compacted to zero length - cetMedianArc //inserted to replace some reducible in fixzerolength - }; - -//--------------------------------------------------------- -// CompactionConstraintGraph -// base class implementing common behaviour of all parameterized -// CompactionConstraintGraph -//--------------------------------------------------------- -class CompactionConstraintGraphBase : protected Graph -{ -public: - - // output for debugging only - void writeGML(const char *fileName) const ; - void writeGML(ostream &os) const; - //output edges on external face - void writeGML(const char *fileName, NodeArray one) const ; - void writeGML(ostream &os, NodeArray one) const; - - //return constraint arc representing input edge e in constraint graph - edge basicArc(edge e) const { - return m_edgeToBasicArc[e]; - } - - //*************************** - //return some edge properties - //*************************** - //returns true if e is vertical edge in PlanRepUML hierarchy - bool verticalGen(edge e) const {return m_verticalGen[e];} - //returns true if e is basic arc of vertical edge in PlanRepUML hierarchy - //Precond.: e is arc in the constraint graph - bool verticalArc(edge e) const {return m_verticalArc[e];} - //edge lies on cage border - bool onBorder(edge e) const {return m_border[e]>0;} - //these are subject to length fixation if length < sep - bool fixOnBorder(edge e) const {return (m_border[e] == 2);} - - //trigger alignment (=>some special edge handling to support al.) - void align(bool b) {m_align = b;} - - //return if arc is important for alignment - //these are the arcs representing node to gen. merger edges - bool alignmentArc(edge e) const {return m_alignmentArc[e];} - - const PlanRep& getPlanRep() const {return *m_pPR;} - - edge pathToOriginal(node v) {return m_pathToEdge[v];} - -protected: - // construction - CompactionConstraintGraphBase(const OrthoRep &OR, - const PlanRep &PG, - OrthoDir arcDir, - int costGen = 1, - int costAssoc = 1, bool align = false); - - // computes topological numbering on the segments of the constraint graph. - void computeTopologicalSegmentNum(NodeArray &topNum); - - // remove "arcs" from visibArcs which we already have in the constraint graph - // (as basic arcs) - void removeRedundantVisibArcs(SListPure > &visibArcs); - - const OrthoRep *m_pOR; - const PlanRep *m_pPR; - OrthoDir m_arcDir; - OrthoDir m_oppArcDir; - - int m_edgeCost[2]; - - NodeArray > m_path; // list of nodes contained in a segment - NodeArray m_pathNode; // segment containing a node in PG - EdgeArray m_edgeToBasicArc; // basic arc representing an edge in PG - - EdgeArray m_cost; // cost of an edge - EdgeArray m_type; - - //test fuer vorkomp. der Generalisierungen - EdgeArray m_verticalGen; //generalization that runs vertical relative to hierarchy - EdgeArray m_verticalArc; //arc corresponding to such an edge - EdgeArray m_border; //only used for cage precompaction in flowcompaction computecoords - - //basic arcs that have to be short for alignment (node to gen expander) - EdgeArray m_alignmentArc; - - NodeArray m_pathToEdge; //save the (single!) edge (segment) for a pathNode - NodeArray m_originalEdge; //save edge for the basic arcs - - // embeds constraint graph such that all sources and sinks lie in a common - // face - void embed(); - - virtual void writeLength(ostream &os, edge e) const = 0; - -private: - - //set special costs for node to merger generalizations - bool m_align; - - void insertPathVertices(const PlanRep &PG); - void dfsInsertPathVertex( - node v, - node pathVertex, - NodeArray &visited, - const NodeArray &genOpposite); - - void insertBasicArcs(const PlanRep &PG); - - node m_superSource; - node m_superSink; - SList m_sources; - SList m_sinks; - - -}; - - -//--------------------------------------------------------- -// CompactionConstraintGraph -// represents a constraint graph used for compaction -// vertices: maximally connected horiz. (resp. vert.) paths -// basic arcs: paths connected by edges of opposite direction -// vertex size arcs: care for minimum size of cages -// visibility arcs: paths seeing each other -// Each edge has a (minimum) length and cost. -//--------------------------------------------------------- -template -class CompactionConstraintGraph : public CompactionConstraintGraphBase -{ -public: - // construction - CompactionConstraintGraph(const OrthoRep &OR, - const PlanRep &PG, - OrthoDir arcDir, - ATYPE sep, - int costGen = 1, - int costAssoc = 1, - bool align = false) : - CompactionConstraintGraphBase(OR, PG, arcDir, costGen, costAssoc, align) - { - OGDF_ASSERT(&(const Graph &)PG == &(const Graph &)OR); - - m_length .init((Graph&)*this, sep); - m_extraNode.init((Graph&)*this, false); - m_extraOfs .init((Graph&)*this, 0); - m_extraRep .init((Graph&)*this, 0); - - m_sep = sep; - - m_centerPriority = true; //should centering of single edges have prio. to gen. length - m_genToMedian = true; //should outgoing merger gen. be drawn to merger median - initializeCosts(); - - }//constructor - - // output for debugging only - void writeGML(const char *fileName) const ; - void writeGML(ostream &os) const; - - - // returns underlying graph - const Graph &getGraph() const { return (Graph&)*this; } - Graph &getGraph() { return (Graph&)*this; } - - - const OrthoRep &getOrthoRep() const { - return *m_pOR; - } - - - // returns list of nodes contained in segment v - // Precodn.: v is in the constraint graph - const SListPure &nodesIn(node v) const { - return m_path[v]; - } - - // returns the segment (path node in constraint graph) containing v - // Precond.: v is a node in the associated planarized representation - node pathNodeOf(node v) const { - return m_pathNode[v]; - } - - // returns length of edge e - // Precond.: e is an edge in the constraint graph - ATYPE length(edge e) const { - return m_length[e]; - } - - // returns cost of edge e - // Precond.: e is an edge in the constraint graph - int cost(edge e) const { - return m_cost[e]; - } - - // returns type of edge e - // Precond.: e is an edge in the constraint graph - ConstraintEdgeType typeOf(edge e) const { - return m_type[e]; - } - - //returns node status - bool extraNode(node v) const { - return m_extraNode[v]; - } - - //returns extraNode position, change to save mem, only need some entries - ATYPE extraOfs(node v) const { - return m_extraOfs[v]; - } - - //returns extraNode existing anchor representant - node extraRep(node v) const { - return m_extraRep[v]; - } - - //get / set centerPriority (center single edges?) - bool centerPriority() {return m_centerPriority;} - void centerPriority(bool b) { m_centerPriority = b;} - - // computes the total costs for coordintes given by pos, i.e., - // the sum of the weighted lengths of edges in the constraint graph. - ATYPE computeTotalCosts(const NodeArray &pos) const; - - - // inserts arcs for respecting sizes of vertices and achieving desired - // placement of generalizations if vertices are represented by variable - // cages; also corrects length of arcs belonging to cages which are - // adjacent to a corner; takes routing channels into account. - void insertVertexSizeArcs( - const PlanRep &PG, - const NodeArray &sizeOrig, - const RoutingChannel &rc); - - // inserts arcs for respecting sizes of vertices and achieving desired - // placement of generalizations if vertices are represented by tight cages; - // also corrects length of arcs belonging to cages which are adjacent to - // a corner; takes special distances between edge segments attached at - // a vertex (delta's and epsilon's) into account. - void insertVertexSizeArcs( - const PlanRep &PG, - const NodeArray &sizeOrig, - const MinimumEdgeDistances &minDist); - - // inserts arcs connecting segments which can see each other in a drawing - // of the associated planarized representation PG which is given by - // posDir and posOppDir. - void insertVisibilityArcs( - const PlanRep &PG, // associated planarized representation - const NodeArray &posDir, // position of segment containing - // vertex in PG - const NodeArray &posOppDir); // position of orthogonal segment - // containing vertex in PG - - void insertVisibilityArcs( - const PlanRep &PG, - const NodeArray &posDir, - const NodeArray &posOrthDir, - const MinimumEdgeDistances &minDist); - - - //set min sep for multi edge original - void setMinimumSeparation(const PlanRep &PG, - const NodeArray coord, - const MinimumEdgeDistances &minDist); - - - // embeds constraint graph such that all sources and sinks lie in a common - // face - void embed() { - CompactionConstraintGraphBase::embed(); - } - - - // performs feasibility test for position assignment pos, i.e., checks if - // the segment positions given by pos fulfill the constraints in the - // compaction constraint graph - // (for debuging only) - bool isFeasible(const NodeArray &pos); - - //returns the separation value - ATYPE separation() const {return m_sep;} - - //return PG result for flowcompaction - bool areMulti(edge e1, edge e2) const; - - -private: - //--------------------------------------------------------- - // CompactionConstraintGraph::Interval - // represents an interval on the sweep line - //--------------------------------------------------------- - struct Interval - { - Interval(node v, ATYPE low, ATYPE high) { - m_low = low; - m_high = high; - m_pathNode = v; - } - - ATYPE m_low, m_high; // lower and upper bound - node m_pathNode; // corresponding segment - - // output operator - friend ostream &operator<<(ostream &os, - const Interval &interval) - { - os << "[" << interval.m_low << "," << interval.m_high << - ";" << interval.m_pathNode << "]"; - return os; - } - - }; - - //--------------------------------------------------------- - // CompactionConstraintGraph::SegmentComparer - // comparer class used for sorting segments by increasing position - // (given by segPos) such that two overlapping segments come in the - // order imposed by the embedding (given by secSort: segment which - // comes first has secSort = 0, the other has 1) - //--------------------------------------------------------- - class SegmentComparer - { - public: - SegmentComparer(const NodeArray &segPos, - const NodeArray &secSort) { - m_pPos = &segPos; - m_pSec = &secSort; - } - - int compare(const node &x, const node &y) const { - ATYPE d = (*m_pPos)[x] - (*m_pPos)[y]; - if (d < 0) - return -1; - else if (d > 0) - return 1; - else - return (*m_pSec)[x] - (*m_pSec)[y]; - } - - OGDF_AUGMENT_COMPARER(node) - private: - const NodeArray *m_pPos; - const NodeArray *m_pSec; - }; - - virtual void writeLength(ostream &os, edge e) const { - os << m_length[e]; - } - - void setBasicArcsZeroLength(const PlanRep &PG); - void resetGenMergerLengths(const PlanRep &PG, adjEntry adjFirst); - void setBoundaryCosts(adjEntry cornerDir,adjEntry cornerOppDir); - - bool checkSweepLine(const List &sweepLine); - - ATYPE m_sep; - - EdgeArray m_length; // length of an edge - - NodeArray m_extraNode; //node does not represent drawing node - //as we dont have positions, we save a drawing representant and an offset - NodeArray m_extraOfs; //offset of extra node to its rep, should change this - NodeArray m_extraRep; //existing representant of extranodes position anchor - - //********************** - //COST SETTINGS SECTION - - // we make vertex size arcs more expensive than basic arcs in order - // to get small cages - // should be replaced by option/value dependent on e.g. degree - int m_vertexArcCost; //get small cages - int m_bungeeCost; //middle position distance penalty - int m_MedianArcCost; //draw merger gen at median of incoming generalizations - int m_doubleBendCost; //try to minimize double bends - bool m_genToMedian; //draw outgoing generalization from merger above ingoing gen. - //this does not work if generalization costs are set very small by the user - //because there must be a minimum cost for centering - bool m_centerPriority; //should centering be more expensive than generalizations - - //factor of costs relative to generalization - static const int c_vertexArcFactor; - static const int c_bungeeFactor; - static const int c_doubleBendFactor; // = 20; //double bends cost factor*vertexArcCost - static const int c_MedianFactor; //median arcs cost factor*vertexArcCost - - -protected: - //node v has no representation in drawing, only internal representation - void setExtra(node v, node rep, ATYPE ofs) { - m_extraNode[v] = true; - m_extraRep[v] = rep; - m_extraOfs[v] = ofs; - } - - void initializeCosts() - { - // we make vertex size arcs more expensive than basic arcs in order - // to get small cages; not necessary if cage size fixed in improvement - // cost should be dependend on degree - // Z.B. DURCH OPTION ODER WERT; DER VON DER ZAHL ADJAZENTER KANTEN ABHAENGIG IST - // should be derived by number of edges times something - int costGen = m_edgeCost[Graph::generalization]; - - m_vertexArcCost = c_vertexArcFactor*costGen; //spaeter aus Kompaktierungsmodul uebergeben - if (m_centerPriority) - m_bungeeCost = c_bungeeFactor*costGen+1;//-1;//for distance to middle position, - else - m_bungeeCost = c_bungeeFactor*4+1;//-1;//for distance to middle position, - //addition value should be < gen cost!!! - m_MedianArcCost = c_MedianFactor*m_vertexArcCost; - m_doubleBendCost = c_doubleBendFactor*m_vertexArcCost; - }//initializeCosts -}; - -//******************************** -//initialization of static members -template -const int CompactionConstraintGraph::c_vertexArcFactor = 20; -template -const int CompactionConstraintGraph::c_bungeeFactor = 20; -template -const int CompactionConstraintGraph::c_doubleBendFactor = 20; //double bends cost mxxx*vertexArcCost -//factor *VertexArcCost, costs for pulling generalization to median position at merger -template -const int CompactionConstraintGraph::c_MedianFactor = 10*c_doubleBendFactor; - - -//************************************ -// -// implementation of member functions -// -//************************************ -} - -#include - -namespace ogdf { - - -// allow 0-length for sides of generalization merger cages -template -void CompactionConstraintGraph::resetGenMergerLengths( - const PlanRep &PG, - adjEntry adjFirst) -{ - adjEntry adj = adjFirst; - int faceSize = 0; - - do { - if ((m_pOR->direction(adj) == m_arcDir || - m_pOR->direction(adj) == m_oppArcDir) && - (PG.typeOf(adj->theNode()) == Graph::dummy || - PG.typeOf(adj->twinNode()) == Graph::dummy)) - { - m_length[m_edgeToBasicArc[adj]] = 0; - } - - adj = adj->faceCycleSucc(); - faceSize++; - } while(adj != adjFirst); - -//**************************************** -//generalization position section -//pull upper generalization to median of merger cage's incoming lower generalizations - - if (m_genToMedian) - { - if ((m_pOR->direction(adjFirst) == m_arcDir) || - (m_pOR->direction(adjFirst) == m_oppArcDir) ) - { - int numIncoming = faceSize - 3; - int median = (numIncoming / 2) + 1; - - //if (numIncoming == 2) ... just the middle position - node upper = m_pathNode[adjFirst->theNode()]; - if (PG.typeOf(adjFirst->theNode()) != Graph::generalizationMerger) - OGDF_THROW(AlgorithmFailureException); - node vMin; - if (m_pOR->direction(adjFirst) == m_arcDir) - vMin = adjFirst->faceCyclePred()->theNode(); - else vMin = adjFirst->faceCycleSucc()->theNode(); - adj = adjFirst->faceCycleSucc(); //target right or left boundary, depending on drawing direction - for (int i = 0; i < median; i++) - adj = adj->faceCycleSucc(); - node lower = m_pathNode[adj->theNode()]; - node vCenter = newNode(); - setExtra(vCenter, vMin, 0); - //it seems we dont need the helper, as only source-adjEntries lying on - //the outer face are considered later, but keep it in mind - /* - edge helper = newEdge(m_pathNode[vMin], vCenter); - m_length[helper] = 0; - m_cost[helper] = 0; - m_type[helper] = cetReducibleArc; - */ - - edge e1 = newEdge(vCenter,upper); - m_length[e1] = 0; - m_cost[e1] = m_MedianArcCost; - m_type[e1] = cetMedianArc; - - edge e2 = newEdge(vCenter,lower); - m_length[e2] = 0; - m_cost[e2] = m_MedianArcCost; - m_type[e2] = cetMedianArc; - }//if compaction dir - }//if gentomedian option set - //******************************************* -} - - -// set cost of edges on the cage boundary to 0 -template -void CompactionConstraintGraph::setBoundaryCosts( - adjEntry cornerDir, - adjEntry cornerOppDir) -{ - /* - adjEntry adj; - for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc()) - m_cost[m_edgeToBasicArc[adj]] = 0; - for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc()) - m_cost[m_edgeToBasicArc[adj]] = 0; - */ - //test fuer multi separation - adjEntry adj; - for (adj = cornerDir; m_pOR->direction(adj) == m_arcDir; adj = adj->faceCycleSucc()) - { - m_cost[m_edgeToBasicArc[adj]] = 0; - - if (m_pathNode[adj->twin()->cyclicSucc()->theNode()] && - (m_pOR->direction(adj->faceCycleSucc()) == m_arcDir) - ) - m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] = - m_pPR->original(adj->twin()->cyclicSucc()->theEdge()); - - } - for (adj = cornerOppDir; m_pOR->direction(adj) == m_oppArcDir; adj = adj->faceCycleSucc()) - { - m_cost[m_edgeToBasicArc[adj]] = 0; - - if (m_pathNode[adj->twin()->cyclicSucc()->theNode()]) - m_originalEdge[m_pathNode[adj->twin()->cyclicSucc()->theNode()]] = - m_pPR->original(adj->twin()->cyclicSucc()->theEdge()); - } -} - - -// -// insert arcs required for respecting vertex sizes, sizes of routing channels -// and position of attached generalizations -// vertices are represented by variable cages -template -void CompactionConstraintGraph::insertVertexSizeArcs( - const PlanRep &PG, - const NodeArray &sizeOrig, - const RoutingChannel &rc) -{ - - // segments in constraint graph are sides sMin and sMax; other two side - // are sides in which adjacency entries run in direction m_arcDir and - // m_oppArcDir - OrthoDir dirMin = OrthoRep::prevDir(m_arcDir); - OrthoDir dirMax = OrthoRep::nextDir(m_arcDir); - - const ATYPE overhang = rc.overhang(); - - node v; - forall_nodes(v,PG) - { - if (PG.expandAdj(v) == 0) continue; - - if(PG.typeOf(v) == Graph::generalizationMerger) - { - resetGenMergerLengths(PG,PG.expandAdj(v)); - - } - else // high/low-degree expander - { - ATYPE size = sizeOrig[v]; - - const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v); - - // determine routing channels rcMin and rcMax - ATYPE rcMin = overhang + rc(v,dirMin); - ATYPE rcMax = overhang + rc(v,dirMax); - - adjEntry cornerDir = vi.m_corner[m_arcDir]; - adjEntry cornerOppDir = vi.m_corner[m_oppArcDir]; - adjEntry cornerMin = vi.m_corner[dirMin]; - adjEntry cornerMax = vi.m_corner[dirMax]; - - // set cost of edges on the cage boundary to 0 - setBoundaryCosts(cornerDir,cornerOppDir); - - const OrthoRep::SideInfoUML &sDir = vi.m_side[m_arcDir]; - const OrthoRep::SideInfoUML &sOppDir = vi.m_side[m_oppArcDir]; - - // correct lengths of edges within cage adjacent to corners - if(sDir.totalAttached() > 0) { - m_length[m_edgeToBasicArc[cornerDir]] = rcMin; - m_length[m_edgeToBasicArc[cornerMax->faceCyclePred()]] = rcMax; - } else { - // if no edges are attached at this side we need no constraint - m_length[m_edgeToBasicArc[cornerDir]] = 0; - delEdge(m_edgeToBasicArc[cornerDir]); - } - - if(sOppDir.totalAttached() > 0) { - m_length[m_edgeToBasicArc[cornerOppDir]] = rcMax; - m_length[m_edgeToBasicArc[cornerMin->faceCyclePred()]] = rcMin; - } else { - // if no edges are attached at this side we need no constraint - m_length[m_edgeToBasicArc[cornerOppDir]] = 0; - delEdge(m_edgeToBasicArc[cornerOppDir]); - } - - - // insert arcs for respecting vertex size / position of generalizations - node vMin = m_pathNode[cornerDir->theNode()]; - node vMax = m_pathNode[cornerOppDir->theNode()]; - - // any attached generalizations ? - if (sDir.m_adjGen == 0 && sOppDir.m_adjGen == 0) - { - // no, only one arc for vertex size + routing channels - edge e = newEdge(vMin,vMax); - m_length[e] = rcMin + size + rcMax - 2*overhang; - m_cost [e] = 2*m_vertexArcCost; - m_type [e] = cetVertexSizeArc; - - } else { - // yes, then two arcs for each side with an attached generalization - ATYPE minHalf = size/2; - ATYPE maxHalf = size - minHalf; - ATYPE lenMin = rcMin + minHalf - overhang; - ATYPE lenMax = maxHalf + rcMax - overhang; - - if (sDir.m_adjGen != 0) { - node vCenter = m_pathNode[sDir.m_adjGen->theNode()]; - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - m_cost [e1] = m_vertexArcCost; - m_type [e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost [e2] = m_vertexArcCost; - m_type [e2] = cetVertexSizeArc; - } - - if (sOppDir.m_adjGen != 0) { - node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()]; - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - m_cost [e1] = m_vertexArcCost; - m_type [e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost [e2] = m_vertexArcCost; - m_type [e2] = cetVertexSizeArc; - } - - } - - } // high/lowDegreeExpander - } -} - - -template -void CompactionConstraintGraph::setBasicArcsZeroLength( - const PlanRep &PG) -{ - edge e; - forall_edges(e,PG) - { - edge arc = m_edgeToBasicArc[e]; - if (arc == 0) continue; - - node v = e->source(); - node w = e->target(); - if ( ((PG.typeOf(v) == Graph::dummy) && (PG.typeOf(w) == Graph::dummy) && - (v->degree() == 2) && w->degree() == 2) && - (m_pOR->angle(e->adjSource()) == m_pOR->angle(e->adjTarget()) ) && //no uturns - (PG.typeOf(e) != Graph::generalization) - ) - { - m_length[arc] = 0; - m_type[arc] = cetFixToZeroArc; - //we make fixtozero arcs as expensive as possible - m_cost[arc] = m_doubleBendCost; - } - } -} - - - -// -// insert arcs required for respecting vertex sizes -// and position of attached generalizations -// vertices are represented by tight cages -template -void CompactionConstraintGraph::insertVertexSizeArcs( - const PlanRep &PG, - const NodeArray &sizeOrig, - const MinimumEdgeDistances &minDist) -{ - // set the length of all basic arcs corresponding to inner edge segments - // to 0 - setBasicArcsZeroLength(PG); - - // segments in constraint graph are sides sMin and sMax; other two side - // are sides in which adjacency entries run in direction m_arcDir and - // m_oppArcDir - OrthoDir dirMin = OrthoRep::prevDir(m_arcDir); - OrthoDir dirMax = OrthoRep::nextDir(m_arcDir); - - node v; - forall_nodes(v,PG) - { - if (PG.expandAdj(v) == 0) continue; - - if(PG.typeOf(v) == Graph::generalizationMerger) - { - resetGenMergerLengths(PG,PG.expandAdj(v)); - - } - else // high/low-degree expander - { - ATYPE size = sizeOrig[v]; - const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v); - - adjEntry cornerDir = vi.m_corner[m_arcDir]; - adjEntry cornerOppDir = vi.m_corner[m_oppArcDir]; - adjEntry cornerMin = vi.m_corner[dirMin]; - adjEntry cornerMax = vi.m_corner[dirMax]; - - adjEntry adj = cornerDir, last = cornerMax->faceCyclePred(); - if(adj != last) { - m_length[m_edgeToBasicArc[adj]] = minDist.epsilon(v,m_arcDir,0); - m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v,m_arcDir,1); - int i = 0; - for(adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) { - if (PG.typeOf(adj->cyclicPred()->theEdge()) == Graph::generalization) - i++; - m_length[m_edgeToBasicArc[adj]] = minDist.delta(v,m_arcDir,i); - } - } - - adj = cornerOppDir, last = cornerMin->faceCyclePred(); - if(adj != last) { - m_length[m_edgeToBasicArc[adj]] = minDist.epsilon(v,m_oppArcDir,0); - m_length[m_edgeToBasicArc[last]] = minDist.epsilon(v,m_oppArcDir,1); - int i = 0; - for(adj = adj->faceCycleSucc(); adj != last; adj = adj->faceCycleSucc()) { - if (PG.typeOf(adj->cyclicPred()->theEdge()) == Graph::generalization) - i++; - m_length[m_edgeToBasicArc[adj]] = minDist.delta(v,m_oppArcDir,i); - } - } - - - // insert arcs for respecting vertex size / position of generalizations - node vMin = m_pathNode[cornerDir->theNode()]; - node vMax = m_pathNode[cornerOppDir->theNode()]; - - const OrthoRep::SideInfoUML &sDir = vi.m_side[m_arcDir]; - const OrthoRep::SideInfoUML &sOppDir = vi.m_side[m_oppArcDir]; - - // any attached generalizations ? - if (sDir.m_adjGen == 0 && sOppDir.m_adjGen == 0) - { - //check for single edge case => special treatment - //generic case could handle all numbers - - if ((sDir.totalAttached() == 1) || (sOppDir.totalAttached() == 1)) - { - //first, insert a new center node and connect it - ATYPE lenMin = size/2; - ATYPE lenMax = size - lenMin; - node vCenter = newNode(); - setExtra(vCenter, cornerDir->theNode(), lenMin); - - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - //if (lenMin < minDist.epsilon(v,m_arcDir,0)) exit(1); - m_cost[e1] = m_vertexArcCost; - m_type[e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost[e2] = m_vertexArcCost; - m_type[e2] = cetVertexSizeArc; - - if (sDir.totalAttached() == 1) - { - - //then, insert a moveable node connecting center - //and outgoing segment - node vBungee = newNode(); - //+1 should fix the fixzerolength problem - setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_arcDir,0) ); - - edge eToBungee = newEdge(vMin, vBungee); - m_type[eToBungee] = cetMedianArc; //cetBasicArc; //is this ok !!!!!!!!!!!!!! - m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eToBungee] = minDist.epsilon(v,m_arcDir,0); - - edge eBungeeCenter = newEdge(vBungee, vCenter); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeCenter] = cetMedianArc; - m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeCenter] = 0; - - //attention: pathnode construct works only if degree 1 - edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerDir->twinNode()]); - if (m_pathNode[cornerDir->twinNode()] == vMin) exit(1); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeOut] = cetMedianArc; - m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeOut] = 0; - /* - //connect outgoing segment and "right" segment, maybe obsolete - edge eFromOut = newEdge(m_pathNode[cornerDir->twinNode()], vMax); - m_type[eFromOut] = cetBasicArc; //!!!!!!!!!!!!!!!!!!!!!!! - m_cost[eFromOut] = 0; //!!!!!!!!!!!!!!!!!!! - m_length[eFromOut] = minDist.epsilon(v,m_arcDir,1); - */ - }//if sDir case - if ( (sOppDir.totalAttached() == 1) && !(m_pathNode[cornerOppDir->twinNode()] == vMin) ) - { - - //then, insert a moveable node connecting center - //and outgoing segment - node vBungee = newNode(); - //+1 for not fixzerolength - setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_oppArcDir,0) ); - - edge eToBungee = newEdge(vMin, vBungee); - m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!! - m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eToBungee] = minDist.epsilon(v,m_oppArcDir,0); - - edge eBungeeCenter = newEdge(vBungee, vCenter); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeCenter] = cetMedianArc; - m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeCenter] = 0; - - //attention: pathnode construct works only if degree 1, sometimes not at all - edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeOut] = cetMedianArc; - m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeOut] = 0; - /* - //connect outgoing segment and "right" segment, maybe obsolete - edge eFromOut = newEdge(m_pathNode[cornerOppDir->twinNode()], vMax); - m_type[eFromOut] = cetBasicArc; //!!!!!!!!!!!!!!!!!!!!!!! - m_cost[eFromOut] = 0; //!!!!!!!!!!!!!!!!!!! - m_length[eFromOut] = minDist.epsilon(v,m_oppArcDir,0); - */ - }//if sOppDir case - }//if special case - else - { - // no, only one arc for vertex size + routing channels - edge e = newEdge(vMin,vMax); - m_length[e] = size; - m_cost[e] = 2*m_vertexArcCost; - m_type[e] = cetVertexSizeArc; - }//else special case - - - } else { - // yes, then two arcs for each side with an attached generalization - ATYPE lenMin = size/2; - ATYPE lenMax = size - lenMin; - - //ATYPE len = size/2; - - if (sDir.m_adjGen != 0) { - node vCenter = m_pathNode[sDir.m_adjGen->theNode()]; - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - m_cost [e1] = m_vertexArcCost; - m_type [e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost [e2] = m_vertexArcCost; - m_type [e2] = cetVertexSizeArc; - } - else - { - if (sDir.totalAttached() == 1) - { - node vCenter = newNode();//m_pathNode[sOppDir.m_adjGen->theNode()]; //newNode(); - setExtra(vCenter, cornerDir->theNode(), lenMin); - - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - m_cost[e1] = m_vertexArcCost; - m_type[e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost[e2] = m_vertexArcCost; - m_type[e2] = cetVertexSizeArc; - - //then, insert a moveable node connecting center - //and outgoing segment - node vBungee = newNode(); - //+1 for not fixzerolength - setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_arcDir,0) ); - - edge eToBungee = newEdge(vMin, vBungee); - m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!! - m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eToBungee] = minDist.epsilon(v,m_arcDir,0); - - edge eBungeeCenter = newEdge(vBungee, vCenter); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeCenter] = cetMedianArc; - m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeCenter] = 0; - - //attention: pathnode construct works only if degree 1 - edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerDir->twinNode()]); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeOut] = cetMedianArc; - m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeOut] = 0; - - }//if sDir case - }//else, only oppdir - if (sOppDir.m_adjGen != 0) { - node vCenter = m_pathNode[sOppDir.m_adjGen->theNode()]; - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - m_cost [e1] = m_vertexArcCost; - m_type [e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost [e2] = m_vertexArcCost; - m_type [e2] = cetVertexSizeArc; - } - else - { - //special case single edge to middle position - if ( (sOppDir.totalAttached() == 1) && !(m_pathNode[cornerOppDir->twinNode()] == vMin) ) - { - node vCenter = newNode();//m_pathNode[sDir.m_adjGen->theNode()];//newNode(); - setExtra(vCenter, cornerDir->theNode(), lenMin); - - edge e1 = newEdge(vMin,vCenter); - m_length[e1] = lenMin; - m_cost[e1] = m_vertexArcCost; - m_type[e1] = cetVertexSizeArc; - edge e2 = newEdge(vCenter,vMax); - m_length[e2] = lenMax; - m_cost[e2] = m_vertexArcCost; - m_type[e2] = cetVertexSizeArc; - //then, insert a moveable node connecting center - //and outgoing segment - node vBungee = newNode(); - //+1 for not fixzerolength - setExtra(vBungee, cornerDir->theNode(), minDist.epsilon(v,m_oppArcDir,0) ); - - edge eToBungee = newEdge(vMin, vBungee); - m_type[eToBungee] = cetMedianArc;//cetBasicArc; //is this ok !!!!!!!!!!!!!! - m_cost[eToBungee] = 0; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eToBungee] = minDist.epsilon(v,m_oppArcDir,0); - - edge eBungeeCenter = newEdge(vBungee, vCenter); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeCenter] = cetMedianArc; - m_cost[eBungeeCenter] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeCenter] = 0; - - //attention: pathnode construct works only if degree 1 - edge eBungeeOut = newEdge(vBungee, m_pathNode[cornerOppDir->twinNode()]); - //bungee, center and outgoing segment may build column if in the middle - m_type[eBungeeOut] = cetMedianArc; - m_cost[eBungeeOut] = m_bungeeCost; //what about this !!!!!!!!!!!!!!!!!!! - m_length[eBungeeOut] = 0; - - }//if sOppDir case - }//else only dir gen - - } - - // set cost of edges on the cage boundary to 0 - setBoundaryCosts(cornerDir,cornerOppDir); - - } // high/lowDegreeExpander - } - //if (m_arcDir == odEast) writeGML("eastvertexsizeinserted.gml"); - //else writeGML("northvertexsizeinserted.gml"); -} - - -// computes the total costs for coordintes given by pos, i.e., -// the sum of the weighted lengths of edges in the constraint graph. -template -ATYPE CompactionConstraintGraph::computeTotalCosts( - const NodeArray &pos) const -{ - ATYPE c = 0; - - edge e; - forall_edges(e,*this) - { - c += cost(e) * (pos[e->target()] - pos[e->source()]); - } - - return c; -} - - -// -// insertion of visibility arcs - -// checks if intervals on the sweep line are in correct order -template -bool CompactionConstraintGraph::checkSweepLine(const List &sweepLine) -{ - if (sweepLine.empty()) - return true; - - ListConstIterator it = sweepLine.begin(); - - if((*it).m_high < (*it).m_low) - return false; - - ATYPE x = (*it).m_low; - - for(++it; it.valid(); ++it) { - if((*it).m_high < (*it).m_low) - return false; - if ((*it).m_high > x) - return false; - x = (*it).m_low; - } - - return true; -} - - -template -void CompactionConstraintGraph::insertVisibilityArcs( - const PlanRep &PG, - const NodeArray &posDir, - const NodeArray &posOrthDir - ) -{ - MinimumEdgeDistances minDist(PG, m_sep); - - node v; - forall_nodes(v,PG) - { - if(PG.expandAdj(v) == 0) continue; - - for(int d = 0; d < 4; ++d) { - minDist.delta(v,OrthoDir(d),0) = m_sep;//currentSeparation; - minDist.delta(v,OrthoDir(d),1) = m_sep;//currentSeparation; - } - } - - insertVisibilityArcs(PG,posDir,posOrthDir,minDist); -} - - - -// inserts arcs connecting segments which can see each other in a drawing -// of the associated planarized representation PG which is given by -// posDir and posOppDir. - -//ersetze mindist.delta durch min(m_sep, mindist.delta) fuer skalierung -template -void CompactionConstraintGraph::insertVisibilityArcs( - const PlanRep &PG, - const NodeArray &posDir, - const NodeArray &posOrthDir, - const MinimumEdgeDistances &minDist) -{ - OrthoDir segDir = OrthoRep::prevDir(m_arcDir); - OrthoDir segOppDir = OrthoRep::nextDir(m_arcDir); - - // list of visibility arcs which have to be inserted - SListPure > visibArcs; - - // lower and upper bound of segments - NodeArray low(getGraph()), lowReal(getGraph()), high(getGraph()); - NodeArray segPos(getGraph(), 0); // position of segments - NodeArray topNum(getGraph()/*,0*/); // secondary sorting criteria for segments - - // compute position and lower/upper bound of segments - // We have to take care that segments cannot be shifted one upon the other, - // e.g., if we have two segments (l1,h1) and (l2,h2) with l2 > h2 and - // the distance l2-h2 is smaller than separation, the segments can see - // each other. We do this by enlarging the lower bound of all segments - // by separation if this lower bound is realized by a bend. - // - // Note: Be careful at segments attached at a vertex which are closer - // than separation to each other. Possible solution: Remove visibility - // arcs of segments which are connected by orthogonal segments to the - // same vertex and bend in opposite directions. - node v; - forall_nodes(v,*this) { - - //special case nodes - if (m_path[v].empty()) continue; - - SListConstIterator it = m_path[v].begin(); - - segPos[v] = posDir[*it]; - low[v] = high[v] = posOrthDir[*it]; - node nodeLow = *it; - for(++it; it.valid(); ++it) { - ATYPE x = posOrthDir[*it]; - if (x < low [v]) { - low [v] = x; - nodeLow = *it; - } - if (x > high[v]) high[v] = x; - } - lowReal[v] = low[v]; - Graph::NodeType typeLow = PG.typeOf(nodeLow); - if(typeLow == Graph::dummy || typeLow == Graph::generalizationExpander) { - /*bool subtractSep = true; - if (nodeLow->degree() == 2) { - adjEntry adj; - forall_adj(adj,nodeLow) { - if(m_pOR->direction(adj) == m_arcDir || m_pOR->direction(adj) == m_oppArcDir) - break; - } - if (adj) { - for(adjEntry adj2 = adj->faceCycleSucc(); - m_pOR->direction(adj2) == m_pOR->direction(adj); - adj2 = adj2->twin()->faceCycleSucc()) ; - if(posDir[adj->theNode()] == posDir[adj2->twinNode()]) - subtractSep = false; - } - } - //if (subtractSep)*/ - low[v] -= m_sep; - } - } - - // correct "-= m_sep" ... - OrthoDir dirMin = OrthoRep::prevDir(m_arcDir); - OrthoDir dirMax = OrthoRep::nextDir(m_arcDir); - bool isCaseA = (m_arcDir == odEast || m_arcDir == odSouth); - const int angleAtMin = (m_arcDir == odEast || m_arcDir == odSouth) ? 3 : 1; - const int angleAtMax = (m_arcDir == odEast || m_arcDir == odSouth) ? 1 : 3; - forall_nodes(v,PG) - { - if(PG.expandAdj(v) == 0) continue; - const OrthoRep::VertexInfoUML &vi = *m_pOR->cageInfo(v); - - int i = 0; - adjEntry adj; - - for (adj = (isCaseA) ? vi.m_corner[dirMin]->faceCycleSucc()->faceCycleSucc() : vi.m_corner[dirMin]->faceCycleSucc(); - m_pOR->direction((isCaseA) ? adj : adj->faceCycleSucc()) == dirMin; //m_pOR->direction(adj) == dirMin; - adj = adj->faceCycleSucc()) - { - adjEntry adjCross = adj->cyclicPred(); - adjEntry adjTwin = adjCross->twin(); - - adjEntry adjPred = adj->faceCyclePred(); - ATYPE delta = (isCaseA) ? - min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep) : - min(abs(posOrthDir[adj->theNode()] - posOrthDir[adj->twinNode()]), m_sep); - ATYPE boundary = (isCaseA) ? - min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()]) : - min(posOrthDir[adj->theNode()], posOrthDir[adj->twinNode()]); - - if (PG.typeOf(adjCross->theEdge()) == Graph::generalization) - { - if (isCaseA) { - if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander && - m_pOR->angle(adjTwin) == 2) - { - node s1 = m_pathNode[adjTwin->theNode()]; - node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()]; - low[s1] = lowReal[s1] - delta; // minDist.delta(v,dirMin,i); - low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i); - } - ++i; - } else { - ++i; - if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander && - m_pOR->angle(adjTwin->cyclicPred()) == 2) - { - node s1 = m_pathNode[adjTwin->theNode()]; - node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()]; - low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMin,i); - low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMin,i); - } - } - continue; - } - - //we save the current direction and stop if we run in opposite - OrthoDir runDir = m_pOR->direction(adjCross); - // if -> while - while (PG.typeOf(adjTwin->theNode()) == Graph::dummy && - adjTwin->theNode()->degree() == 2 && - m_pOR->angle(adjTwin) == angleAtMin) - { - // We handle the case if an edge segment adjacent to a vertex - // is separated by less than separation from edge segments above. - node s = m_edgeToBasicArc[adjCross]->source(); - if(lowReal[s] != low[s]) - { - if(low[s] >= boundary) // nothing to do? - break; - low[s] = boundary; - //low[s] += m_sep - delta; //minDist.delta(v,dirMin,i); - - // If the compaction has eliminated bends, we can have the situation - // that segment s has length 0 and the next segment s' (following the - // edge) is at the same position (the edge arc has length 0). - // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s'] - // is approproate). The same situation can appear several times in a - // row. - //collect chains of segments compacted to zero length - for( ; ; ) { //while(true/*lowReal[s] == high[s]*/) { - do { - adjCross = adjCross->faceCycleSucc(); - } while(m_pOR->direction(adjCross) == segDir || - m_pOR->direction(adjCross) == segOppDir); - - if(adjCross->theNode()->degree() != 2) // no longer a bend point? - break; - - node sNext = m_edgeToBasicArc[adjCross]->opposite(s); - - if(segPos[sNext] != segPos[s]) - break; - - low[sNext] = lowReal[sNext]; //? - s = sNext; - }//while - }//if - - adjTwin = adjCross->twin(); // update of twin for while - //check if we have to stop - if (runDir != m_pOR->direction(adjCross)) break; - }//while dummy bend - } - - i = 0; - for (adj = (isCaseA) ? vi.m_corner[dirMax]->faceCycleSucc() : vi.m_corner[dirMax]->faceCycleSucc()->faceCycleSucc(); - m_pOR->direction((isCaseA) ? adj->faceCycleSucc() : adj) == dirMax; // m_pOR->direction(adj) == dirMax; - adj = adj->faceCycleSucc()) - { - adjEntry adjCross = adj->cyclicPred(); - adjEntry adjTwin = adjCross->twin(); - - //ATYPE delta = -posOrthDir[adj->twinNode()] + posOrthDir[adj->theNode()]; - adjEntry adjPred = adj->faceCyclePred(); - ATYPE delta = (isCaseA) ? - min(abs(posOrthDir[adj->twinNode()] - posOrthDir[adj->theNode()]), m_sep) : - min(abs(posOrthDir[adjPred->theNode()] - posOrthDir[adjPred->twinNode()]), m_sep); - ATYPE boundary = (isCaseA) ? - min(posOrthDir[adj->twinNode()], posOrthDir[adj->theNode()]) : - min(posOrthDir[adjPred->theNode()], posOrthDir[adjPred->twinNode()]); - - if (PG.typeOf(adjCross->theEdge()) == Graph::generalization) - { - if (isCaseA) { - ++i; - if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander && - m_pOR->angle(adjTwin->cyclicPred()) == 2) - { - node s1 = m_pathNode[adjTwin->theNode()]; - node s2 = m_pathNode[adjTwin->cyclicPred()->twinNode()]; - low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i); - low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i); - } - } else { - if(PG.typeOf(adjTwin->theNode()) == Graph::generalizationExpander && - m_pOR->angle(adjTwin) == 2) - { - node s1 = m_pathNode[adjTwin->theNode()]; - node s2 = m_pathNode[adjTwin->cyclicSucc()->twinNode()]; - low[s1] = lowReal[s1] - delta; //minDist.delta(v,dirMax,i); - low[s2] = lowReal[s2] - delta; //minDist.delta(v,dirMax,i); - } - ++i; - } - continue; - } - - - //we save the current direction and stop if we run in opposite - OrthoDir runDir = m_pOR->direction(adjCross); - // if -> while - while (PG.typeOf(adjTwin->theNode()) == Graph::dummy && - adjTwin->theNode()->degree() == 2 && - m_pOR->angle(adjTwin) == angleAtMax) - { - node s = m_edgeToBasicArc[adjCross]->target(); - if(lowReal[s] != low[s]) - { - if(low[s] >= boundary) // nothing to do? - break; - low[s] = boundary; - //low[s] += m_sep - delta; //minDist.delta(v,dirMax,i); - - // If the compaction has eliminated bends, we can have the situation - // that segment s has length 0 and the next segment s' (following the - // edge) is at the same position (the edge arc has length 0). - // In this case, the low-value of s' must be lowered (low[s'] := lowReal[s'] - // is approproate). The same situation can appear several times in a - // row. - //collect chains of segments compacted to zero length - for( ; ; ) /*lowReal[s] == high[s]*/ - { - do - { - adjCross = adjCross->faceCycleSucc(); - } while(m_pOR->direction(adjCross) == segDir || - m_pOR->direction(adjCross) == segOppDir); - - if(adjCross->theNode()->degree() != 2) // no longer a bend point? - break; - - node sNext = m_edgeToBasicArc[adjCross]->opposite(s); - - if(segPos[sNext] != segPos[s]) - break; - - low[sNext] = lowReal[sNext];//was: low[s] - s = sNext; - } - }//if lowreal != low - - adjTwin = adjCross->twin(); // update of twin for while - - //check if we have to stop - if (runDir != m_pOR->direction(adjCross)) break; - }//while dummy - } - } - - // compute topological numbering of segments as second sorting criteria - // in order to process overlapping segments in the order imposed by the - // embedding - computeTopologicalSegmentNum(topNum); - - - // sort segments - SegmentComparer cmpBySegPos(segPos,topNum); - List sortedPathNodes; - allNodes(sortedPathNodes); - sortedPathNodes.quicksort(cmpBySegPos); - - // add segments in the order given by sortedPathNodes to sweep line - List sweepLine; - - ListIterator itV; - for(itV = sortedPathNodes.begin(); itV.valid(); ++itV) - { - //special case nodes - if (m_path[*itV].empty()) continue; - OGDF_ASSERT_IF(dlExtendedChecking,checkSweepLine(sweepLine)); - - node v = *itV; - ListIterator it; - for(it = sweepLine.begin(); it.valid(); ++it) { - if ((*it).m_low < high[v]) - break; - } - - if (!it.valid()) { - sweepLine.pushBack(Interval(v,low[v],high[v])); - continue; - } - - if((*it).m_high <= low[v]) { - sweepLine.insertBefore(Interval(v,low[v],high[v]),it); - continue; - } - - ListIterator itUp = it, itSucc; - // we store if itUp will be deleted in order not to - // access the deleted iterator later - bool isItUpDel = ( ((*itUp).m_low >= low[v]) && ((*itUp).m_high <= high[v]) ); - - for(; it.valid() && (*it).m_low >= low[v]; it = itSucc) { - itSucc = it.succ(); - if ((*it).m_high <= high[v]) { - visibArcs.pushBack(Tuple2((*it).m_pathNode,v)); - sweepLine.del(it); - } - } - - if (it == itUp && (*it).m_high > high[v]) { - node w = (*it).m_pathNode; - sweepLine.insertAfter(Interval(w,(*it).m_low,low[v]),it); - (*it).m_low = high[v]; - sweepLine.insertAfter(Interval(v,low[v],high[v]),it); - visibArcs.pushBack(Tuple2(w,v)); - - } else { - if ( (!isItUpDel) && itUp != it && (*itUp).m_low < high[v]) { - (*itUp).m_low = high[v]; - visibArcs.pushBack(Tuple2((*itUp).m_pathNode,v)); - } - if (it.valid()) { - if ((*it).m_high > low[v]) { - (*it).m_high = low[v]; - visibArcs.pushBack(Tuple2((*it).m_pathNode,v)); - } - sweepLine.insertBefore(Interval(v,low[v],high[v]),it); - - } else { - sweepLine.pushBack(Interval(v,low[v],high[v])); - } - } - - } - - // remove all arcs from visibArcs that are already in the constraint graph - removeRedundantVisibArcs(visibArcs); - - // compute original adjacency entry corresponding to a segment - // We use this in order to omit visibility arcs between segments which - // belong to the same edge if they can see each other from the same side - // of the edge; if they see each other from different sides the arc is - // essential! - NodeArray correspEdge(getGraph(),0); - forall_nodes(v,PG) { - node seg = m_pathNode[v]; - adjEntry adj; - forall_adj(adj,v) { - if(m_pOR->direction(adj) != segDir) continue; - edge eAdj = adj->theEdge(); - edge eOrig = PG.original(eAdj); - if (eOrig == 0) continue; - if (adj == eAdj->adjSource()) - correspEdge[seg] = eOrig->adjSource(); - else - correspEdge[seg] = eOrig->adjTarget(); - } - } - - // remove visibility arcs between ... - SListIterator > itT, itTSucc, itTPred; - for(itT = visibArcs.begin(); itT.valid(); itT = itTSucc) { - itTSucc = itT.succ(); - node v = (*itT).x1(), w = (*itT).x2(); - - // remove arcs which connect segments belonging to the same edge - if (correspEdge[v] && (correspEdge[v] == correspEdge[w])) - { - if (itTPred.valid()) - visibArcs.delSucc(itTPred); - else - visibArcs.popFront(); - } - - else - itTPred = itT; - } - - - - for(itT = visibArcs.begin(); itT.valid(); ++itT) { - //***********************************CHECK if - node v = (*itT).x1(), w = (*itT).x2(); - if (!(m_extraNode[v] || m_extraNode[w])) - { - //******************************CHECK if - node boundRepresentant1 = m_path[v].front(); - node boundRepresentant2 = m_path[w].front(); - node en1 = m_pPR->expandedNode(boundRepresentant1); - node en2 = m_pPR->expandedNode(boundRepresentant2); - //do not insert visibility in cages - if (!( ( en1 && en2 ) && ( en1 == en2) )) - { - edge e = newEdge(v,w); - - //hier vielleicht multiedges abfangen: length auf max(min(sep, dists), minDist.sep) - - m_length[e] = max(m_sep, minDist.separation()); //m_sep; - m_cost [e] = 0; - m_type [e] = cetVisibilityArc; - - //writeGML("visibilityinserted.gml"); - }//special if 2 - }//special if 1 - } - - OGDF_ASSERT_IF(dlExtendedChecking,checkSweepLine(sweepLine)); - -}//insertvisibilityarcs - - - -// performs feasibility test for position assignment pos, i.e., checks if -// the segment positions given by pos fulfill the constraints in the -// compaction constraint graph -template -bool CompactionConstraintGraph::isFeasible( - const NodeArray &pos) -{ - edge e; - forall_edges(e, getGraph()) { - node v = m_path[e->source()].front(); - node w = m_path[e->target()].front();; - if (pos[w] - pos[v] < length(e)) { - cout << "feasibility check failed for edge " << e << endl; - cout << " representatives: " << v << ", " << w << endl; - cout << " length: " << length(e) << endl; - cout << " actual distance: " << pos[w] - pos[v] << endl; - cout << " type of " << e << ": "; - switch(m_type[e]) { - case cetBasicArc: cout << "basic arc" << endl; - break; - case cetVertexSizeArc: cout << "vertex-size arc" << endl; - break; - case cetVisibilityArc: cout << "visibility arc" << endl; - break; - case cetMedianArc: cout << "median arc" << endl; - break; - case cetReducibleArc: cout << "reducible arc" < -void CompactionConstraintGraph::writeGML(const char *filename) const -{ - ofstream os(filename); - writeGML(os); -} - -template -void CompactionConstraintGraph::writeGML(ostream &os) const -{ - const Graph &G = *this; - - NodeArray id(getGraph()); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - os << " id " << (id[v] = nextId++) << "\n"; - - if (m_extraNode[v]) { - os << " label \"" << "0" << "\"\n"; - } else { - os << " label \"" << m_pPR->expandedNode(m_path[v].front()) << "\"\n"; - } - - os << " graphics [\n"; - os << " x 0.0\n"; - os << " y 0.0\n"; - os << " w 30.0\n"; - os << " h 30.0\n"; - if (m_extraNode[v]) - os << " fill \"#00FFFF\"\n"; - else - os << " fill \"#FFFF00\"\n"; - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - // nice idea to use the edge length as edge labels, but Graphwin- - // garbage is not able to show the graph (thinks it has to set - // the y-coordinates of all nodes to NAN) -#if 0 - os << " label \""; - writeLength(os, e); - os << "\"\n"; -#endif - - os << " graphics [\n"; - - os << " type \"line\"\n"; - os << " arrow \"last\"\n"; - switch(m_type[e]) - { - case cetBasicArc: // red - os << " fill \"#FF0000\"\n"; - break; - case cetVertexSizeArc: // blue - os << " fill \"#0000FF\"\n"; - break; - case cetVisibilityArc: // green - os << " fill \"#00FF00\"\n"; - break; - case cetReducibleArc: // red - os << " fill \"#FF0000\"\n"; - break; - case cetFixToZeroArc: // violett - os << " fill \"#AF00FF\"\n"; - break; - case cetMedianArc: // rose - os << " fill \"#FF00FF\"\n"; - break; - } - - os << " ]\n"; // graphics - -#if 0 - os << " LabelGraphics [\n"; - os << " type \"text\"\n"; - os << " fill \"#000000\"\n"; - os << " anchor \"w\"\n"; - os << " ]\n"; -#endif - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/EdgeRouter.h b/ext/OGDF/ogdf/orthogonal/EdgeRouter.h deleted file mode 100644 index 90e4581d9..000000000 --- a/ext/OGDF/ogdf/orthogonal/EdgeRouter.h +++ /dev/null @@ -1,294 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of EdgeRouter... - * - * ... which places node boxes in replacement areas of an orthogonal - * drawing step and routes edges to minimize bends. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_ROUTER_H -#define OGDF_EDGE_ROUTER_H - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ogdf { - -//! edge types, defined by necessary bends -enum bend_type { - bend_free, - bend_1left, - bend_1right, - bend_2left, - bend_2right, //results - prob_bf, - prob_b1l, - prob_b1r, - prob_b2l, - prob_b2r -}; //and preliminary - - -// unprocessed, processed in degree1 preprocessing, used by degree1 -enum process_type { - unprocessed, - processed, - used -}; - - -/** - * Places node boxes in replacement areas of orthogonal - * drawing step and route edges to minimize bends - */ -class OGDF_EXPORT EdgeRouter -{ -public: - //constructor - EdgeRouter() { } - - EdgeRouter( - PlanRep& pru, - OrthoRep& H, - GridLayoutMapped& L, - CombinatorialEmbedding& E, - RoutingChannel& rou, - MinimumEdgeDistances& med, - NodeArray& nodewidth, - NodeArray& nodeheight); - - virtual ~EdgeRouter() { } - - void init( - PlanRep& pru, - RoutingChannel& rou, - bool align = false); - - //! sets the computed distances in structure MinimumEdgeDistance m_med - void setDistances(); - - //! places nodes in cages and routes incident edges - void call(); - - //! places nodes in cages and routes incident edges - void call( - PlanRep& pru, - OrthoRep& H, - GridLayoutMapped& L, - CombinatorialEmbedding& E, - RoutingChannel& rou, - MinimumEdgeDistances& med, - NodeArray& nodewidth, - NodeArray& nodeheight, - bool align = false); - - //! applies precomputed placement - void place(node v/*, int l_sep, int l_overh*/); - - //! computes placement - void compute_place(node v, NodeInfo& inf/*, int sep = 10.0, int overh = 2*/); - - //! computes routing after compute_place - void compute_routing(node v); - - //! compute glue points positions - void compute_glue_points_y(node v); - - //! compute glue points positions - void compute_gen_glue_points_y(node v); - - //! compute glue points positions - void compute_glue_points_x(node& v); - - //! compute glue points positions - void compute_gen_glue_points_x(node v); - - //! sets values derivable from input - void initialize_node_info(node v, int sep); - - // returns assigned connection point and glue point coordinates for each edge - int cp_x(adjEntry ae) { return m_acp_x[ae]; } //!< connection point (cage border) coord of source - int cp_y(adjEntry ae) { return m_acp_y[ae]; } //!< connection point (cage border) coord of source - int gp_x(adjEntry ae) { return m_agp_x[ae]; } //!< glue point (node border) - int gp_y(adjEntry ae) { return m_agp_y[ae]; } //!< glue point (node border) - - bend_type abendType(adjEntry ae) { return m_abends[ae]; } - - void addbends(BendString& bs, const char* s2); - - edge addRightBend(edge e); - - edge addLeftBend(edge e); - - //! adjEntries for edges in inLists - adjEntry outEntry(NodeInfo& inf, OrthoDir d, int pos) { - if (inf.is_in_edge(d, pos)) - return (*inf.inList(d).get(pos))->adjTarget(); - else - return (*inf.inList(d).get(pos))->adjSource();//we only bend on outentries - } - - //! adjEntries for edges in inLists - adjEntry inEntry(NodeInfo& inf, OrthoDir d, int pos) { - if (inf.is_in_edge(d, pos)) - return (*inf.inList(d).get(pos))->adjSource(); - else - return (*inf.inList(d).get(pos))->adjTarget(); - } - - //! sets position for node v in layout to value x,y, invoked to have central control over change - void set_position(node v, int x = 0, int y = 0); - - //! same as set but updates m_fixed, coordinates cant be changed afterwards - void fix_position(node v, int x = 0, int y = 0); - - //! for all multiple edges, set the delta value on both sides to minimum if not m_minDelta - /** - * postprocessing function, hmm maybe preprocessing - */ - void multiDelta(); - - //! set alignment option: place nodes in cage at outgoing generalization - /** - * postprocessing function, hmm maybe preprocessing - */ - void align(bool b) { m_align = b; } - - //test fuer skalierende Kompaktierung - //void setOrSep(int sep) - //{m_hasOrSep = true; m_orSep = sep;} - - -private: - PlanRep* m_prup; - GridLayoutMapped* m_layoutp; - OrthoRep* m_orp; - CombinatorialEmbedding* m_comb; - RoutingChannel* m_rc; - MinimumEdgeDistances* m_med; - NodeArray* m_nodewidth; - NodeArray* m_nodeheight; - - NodeArray infos; //!< holds the cage and placement information - - int m_sep; //!< minimum separation - int m_overh; //!< minimum overhang - double Cconst; //!< relative sep to overhang / delta to eps - - void unsplit(edge e1, edge e2); - - //! set coordinates of cage corners after placement - void set_corners(node v); - - //! computes the alpha value described in the paper - int alpha_move(OrthoDir s_to, OrthoDir s_from, node v); - - //! set minimum delta values for flip decision and adjust distances correspondingly - bool m_minDelta; - - //! helper for oppositeExpander - node oppositeNode(adjEntry ae) { return ae->twinNode(); } - - //! check if the target node of the outgoing adjEntry still is a expander - bool oppositeExpander(adjEntry ae) { - Graph::NodeType nt; - nt = m_prup->typeOf(oppositeNode(ae)); - return ((nt == Graph::highDegreeExpander) || (nt == Graph::lowDegreeExpander)); - } - //if yes, set its m_oppositeBendType value according to the newly introduced bend - - //! computes the beta value described in the paper - /** - * number of additional bend free edges on side s_from - * if move_num edges are moved from side s_from to s_to - */ - int beta_move(OrthoDir s_from, OrthoDir s_to, int move_num, node v); - - //! compute the maximum number of moveable edges - /** - * dependant on space on available edges, return number of saved bends - */ - int compute_move(OrthoDir s_from, OrthoDir s_to, int& kflip, node v); - - NodeArray m_newx, m_newy; //!< new placement position for original node - //!< node array saves info about changed position, no further change is allowed - NodeArray m_fixed; - EdgeArray lowe, uppe, lefte, righte; //!< max box borders for bendfree edges - AdjEntryArray alowe, auppe, alefte, arighte; - AdjEntryArray m_agp_x, m_agp_y; //!< because edges can connect two replacement cages - AdjEntryArray m_cage_point; //!< newly introduced bends destroy edge to point connection - AdjEntryArray m_acp_x, m_acp_y;//!< edge connection point coordinates before treatment - - //! bends - /** - * 0 = bendfree, 1 = single bend from left to node, - * 2 = single from right, 3 = int from left, - * 4 = int from right,... - */ - AdjEntryArray m_abends; - - //! keep the information about the type of bend inserted at one end of an (originally unbend) edge, so that we can check possible bendsaving - NodeArray m_oppositeBendType; - - //! keep information about already processed Nodes - NodeArray m_processStatus; - - //alignment test - NodeArray m_mergerSon; //!< is part of merger son cage - NodeArray m_mergeDir; //!< direction of adjacent (to) merger edges - bool m_align; -}; - -} //end namespace - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/FlowCompaction.h b/ext/OGDF/ogdf/orthogonal/FlowCompaction.h deleted file mode 100644 index 724779ba1..000000000 --- a/ext/OGDF/ogdf/orthogonal/FlowCompaction.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief constructive compaction applying computation of min-cost - * flow in the dual of the constraint graphs - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_FLOW_COMPACTION_H -#define OGDF_FLOW_COMPACTION_H - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - template class CompactionConstraintGraph; - class Layout; - - -//! represents compaction algorithm using min-cost flow in the dual of the constraint graph -class OGDF_EXPORT FlowCompaction -{ -public: - //! construction - FlowCompaction(int maxImprovementSteps = 0, - int costGen = 1, - int costAssoc = 1); - - //! call of constructive heuristics for orthogonal representation - void constructiveHeuristics( - PlanRep &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing); - - - //! call of improvement heuristics for orthogonal drawing (variable cages) - void improvementHeuristics( - PlanRep &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing); - - //! call of improvement heuristics for orthogonal drawing (tight cages) - void improvementHeuristics( - PlanRep &PG, - OrthoRep &OR, - //const - MinimumEdgeDistances &minDist, - GridLayoutMapped &drawing, - int originalSeparation //the input value before multiplication test for compaction improvement - ); - - // - // options - - //! sets option maxImprovementSteps, which is the maximal number of steps performed by improvementHeuristics(). - void maxImprovementSteps(int maxSteps) { - m_maxImprovementSteps = maxSteps; - } - - //! returns option maxImprovementSteps - int maxImprovementSteps() const { - return m_maxImprovementSteps; - } - - //! sets cost of arcs in constraint graph corresponding to generalizations - void costGen(int c) { - m_costGen = c; - } - - //! returns option costGen - int costGen() const { - return m_costGen; - } - - //! sets cost of arcs in constraint graph corresponding to associations - void costAssoc(int c) { - m_costAssoc = c; - } - - //! returns option costGen - int costAssoc() const { - return m_costAssoc; - } - - //! sets number of separation scaling improvement steps - void scalingSteps(int sc) {m_scalingSteps = sc;} - - //! set alignment option - void align(bool b) {m_align = b;} - - -private: - void computeCoords( - CompactionConstraintGraph &D, - NodeArray &pos, - bool fixZeroLength = false, - bool fixVertexSize = false, - bool improvementHeuristics = false, - bool onlyGen = false); - void dfsAssignPos( - NodeArray &visited, - NodeArray &pos, - node v, - int x); - - // options - int m_maxImprovementSteps; //!< maximal number of improvement steps - int m_costGen; //!< cost of arcs in constraint graph corresponding to generalization - int m_costAssoc; //!< cost of arcs in constraint graph corresponding to associations - bool m_cageExpense; //!< should cageedges be more expensive than others? will be propagated to compactionConstraintGraph - //int m_costCage; //!< preliminary: Carsten uses 10 - int m_numGenSteps; //!< number of steps reserved for generalization compaction - int m_scalingSteps; //!< number of improvement steps with decreasing separation - bool m_align; //!< toggle if brother nodes in hierarchies should be aligned - - - EdgeArray m_dualEdge; - EdgeArray m_flow; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/LongestPathCompaction.h b/ext/OGDF/ogdf/orthogonal/LongestPathCompaction.h deleted file mode 100644 index 81decda1a..000000000 --- a/ext/OGDF/ogdf/orthogonal/LongestPathCompaction.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains constructive and improvement compaction by - * applying computation of longest paths in constraint graphs - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_LONGEST_PATH_COMPACTION_H -#define OGDF_LONGEST_PATH_COMPACTION_H - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - template class CompactionConstraintGraph; - class Layout; - - -/** - * \brief Compaction algorithm using longest paths in the constraint graph. - * - *

    Optional Parameters

    - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription
    tightenbooltrueif true, an additional improvement step tries to reduce the total edge length
    max improvement stepsint0the maximal number of steps performed by the improvement heuristic; 0 means no upper limit.
    -*/ -class OGDF_EXPORT LongestPathCompaction -{ -public: - //! Creates an instance of the longest path compaction algorithm. - LongestPathCompaction(bool tighten = true, - int maxImprovementSteps = 0); - - //! Constructive heurisitic for orthogonal representations. - void constructiveHeuristics( - PlanRepUML &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing); - - - //! Improvement heurisitic for orthogonal drawings. - void improvementHeuristics( - PlanRepUML &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing); - - // - // options - - //! Sets option tighten to \a select. - void tighten(bool select) { - m_tighten = select; - } - - //! Returns the option tighten. - bool tighten() const { - return m_tighten; - } - - - //! Sets the option max improvement steps. - void maxImprovementSteps(int maxSteps) { - m_maxImprovementSteps = maxSteps; - } - - //! Returns the option max improvement steps. - int maxImprovementSteps() const { - return m_maxImprovementSteps; - } - - -private: - void computeCoords( - const CompactionConstraintGraph &D, - NodeArray &pos); - - void applyLongestPaths(const CompactionConstraintGraph &D, - NodeArray &pos); - - void moveComponents(const CompactionConstraintGraph &D, - NodeArray &pos); - - - // options - bool m_tighten; //!< Tighten pseudo-components. - int m_maxImprovementSteps; //!< The maximal number of improvement steps. - - SList m_pseudoSources; //!< The list of pseudo-sources. - NodeArray m_component; //!< The pseudo component of a node. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/MinimumEdgeDistances.h b/ext/OGDF/ogdf/orthogonal/MinimumEdgeDistances.h deleted file mode 100644 index 528096190..000000000 --- a/ext/OGDF/ogdf/orthogonal/MinimumEdgeDistances.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MinimumEdgeDistances which maintains - * minimum distances between attached edges at a vertex - * (delta's and epsilon's) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_MINIMUM_EDGE_DISTANCE_H -#define OGDF_MINIMUM_EDGE_DISTANCE_H - - -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// MinimumEdgeDistances -// maintains input sizes for improvement compaction (delta's -// and epsilon's) -//--------------------------------------------------------- -template -class MinimumEdgeDistances { -public: - // constructor - MinimumEdgeDistances(const Graph &G, ATYPE sep) : m_delta(G), m_epsilon(G) - { - m_sep = sep; - } - - // returns delta_s(v)^i (with i = 0 => l, i = 1 => r) - const ATYPE &delta(node v, OrthoDir s, int i) const { - OGDF_ASSERT(0 <= int(s) && int(s) <= 3 && 0 <= i && i <= 1); - return m_delta[v].info[s][i]; - } - - ATYPE &delta(node v, OrthoDir s, int i) { - OGDF_ASSERT(0 <= int(s) && int(s) <= 3 && 0 <= i && i <= 1); - return m_delta[v].info[s][i]; - } - - // returns epsilon_s(v)^i (with i = 0 => l, i = 1 => r) - const ATYPE &epsilon(node v, OrthoDir s, int i) const { - OGDF_ASSERT(0 <= int(s) && int(s) <= 3 && 0 <= i && i <= 1); - return m_epsilon[v].info[s][i]; - } - - ATYPE &epsilon(node v, OrthoDir s, int i) { - OGDF_ASSERT(0 <= int(s) && int(s) <= 3 && 0 <= i && i <= 1); - return m_epsilon[v].info[s][i]; - } - - ATYPE separation() const { - return m_sep; - } - - void separation(ATYPE sep) {m_sep = sep;} - - -private: - struct InfoType { - ATYPE info[4][2]; - }; - - NodeArray m_delta; - NodeArray m_epsilon; - ATYPE m_sep; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/OrthoLayout.h b/ext/OGDF/ogdf/orthogonal/OrthoLayout.h deleted file mode 100644 index a12e0a202..000000000 --- a/ext/OGDF/ogdf/orthogonal/OrthoLayout.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class OrthoLayout which represents an - * orthogonal planar drawing algorithm for mixed-upward - * embedded graphs. - * - * \author Carsten Gutwenger and Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_UML_ORTHO_LAYOUT_H -#define OGDF_UML_ORTHO_LAYOUT_H - - -#include -#include - - -namespace ogdf { - - enum OptionProfile { standard, minBendsperEdge, fullService }; //just to think about it... - - enum OrthoDir; - - -//--------------------------------------------------------- -// OrthoLayout -// represents planar orthogonal drawing algorithm for -// mixed-upward planar embedded graphs (UML-diagrams) -//--------------------------------------------------------- -class OGDF_EXPORT OrthoLayout : public LayoutPlanRepModule -{ -public: - // constructor - OrthoLayout(); - - - // calls planar UML layout algorithm. Input is a planarized representation - // PG of a connected component of the graph, output is a layout of the - // (modified) planarized representation in drawing - void call(PlanRepUML &PG, adjEntry adjExternal, Layout &drawing); - - // - // options - - // the minimum distance between edges and vertices - double separation() const { - return m_separation; - } - - void separation(double sep) { - m_separation = sep; - } - - // cOverhang * separation is the minimum distance between the glue point - // of an edge and a corner of the vertex boundary - double cOverhang() const { - return m_cOverhang; - } - - void cOverhang(double c) { - m_cOverhang = c; - } - - - // the distance from the tight bounding box to the boundary of the drawing - double margin() const { - return m_margin; - } - - void margin(double m) { - m_margin = m; - } - - - // the preferred direction of generalizations - OrthoDir preferedDir() const { - return m_preferedDir; - } - - void preferedDir(OrthoDir dir) { - m_preferedDir = dir; - } - - // cost of associations - int costAssoc() const { - return m_costAssoc; - } - - void costAssoc(int c) { - m_costAssoc = c; - } - - // cost of generalizations - int costGen() const { - return m_costGen; - } - - void costGen(int c) { - m_costGen = c; - } - - //! Set the option profile, thereby fixing a set of drawing options - void optionProfile(int i) {m_optionProfile = i;} - - //! Set alignment option - void align(bool b) {m_align = b;} - - //! Set scaling compaction - void scaling(bool b) {m_useScalingCompaction = b;} - - //! Set bound on the number of bends - void setBendBound(int i) { OGDF_ASSERT(i >= 0); m_bendBound = i; } - - //in planarlayout - //enum LayoutOptions {umloptAlignment = 1, optScaling = 2, optProgressive = 4} - //set generic options by setting field bits, - //necessary to allow setting over base class pointer - //bit 0 = alignment - //bit 1 = scaling - //bit 2 = progressive/traditional - //=> 0 is standard - virtual void setOptions(int optionField) - { - if (optionField & umlOpAlign) m_align = true; - else m_align = false; - if (optionField & umlOpScale) m_useScalingCompaction = true; - else m_useScalingCompaction = false; - if (optionField & umlOpProg) m_orthoStyle = 1; - else m_orthoStyle = 0; //traditional - }//setOptions - - virtual int getOptions() - { - int result = 0; - if (m_align) result = umlOpAlign; - if (m_useScalingCompaction) result += umlOpScale; - if (m_orthoStyle == 1) result += umlOpProg; - - return result; - }//getOptions - - -protected: - void classifyEdges(PlanRepUML &PG, adjEntry &adjExternal); - -private: - // compute bounding box and move final drawing such that it is 0 aligned - // respecting margins - void computeBoundingBox(const PlanRepUML &PG, Layout &drawing); - - - // options - double m_separation; - double m_cOverhang; - double m_margin; - OrthoDir m_preferedDir; - int m_optionProfile; - int m_costAssoc; - int m_costGen; - //align merger sons on same level - bool m_align; - //settings for scaling compaction - bool m_useScalingCompaction; - int m_scalingSteps; - //mainly used for OrthoShaper traditional/progressive - int m_orthoStyle; - int m_bendBound; //!< bounds number of bends per edge in ortho shaper -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/OrthoRep.h b/ext/OGDF/ogdf/orthogonal/OrthoRep.h deleted file mode 100644 index 679e06b66..000000000 --- a/ext/OGDF/ogdf/orthogonal/OrthoRep.h +++ /dev/null @@ -1,499 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of orthogonal representation of planar graphs. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_ORTHO_REP_H -#define OGDF_ORTHO_REP_H - - -#include -#include -#include -#include - - -namespace ogdf { - - class OGDF_EXPORT PlanRep; - class OGDF_EXPORT PlanRepUML; - - -// type for bends (convex or reflex) -enum BendType { convexBend = '0', reflexBend = '1' }; - -// type of (orthogonal) directions -// horizontal: odEast or odWest -// vertical: odNorth or odSouth -enum OrthoDir { - odNorth = 0, - odEast = 1, - odSouth = 2, - odWest = 3, - odUndefined = 4 -}; - - -//--------------------------------------------------------- -// BendString -// represents the bends on an edge e consisting of vertical -// and horizontal segments -//--------------------------------------------------------- -class OGDF_EXPORT BendString -{ -public: - // constructs empty bend string - BendString() { - m_pBend = 0; - m_len = 0; - } - - // constructs bend string as given by str - // Precond.: str is a 0 terminated C++ string consisting of '0's and '1's - BendString(const char *str) { - init(str); - } - - // constructs bend string consisting of n c's - // Precond.: c is '0' or '1' - BendString(char c, size_t n) { - init(c,n); - } - - // copy constructor - BendString(const BendString &bs) { - init(bs); - } - - - // destructor - ~BendString() { - delete [] m_pBend; - } - - - // returns i'th character in bend string - char operator[](size_t i) const { - // range check - OGDF_ASSERT(i < m_len); - return m_pBend[i]; - } - - char &operator[](size_t i) { - // range check - OGDF_ASSERT(i < m_len); - return m_pBend[i]; - } - - // returns number of characters in bend string - size_t size() const { - return m_len; - } - - // returns a pointer to the 0 terminated string - // or a 0-pointer if empty - const char *toString() const { - return m_pBend; - } - - // sets bend string to the string given by str - // Precond.: str is a 0 terminated C++ string consisting of '0's and '1's - void set(const char *str) { - delete [] m_pBend; - init(str); - } - - // sets bend string to the string consisting of n c's - // Precond.: c is '0' or '1' - void set(char c, size_t n) { - delete [] m_pBend; - init(c,n); - } - - - // sets bend string to the empty bend string - void set() { - delete [] m_pBend; - m_pBend = 0; - m_len = 0; - } - - - // assignment operator - BendString &operator=(const BendString &bs) { - delete [] m_pBend; - init(bs); - return *this; - } - - BendString &operator+=(const BendString &bs) { - char* temp = new char[m_len+bs.m_len+1]; - - m_len = m_len + bs.m_len; - - if (m_len == 0) - { - *temp = 0;//temp = 0; - } - else - { - char *p = temp; - if (m_pBend != 0) - { - const char *str = m_pBend; - while ((*p++ = *str++) != 0) ; - } - else {*p = '0'; p++;} - if (bs.m_len > 0) - { - p--; - const char *str1 = bs.m_pBend; - while ((*p++ = *str1++) != 0) ; - } - } - - delete[] m_pBend; - m_pBend = temp; - - return *this; - } - - // output operator - // example output: "001101001" or "" - friend ostream &operator<<(ostream &os, const BendString &bs) { - if (bs.size() == 0) - os << "\"\""; - else - os << "\"" << bs.m_pBend << "\""; - return os; - } - -private: - void init(const char *str); - void init(char c, size_t n); - void init(const BendString &bs); - - - // poiner to 0 terminated character string - char *m_pBend; - // length of string (number of characters without ending 0) - size_t m_len; -}; - - - -//--------------------------------------------------------- -// OrthoRep -// orthogonal representation of an embedded graph -//--------------------------------------------------------- -class OGDF_EXPORT OrthoRep -{ -public: - - //--------------------------------------------------------- - // information about a side of a vertex in UML diagrams - //--------------------------------------------------------- - struct SideInfoUML { - // adjacency entry of generalization attached at the side - // (or 0 if none) - adjEntry m_adjGen; - // number of attached edges which have corresponding edges in the - // original graph to the left (index 0) or right of the - // attached generalization. If no generalization is attached, - // m_nAttached[0] is the total number of attached edges. - int m_nAttached[2]; - - // constructor - SideInfoUML() { - m_adjGen = 0; - m_nAttached[0] = m_nAttached[1] = 0; - } - - // returns the total number of edges attached at this side - int totalAttached() const { - int nGen = (m_adjGen == 0) ? 0 : 1; - return nGen + m_nAttached[0] + m_nAttached[1]; - } - - - // output operator for debugging - friend ostream &operator<<(ostream &os, const SideInfoUML &si) - { - os << "{ " << si.m_nAttached[0] << - ", " << si.m_adjGen << - ", " << si.m_nAttached[1] << " }"; - return os; - } - }; - - //only for debugging purposes - adjEntry externalAdjEntry() const {return m_adjExternal;} - adjEntry alignAdjEntry() const {return m_adjAlign;} - - - //--------------------------------------------------------- - // further information about the cages of vertices in UML diagrams - //--------------------------------------------------------- - struct VertexInfoUML { - // side information (odNorth, odEast, odSouth, odWest corresponds to - // left, top, right, bottom) - SideInfoUML m_side[4]; - // m_corner[dir] is adjacency entry in direction dir starting at - // a corner - adjEntry m_corner[4]; - - // constructor - VertexInfoUML() { -#ifdef OGDF_DEBUG - m_corner[0] = m_corner[1] = m_corner[2] = m_corner[3] = 0; -#endif - } - OGDF_NEW_DELETE - }; - - - // construction - - // dummy - OrthoRep() { m_pE = 0; } - // associates orthogonal representation with embedding E - OrthoRep(CombinatorialEmbedding &E); - - // destruction - ~OrthoRep() { - freeCageInfoUML(); - } - - // reinitialization: associates orthogonal representation with embedding E - void init(CombinatorialEmbedding &E); - - - // - // access functions - // - - // returns associated embedding - operator const CombinatorialEmbedding &() const { - return *m_pE; - } - - // returns associated graph - operator const Graph &() const { - return *m_pE; - } - - // returns angle between adj and its successor - // (return value is angle divided by 90 degree) - int angle(adjEntry adj) const { - return m_angle[adj]; - } - - int &angle(adjEntry adj) { - return m_angle[adj]; - } - - - // returns bend string of adjacency entry adj - const BendString &bend(adjEntry adj) const { - return m_bends[adj]; - } - - BendString &bend(adjEntry adj) { - return m_bends[adj]; - } - - // returns direction of adjacency entry - OrthoDir direction(adjEntry adj) const { - return m_dir[adj]; - } - - - // returns cage info - const VertexInfoUML *cageInfo(node v) const { - return m_umlCageInfo[v]; - } - - // returns cage info - VertexInfoUML *cageInfo(node v) { - return m_umlCageInfo[v]; - } - - - - // - // update functions - // - - // normalizes the orthogonal representation, i.e., sets an artficial - // vertex on each bend - void normalize(); - - // checks if the orth. repr. is normalized, i.e., each bend string is empty - bool isNormalized() const; - - // removes rectangular ears (pattern "100") by splitting edges and faces. - // Afterwards, each internal face is a rectangle and the external face - // contains no rectangular ear (but is not necessarily the complement of - // a rectangle). - // Precond.: The orth. repr. is normalized and contains no 0-degree angles - void dissect(); - // same as dissect, attempting to save artificial nodes and allow preprocessing - void dissect2(PlanRepUML* PG = 0); - // undoes a previous dissect() by removing dissection edges and unsplitting - // vertices - void undissect(bool align = false); - - - // assigns consistent directions to adjacency entries - void orientate(); - - // assigns consistent directions to adj. entries such that most - // generalizations are directed in preferedDir - void orientate(const PlanRep &PG, OrthoDir preferedDir); - - // assigns consistent directions to adjacency entries, - // assigning dir to adj (fixing all others) - void orientate(adjEntry adj, OrthoDir dir); - - // returns true iff orientate() has been called before. - // If not, direction() may not be called since adj. entry array is not - // initialized! - bool isOrientated() const { - return m_dir.valid(); - } - - - // rotates all directions of adjacency entries by r - void rotate(int r); - - - // computes further information about cages - void computeCageInfoUML(const PlanRep &PG/*, double sep*/); - - - // checks if the orth. repr. is a legal shape description, i.e., if there - // is an orthogonal embedding realizing this shape (if 0-degree angles are - // present, the condition is necessary but not sufficient). - // If false is returned, error contains a description of the reason. - bool check(String &error); - - - // - // static members - // - - // exchanges '1'->'0' and vice versa - static char flip(char c) { - return (c == '0') ? '1' : '0'; - } - - static OrthoDir oppDir(OrthoDir d) { - return OrthoDir((d + 2) & 3); - } - - static OrthoDir nextDir(OrthoDir d) { - return OrthoDir((d + 1) & 3); - } - - static OrthoDir prevDir(OrthoDir d) { - return OrthoDir((d + 3) & 3); - } - - friend ostream &operator<<(ostream &os, const OrthoRep &op) { - edge e; - const Graph& E = op; - forall_edges(e, E) - { - os << e <<": src angle "<adjSource())<<" bend "<adjSource()) - <<"\n"<<" tgt angle "<adjTarget())<<" bend "<adjTarget()) - - <<"\n"; - } - return os; - } - - - -private: - void orientateFace(adjEntry adj, OrthoDir dir); - void freeCageInfoUML(); - - // associated combinatorial embedding - CombinatorialEmbedding *m_pE; - - // * 90 deg = angle between e and its successor - AdjEntryArray m_angle; - // bends on edge e - AdjEntryArray m_bends; - // direction of adjacency entries - AdjEntryArray m_dir; - - // information about cages of original vertices; used for orthogonal - // representations of PlanRep's - NodeArray m_umlCageInfo; - - // The following members are used for undoing dissection - EdgeArray m_dissectionEdge; // = true iff dissection edge - //check if special gener. sons alignment edge - EdgeArray m_alignmentEdge; // = true iff alignment edge - // contains all nodes created by splitting non-dissection edges while - // dissect() - StackPure m_splitNodes; - // stores adjacency entry on external face for restoring in undissect() - adjEntry m_adjExternal; - // stores adjacency entry on preliminary external face in alignment case - adjEntry m_adjAlign; - //starts dissection phase for special pattern 1 replacement before standard dissection - bool m_preprocess; - //special pattern after pattern 1 - bool m_pattern2; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/orthogonal/OrthoShaper.h b/ext/OGDF/ogdf/orthogonal/OrthoShaper.h deleted file mode 100644 index fb0f56a02..000000000 --- a/ext/OGDF/ogdf/orthogonal/OrthoShaper.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes the orthogonal representation of a planar - * representation of a UML graph using the simple flow - * approach. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_ORTHO_FORMER_GENERIC_H -#define OGDF_ORTHO_FORMER_GENERIC_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT OrthoShaper -{ -public: - - enum n_type { low, high, inner, outer }; //types of network nodes: nodes and faces - - OrthoShaper() { - setDefaultSettings(); - } - - ~OrthoShaper() { } - - // Given a planar representation for a UML graph and its planar - // combinatorial embedding, call() produces an orthogonal - // representation using Tamassias bend minimization algorithm - // with a flow network where every flow unit defines 90 degree angle - // in traditional mode. - - void call(PlanRepUML &PG, - CombinatorialEmbedding &E, - OrthoRep &OR, - bool fourPlanar = true); - - //sets the default settings used in the standard constructor - void setDefaultSettings() - { - m_distributeEdges = true; // true; //try to distribute edges to all node sides - m_fourPlanar = true; //do not allow zero degree angles at high degree - m_allowLowZero = false; //do allow zero degree at low degree nodes - m_multiAlign = true;//true; //start/end side of multi edges match - m_traditional = true;//true; //prefer 3/1 flow at degree 2 (false: 2/2) - m_deg4free = false; //allow free angle assignment at degree four - m_align = false; //align nodes on same hierarchy level - m_startBoundBendsPerEdge = 0; //don't use bound on bend number per edge - } - - // returns option distributeEdges - bool distributeEdges() { return m_distributeEdges; } - // sets option distributeEdges to b - void distributeEdges(bool b) { m_distributeEdges = b; } - - // returns option multiAlign - bool multiAlign() { return m_multiAlign; } - // sets option multiAlign to b - void multiAlign(bool b) { m_multiAlign = b; } - - // returns option traditional - bool traditional() { return m_traditional; } - // sets option traditional to b - void traditional(bool b) { m_traditional = b; } - - //returns option deg4free - bool fixDegreeFourAngles() { return m_deg4free; } - //sets option deg4free - void fixDegreeFourAngles(bool b) { m_deg4free = b; } - - //alignment of brothers in hierarchies - void align(bool al) {m_align = al;} - bool align() {return m_align;} - - //! Set bound for number of bends per edge (none if set to 0). If shape - //! flow computation is unsuccessful, the bound is increased iteratively. - void setBendBound(int i){ OGDF_ASSERT(i >= 0); m_startBoundBendsPerEdge = i;} - int getBendBound(){return m_startBoundBendsPerEdge;} - -private: - bool m_distributeEdges; // distribute edges among all sides if degree > 4 - bool m_fourPlanar; // should the input graph be four planar - // (no zero degree) - bool m_allowLowZero; // allow low degree nodes zero degree - // (to low for zero...) - bool m_multiAlign; // multi edges aligned on the same side - bool m_deg4free; // allow degree four nodes free angle assignment - bool m_traditional; // do not prefer 180 degree angles, - // traditional is not tamassia, - // traditional is a kandinsky - ILP - like network with node supply 4, - // not traditional interprets angle flow zero as 180 degree, "flow - // through the node" - bool m_align; //try to achieve an alignment in hierarchy levels - // A maximum number of bends per edge can be specified in - // m_startBoundBendsPerEdge. If the algorithm is not successful in - // producing a bend minimal representation subject to - // startBoundBendsPerEdge, it successively enhances the bound by - // one trying to compute an orthogonal representation. - // - // Using m_startBoundBendsPerEdge may not produce a bend minimal - // representation in general. - int m_startBoundBendsPerEdge; //!< bound on the number of bends per edge for flow - //!< if == 0, no bound is used - - //set angle boundary - //warning: sets upper AND lower bounds, therefore may interfere with existing bounds - void setAngleBound( - edge netArc, - int angle, - EdgeArray& lowB, - EdgeArray& upB, - EdgeArray& aTwin, - bool maxBound = true) - { - //vorlaeufig - OGDF_ASSERT(!m_traditional); - if (m_traditional) - { - switch (angle) - { - case 0: - case 90: - case 180: - break; - OGDF_NODEFAULT - }//switch - }//trad - else - { - switch (angle) - { - case 0: if (maxBound) - { - upB[netArc] = lowB[netArc] = 2; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = lowB[e2] = 0; - } - } - else - { - upB[netArc] = 2; lowB[netArc] = 0; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = 2; - lowB[e2] = 0; - } - - } - break; - case 90: - if (maxBound) - { - lowB[netArc] = 1; - upB[netArc] = 2; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = lowB[e2] = 0; - } - } - else - { - upB[netArc] = 1; - lowB[netArc] = 0; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = 2; - lowB[e2] = 0; - } - - } - break; - case 180: - if (maxBound) - { - lowB[netArc] = 0; - upB[netArc] = 2; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = lowB[e2] = 0; - } - } - else - { - upB[netArc] = 0; - lowB[netArc] = 0; - edge e2 = aTwin[netArc]; - if (e2) - { - upB[e2] = 2; - lowB[e2] = 0; - } - - } - break; - OGDF_NODEFAULT // wrong bound - }//switch - }//progressive - - }//setAngle -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/packing/ComponentSplitterLayout.h b/ext/OGDF/ogdf/packing/ComponentSplitterLayout.h deleted file mode 100644 index 6202522a7..000000000 --- a/ext/OGDF/ogdf/packing/ComponentSplitterLayout.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Splits and packs the components of a Graph. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_COMPONENT_SPLITTER_LAYOUT_H -#define OGDF_COMPONENT_SPLITTER_LAYOUT_H - -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT ComponentSplitterLayout : public LayoutModule -{ -private: - ModuleOption m_secondaryLayout; - ModuleOption m_packer; - - // keeps a list of nodes for each connected component, - // up to date only in call method - Array > nodesInCC; - int m_numberOfComponents; - double m_targetRatio; - int m_minDistCC; - int m_rotatingSteps; - int m_border; - - //! Combines drawings of connected components to - //! a single drawing by rotating components and packing - //! the result (optimizes area of axis-parallel rectangle). - void reassembleDrawings(GraphAttributes &GA); - -public: - ComponentSplitterLayout(); - - void call(GraphAttributes &GA); - - void setLayoutModule(LayoutModule *layout) { - m_secondaryLayout.set(layout); - } - - void setPacker(CCLayoutPackModule *packer) { - m_packer.set(packer); - } -}; - -} // namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/packing/TileToRowsCCPacker.h b/ext/OGDF/ogdf/packing/TileToRowsCCPacker.h deleted file mode 100644 index cd2a0c9d8..000000000 --- a/ext/OGDF/ogdf/packing/TileToRowsCCPacker.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class TileToRowsCCPacker. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_TILE_TO_ROWS_CC_PACKER_H -#define OGDF_TILE_TO_ROWS_CC_PACKER_H - - - -#include - - - -namespace ogdf { - - -//! The tile-to-rows algorithm for packing drawings of connected components. -class OGDF_EXPORT TileToRowsCCPacker : public CCLayoutPackModule -{ - template struct RowInfo; - -public: - //! Creates an instance of tile-to-rows packer. - TileToRowsCCPacker() { } - - virtual ~TileToRowsCCPacker() { } - - /** - * \brief Arranges the rectangles given by \a box. - * - * The algorithm call takes an input an array \a box of rectangles with - * real coordinates and computes in \a offset the offset to (0,0) of each - * rectangle in the layout. - * @param box is the array of input rectangles. - * @param offset is assigned the offset of each rectangle to the origin (0,0). - * The offset of a rectangle is its lower left point in the layout. - * @param pageRatio is the desired page ratio (width / height) of the - * resulting layout. - */ - void call(Array &box, - Array &offset, - double pageRatio = 1.0); - - /** - * \brief Arranges the rectangles given by \a box. - * - * The algorithm call takes an input an array \a box of rectangles with - * real coordinates and computes in \a offset the offset to (0,0) of each - * rectangle in the layout. - * @param box is the array of input rectangles. - * @param offset is assigned the offset of each rectangle to the origin (0,0). - * The offset of a rectangle is its lower left point in the layout. - * @param pageRatio is the desired page ratio (width / height) of the - * resulting layout. - */ - void call(Array &box, - Array &offset, - double pageRatio = 1.0); - -private: - template - static void callGeneric(Array &box, - Array &offset, - double pageRatio); - - template - static int findBestRow(Array > &row, - int nRows, - double pageRatio, - const POINT &rect); - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/BoothLueker.h b/ext/OGDF/ogdf/planarity/BoothLueker.h deleted file mode 100644 index 4e7202384..000000000 --- a/ext/OGDF/ogdf/planarity/BoothLueker.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of BoothLueker which implements a planarity - * test and planar embedding algorithm. - * - * \author Sebastian Leipert, Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BOOTH_LUEKER_H -#define OGDF_BOOTH_LUEKER_H - -//========================================================= -// Main functions: -// -// isPlanar(Graph &G) Tests a graph for planarity. -// -// planarEmbed(Graph &G) Tests a graph for planarity and returns -// a planar embedding if G is planar. -// -//========================================================= - -#include -#include -#include -#include - -namespace ogdf { - -//! Booth-Lueker planarity test. -/** This class implements the linear-time planarity test proposed by Booth and Luecker, based on PQ-trees.\n - * This class is deprecated! You will usually want to use the more modern/faster/versatile linear-time planarity test - * by Boyer and Myrvold instead, implemented in the class BoyerMyrvold. - * Generally, it is suggested to use the direct function calls isPlanar and planarEmbed in extended_graph_alg.h (which in turn use BoyerMyrvold). - */ -class OGDF_EXPORT BoothLueker : public PlanarityModule { - -public: - - BoothLueker() { } - ~BoothLueker() { } - - //! Returns true, if G is planar, false otherwise. - bool isPlanarDestructive(Graph &G); - //! Returns true, if G is planar, false otherwise. - bool isPlanar(const Graph &G); - - //! Returns true, if G is planar, false otherwise. If true, G contains a planar embedding. - bool planarEmbed(Graph &G){return preparation(G,true);} - //! Returns true, if G is planar, false otherwise. If true, G contains a planar embedding. - /** - * For BoothLueker, this procedure is exactly the same as planarEmbed. (See PlanarityModule or - * BoyerMyrvold for the rationale of this function's existence. - */ - bool planarEmbedPlanarGraph(Graph &G){return preparation(G,true);} - -private: - - //! Prepares the planarity test and the planar embedding - bool preparation(Graph &G,bool embed); - - //! Performs a planarity test on a biconnected component of \a G. - /** - * Performs a planarity test on a biconnected component of \a G. - * - * \a numbering contains an st-numbering of the component. - */ - bool doTest(Graph &G,NodeArray &numbering); - - //! Performs a planarity test on a biconnected component of \a G and embedds it planar. - /** - * Performs a planarity test on a biconnected component of \a G and embedds it planar. - * - * \a numbering contains an st-numbering of the component. - */ - bool doEmbed(Graph &G, - NodeArray &numbering, - EdgeArray &backTableEdges, - EdgeArray &forwardTableEdges); - - // Used by doEmbed. Computes an entire embedding from an - // upward embedding. - void entireEmbed(Graph &G, - NodeArray > &entireEmbedding, - NodeArray > &adjMarker, - NodeArray &mark, - node v); - - void prepareParallelEdges(Graph &G); - - - //private Members for handling parallel edges - EdgeArray > m_parallelEdges; - EdgeArray m_isParallel; - int m_parallelCount; - - - -}; - -} -#endif diff --git a/ext/OGDF/ogdf/planarity/BoyerMyrvold.h b/ext/OGDF/ogdf/planarity/BoyerMyrvold.h deleted file mode 100644 index a4e3ad1d0..000000000 --- a/ext/OGDF/ogdf/planarity/BoyerMyrvold.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * $Revision: 2609 $ - * - * last checkin: - * $Author: klein $ - * $Date: 2012-07-16 09:59:18 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the wrapper class of the Boyer-Myrvold planarity test - * - * \author Jens Schmidt, Markus Chimani - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BOYER_MYRVOLD_H -#define OGDF_BOYER_MYRVOLD_H - -#include -#include -#include -#include -#include - -namespace ogdf { - -class KuratowskiWrapper; - -//! Wrapper class used for preprocessing and valid invocation of the planarity test. -/** This class is part of the extended Boyer-Myrvold planarity embedding algorithm - * to simplify invocation besides adding standard parameters (see classes in - * \a BoyerMyrvoldInit.h and \a BoyerMyrvoldPlanar.h). In addition the linear-time - * Boyer-Myrvold embedding algorithm was extended to extract multiple Kuratowski - * Subdivisions, whose number can be limited as desired (see classes in - * \a FindKuratowskis.h and \a ExtractKuratowskis.h). Furthermore all extracted - * subdivisions are unique. - * - * Input graph:\n - * There are no restrictions on the input graph \a G (except that it has to be finite, - * but if you do not have infinite RAM, that should do it :) ). In particular, \a G hasn't - * to be biconnected nor connected. Self-loops and multigraphs are possible, too.\n - * Note: But if you want to use the extraction of Kuratowski Subdivisions, \a G has to be simple! - * - * How to use it:\n - * There exist two main functions, consisting of the planarity test itself and the - * planar embedding algorithm, which embeds the graph on the plane if possible. - * Each one has a fast but destructive variant, designed to - * be used on graphs that may be modified and a slower variant, which is for graphs - * that must not be altered. Embeddings on the plane are given by a (genus 0) - * cyclic ordering of adjacency lists in the graph. Functions for constant graphs - * are available, too, if that makes sense for the function. - * - * Examples:\n - * \a isPlanarDestructive(G), \a isPlanar(G):\n - * Tests graph \a G for planarity with the Boyer-Myrvold planarity test. - * - * \a planarEmbedDestructive(G), \a planarEmbed(G), \a planarEmbed(G,H):\n - * Tests graph \a G for planarity and returns a planar embedding in G, - * if \a G is planar. If G is a constant graph, the embedding is given in the GraphCopySimple - * \a H, so that both, the constant input graph and the resulting planar embedding are available. - * - * \a planarEmbedDestructive(G,output,i), \a planarEmbed(G,output,i):\n - * Tests graph \a G for planarity and returns a planar embedding, - * if \a G is planar. Otherwise up to \a i Kuratowski subdivisions are returned to the list - * \a output. Use \a i = -1 for extraction of all subdivisions. - * - * \a planarEmbedDestructive(G,output,i), \a planarEmbed(G,output,i):\n - * Tests graph \a G for planarity and returns a planar embedding, - * if \a G is planar. Otherwise up to \a i Kuratowski subdivisions are returned to the list - * \a output. Use \a i = -1 for extraction of all subdivisions. The extraction algorithm - * doesn't use sets of \a bundles instead of subdivisions paths, so this is designed for - * a fast computation while extracting some, but not a huge amount of Kuratowski Subdivisions. - * - * \a planarEmbedDestructive(G,output,i,true), \a planarEmbed(G,output,i,true):\n - * This is the same as above, but now \a bundles are used to compute much more subdivisions. - * Naturally the computation is slower than the function above, especially on large graphs. - * - * Complete list of parameters for embedding functions:\n - * e.g. \a planarEmbedDestructive( - * - Graph& g,\n - * This is the input Graph. - * - SList& output,\n - * All subdivisions are returned in this list. - * - int embeddingGrade,\n - * This flag has 5 options dependent on value \a i: \n - * \a i = -3: no Embedding is computed\n - * \a i = -2: no FindKuratowskiProcedure is performed\n - * \a i = -1: all Kuratowski Subdivisions are extracted\n - * \a i = 0: no Kuratowski Subdivision is extracted, but FindKuratowskiProcedure is started\n - * \a i > 0: up to \a i Kuratowski Subdivisions are extracted. - * - bool bundles,\n - * If \a bundles are used, some paths between two Kuratowski nodes are replaced by whole - * bundles of paths. On the one hand much more subdivisions can be extracted on the other - * computation time growths. - * - bool limitStructures,\n - * If Kuratowski Structures are \a limited, all subdivisions in that Structures are extracted. - * Thereby none of the efforts made in FindKuratowskiProcedure are lost, which is creditable - * in comparison with limiting the number of extracted subdivisions. Note that the number - * of extracted subdivisions can highly vary. - * - bool randomDFSTree,\n - * Iff \a true, a completely random DFS-Tree (the list of nodes and the adjacency-lists for - * each node are permuted at random) is created each time the planarity test is called. - * This is important for extracting huge amounts of Kuratowski subdivisions of - * one single Graph, since randomizing the DFSTree yields to new unknown subdivisions. - * Note that computation time growths up to 20 percent longer. - * - bool avoidE2Minors\n - * Two minortypes, namely \a E2/AE2 and \a A, construct identical subdivisions on some graphs. - * To avoid this, set this flag \a true, otherwise \a false. - * - * ) - * - * To experience the computation time difference to the PQTree-Planarity test please - * switch to release-mode, since a lot of slow testroutines and assertions - * were implemented in debug-mode. Also note the ability to transform KuratowskiWrapperLists - * to Lists of KuratowskiSubdivision through calling the function \a transform. Within - * this transformation is a switch to filter all similar or not similar Kuratowski - * Subdivisions. - */ -class OGDF_EXPORT BoyerMyrvold : public PlanarityModule -{ -protected: - //! Class BoyerMyrvoldPlanar on heap - BoyerMyrvoldPlanar* pBMP; - - //! Deletes BoyerMyrvoldPlanar on heap - void clear() { delete pBMP; } - - //! The number of extracted Structures for statistical purposes - int nOfStructures; - -public: - //! Constructor - BoyerMyrvold() { pBMP = 0; } - //! Destructor - ~BoyerMyrvold() { clear(); } - - //! The number of extracted Structures for statistical purposes - int numberOfStructures() { return nOfStructures; } - - //! Returns true, iff \a g is planar - /** This is the routine, which avoids the overhead of copying the input graph. - * It is therefore not suitable, if your graph must not be alterated! - */ - virtual bool isPlanarDestructive(Graph& g); - - //! Returns true, iff a copy of the constant graph \a g is planar - /** Use this slower routine, if your graph must not be alterated. - */ - virtual bool isPlanar(const Graph& g); - - //! Returns true, if G is planar, false otherwise. If true, G contains a planar embedding. - virtual bool planarEmbed(Graph &G) { - SList list; - return planarEmbed(G,list); - } - - //! Constructs a planar embedding of G. \a G \b has to be planar! - /** - * Returns true if the embedding was successful. - * Returns false, if the given graph was non-planar (and leaves the - * graph in an at least partially deleted state) - * - * This routine is slightly faster than planarEmbed, but requires \a G to be planar. - * If \a G is not planar, the graph will be destroyed while trying to embed it! - */ - virtual bool planarEmbedPlanarGraph(Graph &G) { - SList list; - return planarEmbedDestructive(G,list); - } - - - - - //! Transforms KuratowskiWrapper in KuratowskiSubdivision - void transform( - const KuratowskiWrapper& source, - KuratowskiSubdivision& target, - NodeArray& count, - EdgeArray& countEdge); - - //! Transforms KuratowskiWrapper-List in KuratowskiSubdivision-List with respect to sieving constraints - void transform( - const SList& sourceList, - SList& targetList, - const Graph& g, - const bool onlyDifferent = false); - - - - //! Returns an embedding, if \a g is planar and Kuratowski Subdivisions otherwise - /** If \a g is planar, the adjLists of \a g specify a planar embedding. - * Use this function, if \a g may be changed. - * @param g is the input graph. - * @param output contains a number of Kuratowski Subdivisions depending on the other parameters - * @param embeddingGrade is a flag bounding the number of extracted subdivisions - * @param bundles extracts much more subdivisions, if set - * @param limitStructures limits the number of Kuratowski Structures to \a embeddingGrade, if set - * @param randomDFSTree randomizes Kuratowski extraction through randomizing the DFSTree, if set - * @param avoidE2Minors avoids all \a E2-Minors and ensures unique subdivisions, if set - */ - bool planarEmbedDestructive( - Graph& g, - SList& output, - int embeddingGrade = BoyerMyrvoldPlanar::doNotFind, - bool bundles = false, - bool limitStructures = false, - bool randomDFSTree = false, - bool avoidE2Minors = true); - - //! Returns an embedding, if \a g is planar and Kuratowski Subdivisions otherwise - /** If \a g is planar, the adjLists of \a g specify a planar embedding. The function - * copies the graph before computation. Use this function, if \a g must not be changed in - * the non-planar case. - * @param g is the input graph. - * @param output contains a number of Kuratowski Subdivisions depending on the other parameters - * @param embeddingGrade is a flag bounding the number of extracted subdivisions - * @param bundles extracts much more subdivisions, if set - * @param limitStructures limits the number of Kuratowski Structures to \a embeddingGrade, if set - * @param randomDFSTree randomizes Kuratowski extraction through randomizing the DFSTree, if set - * @param avoidE2Minors avoids all \a E2-Minors and ensures unique subdivisions, if set - */ - bool planarEmbed( - Graph& g, - SList& output, - int embeddingGrade = BoyerMyrvoldPlanar::doNotFind, - bool bundles = false, - bool limitStructures = false, - bool randomDFSTree = false, - bool avoidE2Minors = true); - - //! Returns an embedding, if graph copy \a h is planar and Kuratowski Subdivisions otherwise - /** If \a h is planar, the adjLists of \a h specify a planar embedding. The function - * copies the graph before computation. Use this function, if \a g must not be changed. - * @param h is the input graph copy. - * @param output contains a number of Kuratowski Subdivisions depending on the other parameters - * @param embeddingGrade is a flag bounding the number of extracted subdivisions - * @param bundles extracts much more subdivisions, if set - * @param limitStructures limits the number of Kuratowski Structures to \a embeddingGrade, if set - * @param randomDFSTree randomizes Kuratowski extraction through randomizing the DFSTree, if set - * @param avoidE2Minors avoids all \a E2-Minors and ensures unique subdivisions, if set - */ - bool planarEmbed( - //const Graph& g, - GraphCopySimple& h, - SList& output, - int embeddingGrade = BoyerMyrvoldPlanar::doNotFind, - bool bundles = false, - bool limitStructures = false, - bool randomDFSTree = false, - bool avoidE2Minors = true); -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/planarity/EdgeTypePatterns.h b/ext/OGDF/ogdf/planarity/EdgeTypePatterns.h deleted file mode 100644 index 985f242d5..000000000 --- a/ext/OGDF/ogdf/planarity/EdgeTypePatterns.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Edge types and patterns for planar representations - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//edge type patterns: - //FOUR TYPE LEVELS: - //primary holds information about generalization/association,... - //secondary about merger edges,... - //user edge types can be set locally - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_TYPE_PATTERNS_H -#define OGDF_EDGE_TYPE_PATTERNS_H - -namespace ogdf { - - typedef long edgeType; - - enum UMLEdgeTypePatterns { - etpPrimary = 0x0000000f, - etpSecondary = 0x000000f0, - etpTertiary = 0x00000f00, - etpFourth = 0x0000f000, - etpUser = 0xff000000, - etpAll = 0xffffffff - }; //!!!attention sign, 7fffffff - - enum UMLEdgeTypeConstants { - //primary types (should be disjoint bits) - etcPrimAssociation = 0x1, etcPrimGeneralization = 0x2, etcPrimDependency = 0x4, - //secondary types: reason of insertion (should be disjoint types, but not bits, - //but may not completely cover others that are allowed to be set together) - //preliminary: setsecondarytype deletes old type - //edge in Expansion, dissection edge, face splitter, cluster boundary - etcSecExpansion = 0x1, etcSecDissect = 0x2, etcSecFaceSplitter = 0x3, - etcSecCluster = 0x4, etcSecClique, //the boundaries - //tertiary types: special types - //merger edge, vertical in hierarchy, alignment, association class connnection - etcMerger = 0x1, etcVertical = 0x2, etcAlign = 0x3, etcAssClass = 0x8, - //fourth types: relation of nodes - //direct neighbours in hierarchy = brother, neighbour = halfbrother - //same level = cousin, to merger = ToMerger, from Merger = FromMerger - etcBrother = 0x1, etcHalfBrother = 0x2, etcCousin = 0x3, - //fifth level types - etcFifthToMerger = 0x1, etcFifthFromMerger = 0x2 - //user type hint: what you have done with the edge, e.g. brother edge - //that is embedded crossing free and should be drawn bend free - }; - enum UMLEdgeTypeOffsets { - etoPrimary = 0, etoSecondary = 4, etoTertiary = 8, etoFourth = 12, etoFifth = 16, - etoUser = 24 - }; - -} //end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/EmbedderMaxFace.h b/ext/OGDF/ogdf/planarity/EmbedderMaxFace.h deleted file mode 100644 index b88a2e57f..000000000 --- a/ext/OGDF/ogdf/planarity/EmbedderMaxFace.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * $Revision: 2589 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 23:31:45 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with maximum external face. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MAX_FACE_H -#define OGDF_EMBEDDER_MAX_FACE_H - -#include -#include -#include - -namespace ogdf { - -//! Planar graph embedding with maximum external face. -/** - * See the paper "Graph Embedding with Minimum Depth and Maximum External - * Face" by C. Gutwenger and P. Mutzel (2004) for details. - */ -class OGDF_EXPORT EmbedderMaxFace : public EmbedderModule -{ -public: - //constructor and destructor - EmbedderMaxFace() { } - ~EmbedderMaxFace() { } - - /** - * \brief Computes an embedding of \a G with maximum external face. - * \param G is the original graph. Its adjacency list has to be changed by the embedder. - * \param adjExternal is assigned an adjacency entry on the external face and has to be set by the embedder. - */ - void call(Graph& G, adjEntry& adjExternal); - -private: - /** - * \brief Computes recursively the block graph for every block. - * - * \param bT is a block node in the BC-tree. - * \param cH is a node of bT in the block graph. - */ - void computeBlockGraphs(const node& bT, const node& cH); - - /** - * \brief Bottom up traversal of BC-tree. - * - * \param bT is the BC-tree node treated in this function call. - * \param cH is the block node which is related to the cut vertex which is - * parent of bT in BC-tree. - */ - int constraintMaxFace(const node& bT, const node& cH); - - /** - * \brief Top down traversal of BC-tree. - * - * \param bT is the tree node treated in this function call. - * \param bT_opt is assigned a block node in BC-tree which contains a face which - * cann be expanded to a maximum face. - * \param ell_opt is the size of a maximum face. - */ - void maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - */ - void embedBlock(const node& bT); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - * \param cT is the parent cut vertex node of bT in the BC-tree. cT is 0 if bT - * is the root block. - * \param after is the adjacency entry of the cut vertex, after which bT has to - * be inserted. - */ - void embedBlock(const node& bT, const node& cT, ListIterator& after); - -private: - /** BC-tree of the original graph */ - BCTree* pBCTree; - - /** an adjacency entry on the external face */ - adjEntry* pAdjExternal; - - /** all blocks */ - NodeArray blockG; - - /** a mapping of nodes in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< NodeArray > nH_to_nBlockEmbedding; - - /** a mapping of edges in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< EdgeArray > eH_to_eBlockEmbedding; - - /** a mapping of nodes in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< NodeArray > nBlockEmbedding_to_nH; - - /** a mapping of edges in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< EdgeArray > eBlockEmbedding_to_eH; - - /** saving for each node in the block graphs its length */ - NodeArray< NodeArray > nodeLength; - - /** is saving for each node in the block graphs its cstrLength */ - NodeArray< NodeArray > cstrLength; - - /** saves for every node of PG the new adjacency list */ - NodeArray< List > newOrder; - - /** treeNodeTreated saves for all block nodes in the - * BC-tree if it has already been treated or not. */ - NodeArray treeNodeTreated; - - /** The SPQR-trees of the blocks */ - NodeArray spqrTrees; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/EmbedderMaxFaceLayers.h b/ext/OGDF/ogdf/planarity/EmbedderMaxFaceLayers.h deleted file mode 100644 index cd4e974b5..000000000 --- a/ext/OGDF/ogdf/planarity/EmbedderMaxFaceLayers.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * $Revision: 2589 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 23:31:45 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with maximum external face (plus layers approach). - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MAX_FACE_LAYERS_H -#define OGDF_EMBEDDER_MAX_FACE_LAYERS_H - -#include -#include -#include - -namespace ogdf { - -//! Planar graph embedding with maximum external face (plus layers approach). -/** - * See the paper "Graph Embedding with Minimum Depth and Maximum External - * Face" by C. Gutwenger and P. Mutzel (2004) for details. - * The algorithm for maximum external face is combined with the - * algorithm for maximum external layers which defines how to embed - * blocks into inner faces. See diploma thesis "Algorithmen zur - * Bestimmung von guten Graph-Einbettungen für orthogonale - * Zeichnungen" (in german) by Thorsten Kerkhof (2007) for details. - */ -class OGDF_EXPORT EmbedderMaxFaceLayers : public EmbedderModule -{ -public: - //constructor and destructor - EmbedderMaxFaceLayers() { } - ~EmbedderMaxFaceLayers() { } - - /** - * \brief Computes an embedding of \a G with maximum external face. - * \param G is the original graph. Its adjacency list has to be changed by the embedder. - * \param adjExternal is assigned an adjacency entry on the external face and has to be set by the embedder. - */ - void call(Graph& G, adjEntry& adjExternal); - -private: - /** - * \brief Computes recursively the block graph for every block. - * - * \param bT is a block node in the BC-tree. - * \param cH is a node of bT in the block graph. - */ - void computeBlockGraphs(const node& bT, const node& cH); - - /** - * \brief Bottom up traversal of BC-tree. - * - * \param bT is the BC-tree node treated in this function call. - * \param cH is the block node which is related to the cut vertex which is - * parent of bT in BC-tree. - */ - int constraintMaxFace(const node& bT, const node& cH); - - /** - * \brief Top down traversal of BC-tree. - * - * \param bT is the tree node treated in this function call. - * \param bT_opt is assigned a block node in BC-tree which contains a face which - * can be expanded to a maximum face. - * \param ell_opt is the size of a maximum face. - */ - void maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - */ - void embedBlock(const node& bT); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - * \param cT is the parent cut vertex node of bT in the BC-tree. cT is 0 if bT - * is the root block. - * \param after is the adjacency entry of the cut vertex, after which bT has to - * be inserted. - */ - void embedBlock(const node& bT, const node& cT, ListIterator& after); - -private: - /** BC-tree of the original graph */ - BCTree* pBCTree; - - /** an adjacency entry on the external face */ - adjEntry* pAdjExternal; - - /** all blocks */ - NodeArray blockG; - - /** a mapping of nodes in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< NodeArray > nH_to_nBlockEmbedding; - - /** a mapping of edges in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< EdgeArray > eH_to_eBlockEmbedding; - - /** a mapping of nodes in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< NodeArray > nBlockEmbedding_to_nH; - - /** a mapping of edges in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< EdgeArray > eBlockEmbedding_to_eH; - - /** saving for each node in the block graphs its length */ - NodeArray< NodeArray > nodeLength; - - /** is saving for each node in the block graphs its cstrLength */ - NodeArray< NodeArray > cstrLength; - - /** saves for every node of G the new adjacency list */ - NodeArray< List > newOrder; - - /** treeNodeTreated saves for all block nodes in the - * BC-tree if it has already been treated or not. */ - NodeArray treeNodeTreated; - - /** The SPQR-trees of the blocks */ - NodeArray spqrTrees; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/EmbedderMinDepth.h b/ext/OGDF/ogdf/planarity/EmbedderMinDepth.h deleted file mode 100644 index 56494ebb6..000000000 --- a/ext/OGDF/ogdf/planarity/EmbedderMinDepth.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * $Revision: 2589 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 23:31:45 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with minimum depth. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MIN_DEPTH_H -#define OGDF_EMBEDDER_MIN_DEPTH_H - -#include -#include -#include - -namespace ogdf { - -//! Planar graph embedding with minimum block-nesting depth. -/** - * See paper "Graph Embedding with Minimum Depth and Maximum External - * Face" by C. Gutwenger and P. Mutzel (2004) for details. - */ -class OGDF_EXPORT EmbedderMinDepth : public EmbedderModule -{ -public: - //constructor - EmbedderMinDepth() { } - - /** - * \brief Computes an embedding of \a G with minimum depth. - * - * \param G is the original graph. - * \param adjExternal is assigned an adjacency entry in the external face. - */ - void call(Graph& G, adjEntry& adjExternal); - -private: - /** - * \brief Computes recursively the block graph for every block. - * - * \param bT is a block node in the BC-tree. - * \param cH is a node of bT in the block graph. - */ - void computeBlockGraphs(const node& bT, const node& cH); - - /** - * \brief Bottom-up-traversal of bcTree computing the values \a m_{cT, bT} - * for all edges \a (cT, bT) in the BC-tree. The length of each vertex - * \f$v \neq c in \a bT\f$ is set to 1 if \f$v \in M_{bT}\f$ and to 0 otherwise. - * - * \param bT is a block vertex in the BC-tree. - * \param cH is a vertex in the original graph \a G. - * \return Minimum depth of an embedding of \a bT with \a cH on the external - * face. - */ - int bottomUpTraversal(const node& bT, const node& cH); - - /** - * \brief Top-down-traversal of BC-tree. The minimum depth of the BC-tree-node - * bT is calculated and before calling the function recursively for all - * children of bT in the BC-tree, the nodeLength of the cut-vertex which bT - * and the child have in common is computed. The length of each node is set to - * 1 if it is in M_B and 0 otherwise, except for |M_B| = 1, than it is set to - * 1 if it is in M2 with m2 = \f$\max_{v \in V_B, v != c} m_B(v)\f$ and - * M2 = \f${c \in V_B \ {v} | m_B(c) = m2}\f$. - * - * \param bT is a block vertex in the BC-tree. - */ - void topDownTraversal(const node& bT); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - */ - void embedBlock(const node& bT); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - * \param cT is the parent cut vertex node of bT in the BC-tree. cT is 0 if bT - * is the root block. - * \param after is the adjacency entry of the cut vertex, after which bT has to - * be inserted. - */ - void embedBlock(const node& bT, const node& cT, ListIterator& after); - -private: - /** BC-tree of the original graph */ - BCTree* pBCTree; - - /** an adjacency entry on the external face */ - adjEntry* pAdjExternal; - - /** all blocks */ - NodeArray blockG; - - /** a mapping of nodes in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< NodeArray > nH_to_nBlockEmbedding; - - /** a mapping of edges in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< EdgeArray > eH_to_eBlockEmbedding; - - /** a mapping of nodes in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< NodeArray > nBlockEmbedding_to_nH; - - /** a mapping of edges in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< EdgeArray > eBlockEmbedding_to_eH; - - /** saving for each node in the block graphs its length */ - NodeArray< NodeArray > nodeLength; - - /** an array containing the minimum depth of each block */ - NodeArray minDepth; - - /** an array saving the length for each edge in the BC-tree */ - EdgeArray m_cB; - - /** - * M_B = \f${cH \in B | m_B(cH) = m_B}\f$ with m_B = \f$\max_{c \in B} m_B(c)\f$ - * and m_B(c) = \f$\max {0} \cup {m_{c, B'} | c \in B', B' \neq B}\f$. - */ - NodeArray< List > M_B; - - /** - * M2 is empty, if |M_B| != 1, otherwise M_B = {cH} - * M2 = \f${cH' \in V_B \ {v} | m_B(cH') = m2}\f$ with - * m2 = \f$\max_{vH \in V_B, vH != cH} m_B(vH)\f$. - */ - NodeArray< List > M2; - - /** saves for every node of G the new adjacency list */ - NodeArray< List > newOrder; - - /** treeNodeTreated saves for all block nodes in the - * BC-tree if it has already been treated or not. */ - NodeArray treeNodeTreated; - - /** The SPQR-trees of the blocks */ - NodeArray spqrTrees; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFace.h b/ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFace.h deleted file mode 100644 index 75a70872c..000000000 --- a/ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFace.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * $Revision: 2589 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 23:31:45 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with minimum depth and - * maximum external face. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MIN_DEPTH_MAX_FACE_H -#define OGDF_EMBEDDER_MIN_DEPTH_MAX_FACE_H - -#include -#include -#include - -namespace ogdf { - -//! Planar graph embedding with minimum block-nesting depth and maximum external face. -/** - * See the paper "Graph Embedding with Minimum Depth and Maximum External Face" - * by C. Gutwenger and P. Mutzel (2004) for details. - */ -class OGDF_EXPORT EmbedderMinDepthMaxFace : public EmbedderModule -{ -public: - //constructor: - EmbedderMinDepthMaxFace() { } - - /** - * \brief Call embedder algorithm. - * \param G is the original graph. Its adjacency list has to be changed by the embedder. - * \param adjExternal is an adjacency entry on the external face and has to be set by the embedder. - */ - void call(Graph& G, adjEntry& adjExternal); - -private: - /** - * \brief Bottom-up-traversal of bcTree computing the values \a m_{cT, bT} - * for all edges \a (cT, bT) in the BC-tree. The length of each vertex - * \f$v \neq c in \a bT\f$ is set to 1 if \f$v \in M_{bT}\f$ and to 0 otherwise. - * - * \param bT is a block vertex in the BC-tree. - * \param cH is a vertex in the original graph \a G. - * \return Minimum depth of an embedding of \a bT with \a cH on the external - * face. - */ - int md_bottomUpTraversal(const node& bT, const node& cH); - - /** - * \brief Top-down-traversal of BC-tree. The minimum depth of the BC-tree-node - * bT is calculated and before calling the function recursively for all - * children of bT in the BC-tree, the nodeLength of the cut-vertex which bT - * and the child have in common is computed. The length of each node is set to - * 1 if it is in M_B and 0 otherwise, except for |M_B| = 1, than it is set to - * 1 if it is in M2 with m2 = \f$\max_{v \in V_B, v != c} m_B(v)\f$ and - * M2 = \f${c \in V_B \ {v} | m_B(c) = m2}\f$. - * - * \param bT is a block vertex in the BC-tree. - */ - void md_topDownTraversal(const node& bT); - - /** - * \brief Bottom up traversal of BC-tree. - * - * \param bT is the BC-tree node treated in this function call. - * \param cH is the block node which is related to the cut vertex which is - * parent of bT in BC-tree. - */ - int mf_constraintMaxFace(const node& bT, const node& cH); - - /** - * \brief Top down traversal of BC-tree. - * - * \param bT is the tree node treated in this function call. - * \param bT_opt is assigned a block node in BC-tree which contains a face which - * cann be expanded to a maximum face. - * \param ell_opt is the size of a maximum face. - */ - void mf_maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - */ - void embedBlock(const node& bT); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - * \param cT is the parent cut vertex node of bT in the BC-tree. cT is 0 if bT - * is the root block. - * \param after is the adjacency entry of the cut vertex, after which bT has to - * be inserted. - */ - void embedBlock(const node& bT, const node& cT, ListIterator& after); - -private: - /** the BC-tree of G */ - BCTree* pBCTree; - - /** an adjacency entry on the external face */ - adjEntry* pAdjExternal; - - /** saving for each node in the block graph its length */ - NodeArray md_nodeLength; - - /** an array containing the minimum depth of each block */ - NodeArray md_minDepth; - - /** an array saving the length for each edge in the BC-tree */ - EdgeArray md_m_cB; - - /** M_B = \f${cH \in B | m_B(cH) = m_B}\f$ with m_B = \f$\max_{c \in B} m_B(c)\f$ - * and m_B(c) = \f$\max {0} \cup {m_{c, B'} | c \in B', B' \neq B}\f$. */ - NodeArray< List > md_M_B; - - /** M2 is empty, if |M_B| != 1, otherwise M_B = {cH} - * M2 = \f${cH' \in V_B \ {v} | m_B(cH') = m2}\f$ with - * m2 = \f$\max_{vH \in V_B, vH != cH} m_B(vH)\f$. */ - NodeArray< List > md_M2; - - /** is saving for each node of the block graph its length */ - NodeArray mf_nodeLength; - - /** is saving for each node of the block graph its cstrLength */ - NodeArray mf_cstrLength; - - /** an array containing the maximum face size of each block */ - NodeArray mf_maxFaceSize; - - /** is saving for each node of the block graph its length */ - NodeArray mdmf_nodeLength; - - /** is saving for each edge of the block graph its length */ - EdgeArray mdmf_edgeLength; - - /** saves for every node of G the new adjacency list */ - NodeArray< List > newOrder; - - /** treeNodeTreated saves for all block nodes in the - * BC-tree if it has already been treated or not. */ - NodeArray treeNodeTreated; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFaceLayers.h b/ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFaceLayers.h deleted file mode 100644 index 54da9277d..000000000 --- a/ext/OGDF/ogdf/planarity/EmbedderMinDepthMaxFaceLayers.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * $Revision: 2584 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 02:38:07 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with minimum depth and - * maximum external face (plus layers approach). - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MIN_DEPTH_MAX_FACE_Layers_H -#define OGDF_EMBEDDER_MIN_DEPTH_MAX_FACE_Layers_H - -#include -#include -#include - -namespace ogdf { - -//! Planar graph embedding with minimum block-nesting depth and maximum external face (plus layers approach). -/** - * See paper "Graph Embedding with Minimum Depth and Maximum External Face" - * by C. Gutwenger and P. Mutzel (2004) for details. - * The algorithm for minimum depth and maximum external face is combined with the - * algorithm for maximum external layers which defines how to embed - * blocks into inner faces. See diploma thesis "Algorithmen zur - * Bestimmung von guten Graph-Einbettungen für orthogonale - * Zeichnungen" (in german) by Thorsten Kerkhof (2007) for details. - */ -class OGDF_EXPORT EmbedderMinDepthMaxFaceLayers : public EmbedderModule -{ -public: - //constructor: - EmbedderMinDepthMaxFaceLayers() { } - - /** - * \brief Call embedder algorithm. - * \param G is the original graph. Its adjacency list has to be changed by the embedder. - * \param adjExternal is an adjacency entry on the external face and has to be set by the embedder. - */ - void call(Graph& G, adjEntry& adjExternal); - -private: - /** - * \brief Bottom-up-traversal of bcTree computing the values \a m_{cT, bT} - * for all edges (\a cT, \a bT) in the BC-tree. The length of each vertex - * \f$ v \neq c \f$ in \a bT is set to 1 if \f$ v \in M_{bT}\f$ and to 0 otherwise. - * - * \param bT is a block vertex in the BC-tree. - * \param cH is a vertex in the original graph \a G. - * \return Minimum depth of an embedding of \a bT with \a cH on the external - * face. - */ - int md_bottomUpTraversal(const node& bT, const node& cH); - - /** - * \brief Top-down-traversal of BC-tree. The minimum depth of the BC-tree-node - * bT is calculated and before calling the function recursively for all - * children of bT in the BC-tree, the nodeLength of the cut-vertex which bT - * and the child have in common is computed. The length of each node is set to - * 1 if it is in M_B and 0 otherwise, except for |M_B| = 1, than it is set to - * 1 if it is in M2 with m2 = \f$\max_{v \in V_B, v != c} m_B(v)\f$ and - * M2 = \f${c \in V_B \ {v} | m_B(c) = m2}\f$. - * - * \param bT is a block vertex in the BC-tree. - */ - void md_topDownTraversal(const node& bT); - - /** - * \brief Bottom up traversal of BC-tree. - * - * \param bT is the BC-tree node treated in this function call. - * \param cH is the block node which is related to the cut vertex which is - * parent of bT in BC-tree. - */ - int mf_constraintMaxFace(const node& bT, const node& cH); - - /** - * \brief Top down traversal of BC-tree. - * - * \param bT is the tree node treated in this function call. - * \param bT_opt is assigned a block node in BC-tree which contains a face that - * can be expanded to a maximum face. - * \param ell_opt is the size of a maximum face. - */ - void mf_maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - */ - void embedBlock(const node& bT); - - /** - * \brief Computes the adjacency list for all nodes in a block and calls - * recursively the function for all blocks incident to nodes in bT. - * - * \param bT is the tree node treated in this function call. - * \param cT is the parent cut vertex node of bT in the BC-tree. cT is 0 if bT - * is the root block. - * \param after is the adjacency entry of the cut vertex, after which bT has to - * be inserted. - */ - void embedBlock(const node& bT, const node& cT, ListIterator& after); - -private: - /** the BC-tree of G */ - BCTree* pBCTree; - - /** an adjacency entry on the external face */ - adjEntry* pAdjExternal; - - /** saving for each node in the block graph its length */ - NodeArray md_nodeLength; - - /** an array containing the minimum depth of each block */ - NodeArray md_minDepth; - - /** an array saving the length for each edge in the BC-tree */ - EdgeArray md_m_cB; - - /** M_B = \f${cH \in B | m_B(cH) = m_B}\f$ with m_B = \f$\max_{c \in B} m_B(c)\f$ - * and m_B(c) = \f$\max {0} \cup {m_{c, B'} | c \in B', B' \neq B}\f$. */ - NodeArray< List > md_M_B; - - /** M2 is empty, if |M_B| != 1, otherwise M_B = {cH} - * M2 = \f${cH' \in V_B \ {v} | m_B(cH') = m2}\f$ with - * m2 = \f$\max_{vH \in V_B, vH != cH} m_B(vH)\f$. */ - NodeArray< List > md_M2; - - /** is saving for each node of the block graph its length */ - NodeArray mf_nodeLength; - - /** is saving for each node of the block graph its cstrLength */ - NodeArray mf_cstrLength; - - /** an array containing the maximum face size of each block */ - NodeArray mf_maxFaceSize; - - /** is saving for each node of the block graph its length */ - NodeArray mdmf_nodeLength; - - /** is saving for each edge of the block graph its length */ - EdgeArray mdmf_edgeLength; - - /** saves for every node of G the new adjacency list */ - NodeArray< List > newOrder; - - /** treeNodeTreated saves for all block nodes in the - * BC-tree if it has already been treated or not. */ - NodeArray treeNodeTreated; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/EmbedderMinDepthPiTa.h b/ext/OGDF/ogdf/planarity/EmbedderMinDepthPiTa.h deleted file mode 100644 index 5c1d209ed..000000000 --- a/ext/OGDF/ogdf/planarity/EmbedderMinDepthPiTa.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief The algorithm computes a planar embedding with minimum - * depth if the embedding for all blocks of the graph is given. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EMBEDDER_MIN_DEPTH_PITA_H -#define OGDF_EMBEDDER_MIN_DEPTH_PITA_H - - -#include -#include - - -namespace ogdf { - -//! Planar graph embedding with minimum block-nesting depth for given embedded blocks. -/** - * For details see the paper "Minimum Depth Graph Drawing" by M. Pizzonia and R. Tamassia. - */ -class OGDF_EXPORT EmbedderMinDepthPiTa : public EmbedderModule -{ -public: - //constructor - EmbedderMinDepthPiTa() : m_useExtendedDepthDefinition(true) { } - - /** - * \brief Computes an embedding of \a G. - * - * \param G is the original graph. - * \param adjExternal is assigned an adjacency entry on the external face. - */ - void call(Graph& G, adjEntry& adjExternal); - - bool useExtendedDepthDefinition() const { return m_useExtendedDepthDefinition; } - void useExtendedDepthDefinition(bool b) { m_useExtendedDepthDefinition = b; } - -private: - bool m_useExtendedDepthDefinition; - - /** - * \brief Computes recursively an embedding for every block by using the - * planarEmbed function. - * - * \param bT is a block node in the BC-tree. - * \param cH is a node of bT in the auxiliary graph. - */ - void embedBlocks(const node& bT, const node& cH); - - /** - * \brief Computes entry in newOrder for a cutvertex. - * - * \param vT is a cut vertex node in the BC-tree. - * \param root is true if vT is the root node of the block-cutface tree. - */ - void embedCutVertex(const node& vT, bool root = false); - - /** - * \brief Computes entries in newOrder for nodes in a block. - * - * \param bT is a node in the BC-tree. - * \param parent_cT is a node in the BC-tree. - */ - void embedBlockVertex(const node& bT, const node& parent_cT); - - /** - * \brief Computes recursively edge lengths for the block-cutface tree. The length - * of an edge from n to a leaf is 1, from n' to n 2 etc. - * - * \param n is a node in the block-cutface tree. - */ - int computeBlockCutfaceTreeEdgeLengths(const node& n); - - /** - * \brief Computes recursively the diametral tree. - * - * \param n is a node in the block-cutface tree. - */ - void computeTdiam(const node& n); - - /** - * \brief Directs all edges to \a n and recursively all edges of its children - - * except the edge to \a n - to the child. - * - * \param G is the tree with the inverted edges. - * \param n is a node in the original tree. - * \param e is an edge in the original tree. - */ - void invertPath(Graph& G, const node& n, const edge& e); - - /** - * \brief Computes for a block bDG of the dual graph the associated block - * in the original graph. - * - * \param bDG is a node in the block-cutface tree. - * \param parent is the parent of bDG in the block-cutface tree. - * \param blocksNodes is assigned a list containing all nodes of the original - * graph of the associated block of bDG. - * \param childBlocks - */ - node computeBlockMapping( - const node& bDG, - const node& parent, - List& blocksNodes, - List& childBlocks); - - /** - * \brief Computes the eccentricity of a node nT in the block-cutface tree - * to all nodes further down in the tree and recursively the eccentricity - * to all nodes yet further down its children. - * - * \param nT is a node in the block-cutface tree. - */ - int eccentricityBottomUp(const node& nT); - - /** - * \brief Computes the eccentricity of a node nT in the block-cutface tree - * and recursively the eccentricity of its children. - * - * \param nT is a node in the block-cutface tree. - */ - void eccentricityTopDown(const node& nT); - - /** - * \brief Computes the depth of an embedding Gamma(B). - * - * \param bT is a block-node of the BC-tree. - */ - int depthBlock(const node& bT); - - /** - * \brief Computes the depth of an embedding Gamma(c). - * - * \param cT is a cutvertex-node of the BC-tree. - */ - int depthCutvertex(const node& cT); - - /** - * \brief Deletes inserted dummy nodes. If adjExternal is an adjacency entry - * of a dummy edge it is reset. - * - * \param G is the graph. - * \param adjExternal is an adjacency entry on the external face. - */ - void deleteDummyNodes(Graph& G, adjEntry& adjExternal); - -private: - /** the BC-tree of G */ - BCTree* pBCTree; - - /** the tree of pBCTree rooted at a cutface. */ - Graph bcTreePG; - - /** a mapping of nodes in bcTreePG to nodes in pBCTree->bcTree() */ - NodeArray nBCTree_to_npBCTree; - - /** a mapping of nodes in pBCTree->bcTree() to nodes in bcTreePG */ - NodeArray npBCTree_to_nBCTree; - - /** an adjacency entry on the external face */ - adjEntry* pAdjExternal; - - /** all blocks */ - NodeArray blockG; - - /** a mapping of nodes in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< NodeArray > nH_to_nBlockEmbedding; - - /** a mapping of edges in the auxiliaryGraph of the BC-tree to blockG */ - NodeArray< EdgeArray > eH_to_eBlockEmbedding; - - /** a mapping of nodes in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< NodeArray > nBlockEmbedding_to_nH; - - /** a mapping of edges in blockG to the auxiliaryGraph of the BC-tree */ - NodeArray< EdgeArray > eBlockEmbedding_to_eH; - - /** saving for each node in the block graphs its length */ - NodeArray< NodeArray > nodeLength; - - /** an array saving the length for each edge in the BC-tree */ - EdgeArray m_cB; - - /** - * \f$M_B = {cH \in B | m_B(cH) = m_B}\f$ with \f$m_B = \max_{c \in B} m_B(c)\f$ - * and \f$m_B(c) = \max {0} \cup {m_{c, B'} | c \in B', B' \neq B}\f$. - */ - NodeArray< List > M_B; - - /** Saving edge lengths for the block-cutface tree. */ - EdgeArray edgeLength_blockCutfaceTree; - - /** The diametrical tree of the block-cutface tree. */ - Graph Tdiam; - - /** Needed in computeTdiam function to know if first vertex was already inserted */ - bool Tdiam_initialized; - - /** Mapping nodes from block-cutvertex tree to the diametrical tree */ - NodeArray nBlockCutfaceTree_to_nTdiam; - - /** Mapping nodes from the diametrical tree to block-cutvertex tree*/ - NodeArray nTdiam_to_nBlockCutfaceTree; - - /** The knot of the diametrical tree */ - node knotTdiam; - - /** adjacency entry of the external face of the embedding of G */ - adjEntry tmpAdjExtFace; - - /** - * a list of all faces in G, a face in this list is containing a list of all - * adjacency entries - */ - List< List > faces; - - /** mapping faces in G to nodes in DG */ - List fPG_to_nDG; - - /** mapping nodes in DG to faces in DG */ - NodeArray nDG_to_fPG; - - /** the block-cutface tree of G (only the graph, rooted at the external face */ - Graph blockCutfaceTree; - - /** the block-cutface tree of G (the BC-tree of the dual graph) */ - BCTree* pm_blockCutfaceTree; - - /** mapping of nodes from the graph blockCutfaceTree to the BC-tree m_blockCutfaceTree */ - NodeArray nBlockCutfaceTree_to_nm_blockCutfaceTree; - - /** mapping of nodes from the BC-tree m_blockCutfaceTree to the graph blockCutfaceTree */ - NodeArray nm_blockCutfaceTree_to_nBlockCutfaceTree; - - /** a mapping of blocks of the graph G to its dual graph DG */ - NodeArray bPG_to_bDG; - - /** a mapping of blocks of the dual graph DG to its original graph G */ - NodeArray bDG_to_bPG; - - /** saving second highest eccentricity for every node of the block-cutface tree */ - NodeArray eccentricity_alt; - - /** saving eccentricity for every node of the block-cutface tree */ - NodeArray eccentricity; - - /** - * list of nodes which are only in one block which exists of extactly this - * node plus a cutvertex - */ - List oneEdgeBlockNodes; - - /** - * this list is saving the dummy nodes which were inserted to produce a face - * in one-edge-blocks - */ - List dummyNodes; - - /** saves for every node of G the new adjacency list */ - NodeArray< List > newOrder; - - /** - * given a node nT (cutvertex or block), G_nT is the subgraph of G - * associated with the subtree of the BC-tree T rooted at nT - */ - NodeArray G_nT; - - /** a mapping of nodes in G_nT to nodes in G */ - NodeArray< NodeArray > nG_nT_to_nPG; - - /** a mapping of nodes in G to nodes in G_nT */ - NodeArray< NodeArray > nPG_to_nG_nT; - - /** a mapping of edges in G_nT to edges in G */ - NodeArray< EdgeArray > eG_nT_to_ePG; - - /** a mapping of edges in G to edges in G_nT */ - NodeArray< EdgeArray > ePG_to_eG_nT; - - /** adjacency entry of the external face of G_nT[nT] */ - NodeArray Gamma_adjExt_nT; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/ExtractKuratowskis.h b/ext/OGDF/ogdf/planarity/ExtractKuratowskis.h deleted file mode 100644 index 18f8a9e44..000000000 --- a/ext/OGDF/ogdf/planarity/ExtractKuratowskis.h +++ /dev/null @@ -1,474 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the class ExtractKuratowskis - * - * \author Jens Schmidt - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EXTRACT_KURATOWSKIS_H -#define OGDF_EXTRACT_KURATOWSKIS_H - -#include -#include -#include - -namespace ogdf { - - -//! Extracts all possible paths with backtracking using given edges and special constraints -class OGDF_EXPORT DynamicBacktrack { - public: - //! Constructor - DynamicBacktrack( - const Graph& g, - const NodeArray& dfi, - const EdgeArray& flags) - : m_flags(flags), - m_dfi(dfi), - m_parent(g,NULL) { - } - - //! Reinitializes backtracking with new constraints. All paths will be traversed again. - /** Startedges are either only \a startInclude or not \a startExclude, all startedges - * have to contain the flag \a startFlag, if \a startFlag != 0. The \a start- and \a endnode - * of extracted paths is given, too. - */ - void init( - const node start, - const node end, - const bool less, - const int flag, - const int startFlag, - const edge startInclude, - const edge startExlude); - - //! Returns next possible path from \a start- to \a endnode, if exists. - /** The path is returned to \a list. After that a process image is made, - * allowing to pause backtracking and extracting further paths later. - * \a Endnode returns the last traversed node. - */ - bool addNextPath(SListPure& list, node& endnode); - - //! Returns next possible path under constraints from \a start- to \a endnode, if exists. - /** All paths avoid \a exclude-edges, except if on an edge with flag \a exceptOnEdge. - * The NodeArray \a nodeflags is used to mark visited nodes. Only that part of the path, - * which doesn't contain \a exclude-edges is finally added. - * The path is returned to \a list. After that a process image is made, - * allowing to pause backtracking and extracting further paths later. - * \a Endnode returns the last traversed node. - */ - bool addNextPathExclude(SListPure& list, - node& endnode, - const NodeArray& nodeflags, - int exclude, - int exceptOnEdge); - - // avoid automatic creation of assignment operator - //! Assignment is not defined! - DynamicBacktrack &operator=(const DynamicBacktrack &); - - //! Marks an edge with three Flags: externalPath, pertinentPath and/or singlePath - enum enumKuratowskiFlag { - externalPath = 0x00001, // external paths, e.g. stopX->Ancestor - pertinentPath = 0x00002, // pertinent paths, e.g. wNode->V - singlePath = 0x00004, // marker for one single path - }; - - protected: - //! Flags, that partition the edges into pertinent and external subgraphs - const EdgeArray& m_flags; - //! The one and only DFI-NodeArray - const NodeArray& m_dfi; - - //! Start node of backtracking - node start; - //! Identifies endnodes - node end; - //! Iff true, DFI of endnodes has to be < \a DFI[end], otherwise the only valid endnode is \a end - bool less; - //! Every traversed edge has to be signed with this flag - int flag; - - //! Saves the parent edge for each node in path - NodeArray m_parent; - - //! Backtracking stack. A NULL-element indicates a return from a child node - StackPure stack; -}; - -//! Wrapper-class for Kuratowski Subdivisions containing the minortype and edgelist -class OGDF_EXPORT KuratowskiWrapper { - public: - //! Constructor - KuratowskiWrapper() { } - - //! Returns true, iff subdivision is a K3,3-minor - inline bool isK33() const { return subdivisionType != E5; } - //! Returns true, iff subdivision is a K5-minor - inline bool isK5() const { return subdivisionType == E5; } - - //! Possible minortypes of a Kuratowski Subdivision - enum enumSubdivisionType { - A=0, - AB=1, - AC=2, - AD=3, - AE1=4, - AE2=5, - AE3=6, - AE4=7, - B=8, - C=9, - D=10, - E1=11, - E2=12, - E3=13, - E4=14, - E5=15 - }; - //! Minortype of the Kuratowski Subdivision - int subdivisionType; - - //! The node which was embedded while the Kuratowski Subdivision was found - node V; - - //! Contains the edges of the Kuratowski Subdivision - SListPure edgeList; -}; - -//! Extracts multiple Kuratowski Subdivisions -/** \pre Graph has to be simple. - */ -class ExtractKuratowskis { - public: - //! Constructor - ExtractKuratowskis(BoyerMyrvoldPlanar& bm); - //! Destructor - ~ExtractKuratowskis() { } - - //! Extracts all Kuratowski Subdivisions and adds them to \a output (without bundles) - void extract( - const SListPure& allKuratowskis, - SList& output); - - //! Extracts all Kuratowski Subdivisions and adds them to \a output (with bundles) - void extractBundles( - const SListPure& allKuratowskis, - SList& output); - - //! Enumeration over Kuratowski Type none, K33, K5 - enum enumKuratowskiType { - none = 0, //!< no kuratowski subdivision exists - K33 = 1, //!< a K3,3 subdivision exists - K5 = 2 //!< a K5 subdivision exists - }; - - //! Checks, if \a list forms a valid Kuratowski Subdivision and returns the type - /** - * @return Returns the following value: - * - none = no Kuratowski - * - K33 = the K3,3 - * - K5 = the K5 - */ - static int whichKuratowski( - const Graph& m_g, - const NodeArray& dfi, - const SListPure& list); - - //! Checks, if edges in Array \a edgenumber form a valid Kuratowski Subdivision and returns the type - /** - * \pre The numer of edges has to be 1 for used edges, otherwise 0. - * @return Returns the following value: - * - none = no Kuratowski - * - K33 = the K3,3 - * - K5 = the K5 - */ - static int whichKuratowskiArray( - const Graph& g, - //const NodeArray& m_dfi, - EdgeArray& edgenumber); - - //! Returns true, iff the Kuratowski is not already contained in output - static bool isANewKuratowski( - const Graph& g, - const SListPure& kuratowski, - const SList& output); - //! Returns true, iff the Kuratowski is not already contained in output - /** \pre Kuratowski Edges are all edges != 0 in the Array. - */ - static bool isANewKuratowski( - //const Graph& g, - const EdgeArray& test, - const SList& output); - - // avoid automatic creation of assignment operator - //! Assignment operator is undefined! - ExtractKuratowskis &operator=(const ExtractKuratowskis &); - - protected: - //! Link to class BoyerMyrvoldPlanar - BoyerMyrvoldPlanar& BMP; - - //! Input graph - const Graph& m_g; - - //! Some parameters, see BoyerMyrvold for further instructions - int m_embeddingGrade; - //! Some parameters, see BoyerMyrvold for further instructions - const bool m_avoidE2Minors; - - //! Value used as marker for visited nodes etc. - /** Used during Backtracking and the extraction of some specific minortypes - */ - int m_nodeMarker; - //! Array maintaining visited bits on each node - NodeArray m_wasHere; - - //! The one and only DFI-NodeArray - const NodeArray& m_dfi; - - //! Returns appropriate node from given DFI - const Array& m_nodeFromDFI; - - //! The adjEntry which goes from DFS-parent to current vertex - const NodeArray& m_adjParent; - - //! Adds external face edges to \a list - inline void addExternalFacePath( - SListPure& list, - const SListPure& externPath) { - SListConstIterator itExtern; - for (itExtern = externPath.begin(); itExtern.valid(); ++itExtern) { - list.pushBack((*itExtern)->theEdge()); - } - } - - //! Returns \a adjEntry of the edge between node \a high and a special node - /** The special node is that node with the lowest DFI not less than the DFI of \a low. - */ - inline adjEntry adjToLowestNodeBelow(node high, int low); - - //! Adds DFS-path from node \a bottom to node \a top to \a list - /** \pre Each virtual node has to be merged. - */ - inline void addDFSPath(SListPure& list, node bottom, node top); - //! Adds DFS-path from node \a top to node \a bottom to \a list - /** \pre Each virtual node has to be merged. - */ - inline void addDFSPathReverse(SListPure& list, node bottom, node top); - - //! Separates \a list1 from edges already contained in \a list2 - inline void truncateEdgelist(SListPure& list1, const SListPure& list2); - - //! Extracts minortype A and adds it to list \a output - void extractMinorA( - SList& output, - const KuratowskiStructure& k, - //const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minortype B and adds it to list \a output (no bundles) - void extractMinorB( - SList& output, - //NodeArray& nodeflags, - //const int nodemarker, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minortype B and adds it to list \a output (with bundles) - void extractMinorBBundles( - SList& output, - NodeArray& nodeflags, - const int nodemarker, - const KuratowskiStructure& k, - EdgeArray& flags, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minortype C and adds it to list \a output - void extractMinorC( - SList& output, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minortype D and adds it to list \a output - void extractMinorD( - SList& output, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minortype E and adds it to list \a output (no bundles) - void extractMinorE( - SList& output, - bool firstXPath, - bool firstPath, - bool firstWPath, - bool firstWOnHighestXY, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minortype E and adds it to list \a output (bundles) - void extractMinorEBundles( - SList& output, - bool firstXPath, - bool firstPath, - bool firstWPath, - bool firstWOnHighestXY, - NodeArray& nodeflags, - const int nodemarker, - const KuratowskiStructure& k, - EdgeArray& flags, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW); - //! Extracts minorsubtype E1 and adds it to list \a output - void extractMinorE1( - SList& output, - int before, - //const node z, - const node px, - const node py, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ); - //! Extracts minorsubtype E2 and adds it to list \a output - void extractMinorE2( - SList& output, - /*int before, - const node z, - const node px, - const node py,*/ - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - //const SListPure& pathW, - const SListPure& pathZ/*, - const node endnodeZ*/); - //! Extracts minorsubtype E3 and adds it to list \a output - void extractMinorE3( - SList& output, - int before, - const node z, - const node px, - const node py, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ); - //! Extracts minorsubtype E4 and adds it to list \a output - void extractMinorE4( - SList& output, - int before, - const node z, - const node px, - const node py, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ); - //! Extracts minorsubtype E5 and adds it to list \a output - void extractMinorE5( - SList& output, - /*int before, - const node z, - const node px, - const node py,*/ - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ); -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/planarity/FastPlanarSubgraph.h b/ext/OGDF/ogdf/planarity/FastPlanarSubgraph.h deleted file mode 100644 index 21a2907fc..000000000 --- a/ext/OGDF/ogdf/planarity/FastPlanarSubgraph.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the FastPlanarSubgraph. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_FAST_PLANAR_SUBGRAPH_H -#define OGDF_FAST_PLANAR_SUBGRAPH_H - - - -#include - - -namespace ogdf { - -/** - * \brief Computation of a planar subgraph using PQ-trees. - * - * Literature: Jayakumar, Thulasiraman, Swamy 1989 - * - *

    Optional Parameters

    - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription
    runsint0the number of randomized runs performed by the algorithm; the best - * solution is picked among all the runs. If runs is 0, one - * deterministic run is performed.
    - * - * Observe that this algorithm by theory does not compute a maximal - * planar subgraph. It is however the fastest known good heuristic. - */ -class OGDF_EXPORT FastPlanarSubgraph : public PlanarSubgraphModule{ - -public: - //! Creates an instance of the fast planar subgraph algorithm. - FastPlanarSubgraph() : PlanarSubgraphModule() { - m_nRuns = 0; - }; - - // destructor - ~FastPlanarSubgraph() { } - - - // options - - //! Sets the number of randomized runs to \a nRuns. - void runs (int nRuns) { - m_nRuns = nRuns; - } - - //! Returns the current number of randomized runs. - int runs() const { - return m_nRuns; - } - - -protected: - //! Returns true, if G is planar, false otherwise. - /** - * \todo Add timeout support (limit number of runs when timeout is reached). - */ - ReturnType doCall(const Graph &G, - const List &preferedEdges, - List &delEdges, - const EdgeArray *pCost, - bool preferedImplyPlanar); - - -private: - int m_nRuns; //!< The number of runs for randomization. - - - //! Computes the list of edges to be deleted in \a G. - /** Also performs randomization of the planarization algorithm. - */ - void computeDelEdges(const Graph &G, - const EdgeArray *pCost, - const EdgeArray *backTableEdges, - List &delEdges); - - //! Performs a planarization on a biconnected component pf \a G. - /** The numbering contains an st-numbering of the component. - */ - void planarize( - const Graph &G, - NodeArray &numbering, - List &delEdges); -}; - -} -#endif diff --git a/ext/OGDF/ogdf/planarity/FixedEmbeddingInserter.h b/ext/OGDF/ogdf/planarity/FixedEmbeddingInserter.h deleted file mode 100644 index 142d1b09b..000000000 --- a/ext/OGDF/ogdf/planarity/FixedEmbeddingInserter.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration of class FixedEmbeddingInserter - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FIXED_EMBEDDING_INSERTER_H -#define OGDF_FIXED_EMBEDDING_INSERTER_H - - - -#include -#include -#include - - -template class FaceArray; - - -namespace ogdf { - - -class OGDF_EXPORT FaceSetSimple; - - -//! Edge insertion module that inserts each edge optimally into a fixed embedding. -class OGDF_EXPORT FixedEmbeddingInserter : public EdgeInsertionModule -{ -public: - //! Creates an instance of fixed-embedding edge inserter. - FixedEmbeddingInserter(); - - ~FixedEmbeddingInserter() { } - - /** - * @name Optional parameters - * @{ - */ - - //! Sets the remove-reinsert postprocessing method. - void removeReinsert(RemoveReinsertType rrOption) { - m_rrOption = rrOption; - } - - //! Returns the current setting of the remove-reinsert postprocessing method. - RemoveReinsertType removeReinsert() const { - return m_rrOption; - } - - - //! Sets the option percentMostCrossed to \a percent. - /** - * This option determines the portion of most crossed edges used if the remove-reinsert - * method is set to #rrMostCrossed. This portion is number of edges * percentMostCrossed() / 100. - */ - void percentMostCrossed(double percent) { - m_percentMostCrossed = percent; - } - - //! Returns the current setting of option percentMostCrossed. - double percentMostCrossed() const { - return m_percentMostCrossed; - } - - //! Sets the option keepEmbedding to \a keep. - /** - * This option determines if the planar embedding of the planarized representation \a PG passed to the call-method - * is preserved, or if always a new embedding is computed. If keepEmbedding is set to true, - * \a PG must always be planarly embedded. - */ - void keepEmbedding(bool keep) { - m_keepEmbedding = keep; - } - - //! Returns the current setting of option keepEmbedding. - bool keepEmbeding() const { - return m_keepEmbedding; - } - - /** @} - * @name Further information - * @{ - */ - - //! Returns the number of runs performed by the remove-reinsert method after the algorithm has been called. - int runsPostprocessing() const { - return m_runsPostprocessing; - } - - //! @} - -private: - //! Implements the algorithm call. - ReturnType doCall( - PlanRep &PG, // planarized representation - const List &origEdges, // original edge to be inserted - bool forbidCrossinGens, // frobid crossings between gen's - const EdgeArray *costOrig, // pointer to array of cost of - // original edges; if pointer is 0 all costs are 1 - const EdgeArray *forbiddenEdgeOrig = 0, - const EdgeArray *edgeSubGraph = 0); // pointer to array deciding - // which original edges are forbidden to cross; if pointer is - // is 0 no edges are explicitly forbidden to cross - - //! Construct the dual graph. - /** - * Marks dual edges corresponding to generalization in m_primalIsGen; - * assumes that m_pDual, m_primalAdj and m_pNodeOf are already constructed. - */ - void constructDualForbidCrossingGens(const PlanRepUML &PG, - const CombinatorialEmbedding &E); - - //! Construct the dual graph. - /** - * Assumes that m_pDual, m_primalAdj and m_pNodeOf are already constructed. - */ - void constructDual(const GraphCopy &GC, - const CombinatorialEmbedding &E, - const EdgeArray *forbiddenEdgeOrig); - - //! Finds a shortest path in the dual graph augmented by \a s and \a t. - /** - * Returns the list of crossed adjacency entries (corresponding - * to used edges in the dual) in \a crossed. - */ - void findShortestPath(const CombinatorialEmbedding &E, - node s, - node t, - Graph::EdgeType eType, - SList &crossed); - - //! Finds a weighted shortest path in the dual graph augmented by \a s and \a t. - /** - * Uses edges weights given by costOrig; - * returns the list of crossed adjacency entries (corresponding to used - * edges in the dual) in \a crossed. - */ - void findShortestPath( - const PlanRep &PG, - const CombinatorialEmbedding &E, - const EdgeArray &costOrig, - node s, - node t, - Graph::EdgeType eType, - SList &crossed, - const EdgeArray *edgeSubGraph, - int eSubGraph); - - void insertEdge(PlanRep &PG, - CombinatorialEmbedding &E, - edge eOrig, - const SList &crossed, - bool forbidCrossingGens, - const EdgeArray *forbiddenEdgeOrig); - - void removeEdge( - PlanRep &PG, - CombinatorialEmbedding &E, - edge eOrig, - bool forbidCrossingGens, - const EdgeArray *forbiddenEdgeOrig); - - edge crossedEdge(adjEntry adj) const; - int costCrossed(edge eOrig, - const PlanRep &PG, - const EdgeArray &costOrig, - const EdgeArray *subgraphs) const; - - Graph m_dual; //!< (Extended) dual graph, constructed/destructed during call. - - EdgeArray m_primalAdj; //!< Adjacency entry in primal graph corresponding to edge in dual. - FaceArray m_nodeOf; //!< The node in dual corresponding to face in primal. - EdgeArray m_primalIsGen; //!< true iff corresponding primal edge is a generalization. - FaceSetSimple *m_delFaces; - FaceSetPure *m_newFaces; - - node m_vS; //!< The node in extended dual representing s. - node m_vT; //!< The node in extended dual representing t. - - - RemoveReinsertType m_rrOption; //!< The remove-reinsert method. - double m_percentMostCrossed; //!< The portion of most crossed edges considered. - bool m_keepEmbedding; - - int m_runsPostprocessing; //!< Runs of remove-reinsert method. -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/KuratowskiSubdivision.h b/ext/OGDF/ogdf/planarity/KuratowskiSubdivision.h deleted file mode 100644 index 8a67e3b3b..000000000 --- a/ext/OGDF/ogdf/planarity/KuratowskiSubdivision.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of KuratowskiSubdivion class - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_KURATOWSKI_SUBDIVISION_H -#define OGDF_KURATOWSKI_SUBDIVISION_H - - -#include -#include - - -namespace ogdf { - -class OGDF_EXPORT KuratowskiSubdivision : public Array > { }; - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/MMFixedEmbeddingInserter.h b/ext/OGDF/ogdf/planarity/MMFixedEmbeddingInserter.h deleted file mode 100644 index 29127ceed..000000000 --- a/ext/OGDF/ogdf/planarity/MMFixedEmbeddingInserter.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration of class MMFixedEmbeddingInserter - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MM_FIXED_EMBEDDING_INSERTER_H -#define OGDF_MM_FIXED_EMBEDDING_INSERTER_H - - - -#include -#include -#include -#include - - - -namespace ogdf { - - -class OGDF_EXPORT FaceSetSimple; -class OGDF_EXPORT NodeSetPure; -class OGDF_EXPORT NodeSet; - - -//! Minor-monotone edge insertion with fixed embedding. -class OGDF_EXPORT MMFixedEmbeddingInserter : public MMEdgeInsertionModule -{ -public: - //! Creates a minor-monotone fixed embedding inserter. - MMFixedEmbeddingInserter(); - - // destruction - virtual ~MMFixedEmbeddingInserter() { } - - - //! Sets the remove-reinsert option for postprocessing. - void removeReinsert(RemoveReinsertType rrOption) { - m_rrOption = rrOption; - } - - //! Returns the current setting of the remove-reinsert option. - RemoveReinsertType removeReinsert() const { - return m_rrOption; - } - - - //! Sets the portion of most crossed edges used during postprocessing. - /** - * The value is only used if the remove-reinsert option is set to rrMostCrossed. - * The number of edges used in postprocessing is then - * number of edges * percentMostCrossed() / 100. - */ - void percentMostCrossed(double percent) { - m_percentMostCrossed = percent; - } - - //! Returns the current setting of the option percentMostCrossed. - double percentMostCrossed() const { - return m_percentMostCrossed; - } - - -private: - /** - * \brief Implementation of algorithm call. - * - * @param PG is the input planarized expansion and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - */ - ReturnType doCall( - PlanRepExpansion &PG, - const List &origEdges, - const EdgeArray *forbiddenEdgeOrig); - - //! Constructs the search network (extended dual graph). - /** - * @param PG is the planarized expansion. - * @param E is the corresponding embeddding. - */ - void constructDual( - const PlanRepExpansion &PG, - const CombinatorialEmbedding &E); - - //! Finds a shortest insertion path for an edge. - /** - * @param PG is the planarized expansion. - * @param E is the corresponding embeddding. - * @param sources is the list of nodes in PG from where the path may start. - * @param targets is the list of nodes in PG where the path may end. - * @param crossed is assigned the insertion path. For each crossed edge or - * node, we have a pair (\a adj1,\a adj2) in the list; in case of a - * crossed edge, \a adj1 corresponds to the crossed edge and adj2 - * is 0; in case of a crossed node, adj1 (adj2) is the first adjacency - * entry assigned to the left (right) node after the split. Additionally, - * the first and last element in the list specify, where the path - * leaves the source and enters the target node. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - */ - void findShortestPath( - const PlanRepExpansion &PG, - const CombinatorialEmbedding &E, - const List &sources, - const List &targets, - List > &crossed, - const EdgeArray *forbiddenEdgeOrig); - - void prepareAnchorNode( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - adjEntry &adjStart, - node srcOrig); - - void preprocessInsertionPath( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - node srcOrig, - node tgtOrig, - //PlanRepExpansion::nodeSplit ns, - List > &crossed); - - /** - * \brief Inserts an edge according to a given insertion path and updates the search network. - * - * If an orignal edge \a eOrig is inserted, \a srcOrig and \a tgtOrig are \a eOrig's source - * and target node, and \a nodeSplit is 0. If a node split is inserted, then \a eOrig is 0, - * and \a srcOrig and \a tgtOrig refer to the same node (which corresponds to the \a nodeSplit). - * - * @param PG is the planarized expansion. - * @param E is the corresponding embeddding. - * @param eOrig is the original edge that has to be inserted. - * @param srcOrig is the original source node. - * @param tgtOrig is the original target node - * @param nodeSplit is the node split that has to be inserted. - * @param crossed is the insertion path as described with findShortestPath(). - */ - void insertEdge( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - edge eOrig, - node srcOrig, - node tgtOrig, - PlanRepExpansion::NodeSplit *nodeSplit, - List > &crossed); - - /** - * \brief Removes the insertion path of an original edge or a node split and updates the search network. - * - * @param PG is the planarized expansion. - * @param E is the corresponding embeddding. - * @param eOrig is the original edge whose insertion path shall be removed. - * @param nodeSplit is the node split whose insertion path shall be removed. - * @param oldSrc is assigned the source node of the removed insertion path - * (might be changed during path removal!). - * @param oldTgt is assigned the target node of the removed insertion path - * (might be changed during path removal!). - */ - void removeEdge( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - edge eOrig, - PlanRepExpansion::NodeSplit *nodeSplit, - node &oldSrc, - node &oldTgt); - - /** - * \brief Inserts dual edges between vertex node \a vDual and left face of \a adj. - * - * @param vDual is the dual node of \a adj's node. - * @param adj is an adjacency entry in the planarized expansion. - * @param E is the corresponding embeddding. - */ - void insertDualEdge(node vDual, adjEntry adj, const CombinatorialEmbedding &E); - - /** - * \brief Inserts all dual edges incident to \a v's dual node. - * - * @param v is a node in the planarized expansion. - * @param E is the corresponding embeddding. - */ - void insertDualEdges(node v, const CombinatorialEmbedding &E); - - /** - * \brief Removes a (redundant) node split consisting of a single edge. - * - * @param PG is the planarized expansion. - * @param E is the corresponding embeddding. - * @param nodeSplit is a node split whose insertion path consists of a single edge. - */ - void contractSplit( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - PlanRepExpansion::NodeSplit *nodeSplit); - - /** - * \brief Reduces the insertion path of a node split at node \a u if required. - * - * The insertion path is reduced by unsplitting \a u if \a u has degree 2. - * @param PG is the planarized expansion. - * @param E is the corresponding embeddding. - * @param u is a node in the planarized expansion. - * @param nsCurrent is a node split which may not be contracted. - */ - void contractSplitIfReq( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - node u, - const PlanRepExpansion::nodeSplit nsCurrent = 0); - - /** - * \brief Converts a dummy node to a copy of an original node. - */ - void convertDummy( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - node u, - node vOrig, - PlanRepExpansion::nodeSplit ns); - - /** - * \brief Collects all anchor nodes (including dummies) of a node. - * - * @param v is the current node when traversing all copy nodes of an original node - * that are connected in a tree-wise manner. - * @param nodes is assigned the set of anchor nodes. - * @param nsParent is the parent node split. - * @param PG is the planarized expansion. - */ - void collectAnchorNodes( - node v, - NodeSet &nodes, - const PlanRepExpansion::NodeSplit *nsParent, - const PlanRepExpansion &PG) const; - - /** - * \brief Returns all anchor nodes of \a vOrig in n\a nodes. - * - * @param vOrig is a node in the original graph. - * @param nodes ia assigned the set of anchor nodes. - * @param PG is the planarized expansion. - */ - void anchorNodes( - node vOrig, - NodeSet &nodes, - const PlanRepExpansion &PG) const; - - /** - * \brief Finds the set of anchor nodes of \a src and \a tgt. - * - * @param src is a node in \a PG representing an original node. - * @param tgt is a node in \a PG representing an original node. - * @param sources ia assigned the set of anchor nodes of \a src's original node. - * @param targets ia assigned the set of anchor nodes of \a tgt's original node. - * @param PG is the planarized expansion. - */ - void findSourcesAndTargets( - node src, node tgt, - NodeSet &sources, - NodeSet &targets, - const PlanRepExpansion &PG) const; - - /** - * \brief Returns a common dummy node in \a sources and \a targets, or 0 of no such node exists. - * - * @param sources is a set of anchor nodes. - * @param targets is a set of anchor nodes. - */ - node commonDummy( - NodeSet &sources, - NodeSet &targets); - - //! Performs several consistency checks on the seach network. - bool checkDualGraph(PlanRepExpansion &PG, const CombinatorialEmbedding &E) const; - - bool checkSplitDeg( - PlanRepExpansion &PG); - - bool origOfDualForbidden( - edge e, - const PlanRepExpansion &PG, - const EdgeArray *forbiddenEdgeOrig) const - { - if(forbiddenEdgeOrig == 0) - return false; - - if(e->source() == m_vS || e->target() == m_vT) - return false; - - if(m_primalNode[e->source()] != 0) - return false; - if(m_primalNode[e->target()] != 0) - return false; - - adjEntry adj = m_primalAdj[e]; - if(adj == 0) return false; - - edge eOrig = PG.originalEdge(adj->theEdge()); - if(eOrig != 0) { - //if((*forbiddenEdgeOrig)[eOrig] == true) - // cout << "forbidden: " << eOrig << ", dual: " << e << endl; - return (*forbiddenEdgeOrig)[eOrig]; - } else return false; - } - - void drawDual( - const PlanRepExpansion &PG, - const EdgeArray *forbiddenEdgeOrig); - - RemoveReinsertType m_rrOption; //!< The remove-reinsert option. - double m_percentMostCrossed; //!< The percentMostCrossed option. - - Graph m_dual; //!< The search network (extended dual graph). - FaceArray m_dualOfFace; //!< The node in dual corresponding to face in primal. - NodeArray m_dualOfNode; //!< The node in dual corresponding to node in primal. - NodeArray m_primalNode; //!< The node in PG corresponding to dual node (0 if face). - EdgeArray m_primalAdj; //!< The adjacency entry in primal graph corresponding to edge in dual. - AdjEntryArray m_dualEdge; //!< The dual edge corresponding to crossing the adjacency entry. - EdgeArray m_dualCost; //!< The cost of an edge in the seach network. - - node m_vS; //!< Represents the start node for the path search. - node m_vT; //!< Represents the end node for the path search. - int m_maxCost; //!< The maximal cost of an edge in the search network + 1. - - FaceSetSimple *m_delFaces; - FaceSetPure *m_newFaces; - NodeSetPure *m_mergedNodes; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/MMSubgraphPlanarizer.h b/ext/OGDF/ogdf/planarity/MMSubgraphPlanarizer.h deleted file mode 100644 index c5427df2d..000000000 --- a/ext/OGDF/ogdf/planarity/MMSubgraphPlanarizer.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MMSubgraphPlanarizer. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_MM_SUBGRAPH_PLANARIZER_H -#define OGDF_MM_SUBGRAPH_PLANARIZER_H - -#include -#include -#include -#include - - -namespace ogdf -{ - -/** - * \brief Planarization approach for minor-monotone crossing minimization. - * - */ -class OGDF_EXPORT MMSubgraphPlanarizer : public MMCrossingMinimizationModule -{ -public: - //! Creates a subgraph planarizer for minor-monotone crossing minimization. - MMSubgraphPlanarizer(); - - //! Sets the module option for the computation of the planar subgraph. - void setSubgraph(PlanarSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - //! Sets the module option for minor-monotone edge insertion. - void setInserter(MMEdgeInsertionModule *pInserter) { - m_inserter.set(pInserter); - } - - //! Returns the number of performed permutations in the edge insertion step. - int permutations() { return m_permutations; } - - //! Sets the number of performed permutations in the edge insertion step. - void permutations(int p) { m_permutations = p; } - -protected: - virtual ReturnType doCall(PlanRepExpansion &PG, - int cc, - const EdgeArray *forbid, - int& crossingNumber, - int& numNS, - int& numSN); - -private: - ModuleOption m_subgraph; //!< The planar subgraph module. - ModuleOption m_inserter; //!< The minor-monotone edge insertion module. - - int m_permutations; //!< The number of permutations. -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/planarity/MMVariableEmbeddingInserter.h b/ext/OGDF/ogdf/planarity/MMVariableEmbeddingInserter.h deleted file mode 100644 index 29d517131..000000000 --- a/ext/OGDF/ogdf/planarity/MMVariableEmbeddingInserter.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration of class MMVariableEmbeddingInserter - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MM_VARIABLE_EMBEDDING_INSERTER_H -#define OGDF_MM_VARIABLE_EMBEDDING_INSERTER_H - - - -#include -#include -#include -#include - - - -namespace ogdf { - -class OGDF_EXPORT NodeSet; -class OGDF_EXPORT StaticPlanarSPQRTree; - - -//! Minor-monotone edge insertion with variable embedding. -class OGDF_EXPORT MMVariableEmbeddingInserter : public MMEdgeInsertionModule -{ -public: - //! Creates a minor-monotone fixed embedding inserter. - MMVariableEmbeddingInserter(); - - // destruction - virtual ~MMVariableEmbeddingInserter() { } - - - //! Sets the remove-reinsert option for postprocessing. - void removeReinsert(RemoveReinsertType rrOption) { - m_rrOption = rrOption; - } - - //! Returns the current setting of the remove-reinsert option. - RemoveReinsertType removeReinsert() const { - return m_rrOption; - } - - - //! Sets the portion of most crossed edges used during postprocessing. - /** - * The value is only used if the remove-reinsert option is set to rrMostCrossed. - * The number of edges used in postprocessing is then - * number of edges * percentMostCrossed() / 100. - */ - void percentMostCrossed(double percent) { - m_percentMostCrossed = percent; - } - - //! Returns the current setting of the option percentMostCrossed. - double percentMostCrossed() const { - return m_percentMostCrossed; - } - - -private: - class Block; - class ExpandedSkeleton; - - typedef PlanRepExpansion::Crossing Crossing; - - struct AnchorNodeInfo { - AnchorNodeInfo() { m_adj_1 = m_adj_2 = 0; } - AnchorNodeInfo(adjEntry adj) { - m_adj_1 = adj; - m_adj_2 = 0; - } - AnchorNodeInfo(adjEntry adj_1, adjEntry adj_2) { - m_adj_1 = adj_1; - m_adj_2 = adj_2; - } - - adjEntry m_adj_1; - adjEntry m_adj_2; - }; - - enum PathType { pathToEdge = 0, pathToSource = 1, pathToTarget = 2 }; - - struct Paths { - Paths() : - m_addPartLeft(3), m_addPartRight(3), - m_paths(3), - m_src(0,2,0), m_tgt(0,2,0), - m_pred(0,2,0) - { } - - Array > m_addPartLeft; - Array > m_addPartRight; - Array > m_paths; - Array m_src; - Array m_tgt; - Array m_pred; - }; - - /** - * \brief Implementation of algorithm call. - * - * @param PG is the input planarized expansion and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - */ - ReturnType doCall( - PlanRepExpansion &PG, - const List &origEdges, - const EdgeArray *forbiddenEdgeOrig); - - /** - * \brief Collects all anchor nodes (including dummies) of a node. - * - * @param v is the current node when traversing all copy nodes of an original node - * that are connected in a tree-wise manner. - * @param nodes is assigned the set of anchor nodes. - * @param nsParent is the parent node split. - */ - void collectAnchorNodes( - node v, - NodeSet &nodes, - const PlanRepExpansion::NodeSplit *nsParent) const; - - /** - * \brief Finds the set of anchor nodes of \a src and \a tgt. - * - * @param src is a node in \a PG representing an original node. - * @param tgt is a node in \a PG representing an original node. - * @param sources ia assigned the set of anchor nodes of \a src's original node. - * @param targets ia assigned the set of anchor nodes of \a tgt's original node. - */ - void findSourcesAndTargets( - node src, node tgt, - NodeSet &sources, - NodeSet &targets) const; - - /** - * \brief Returns all anchor nodes of \a vOrig in n\a nodes. - * - * @param vOrig is a node in the original graph. - * @param nodes ia assigned the set of anchor nodes. - */ - void anchorNodes( - node vOrig, - NodeSet &nodes) const; - - static node commonDummy( - NodeSet &sources, - NodeSet &targets); - - /** - * \brief Computes insertion path \a eip. - * - * The possible start and end nodes of the insertion path have to be stored in - * \a m_pSources and \a m_pTargets. - * @param eip is assigned the insertion path (the crossed edges). - * @param vStart is assigned the start point of the insertion path. - * @param vEnd is assigned the end point of the insertion path. - */ - void insert(List &eip, AnchorNodeInfo &vStart, AnchorNodeInfo &vEnd); - - node prepareAnchorNode( - const AnchorNodeInfo &anchor, - node vOrig, - bool isSrc, - edge &eExtra); - - void preprocessInsertionPath( - const AnchorNodeInfo &srcInfo, - const AnchorNodeInfo &tgtInfo, - node srcOrig, - node tgtOrig, - node &src, - node &tgt, - edge &eSrc, - edge &eTgt); - - node preparePath( - node vAnchor, - adjEntry adjPath, - bool bOrigEdge, - node vOrig); - - void findPseudos( - node vDummy, - adjEntry adjSrc, - AnchorNodeInfo &infoSrc, - SListPure &pseudos); - - void insertWithCommonDummy( - edge eOrig, - node vDummy, - node &src, - node &tgt); - - /** - * \brief Implements vertex case of recursive path search in BC-tree. - * - * @param v is the node in the graph currently visited during BC-tree traversal. - * @param parent is the parent block in DFS-traversal. - * @param eip is (step-by-step) assigned the insertion path (crossed edges). - * @param vStart is assigned the start point of \a eip. - * @param vEnd is assigned the end point of \a eip. - */ - bool dfsVertex(node v, - int parent, - List &eip, - AnchorNodeInfo &vStart, - AnchorNodeInfo &vEnd); - - /** - * \brief Implements block case of recursive path search in BC-tree. - * - * @param i is the block in the graph currently visited during BC-tree traversal. - * @param parent is the parent node in DFS-traversal. - * @param repS is assigned the representative (nodein the graph) of a source node. - * @param eip is (step-by-step) assigned the insertion path (crossed edges). - * @param vStart is assigned the start point of \a eip. - * @param vEnd is assigned the end point of \a eip. - */ - bool dfsBlock(int i, - node parent, - node &repS, - List &eip, - AnchorNodeInfo &vStart, - AnchorNodeInfo &vEnd); - - bool pathSearch(node v, edge parent, const Block &BC, List &path); - - /** - * \brief Computes optimal insertion path in block \a BC. - * - * @param BC is the block. - * @param L is assigned the insertion path (the crossed edges). - * @param srcInfo is assigned the start point of the insertion path. - * @param tgtInfo is assigned the end point of the insertion path. - */ - void blockInsert( - Block &BC, - List &L, - AnchorNodeInfo &srcInfo, - AnchorNodeInfo &tgtInfo); - - void buildSubpath( - node v, - edge eIn, - edge eOut, - Paths &paths, - bool &bPathToEdge, - bool &bPathToSrc, - bool &bPathToTgt, - ExpandedSkeleton &Exp); - - void contractSplitIfReq(node u); - void convertDummy( - node u, - node vOrig, - PlanRepExpansion::nodeSplit ns_0); - - void writeEip(const List &eip); - - RemoveReinsertType m_rrOption; //!< The remove-reinsert option. - double m_percentMostCrossed; //!< The percentMostCrossed option. - - PlanRepExpansion *m_pPG; //!< Pointer to the planarized expansion. - - NodeSet *m_pSources; //!< The set of possible start nodes of an insertion path. - NodeSet *m_pTargets; //!< The set of possible end nodes of an insertion path. - - NodeArray > m_compV; //!< The list of blocks containing a node \a v. - Array > m_nodeB; //!< The list of nodes in block \a i. - Array > m_edgeB; //!< The list of edges in block \a i. - NodeArray m_GtoBC; //!< Maps a node in the planarized expansion to the corresponding node in block. - - bool m_conFinished; //!< Stores if a possible target node in a block has already been found. - const EdgeArray *m_forbiddenEdgeOrig; -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/MaximalPlanarSubgraphSimple.h b/ext/OGDF/ogdf/planarity/MaximalPlanarSubgraphSimple.h deleted file mode 100644 index 27b385518..000000000 --- a/ext/OGDF/ogdf/planarity/MaximalPlanarSubgraphSimple.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MaximalPlanarSubgraphSimple - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_MAXIMAL_PLANAR_SUBGRAPH_SIMPLE_H -#define OGDF_MAXIMAL_PLANAR_SUBGRAPH_SIMPLE_H - - - - -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// MaximalPlanarSubgraphSimple -// implements a maximal planar subgraph algorithm using -// planarity testing -//--------------------------------------------------------- -class OGDF_EXPORT MaximalPlanarSubgraphSimple : public PlanarSubgraphModule -{ -public: - // construction - MaximalPlanarSubgraphSimple() { } - // destruction - ~MaximalPlanarSubgraphSimple() { } - - -protected: - // computes set of edges delEdges, which have to be deleted - // in order to get a planar subgraph; edges in preferedEdges - // should be contained in planar subgraph - ReturnType doCall(const Graph &G, - const List &preferedEdges, - List &delEdges, - const EdgeArray *pCost, - bool preferedImplyPlanar); -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/MaximumPlanarSubgraph.h b/ext/OGDF/ogdf/planarity/MaximumPlanarSubgraph.h deleted file mode 100644 index 06030a4ef..000000000 --- a/ext/OGDF/ogdf/planarity/MaximumPlanarSubgraph.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MaximumPlanarSubgraph. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MAXIMUM_PLANAR_SUBGRAPH_H -#define OGDF_MAXIMUM_PLANAR_SUBGRAPH_H - -#include -#include - -#include -#include - -#include - -namespace ogdf { - -//-------------------------------------------------------------------------- -//MaximumPlanarSubgraph -//Exact computation of a maximum planar subgraph -//-------------------------------------------------------------------------- -class OGDF_EXPORT MaximumPlanarSubgraph : public PlanarSubgraphModule -{ - -#ifndef USE_ABACUS -protected: - virtual ReturnType doCall(const Graph &G, - const List &preferedEdges, - List &delEdges, - const EdgeArray *pCost, - bool preferedImplyPlanar) - { THROW_NO_ABACUS_EXCEPTION; return retError; } -}; -#else // Use_ABACUS - -public: - // Construction - MaximumPlanarSubgraph() {} - // Destruction - virtual ~MaximumPlanarSubgraph() {} - -protected: - // Implements the Planar Subgraph interface. - // For the given graph \a G, a clustered graph with only - // a single root cluster is generated. - // Computes set of edges delEdges, which have to be deleted - // in order to get a planar subgraph; edges in preferredEdges - // should be contained in planar subgraph. - // Status: pCost and preferredEdges are ignored in current implementation. - virtual ReturnType doCall(const Graph &G, - const List &preferredEdges, - List &delEdges, - const EdgeArray *pCost, - bool preferredImplyPlanar); -}; - -#endif // USE_ABACUS - -} //end namespace ogdf - - -#endif // OGDF_MAXIMUM_PLANAR_SUBGRAPH_H diff --git a/ext/OGDF/ogdf/planarity/MultiEdgeApproxInserter.h b/ext/OGDF/ogdf/planarity/MultiEdgeApproxInserter.h deleted file mode 100644 index bdcd5218c..000000000 --- a/ext/OGDF/ogdf/planarity/MultiEdgeApproxInserter.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MultiEdgeApproxInserter. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MULTI_EDGE_APPROX_INSERTER_H -#define OGDF_MULTI_EDGE_APPROX_INSERTER_H - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT MultiEdgeApproxInserter : public EdgeInsertionModule -{ -public: - //! Creates an instance of multi-edge inserter. - MultiEdgeApproxInserter(); - - ~MultiEdgeApproxInserter() { } - - - //! Sets the remove-reinsert postprocessing method. - void removeReinsertFix(RemoveReinsertType rrOption) { - m_rrOptionFix = rrOption; - } - - //! Returns the current setting of the remove-reinsert postprocessing method. - RemoveReinsertType removeReinsertFix() const { - return m_rrOptionFix; - } - - //! Sets the remove-reinsert postprocessing method. - void removeReinsertVar(RemoveReinsertType rrOption) { - m_rrOptionVar = rrOption; - } - - //! Returns the current setting of the remove-reinsert postprocessing method. - RemoveReinsertType removeReinsertVar() const { - return m_rrOptionVar; - } - - //! Sets the option percentMostCrossed to \a percent. - /** - * This option determines the portion of most crossed edges used if the remove-reinsert - * method is set to #rrMostCrossed. This portion is number of edges * percentMostCrossed() / 100. - */ - void percentMostCrossedFix(double percent) { - m_percentMostCrossedFix = percent; - } - - //! Returns the current setting of option percentMostCrossed. - double percentMostCrossedFix() const { - return m_percentMostCrossedFix; - } - - //! Sets the option percentMostCrossedVar to \a percent. - /** - * This option determines the portion of most crossed edges used if the remove-reinsert - * method (variable embedding) is set to #rrMostCrossed. This portion is number of edges * percentMostCrossed() / 100. - */ - void percentMostCrossedVar(double percent) { - m_percentMostCrossedVar = percent; - } - - //! Returns the current setting of option percentMostCrossed (variable embedding). - double percentMostCrossedVar() const { - return m_percentMostCrossedVar; - } - - void statistics(bool b) { - m_statistics = b; - } - - bool statistics() const { - return m_statistics; - } - - int sumInsertionCosts() const { return m_sumInsertionCosts; } - int sumFEInsertionCosts() const { return m_sumFEInsertionCosts; } - -private: - enum PathDir { pdLeft, pdRight, pdNone }; - static PathDir s_oppDir[3]; - - class Block; - class EmbeddingPreference; - - struct VertexBlock { - VertexBlock(node v, int b) : m_vertex(v), m_block(b) { } - - node m_vertex; - int m_block; - }; - - //! Implements the algorithm call. - ReturnType doCall( - PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig, - const EdgeArray *edgeSubGraph); - - MultiEdgeApproxInserter::Block *constructBlock(int i); - node copy(node vOrig, int b); - - static bool dfsPathSPQR(node v, node v2, edge eParent, List &path); - int computePathSPQR(int b, node v, node w, int k); - - bool dfsPathVertex(node v, int parent, int k, node t); - bool dfsPathBlock(int b, node parent, int k, node t); - void computePathBC(int k); - - void embedBlock(int b, int m); - void recFlipPref(adjEntry adjP, NodeArray &pi_pick, const NodeArray &visited, StaticPlanarSPQRTree &spqr); - - void cleanup(); - - RemoveReinsertType m_rrOptionFix; //!< The remove-reinsert method for fixed embedding. - RemoveReinsertType m_rrOptionVar; //!< The remove-reinsert method for variable embedding. - double m_percentMostCrossedFix; //!< The portion of most crossed edges considered (fixed embedding). - double m_percentMostCrossedVar; //!< The portion of most crossed edges considered (variable embedding). - bool m_statistics; // !< Generates further statistic information. - - PlanRep *m_pPG; // pointer to plan-rep passed in call - const EdgeArray *m_costOrig; - - NodeArray > m_compV; // m_compV[v] = list of blocks containing v - Array > m_verticesB; // m_verticesB[i] = list of vertices in block i - Array > m_edgesB; // edgesB[i] = list of edges in block i - NodeArray m_GtoBC; // temporary mapping of nodes in PG to copies in block - NodeArray > m_copyInBlocks; // mapping of nodes in PG to copies in block - - Array m_edge; // array of edges to be inserted - Array > m_pathBCs; // insertion path in BC-tree for each edge - Array m_insertionCosts; // computed insertion costs for each edge - Array m_block; // array of blocks - - // statistics of last run - int m_sumInsertionCosts; - int m_sumFEInsertionCosts; - - // just for testing - void constructDual(const PlanRep &PG); - int findShortestPath(node s, node t); - - ConstCombinatorialEmbedding m_E; - Graph m_dual; - FaceArray m_faceNode; - AdjEntryArray m_primalAdj; - node m_vS, m_vT; -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/NodeTypePatterns.h b/ext/OGDF/ogdf/planarity/NodeTypePatterns.h deleted file mode 100644 index 9e66cedf8..000000000 --- a/ext/OGDF/ogdf/planarity/NodeTypePatterns.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of node types and patterns for planar - * representations - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//edge type patterns: -//THREE TYPE LEVELS: -//primary: holds information about structural/non-structural -// nodes, this influences the handling in algorithms -//secondary: type of node, e.g. flow node, simple label node, ... -//user edge types can be set locally - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_TYPE_PATTERNS_H -#define OGDF_NODE_TYPE_PATTERNS_H - -namespace ogdf { - - typedef long nodeType; - - enum UMLNodeTypePatterns { - ntpPrimary = 0x0000000f, - ntpSecondary = 0x000000f0, - ntpTertiary = 0x00000f00, - ntpFourth = 0x0000f000, - ntpUser = 0xff000000, - ntpAll = 0xffffffff - }; //!!!attention sign, 7fffffff - - enum UMLNodeTypeConstants { - //primary types (should be disjoint bits) - ntPrimOriginal = 0x1, ntPrimCopy = 0x2, - //secondary types: type of node (should be disjoint types, but not bits, - //but may not completely cover others that are allowed to be set together) - //preliminary: setsecondarytype deletes old type - //defines the structure of the diagram, e.g. as flow transmitter - ntSecStructural = 0x1, ntSecNonStructural = 0x2, - //tertiary - //crossing node, high/low degree expander - ntTerCrossing = 0x1, ntTerExpander = 0x2, ntTerHDExpander = 0x6, - ntTerLDExpander = 0xA, - //fourth level types: special types - //flow node, simple label node, type label node, expansion corner node - ntFourFlow = 0x1, ntFourLabel = 0x2, ntFourType = 0x3, ntFourCorner = 0x4 - - //user type hint: what you have done with the edge, e.g. brother edge - //that is embedded crossing free and should be drawn bend free - }; - enum UMLNodeTypeOffsets { - ntoPrimary = 0, ntoSecondary = 4, ntoTertiary = 8, ntoFourth = 12, ntoFifth = 16, - ntoUser = 24 - }; - -} //end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/NonPlanarCore.h b/ext/OGDF/ogdf/planarity/NonPlanarCore.h deleted file mode 100644 index 4b8f4d247..000000000 --- a/ext/OGDF/ogdf/planarity/NonPlanarCore.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class NonPlanarCore which represents the - * non-planar core reduction for biconnected graphs. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_NON_PLANAR_CORE_H -#define OGDF_NON_PLANAR_CORE_H - - -#include -#include -#include - - -namespace ogdf { - - class OGDF_EXPORT SPQRTree; - class OGDF_EXPORT Skeleton; - - -//--------------------------------------------------------- -// NonPlanarCore -//--------------------------------------------------------- -class OGDF_EXPORT NonPlanarCore -{ -public: - NonPlanarCore(const Graph &G); - - const Graph &core() const { return m_graph; } - const Graph &originalGraph() const { return *m_pOriginal; } - - node original(node v) const { return m_orig[v]; } - - bool isVirtual(edge e) const { return m_real[e] == 0; } - edge realEdge(edge e) const { return m_real[e]; } - - const EdgeArray &cost() const { return m_cost; } - int cost(edge e) const { return m_cost[e]; } - const List &mincut(edge e) const { return m_mincut[e]; } - -protected: - void markCore(const SPQRTree &T, NodeArray &mark); - void traversingPath(Skeleton &S, edge eS, List &path, NodeArray &mapV); - - Graph m_graph; - const Graph *m_pOriginal; - - NodeArray m_orig; // corresp. original node - EdgeArray m_real; // corresp. original edge (0 if virtual) - EdgeArray > m_mincut; // traversing path for an edge in the core - EdgeArray m_cost; -}; // class NonPlanarCore - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/PlanRep.h b/ext/OGDF/ogdf/planarity/PlanRep.h deleted file mode 100644 index 89586989a..000000000 --- a/ext/OGDF/ogdf/planarity/PlanRep.h +++ /dev/null @@ -1,770 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a base class for planar representations - * of graphs and cluster graphs. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -//PlanRep should not know about generalizations and association, -//but we already set types in Attributedgraph, therefore set them -//in PlanRep, too - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANREP_H -#define OGDF_PLANREP_H - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -/** - * \brief Planarized representations (of a connected component) of a graph. - * - * Maintains types of edges (generalization, association) and nodes, - * and the connected components of the graph. - */ -class OGDF_EXPORT PlanRep : public GraphCopy -{ -public: - //! Information for restoring degree-1 nodes. - struct Deg1RestoreInfo - { - Deg1RestoreInfo() : m_eOriginal(0), m_deg1Original(0), m_adjRef(0) { } - Deg1RestoreInfo(edge eOrig, node deg1Orig, adjEntry adjRef) - : m_eOriginal(eOrig), m_deg1Original(deg1Orig), m_adjRef(adjRef) { } - - edge m_eOriginal; //!< the original edge leading to the deg-1 node - node m_deg1Original; //!< the original deg-1 node - adjEntry m_adjRef; //!< the reference adjacency entry for restoring the edge - }; - - - /* @{ - * \brief Creates a planarized representation of graph \a G. - */ - PlanRep(const Graph& G); - - /** - * \brief Creates a planarized representation of graph \a AG. - */ - PlanRep(const GraphAttributes& AG); - - virtual ~PlanRep() {} - - - //@} - /** - * @name Processing connected components - * Planarized representations provide a mechanism for always representing - * a copy of a single component of the original graph. - */ - //@{ - - /** - * \brief Returns the number of connected components in the original graph. - */ - int numberOfCCs() const { - return m_nodesInCC.size(); - } - - /** - * \brief Returns the index of the current connected component (-1 if not yet initialized). - */ - int currentCC() const { - return m_currentCC; - } - - /** - * \brief Returns the list of (original) nodes in connected component \a i. - * - * Note that connected components are numbered 0,1,... - */ - const List &nodesInCC(int i) const { - return m_nodesInCC[i]; - } - - /** - * \brief Returns the list of (original) nodes in the current connected component. - */ - const List &nodesInCC() const { - return m_nodesInCC[m_currentCC]; - } - - /** - * \brief Initializes the planarized representation for connected component \a i. - * - * This initialization is always required. After performing this initialization, - * the planarized representation represents a copy of the i-th connected - * component of the original graph, where connected components are numbered - * 0,1,2,... - */ - void initCC(int i); - - - //@} - /** - * @name Node expansion - */ - //@{ - - /** - * \brief Returns the adjacency entry of a node of an expanded face. - * - * If no such entry is stored at node \a v, 0 is returned. - */ - adjEntry expandAdj(node v) const { - return m_expandAdj[v]; - } - - adjEntry& expandAdj(node v) { - return m_expandAdj[v]; - } - - //@} - /** - * @name Clique boundary - */ - //@{ - - /** - * Returns the adjacency entry of the first edge of the inserted boundary - * at a center node (original) of a clique, 0 if no boundary exists - */ - adjEntry boundaryAdj(node v) const { - return m_boundaryAdj[v]; - } - - /** - * Returns a reference to the adjacency entry of the first edge of the inserted boundary - * at a center node (original) of a clique, 0 if no boundary exists - */ - adjEntry& boundaryAdj(node v){ - return m_boundaryAdj[v]; - } - - //edge on the clique boundary, adjSource - void setCliqueBoundary(edge e) { - setEdgeTypeOf(e, edgeTypeOf(e) | cliquePattern()); - } - bool isCliqueBoundary(edge e) { - return ((edgeTypeOf(e) & cliquePattern()) == cliquePattern()); - } - - - //@} - /** - * @name Node types - */ - //@{ - - /** - * \brief Returns the type of node \a v. - * @param v is a node in the planarized representation. - */ - Graph::NodeType typeOf(node v) const { - return m_vType[v]; - } - - /** - * \brief Returns a reference to the type of node \a v. - * @param v is a node in the planarized representation. - */ - Graph::NodeType& typeOf(node v) { - return m_vType[v]; - } - - /** - * \brief Returns true if the node represents a "real" object in the original graph. - * - * \todo It is necessary to check for several different possible types. - * This should be solved by combining representation types (vertex, dummy,...) - * with semantic types (class, interface,...) within GraphAttributes; - * we then can return to vertex only. - */ - inline bool isVertex(node v) - { - return ( (typeOf(v) == Graph::vertex) || - (typeOf(v) == Graph::associationClass)); - } - - /** - * \brief Returns the extended node type of \a v. - * @param v is a node in the planarized representation. - */ - nodeType nodeTypeOf(node v) - { - return m_nodeTypes[v]; - } - - /** - * \brief Classifies node \a v as a crossing. - * @param v is a node in the planarized representation. - */ - void setCrossingType(node v) - { - m_nodeTypes[v] |= ntTerCrossing << ntoTertiary; - } - - /** - * \brief Returns true iff node \a v is classified as a crossing. - * @param v is a node in the planarized representation. - */ - bool isCrossingType(node v) - { - return (m_nodeTypes[v] &= (ntTerCrossing << ntoTertiary)) != 0; - } - - //@} - /** - * @name Edge types - */ - //@{ - - /** - * \brief Returns the type of edge \a e. - * @param e is an edge in the planarized representation. - */ - EdgeType typeOf(edge e) const { - return m_eType[e]; - } - - /** - * \brief Returns a reference to the type of edge \a e. - * @param e is an edge in the planarized representation. - */ - EdgeType& typeOf(edge e) { - return m_eType[e]; - } - - /** - * \brief Returns a reference to the type of original edge \a e. - * @param e is an edge in the original graph. - */ - edgeType& oriEdgeTypes(edge e) - { - return m_oriEdgeTypes[e]; - } - - /** - * \brief Returns the new type field of \a e. - * @param e is an edge in the planarized representation. - */ - edgeType edgeTypeOf(edge e) - { - return m_edgeTypes[e]; - } - - /** - * \brief Returns a reference to the new type field of \a e. - * @param e is an edge in the planarized representation. - */ - edgeType& edgeTypes(edge e) - { - return m_edgeTypes[e]; - } - - /** - * \brief Sets the new type field of edge \a e to \a et. - * @param e is an edge in the planarized representation. - * @param et is the type assigned to \a e. - */ - void setEdgeTypeOf(edge e, edgeType et) - { - m_edgeTypes[e] = et; - } - - /** - * \brief Set both type values of \a e at once. - * - * This is a temporary solution that sets both type values; this way, all - * additional edge types in the new field are lost. - * @param e is an edge in the planarized representation. - * @param et is the type assigned to \a e. - */ - void setType(edge e, EdgeType et) - { - m_eType[e] = et; - switch (et) - { - case Graph::association: m_edgeTypes[e] = etcPrimAssociation;break; - case Graph::generalization: m_edgeTypes[e] = etcPrimGeneralization; - break; - case Graph::dependency: m_edgeTypes[e] = etcPrimDependency; break; - default: break; - } - } - - //------------------------------------------------------------------------- - //new edge types - //to set or check edge types use the pattern function in the private section - - //------------------- - //primary level types - - //! Returns true iff edge \a e is classified as generalization. - bool isGeneralization(edge e) { - bool check = (((m_edgeTypes[e] & etpPrimary) & etcPrimGeneralization) == etcPrimGeneralization); - return check; - } - - //! Classifies edge \a e as generalization (primary type). - void setGeneralization(edge e) { - setPrimaryType(e, etcPrimGeneralization); - - //preliminary set old array too - m_eType[e] = generalization; //can be removed if edgetypes work properly - } - - //! Returns true iff edge \a e is classified as dependency. - bool isDependency(edge e) { - bool check = (((m_edgeTypes[e] & etpPrimary) & etcPrimDependency) == etcPrimDependency); - return check; - } - - //! Classifies edge \a e as dependency (primary type). - void setDependency(edge e) { - setPrimaryType(e, etcPrimDependency); - - //preliminary set old array too - m_eType[e] = dependency; //can be removed if edgetypes work properly - } - - //! Classifies edge \a e as association (primary type). - void setAssociation(edge e) { - setPrimaryType(e, etcPrimAssociation); - - //preliminary set old array too - m_eType[e] = association; //can be removed if edgetypes work properly - } - - //------------------ - //second level types - - //in contrast to setsecondarytype: do not delete old value - - //! Classifies edge \a e as expansion edge (secondary type). - void setExpansion(edge e) { - m_edgeTypes[e] |= expansionPattern(); - - //preliminary set old array too - m_expansionEdge[e] = 1;//can be removed if edgetypes work properly - } - - //! Returns true iff edge \a e is classified as expansion edge. - bool isExpansion(edge e) { - return ((m_edgeTypes[e] & expansionPattern()) == expansionPattern()); - } - - //should add things like cluster and clique boundaries that need rectangle shape - - //! Returns true iff edge \a e is a clique boundary. - bool isBoundary(edge e) { - return isCliqueBoundary(e); } - - //-------------- - //tertiary types - - //! Classifies edge \a e as connection at an association class (tertiary type). - void setAssClass(edge e) - { - m_edgeTypes[e] |= assClassPattern(); - } - - //! Returns true iff edge \a e is classified as connection at an association class. - bool isAssClass(edge e) - { - return ((m_edgeTypes[e] & assClassPattern()) == assClassPattern()); - } - - - //------------------ - //fourth level types - - //! Classifies edge \a e as connection between hierarchy neighbours (fourth level type). - void setBrother(edge e) { - m_edgeTypes[e] |= brotherPattern(); - } - - //! Classifies edge \a e as connection between ... (fourth level type). - void setHalfBrother(edge e) { - m_edgeTypes[e] |= halfBrotherPattern(); - } - - //! Returns true if edge \a e is classified as brother. - bool isBrother(edge e) { - return ( (((m_edgeTypes[e] & etpFourth) & brotherPattern())>> etoFourth) == etcBrother); - } - - //! Returns true if edge \a e is classified as half-brother. - bool isHalfBrother(edge e) { - return ( (((m_edgeTypes[e] & etpFourth) & halfBrotherPattern())>> etoFourth) == etcHalfBrother); - } - - //----------------- - //set generic types - - edgeType edgeTypeAND(edge e, edgeType et) {m_edgeTypes[e] &= et; return m_edgeTypes[e];} - - edgeType edgeTypeOR(edge e, edgeType et) {m_edgeTypes[e] |= et; return m_edgeTypes[e];} - - //set primary edge type of edge e to primary edge type in et - //deletes old primary value - void setPrimaryType(edge e, edgeType et) { - m_edgeTypes[e] &= 0xfffffff0; - m_edgeTypes[e] |= (etpPrimary & et); - } - - void setSecondaryType(edge e, edgeType et) { - m_edgeTypes[e] &= 0xffffff0f; - m_edgeTypes[e] |= (etpSecondary & ( et << etoSecondary)); - } - - //sets primary type to bitwise AND of et's primary value and old value - edgeType edgeTypePrimaryAND(edge e, edgeType et) {m_edgeTypes[e] &= (etpAll & et); return m_edgeTypes[e];} - - //sets primary type to bitwise OR of et's primary value and old value - edgeType edgeTypePrimaryOR(edge e, edgeType et) {m_edgeTypes[e] |= et; return m_edgeTypes[e];} - - //set user defined type locally - void setUserType(edge e, edgeType et) - { - OGDF_ASSERT( et < 147); - m_edgeTypes[e] |= (et << etoUser); - } - - bool isUserType(edge e, edgeType et) - { - OGDF_ASSERT( et < 147); - return ( (m_edgeTypes[e] & (et << etoUser)) == (et << etoUser)); - } - - //--------------- - // - // old edge types - - //this is pure nonsense, cause we have uml-edgetype and m_etype, and should be able to - //use them with different types, but as long as they arent used correctly (switch instead of xor), - //use this function to return if e is expansionedge - //if it is implemented correctly later, delete the array and return m_etype == Graph::expand - //(the whole function then is obsolete, cause you can check it directly, but for convenience...) - //should use genexpand, nodeexpand, dissect instead of bool - void setExpansionEdge(edge e, int expType) { - m_expansionEdge[e] = expType; - } - - bool isExpansionEdge(edge e) const { - return (m_expansionEdge[e] > 0); - } - - int expansionType(edge e) const { return m_expansionEdge[e]; } - - //precondition normalized - bool isDegreeExpansionEdge(edge e) const { - //return (m_eType[e] == Graph::expand); - return ( m_expansionEdge[e] == 2); - } - - - //@} - /** - * @name Access to attributes in original graph - * These methods provide easy access to attributes of original nodes and - * edges. - */ - //@{ - - - //! Gives access to the node array of the widths of original nodes. - const NodeArray &widthOrig() const { - return m_pGraphAttributes->width(); - } - - //! Returns the width of original node \a v. - double widthOrig(node v) const { - return m_pGraphAttributes->width(v); - } - - //! Gives access to the node array of the heights of original nodes. - const NodeArray &heightOrig() const { - return m_pGraphAttributes->height(); - } - - //! Returns the height of original node \a v. - double heightOrig(node v) const { - return m_pGraphAttributes->height(v); - } - - //! Returns the type of original edge \a e. - EdgeType typeOrig(edge e) const { - return m_pGraphAttributes->type(e); - } - - //! Returns the graph attributes of the original graph (the pointer may be 0). - const GraphAttributes &getGraphAttributes() const { - return *m_pGraphAttributes; - } - - //@} - /** - * @name Structural alterations - */ - //@{ - - // Expands nodes with degree > 4 and merge nodes for generalizations - void expand(bool lowDegreeExpand = false); - - void expandLowDegreeVertices(OrthoRep &OR); - - void collapseVertices(const OrthoRep &OR, Layout &drawing); - - void removeCrossing(node v); //removes the crossing at node v - - //model a boundary around a star subgraph centered at center - //and keep external face information (outside the clique - void insertBoundary(node center, adjEntry& adjExternal); - - - //@} - /** - * @name Extension of methods defined by GraphCopys - */ - //@{ - - //! Splits edge \a e. - virtual edge split(edge e); - - - //returns node which was expanded using v - node expandedNode(node v) const { return m_expandedNode[v]; } - - void setExpandedNode(node v, node w) { m_expandedNode[v] = w; } - - - //@} - /** - * @name Creation of new nodes and edges - */ - //@{ - - /** - * \brief Creates a new node with node type \a vType in the planarized representation. - * @param vOrig becomes the original node of the new node. - * @param vType becomes the type of the new node. - */ - node newCopy(node vOrig, Graph::NodeType vType); - - /** - * \brief Creates a new edge in the planarized representation. - * @param v is the source node of the new edge. - * @param adjAfter is the adjacency entry at the target node, after which the - * new edge is inserted. - * @param eOrig becomes the original edge of the new edge. - */ - edge newCopy(node v, adjEntry adjAfter, edge eOrig); - - /** - * \brief Creates a new edge in the planarized representation while updating the embedding \a E. - * @param v is the source node of the new edge. - * @param adjAfter is the adjacency entry at the target node, after which the - * new edge is inserted. - * @param eOrig becomes the original edge of the new edge. - * @param E is an embedding of the planarized representation. - */ - edge newCopy(node v, adjEntry adjAfter, edge eOrig, CombinatorialEmbedding &E); - - - //@} - /** - * @name Crossings - */ - //@{ - - // embeds current copy - bool embed(); - - // removes all crossing nodes which are actually only two "touching" edges - void removePseudoCrossings(); - - // re-inserts edge eOrig by "crossing" the edges in crossedEdges; - // splits each edge in crossedEdges - // Precond.: eOrig is an edge in the original graph, - // the edges in crossedEdges are in this graph - void insertEdgePath(edge eOrig, const SList &crossedEdges); - - // same as insertEdgePath, but assumes that the graph is embedded - void insertEdgePathEmbedded( - edge eOrig, - CombinatorialEmbedding &E, - const SList &crossedEdges); - - // removes the complete edge path for edge eOrig - // Precond.: eOrig s an edge in the original graph - void removeEdgePathEmbedded(CombinatorialEmbedding &E, - edge eOrig, - FaceSetPure &newFaces) { - GraphCopy::removeEdgePathEmbedded(E,eOrig,newFaces); - } - - //! Inserts crossings between two copy edges. - /** - * This method is used in TopologyModule. - * - * Let \a crossingEdge = (\a a, \a b) and \a crossedEdge = (\a v, \a w). - * Then \a crossedEdge is split creating two edges \a crossedEdge = (\a v, \a u) - * and (\a u, \a w), \a crossingEdge is removed and replaced by two new edges - * \a e1 = (\a a, \a u) and \a e1 = (\a u, \a b). - * Finally it sets \a crossingEdge to \a e2 and returns (\a u, \a w). - * - * @param crossingEdge is the edge that gets split. - * @param crossedEdge is the edge that is replaced by two new edges. - * @param topDown is used as follows: If set to true, \a crossingEdge will cross - * \a crossedEdge from right to left, otherwise from left to right. - */ - edge insertCrossing( - edge &crossingEdge, - edge crossedEdge, - bool topDown); - - //@} - /** - * @name Degree-1 nodes - * These methods realize a mechanism for temporarily removing degree-1 nodes. - */ - //@{ - - /** - * \brief Removes all marked degree-1 nodes from the graph copy and stores restore information in \a S. - * @param S returns the restore information required by restoreDeg1Nodes(). - * @param mark defines which nodes are marked for removal; all nodes \a v with - * mark[v]=true are removed. - * \pre Only nodes with degree 1 may be marked. - */ - void removeDeg1Nodes(Stack &S, const NodeArray &mark); - - /** - * \brief Restores degree-1 nodes previously removed with removeDeg1Nodes(). - * @param S contains the restore information. - * @param deg1s returns the list of newly created nodes in the copy. - */ - void restoreDeg1Nodes(Stack &S, List °1s); - - //@} - -protected: - - int m_currentCC; //!< The index of the current component. - int m_numCC; //!< The number of components in the original graph. - - Array > m_nodesInCC; //!< The list of original nodes in each component. - - const GraphAttributes* m_pGraphAttributes; //!< Pointer to graph attributes of original graph. - - //------------ - //object types - - //set the type of eCopy according to the type of eOrig - //should be virtual if PlanRepUML gets its own - void setCopyType(edge eCopy, edge eOrig); - - //helper to cope with the edge types, shifting to the right place - edgeType generalizationPattern() {return etcPrimGeneralization;} - edgeType associationPattern() {return etcPrimAssociation;} - edgeType expansionPattern() {return etcSecExpansion << etoSecondary;} - edgeType assClassPattern() {return etcAssClass << etoTertiary;} - edgeType brotherPattern() {return etcBrother << etoFourth;} - edgeType halfBrotherPattern() {return etcHalfBrother << etoFourth;} - edgeType cliquePattern() {return etcSecClique << etoSecondary;} //boundary - - - void removeUnnecessaryCrossing( - adjEntry adjA1, - adjEntry adjA2, - adjEntry adjB1, - adjEntry adjB2); - -//-------------------------------------------------------------------------- - - NodeArray m_vType; //!< Simple node types. - - NodeArray m_nodeTypes; //!< Node types for extended semantic information. - - NodeArray m_expandedNode; //!< For all expansion nodes, save expanded node. - NodeArray m_expandAdj; - - //clique handling: We save an adjEntry of the first edge of an inserted - //boundary around a clique at its center v - NodeArray m_boundaryAdj; - - //zusammenlegbare Typen - EdgeArray m_expansionEdge; //1 genmerge, 2 degree (2 highdegree, 3 lowdegree) - EdgeArray m_eType; - - //m_edgeTypes stores semantic edge type information on several levels: - //primary type: generalization, association,... - //secondary type: merger,... - //tertiary type: vertical in hierarchy, inner, outer, ... - //fourth type: neighbour relation (brother, cousin in hierarchy) - //user types: user defined for local changes - EdgeArray m_edgeTypes; //store all type information - - //workaround fuer typsuche in insertedgepathembed - //speichere kopietyp auf originalen - //maybe it's enough to set gen/ass without extra array - EdgeArray m_oriEdgeTypes; - - EdgeArray m_eAuxCopy; // auxiliary (GraphCopy::initByNodes()) - -};//PlanRep - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/PlanRepExpansion.h b/ext/OGDF/ogdf/planarity/PlanRepExpansion.h deleted file mode 100644 index 340e1ede5..000000000 --- a/ext/OGDF/ogdf/planarity/PlanRepExpansion.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanRepExpansion representing a - * planarized representation of the expansion of a graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLAN_REP_EXPANSION_H -#define OGDF_PLAN_REP_EXPANSION_H - - -#include -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT CombinatorialEmbedding; -class OGDF_EXPORT FaceSetPure; -class OGDF_EXPORT NodeSetPure; - - -/** - * \brief Planarized representations (of a connected component) of a graph. - * - * Maintains types of edges (generalization, association) and nodes, - * and the connected components of the graph. - */ -class OGDF_EXPORT PlanRepExpansion : public Graph -{ -public: - struct Crossing { - Crossing() { m_adj = 0; } - Crossing(adjEntry adj) { m_adj = adj; } - - adjEntry m_adj; - SList m_partitionLeft; - SList m_partitionRight; - - friend ostream &operator<<(ostream &os, const Crossing &c) { - os << "(" << c.m_adj << ")"; - return os; - } - }; - - - /** - * \brief Representation of a node split in a planarized expansion. - * - * Stores in particular the insertion path of the node split (just like the - * chain of an original edge). - */ - class NodeSplit - { - public: - /** - * \brief Creates an empty node split. - */ - NodeSplit() { } - - /** - * \brief Creates a node split and sets its iterator in the list of all node splits. - */ - NodeSplit(ListIterator it) : m_nsIterator(it) { } - - /** - * \brief Returns the first node on the node split's insertion path. - */ - node source() const { return m_path.front()->source(); } - - /** - * \brief Returns the last node on the node split's insertion path. - */ - node target() const { return m_path.back ()->target(); } - - List m_path; //!< The insertion path of the node split. - ListIterator m_nsIterator; //!< This node split's iterator in the list of all node splits. - }; - - //! Pointer to a node split. - typedef PlanRepExpansion::NodeSplit *nodeSplit; - - - /** - * \brief Creates a planarized expansion of graph \a G. - * - * All nodes are allowed to be split. - */ - PlanRepExpansion(const Graph& G); - - /** - * \brief Creates a planarized expansion of graph \a G with given splittable nodes. - * - * Only the node in \a splittableNodes are allowed to be split. - * @param G is the original graph of this planarized expansion. - * @param splittableNodes contains all the nodes in \a G that are splittable. - */ - PlanRepExpansion(const Graph& G, const List &splittableNodes); - - ~PlanRepExpansion() {} - - - /** - * @name Acess methods - */ - //@{ - - //! Returns a reference to the original graph. - const Graph &original() const { return *m_pGraph; } - - //! Returns the original node of \a v, or 0 if \a v is a dummy. - node original(node v) const { return m_vOrig[v]; } - - //! Returns the list of copy nodes of \a vOrig. - const List &expansion(node vOrig) const { return m_vCopy[vOrig]; } - - //! Returns the first copy node of \a vOrig. - node copy(node vOrig) const { return m_vCopy[vOrig].front(); } - - //! Returns the original edge of \ e, or 0 if \a e has none (e.g., \a e belongs to a node split). - edge originalEdge(edge e) const { return m_eOrig[e]; } - - //! Returns the insertion path of edge \a eOrig. - const List &chain(edge eOrig) const { return m_eCopy[eOrig]; } - - //! Returns the first edge in \a eOrig's insertion path. - edge copy(edge eOrig) const { return m_eCopy[eOrig].front(); } - - //! Returns true iff \a v is splittable. - bool splittable(node v) const { return m_splittable[v]; } - - //! Returns true iff \a vOrig is splittable. - bool splittableOrig(node vOrig) const { return m_splittableOrig[vOrig]; } - - //! Returns the node split associated with \a e, or 0 if none (e.g., \a e belongs to an original edge). - NodeSplit *nodeSplitOf(edge e) const { return m_eNodeSplit[e]; } - - //! Returns the number of node splits. - int numberOfNodeSplits() const { return m_nodeSplits.size(); } - int numberOfSplittedNodes() const; - - //! Returns the list of node splits. - List &nodeSplits() { return m_nodeSplits; } - - /** - * \brief Sets the original edge and corresponding node split of \a e and returns the corresponding insertion path. - * - * @param e is an edge in the planarized expansion. - * @param eOrig is assigned the original edge of \a e (or 0 if none). - * @param ns is assigned the node split corresponding to \a e (or 0 if none). - * @return a reference to the insertion path containing \a e; this is either the insertion - * path of \a eOrig (if this is not 0), or of \a ns. - */ - List &setOrigs(edge e, edge &eOrig, nodeSplit &ns); - - ListConstIterator position(edge e) const { return m_eIterator[e]; } - - bool isPseudoCrossing(node v) const; - - //! Computes the number of crossings. - int computeNumberOfCrossings() const; - - //@} - /** - * @name Processing connected components - */ - //@{ - - - /** - * \brief Returns the number of connected components in the original graph. - */ - int numberOfCCs() const { - return m_nodesInCC.size(); - } - - /** - * \brief Returns the index of the current connected component (-1 if not yet initialized). - */ - int currentCC() const { - return m_currentCC; - } - - /** - * \brief Returns the list of (original) nodes in connected component \a i. - * - * Note that connected components are numbered 0,1,... - */ - const List &nodesInCC(int i) const { - return m_nodesInCC[i]; - } - - /** - * \brief Returns the list of (original) nodes in the current connected component. - */ - const List &nodesInCC() const { - return m_nodesInCC[m_currentCC]; - } - - /** - * \brief Initializes the planarized representation for connected component \a i. - * - * This initialization is always required. After performing this initialization, - * the planarized representation represents a copy of the i-th connected - * component of the original graph, where connected components are numbered - * 0,1,2,... - */ - void initCC(int i); - - - //@} - /** - * @name Update operations - */ - //@{ - - edge split(edge e); - - void unsplit(edge eIn, edge eOut); - - //! Removes edge \a e from the planarized expansion. - void delCopy(edge e); - - //! Embeds the planarized expansion; returns true iff it is planar. - bool embed(); - - void insertEdgePath( - edge eOrig, - nodeSplit ns, - node vStart, - node vEnd, - List &eip, - edge eSrc, - edge eTgt); - - /** - * \brief Inserts an edge or a node split according to insertion path \a crossedEdges. - * - * If \a eOrig is not 0, a new insertion path for \a eOrig is inserted; otherwise, - * a new insertion path for node split \a ns is inserted. - * @param eOrig is an original edge in the graph (or 0). - * @param ns is a node split in the planarized expansion. - * @param E is an embedding of the planarized expansion. - * @param crossedEdges defines the insertion path. - * \pre Not both \a eOrig and \a ns may be 0. - * \see GraphCopy::insertEdgePathEmbedded() for a specification of \a crossedEdges. - */ - void insertEdgePathEmbedded( - edge eOrig, - nodeSplit ns, - CombinatorialEmbedding &E, - const List > &crossedEdges); - - /** - * \brief Removes the insertion path of \a eOrig or \a ns. - * - * @param E is an embedding of the planarized expansion. - * @param eOrig is an original edge in the graph (or 0). - * @param ns is a node split in the planarized expansion. - * @param newFaces is assigned the set of new faces resulting from joining faces when removing edges. - * @param mergedNodes is assigned the set of nodes in the planarized expansion that resulted - * from merging (splittable) nodes. - * @param oldSrc is assigned the source node of the removed insertion path. - * @param oldTgt is assigned the target node of the removed insertion path. - * \pre Not both \a eOrig and \a ns may be 0. - */ - void removeEdgePathEmbedded( - CombinatorialEmbedding &E, - edge eOrig, - nodeSplit ns, - FaceSetPure &newFaces, - NodeSetPure &mergedNodes, - node &oldSrc, - node &oldTgt); - - /** - * \brief Removes the insertion path of \a eOrig or \a ns. - * - * @param eOrig is an original edge in the graph (or 0). - * @param ns is a node split in the planarized expansion. - * @param oldSrc is assigned the source node of the removed insertion path. - * @param oldTgt is assigned the target node of the removed insertion path. - * \pre Not both \a eOrig and \a ns may be 0. - */ - void removeEdgePath( - edge eOrig, - nodeSplit ns, - node &oldSrc, - node &oldTgt); - - /** - * \brief Removes an (unneccessary) node split consisting of a single edge. - * - * Nodes splits consisting of a single edge are superfluous and canbe removed - * by contracting the respective edge. - * @param ns is the node split to be removed. - * @param E is an embedding of the planarized expansion. - */ - void contractSplit(nodeSplit ns, CombinatorialEmbedding &E); - - /** - * \brief Removes an (unneccessary) node split consisting of a single edge. - * - * Nodes splits consisting of a single edge are superfluous and canbe removed - * by contracting the respective edge. - * @param ns is the node split to be removed. - */ - void contractSplit(nodeSplit ns); - - /** - * \brief Unsplits a superfluous expansion node of degree 2. - * @param u is a node in the planarized expansion which has degree 2 and is part of the - * expansion of an original node. - * @param eContract is the edge incident to \a u which is part of a node split; this edge - * gets contracted. - * @param eExpand is the edge incident to \a u which belongs to the insertion path - * that gets enlarged. - * @param E is an embedding of the planarized expansion. - */ - edge unsplitExpandNode( - node u, - edge eContract, - edge eExpand, - CombinatorialEmbedding &E); - - /** - * \brief Unsplits a superfluous expansion node of degree 2. - * @param u is a node in the planarized expansion which has degree 2 and is part of the - * expansion of an original node. - * @param eContract is the edge incident to \a u which is part of a node split; this edge - * gets contracted. - * @param eExpand is the edge incident to \a u which belongs to the insertion path - * that gets enlarged. - */ - edge unsplitExpandNode( - node u, - edge eContract, - edge eExpand); - - /** - * \brief Splits edge \a e and introduces a new node split starting at \a v. - * - * @param v is a node in the planarized expansion; the expansion of \a v's original - * node is enlarged. - * @param e is the edge to be split; the insertion path of \a e's original edge - * must start or end at \a v. - * @param E is an embedding of the planarized expansion. - * @return the newly created edge; the node resulting from splitting \a e is the - * target node of this edge. - */ - edge enlargeSplit(node v, edge e, CombinatorialEmbedding &E); - - /** - * \brief Splits edge \a e and introduces a new node split starting at \a v. - * - * @param v is a node in the planarized expansion; the expansion of \a v's original - * node is enlarged. - * @param e is the edge to be split; the insertion path of \a e's original edge - * must start or end at \a v. - * @return the newly created edge; the node resulting from splitting \a e is the - * target node of this edge. - */ - edge enlargeSplit(node v, edge e); - - /** - * \brief Introduces a new node split by splitting an exisiting node split. - * - * @param e is the edge to be split; the node split corresponding to \a e is split - * into two node splits. - * @param E is an embedding of the planarized expansion. - * @return the newly created edge; the node resulting from splitting \a e is the - * target node of this edge. - */ - edge splitNodeSplit(edge e, CombinatorialEmbedding &E); - - /** - * \brief Introduces a new node split by splitting an exisiting node split. - * - * @param e is the edge to be split; the node split corresponding to \a e is split - * into two node splits. - * @return the newly created edge; the node resulting from splitting \a e is the - * target node of this edge. - */ - edge splitNodeSplit(edge e); - - /** - * \brief Removes a self-loop \a e = (\a u,\a u). - * - * \a u must be a dummy node; hence, \a u has degree 2 node after removing \ e, and - * \a u is unsplit afterwards. - * @param e must be a self loop in the planarized expansion. - * @param E is an embedding of the planarized expansion. - */ - void removeSelfLoop(edge e, CombinatorialEmbedding &E); - - void removeSelfLoop(edge e); - - /** - * \brief Converts a dummy node \a u to a copy of an original node \a vOrig. - * - * This method is used if two copy nodes \a x and \a y of the same original node \a vOrig - * can be connected by converting a dummy node \a u into a copy node of \a vOrig, since an - * insertion path starting (or ending) at \a x crosses an insertion path starting (or - * ending) at \a y. - * @param u is a dummy node in the planarized expansion. - * @param vOrig is an original node. - * @param ns is a node split that can be reused for connecting \a x with \a u. - */ - PlanRepExpansion::nodeSplit convertDummy( - node u, - node vOrig, - PlanRepExpansion::nodeSplit ns); - - edge separateDummy( - adjEntry adj_1, - adjEntry adj_2, - node vStraight, - bool isSrc); - - void resolvePseudoCrossing(node v); - - //@} - /** - * @name Miscelleaneous - */ - //@{ - - /** - * \brief Performs various consistency checks on the data structure. - */ - bool consistencyCheck() const; - - //@} - -private: - void doInit(const Graph &G, const List &splittableNodes); - void prepareNodeSplit( - const SList &partitionLeft, - adjEntry &adjLeft, - adjEntry &adjRight); - - const Graph *m_pGraph; //!< The original graph. - NodeArray m_vOrig; //!< The corresponding node in the original graph. - EdgeArray m_eOrig; //!< The corresponding edge in the original graph. - EdgeArray > m_eIterator; //!< The position of copy edge in the list. - EdgeArray > m_eCopy; //!< The corresponding list of edges in the graph copy. - NodeArray > m_vIterator; //!< The position of copy node in the list. - NodeArray > m_vCopy; //!< The corresponding list of nodes in the graph copy. - - NodeArray m_splittable; - NodeArray m_splittableOrig; - EdgeArray m_eNodeSplit; - List m_nodeSplits; - - int m_currentCC; //!< The index of the current component. - int m_numCC; //!< The number of components in the original graph. - - Array > m_nodesInCC; //!< The list of original nodes in each component. - EdgeArray m_eAuxCopy; // auxiliary -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/PlanRepInc.h b/ext/OGDF/ogdf/planarity/PlanRepInc.h deleted file mode 100644 index 63390abc8..000000000 --- a/ext/OGDF/ogdf/planarity/PlanRepInc.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanRepInc. - * - * The PlanRepInc is especially suited for incremental drawing - * modes. It derives from GraphObserver and therefore is always - * informed about changes of the underlying graph. Keeps the - * m_nodesInCC and m_numCC fields up-to-date. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLAN_REP_INC_H -#define OGDF_PLAN_REP_INC_H - - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//=============================================== -//main function(s): -// -// this class is only an adaption of PlanRep -// for the special incremental drawing case -// As incremental layout only makes sense with -// a given layout, this PlanRepInc copes with -// layout information and embedding -//=============================================== - -class OGDF_EXPORT PlanRepInc : public PlanRepUML, public GraphObserver -{ -public: - //construction - //constructor for interactive updates (parts added step by step) - PlanRepInc(const UMLGraph& UG); - //constructor for incremental updates (whole graph already given) - //part to stay fixed has fixed value set to true - PlanRepInc(const UMLGraph& UG, const NodeArray &fixed); - - //init a CC only with active elements - void initActiveCC(int i); - //but with at least one active node, makes a node active if necessary - //and returns it. returns 0 otherwise - node initMinActiveCC(int i); - - //in the case that the underlying incremental structure - //changes, we update this copy - virtual void nodeDeleted(node v); - virtual void nodeAdded(node v); - virtual void edgeDeleted(edge e); - virtual void edgeAdded(edge e); - virtual void reInit(); - virtual void cleared();//Graph cleared - - //sets activity status to true and updates the structures - //node activation activates all adjacent edges - void activateNode(node v); - //TODO: auch deaktivieren - //void activateNode(node v, bool b); - void activateEdge(edge e); - - //handles copies of original CCs that are split into - //unconnected parts of active nodes by connecting them - //tree-like adding necessary edges at "external" nodes - //of the partial CCs. Note that this only makes sense - //when the CC parts are already correctly embedded - bool makeTreeConnected(adjEntry adjExternal); - //delete an edge again - void deleteTreeConnection(int i, int j); - void deleteTreeConnection(int i, int j, CombinatorialEmbedding &E); - //sets a list of adjentries on "external" faces of - //unconnected active parts of the current CC - void getExtAdjs(List &extAdjs); - adjEntry getExtAdj(GraphCopy &GC, CombinatorialEmbedding &E); - - //component number - int& componentNumber(node v) {return m_component[v];} - - bool& treeEdge(edge e) {return m_treeEdge[e];} - //only valid if m_eTreeArray initialized, should be replaced later - edge treeEdge(int i, int j) const - { - if (m_treeInit) { - return m_eTreeArray(i, j); - } - return 0; - } - bool treeInit() {return m_treeInit;} - - // - // extension of methods defined by GraphCopy/PlanRep - // - - // splits edge e, can be removed when edge status in edgetype - // m_treedge can be removed afterwards - virtual edge split(edge e) { - - edge eNew = PlanRepUML::split(e); - if (m_treeEdge[e]) m_treeEdge[eNew] = true; - - return eNew; - - }//split - - //debug output -#ifdef OGDF_DEBUG - void writeGML(const char *fileName) - { - const GraphAttributes &AG = getUMLGraph(); - ofstream os(fileName); - PlanRepInc::writeGML(os, AG);//getUMLGraph());//l); - } - void writeGML(const char *fileName, const Layout &drawing) - { - ofstream os(fileName); - writeGML(os, drawing); - } - - void writeGML(ostream &os, const GraphAttributes &AG); - void writeGML(ostream &os, const Layout &drawing, bool colorEmbed = true); - void writeGML(const char *fileName, GraphAttributes &AG, bool colorEmbed = true); - - //outputs a drawing if genus != 0 - int genusLayout(Layout &drawing) const; -#endif - -protected: - void initMembers(const UMLGraph &UG); - //initialize CC with active nodes (minNode ? at least one node) - node initActiveCCGen(int i, bool minNode); - -private: - NodeArray m_activeNodes; //stores the status of the nodes - EdgeArray m_treeEdge; //edge inserted for connnectivity - NodeArray m_component; //number of partial component in current CC - //used for treeConnection - Array2D m_eTreeArray; //used for treeConnection - bool m_treeInit; //check if the tree edge Array2D was initialized -};//PlanrepInc - - -}//namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/PlanRepUML.h b/ext/OGDF/ogdf/planarity/PlanRepUML.h deleted file mode 100644 index ee48f28c9..000000000 --- a/ext/OGDF/ogdf/planarity/PlanRepUML.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * $Revision: 2577 $ - * - * last checkin: - * $Author: klein $ - * $Date: 2012-07-11 08:08:37 +0200 (Mi, 11. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanRepUML. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLAN_REP_UML_H -#define OGDF_PLAN_REP_UML_H - - - -#include -#include - -#include -#include - - - -namespace ogdf { - - class Layout; - class GridLayoutMapped; - class OrthoRep; - - -//--------------------------------------------------------- -// PlanRepUML -// Planarized representation (of a connected component) -// of a UMLGraph; allows special handling of hierarchies -// in the graph -//--------------------------------------------------------- -class OGDF_EXPORT PlanRepUML : public PlanRep { -public: - - // construction - PlanRepUML(const UMLGraph ¨Graph); - PlanRepUML(const GraphAttributes &GA); - - // deconstruction - ~PlanRepUML() {} - - void initCC(int i); - - // Returns true if an edge splits a face into two subfaces to - // guarantee generalizations to be on opposite sides of a node. - bool faceSplitter(edge e) const{ - return m_faceSplitter[e]; - } - - // Removes all face splitting edges. - void removeFaceSplitter(){ - edge e; - forall_edges(e,(*this)) - if (m_faceSplitter[e]) - delEdge(e); - } - - //------------------- - //incremental drawing - //------------------- - //initialize incremental stuff, e.g. insert incremental mergers - void setupIncremental(int indexCC, CombinatorialEmbedding &E); - //Return the list of inserted incremental mergers - const SList& incrementalMergers(int indexCC) const { return m_incMergers[indexCC]; } - - - //********************************************************** - //set generic types - - //the edges that are embedded next to outgoing generalizations if alignment set - //attention: this information is NOT updated during graph changes and only - //to be used during the embedding phase - bool alignUpward(adjEntry ae) {return m_alignUpward[ae];} - void alignUpward(adjEntry ae, bool b) {m_alignUpward[ae] = b;} - - - //************************************************************************* - - - const UMLGraph &getUMLGraph() const { - return *m_pUmlGraph; - } - - //************************************************************************* - //structural alterations - - // inserts a generalization merge node for all incoming - // generalizations of v and returns it - //conserving embedding - node insertGenMerger(node v, const SList &inGens, - CombinatorialEmbedding &E); - - // Expands nodes with degree > 4 and merge nodes for generalizations - void expand(bool lowDegreeExpand = false); - - //expands nodes with degree <= 4 and aligns opposite edges at degree 2 nodes - void expandLowDegreeVertices(OrthoRep &OR, bool alignSmallDegree = false); - - void collapseVertices(const OrthoRep &OR, Layout &drawing); - - //************************************************************************* - - - // - // extension of methods defined by GraphCopy/PlanRep - // - - // splits edge e - virtual edge split(edge e) { - - edge eNew = PlanRep::split(e); - - //check this - if (m_alignUpward[e->adjSource()]) m_alignUpward[eNew->adjSource()] = true; - if (m_alignUpward[e->adjTarget()]) m_alignUpward[eNew->adjTarget()] = true; - - return eNew; - } - - - // writes attributed graph in GML format to file fileName - // For Debugging only - void writeGML(const char *fileName, const Layout &drawing); - void writeGML(const char *fileName); - void writeGML(const char *fileName, GraphAttributes &AG); - - // writes attributed graph in GML format to output stream os - // For Debugging only - void writeGML(ostream &os, const Layout &drawing); - void writeGML(const char *fileName, const OrthoRep &OR, const Layout &drawing); - void writeGML(ostream &os, const OrthoRep &OR, const Layout &drawing); - void writeGML(const char *fileName, const OrthoRep &OR, const GridLayoutMapped &drawing); - void writeGML(ostream &os, const OrthoRep &OR, const GridLayoutMapped &drawing); - - -protected: - //insert mergers of generalizations in copy - void prepareIncrementalMergers(int indexCC, CombinatorialEmbedding &E); - - -protected: - //still some AdjEntry type: used by alignment procedures - //attention: this information is NOT updated during graph changes and only - //to be used during the embedding phase - AdjEntryArray m_alignUpward; - -private: - const UMLGraph *m_pUmlGraph; - - EdgeArray m_faceSplitter; - - SListPure m_mergeEdges; - Array< SList > m_incMergers; //stores all incremental mergers in CC -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/PlanarizationGridLayout.h b/ext/OGDF/ogdf/planarity/PlanarizationGridLayout.h deleted file mode 100644 index af56482a5..000000000 --- a/ext/OGDF/ogdf/planarity/PlanarizationGridLayout.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of planarization with grid layout. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PLANARIZATION_GRID_LAYOUT_H -#define OGDF_PLANARIZATION_GRID_LAYOUT_H - - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -/** - * \brief The planarization grid layout algorithm. - * - * The class PlanarizationGridLayout represents a customizable implementation - * of the planarization approach for drawing graphs. The class uses a - * planar grid layout algorithm as a subroutine and allows to generate - * a usual layout or a grid layout. - * - * If the planarization layout algorithm shall be used for simultaneous drawing, - * you need to define the different subgraphs by setting the subgraphs - * option. - * - * The implementation used in PlanarizationGridLayout is based on the following - * publication: - * - * C. Gutwenger, P. Mutzel: An Experimental Study of Crossing - * Minimization Heuristics. 11th International Symposium on %Graph - * Drawing 2003, Perugia (GD '03), LNCS 2912, pp. 13-24, 2004. - * - *

    Optional parameters

    - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    pageRatiodouble1.0 - * Specifies the desired ration of width / height of the computed - * layout. It is currently only used when packing connected components. - *
    - * - *

    %Module options

    - * The various phases of the algorithm can be exchanged by setting - * module options allowing flexible customization. The algorithm provides - * the following module options: - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    subgraphPlanarSubgraphModuleFastPlanarSubgraph - * The module for the computation of the planar subgraph. - *
    inserterEdgeInsertionModuleFixedEmbeddingInserter - * The module used for edge insertion which is applied in the second - * step of the planarization method. The edges not contained in the planar - * subgraph are re-inserted one-by-one, each with as few crossings as possible. - *
    planarLayouterGridLayoutPlanRepModuleMixedModelLayout - * The planar layout algorithm used to compute a planar layout - * of the planarized representation resulting from the crossing minimization step. - *
    packerCCLayoutPackModuleTileToRowsCCPacker - * The packer module used for arranging connected components. - *
    - */ -class OGDF_EXPORT PlanarizationGridLayout : public GridLayoutModule -{ -public: - //! Creates an instance of planarization layout and sets options to default values. - PlanarizationGridLayout(); - - ~PlanarizationGridLayout() { } - - /** - * @name Optional parameters - * @{ - */ - - /** - * \brief Returns the current setting of option pageRatio. - * - * This option specifies the desired ration width / height of the computed - * layout. It is currently only used for packing connected components. - */ - double pageRatio() const { - return m_pageRatio; - } - - //! Sets the option pageRatio to \a ratio. - void pageRatio(double ratio) { - m_pageRatio = ratio; - } - - /** @} - * @name Module options - * @{ - */ - - /** - * \brief Sets the module option for the computation of the planar subgraph. - * - * The computation of a planar subgraph is the first step in the crossing - * minimization procedure of the planarization approach. - */ - void setSubgraph(PlanarSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - /** - * \brief Sets the module option for edge insertion. - * - * The edge insertion module is applied in the second step of the planarization - * method. The edges not contained in the planar subgraph are re-inserted - * one-by-one, each with as few crossings as possible. The edge insertion - * module implements the whole second step, i.e., it inserts all edges. - */ - void setInserter(EdgeInsertionModule *pInserter) { - m_inserter.set(pInserter); - } - - /** - * \brief Sets the module option for the planar grid layout algorithm. - * - * The planar layout algorithm is used to compute a planar layout - * of the planarized representation resulting from the crossing - * minimization step. Planarized representation means that edge crossings - * are replaced by dummy nodes of degree four, so the actual layout - * algorithm obtains a planar graph as input. By default, the planar - * layout algorithm produces an orthogonal drawing. - */ - void setPlanarLayouter(GridLayoutPlanRepModule *pPlanarLayouter) { - m_planarLayouter.set(pPlanarLayouter); - } - - /** - * \brief Sets the module option for the arrangement of connected components. - * - * The planarization layout algorithm draws each connected component of - * the input graph seperately, and then arranges the resulting drawings - * using a packing algorithm. - */ - void setPacker(CCLayoutPackModule *pPacker) { - m_packer.set(pPacker); - } - - - /** @} - * @name Further information - * @{ - */ - - //! Returns the number of crossings in computed layout. - int numberOfCrossings() const { - return m_nCrossings; - } - - //! @} - -protected: - void doCall(const Graph &G, GridLayout &gridLayout, IPoint &boundingBox); - - -private: - //! The module for computing a planar subgraph. - ModuleOption m_subgraph; - - //! The module for edge re-insertion. - ModuleOption m_inserter; - - //! The module for computing a planar grid layout. - ModuleOption m_planarLayouter; - - //! The module for arranging connected components. - ModuleOption m_packer; - - double m_pageRatio; //!< The desired page ratio. - - int m_nCrossings; //!< The number of crossings in the computed layout. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/PlanarizationLayout.h b/ext/OGDF/ogdf/planarity/PlanarizationLayout.h deleted file mode 100644 index 6f3965cf5..000000000 --- a/ext/OGDF/ogdf/planarity/PlanarizationLayout.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarizationLayout. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UML_PLANARIZATION_LAYOUT_H -#define OGDF_UML_PLANARIZATION_LAYOUT_H - - - -#include -#include -#include -#include -#include -#include -#include -#include - - - -namespace ogdf { - - -/** - * \brief The planarization layout algorithm. - * - * The class PlanarizationLayout represents a customizable implementation - * of the planarization approach for drawing graphs. The class provides - * three different algorithm calls: - * - Calling the algorithm for a usual graph (call with GraphAttributes). - * - Calling the algorithm for a mixed-upward graph (e.g., a UML class - * diagram; call with UMLGraph); a simplified version is provided by - * simpleCall. - * - Calling the algorithm for simultaneous drawing. - * - * If the planarization layout algorithm shall be used for simultaneous drawing, - * you need to define the different subgraphs by setting the subgraphs - * option. - * - * The implementation used in PlanarizationLayout is based on the following - * publication: - * - * C. Gutwenger, P. Mutzel: An Experimental Study of Crossing - * Minimization Heuristics. 11th International Symposium on %Graph - * Drawing 2003, Perugia (GD '03), LNCS 2912, pp. 13-24, 2004. - * - *

    Optional parameters

    - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    pageRatiodouble1.0 - * Specifies the desired ration of width / height of the computed - * layout. It is currently only used when packing connected components. - *
    preprocessCliquesboolfalse - * If set to true, a preprocessing for cliques (complete subgraphs) - * is performed and cliques will be laid out in a special form (straight-line, - * not orthogonal). The preprocessing may reduce running time and improve - * layout quality if the input graphs contains dense subgraphs. - *
    minCliqueSizeint10If preprocessing of cliques is - * enabled, this option determines the minimal size of cliques to search for. - *
    - * - *

    %Module options

    - * The various phases of the algorithm can be exchanged by setting - * module options allowing flexible customization. The algorithm provides - * the following module options: - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    subgraphPlanarSubgraphModuleFastPlanarSubgraph - * The module for the computation of the planar subgraph. - *
    inserterEdgeInsertionModuleFixedEmbeddingInserter - * The module used for edge insertion which is applied in the second - * step of the planarization method. The edges not contained in the planar - * subgraph are re-inserted one-by-one, each with as few crossings as possible. - *
    embedderEmbedderModuleSimpleEmbedder - * The graph embedding algorithm applied after the crossing minimization - * step. - *
    planarLayouterLayoutPlanRepModuleOrthoLayout - * The planar layout algorithm used to compute a planar layout - * of the planarized representation resulting from the crossing minimization step. - *
    packerCCLayoutPackModuleTileToRowsCCPacker - * The packer module used for arranging connected components. - *
    - */ -class OGDF_EXPORT PlanarizationLayout : public UMLLayoutModule -{ -public: - //! Creates an instance of planarization layout and sets options to default values. - PlanarizationLayout(); - - // destructor - virtual ~PlanarizationLayout() { } - - /** - * @name Algorithm call - * @{ - */ - - /** - * \brief Calls planarization layout for GraphAttributes \a GA and computes a layout. - * \pre The graph has no self-loops. - * @param GA is the input graph and will also be assigned the layout information. - */ - void call(GraphAttributes &GA) { - doSimpleCall(&GA); - } - - /** - * \brief Calls planarization layout for UML-graph \a umlGraph and computes a mixed-upward layout. - * \pre The graph has no self-loops. - * @param umlGraph is the input graph and will also be assigned the layout information. - */ - virtual void call(UMLGraph ¨Graph); - - //! Simple call function that does not care about cliques etc. - void simpleCall(UMLGraph ¨Graph) { - //this simple call method does not care about any special treatments - //of subgraphs, layout informations etc., therefore we save the - //option status and set them back later on - //cliques are only handled for UMLGraphs, so it is save to - //only set this value here and not in the GraphAtrtibutes interface method. - bool l_saveCliqueHandling = m_processCliques; - m_processCliques = false; - - //--------------------------------------------------- - // preprocessing: insert a merger for generalizations - - preProcess(umlGraph); - umlGraph.insertGenMergers(); - - doSimpleCall(¨Graph); - - umlGraph.undoGenMergers(); - - umlGraph.removeUnnecessaryBendsHV(); - - postProcess(umlGraph); - - m_processCliques = l_saveCliqueHandling; - } - - void simpleCall(GraphAttributes & GA) - { - doSimpleCall(&GA); - GA.removeUnnecessaryBendsHV(); - } - - //! Call for simultaneous drawing with graph \a umlGraph. - virtual void callSimDraw(UMLGraph ¨Graph); - - /** - * \brief Calls planarization layout with fixed embedding given by \a umlGraph. - * \pre The graph has no self-loops. - * @param umlGraph is the input graph and will also be assigned the layout information. - * The fixed embedding is obtained from the layout information (node - * coordinates, bend points) in \a umlGraph. - */ - virtual void callFixEmbed(UMLGraph ¨Graph); - - //call with information about objects that should be - //fixed as much as possible in the old/new drawing - //for incremental drawing: takes a fixed part of the input - //graph (indicated by fixedNodes(Edges)==true), embeds it using - //the input layout, then inserts the remaining part into this embedding - virtual void callIncremental(UMLGraph ¨graph, - NodeArray &fixedNodes, const EdgeArray &fixedEdges); - - - /** @} - * @name Optional parameters - * @{ - */ - - /** - * \brief Returns the current setting of option pageRatio. - * - * This option specifies the desired ration width / height of the computed - * layout. It is currently only used for packing connected components. - */ - double pageRatio() const { - return m_pageRatio; - } - - //! Sets the option pageRatio to \a ratio. - void pageRatio(double ratio) { - m_pageRatio = ratio; - } - - /** - * \brief Returns the current setting of option preprocessCliques - * - * If this option is enabled (set to true), a preprocessing for cliques - * (complete subgraphs) is performed and cliques will be laid out - * in a special form (straight-line, not orthogonal). The preprocessing - * may reduce running time and improve layout quality if the input - * graphs contains dense subgraphs. - */ - bool preprocessCliques() const { - return m_processCliques; - } - - //! Sets the option preProcessCliques to \a b. - void preprocessCliques(bool b) { - m_processCliques = b; - } - - /** - * \brief Returns the current setting of option minCliqueSize. - * - * If preprocessing of cliques is enabled, this option determines the - * minimal size of cliques to search for. - */ - int minCliqueSize() const { - return m_cliqueSize; - } - - //! Set the option minCliqueSize to \a i. - void minCliqueSize(int i) { - m_cliqueSize = max(i, 3); - } - - //set the option field for the planar layouter - void setLayouterOptions(int ops) - {m_planarLayouter.get().setOptions(ops);} - - //draw hierarchy nodes corresponding to their level - void alignSons(bool b) - { - int opts = m_planarLayouter.get().getOptions(); - - if (b) m_planarLayouter.get().setOptions(opts | umlOpAlign); - else m_planarLayouter.get().setOptions(opts & ~umlOpAlign); - } - - - /** @} - * @name Module options - * @{ - */ - - /** - * \brief Sets the module option for the computation of the planar subgraph. - * - * The computation of a planar subgraph is the first step in the crossing - * minimization procedure of the planarization approach. - */ - void setSubgraph(PlanarSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - /** - * \brief Sets the module option for edge insertion. - * - * The edge insertion module is applied in the second step of the planarization - * method. The edges not contained in the planar subgraph are re-inserted - * one-by-one, each with as few crossings as possible. The edge insertion - * module implements the whole second step, i.e., it inserts all edges. - */ - void setInserter(EdgeInsertionModule *pInserter) { - m_inserter.set(pInserter); - } - - /** - * \brief Sets the module option for the graph embedding algorithm. - * - * The result of the crossing minimization step is a planar graph, - * in which crossings are replaced by dummy nodes. The embedding - * module then computes a planar embedding of this planar graph. - */ - void setEmbedder(EmbedderModule *pEmbedder) { - m_embedder.set(pEmbedder); - } - - /** - * \brief Sets the module option for the planar layout algorithm. - * - * The planar layout algorithm is used to compute a planar layout - * of the planarized representation resulting from the crossing - * minimization step. Planarized representation means that edge crossings - * are replaced by dummy nodes of degree four, so the actual layout - * algorithm obtains a planar graph as input. By default, the planar - * layout algorithm produces an orthogonal drawing. - */ - void setPlanarLayouter(LayoutPlanRepModule *pPlanarLayouter) { - m_planarLayouter.set(pPlanarLayouter); - } - - /** - * \brief Sets the module option for the arrangement of connected components. - * - * The planarization layout algorithm draws each connected component of - * the input graph seperately, and then arranges the resulting drawings - * using a packing algorithm. - */ - void setPacker(CCLayoutPackModule *pPacker) { - m_packer.set(pPacker); - } - - /** @} - * @name Further information - * @{ - */ - - //! Returns the number of crossings in computed layout. - int numberOfCrossings() const { - return m_nCrossings; - } - - //! Throws a PreconditionViolatedException if \a umlGraph violates a precondition of planarization layout. - void assureDrawability(UMLGraph& umlGraph); - - //! @} - -protected: - void doSimpleCall(GraphAttributes *pGA); - - //sorts the additional nodes for piecewise insertion - void sortIncrementalNodes(List &addNodes, const NodeArray &fixedNodes); - void getFixationDistance(node startNode, HashArray &distance, - const NodeArray &fixedNodes); - //reembeds already planarized PG in case of errors - void reembed(PlanRepUML &PG, int ccNumber, bool l_align = false, - bool l_gensExist = false); - - virtual void preProcess(UMLGraph &UG); - virtual void postProcess(UMLGraph& UG); //redo changes at original - - //collect and store nodes around center in correct order - void fillAdjNodes(List& adjNodes, PlanRepUML& PG, node centerNode, - NodeArray& isClique, Layout& drawing); - - void arrangeCCs(PlanRep &PG, GraphAttributes &GA, Array &boundingBox); - -private: - //! The module for computing a planar subgraph. - ModuleOption m_subgraph; - - //! The module for edge re-insertion. - ModuleOption m_inserter; - - //! The module for planar embedding. - ModuleOption m_embedder; - - //! The module for computing a planar layout. - ModuleOption m_planarLayouter; - - //! The module for arranging connected components. - ModuleOption m_packer; - - double m_pageRatio; //!< The desired page ratio. - int m_nCrossings; //!< The number of crossings in the computed layout. - bool m_arrangeLabels; //!< Option for re-arranging labels. - bool m_processCliques; //!< Option for preprocessing cliques (not UML layout). - int m_cliqueSize; //!< The minimum size of cliques to search for. - - // temporary changes to avoid errors - List m_fakedGens; // made to associations - bool m_fakeTree; - - face findBestExternalFace( - const PlanRep &PG, - const CombinatorialEmbedding &E); -}; - - -//-------------------------------------------------------- -//incremental part - -//! Node comparer for sorting by decreasing int values. -class AddNodeComparer -{ - HashArray *m_indToDeg; - -public: - AddNodeComparer(HashArray &ha) : m_indToDeg(&ha) { } - - int compare(const node &v1, const node &v2) const { - if ((*m_indToDeg)[v1->index()] < (*m_indToDeg)[v2->index()]) - return 1; - else if ((*m_indToDeg)[v1->index()] > (*m_indToDeg)[v2->index()]) - return -1; - else - return 0; - } - - OGDF_AUGMENT_COMPARER(node) -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarity/SimpleEmbedder.h b/ext/OGDF/ogdf/planarity/SimpleEmbedder.h deleted file mode 100644 index aa7cd81d4..000000000 --- a/ext/OGDF/ogdf/planarity/SimpleEmbedder.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief A simple embedder algorithm. - * - * \author Thorsten Kerkhof (thorsten.kerkhof@udo.edu) - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SIMPLE_EMBEDDER_H -#define OGDF_SIMPLE_EMBEDDER_H - -#include -#include -#include -#include - -namespace ogdf { - -//! Planar graph embedding by using default planarEmbed. -class OGDF_EXPORT SimpleEmbedder : public EmbedderModule -{ -public: - // construction / destruction - SimpleEmbedder() { } - ~SimpleEmbedder() { } - - /** - * \brief Call embedder algorithm. - * \param G is the original graph. Its adjacency list is changed by the embedder. - * \param adjExternal is an adjacency entry on the external face and is set by the embedder. - */ - void call(Graph& G, adjEntry& adjExternal); - -private: - /** - * \brief Find best suited external face according to certain criteria. - * \param PG is a planar representation of the original graph. - * \param E is a combinatorial embedding of the original graph. - * \return Best suited external face. - */ - face findBestExternalFace(const PlanRep& PG, const CombinatorialEmbedding& E); - -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/SimpleIncNodeInserter.h b/ext/OGDF/ogdf/planarity/SimpleIncNodeInserter.h deleted file mode 100644 index 4509ec1f4..000000000 --- a/ext/OGDF/ogdf/planarity/SimpleIncNodeInserter.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class SimpleIncNodeInserter. - * - * This class represents a strategy for the incremental drawing - * approach to insert nodes (having no layout fixation) into the - * fixed part of a PlanRep. The simple strategy searches for the - * face with the maximum number of neighbours without counting - * the cost of introduced crossings. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_SIMPLE_INC_NODE_INSERTER_H -#define OGDF_SIMPLE_INC_NODE_INSERTER_H - - -#include -#include -#include -#include -#include - -namespace ogdf { - - -//=============================================== -//main function(s): -// - -//=============================================== - - -class OGDF_EXPORT SimpleIncNodeInserter : public IncNodeInserter -{ -public: - //creates inserter on PG - SimpleIncNodeInserter(PlanRepInc &PG); - virtual ~SimpleIncNodeInserter(); - - //insert copy in m_planRep for original node v - void insertCopyNode(node v, CombinatorialEmbedding &E, - Graph::NodeType vTyp); - - //insert copy without respecting embedding - void insertCopyNode(node v, Graph::NodeType vTyp); - -protected: - //insertAfterAdj will be filled with adjEntries for the - //(new) edges around the copy of v to be inserted after. - //sorted in the order of the edge around v - face getInsertionFace(node v, CombinatorialEmbedding &E); - - //constructs a dual graph on the copy PlanRep, - //vCopy is the node to be inserted - void constructDual(const Graph &G, const CombinatorialEmbedding &E, - bool forbidCrossings = true); - - void insertFaceEdges(node v, node vCopy, face f, CombinatorialEmbedding &E, - adjEntry &adExternal); - void insertCrossingEdges(node v, node vCopy, CombinatorialEmbedding &E, adjEntry &adExternal); - void findShortestPath(const CombinatorialEmbedding &E, node s, - node t, Graph::EdgeType eType, SList &crossed); - void insertEdge(CombinatorialEmbedding &E, edge eOrig, - const SList &crossed, bool forbidCrossingGens); - -private: - //dual graph for the edge insertion - Graph m_dual; - FaceArray m_nodeOf; // node in dual corresponding to to face in primal - NodeArray m_insertFaceNode; //node lies at border of insertionface - NodeArray m_vAdjNodes; //node is adjacent to insertion node - NodeArray< List* > m_incidentEdges; //original edges(insertionnode) incident to original(node) - EdgeArray m_primalAdj; //copy adj for edges in dual graph - EdgeArray m_primalIsGen; // true iff corresponding primal edge is a generalization - bool m_forbidCrossings; //should generalization crossings be avoided - node m_vS; //source and sink in the dual graph for edge insertion - node m_vT; - -}; //simpleincnodeinserter - -} //end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/SubgraphPlanarizer.h b/ext/OGDF/ogdf/planarity/SubgraphPlanarizer.h deleted file mode 100644 index bf1b460d3..000000000 --- a/ext/OGDF/ogdf/planarity/SubgraphPlanarizer.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class SubgraphPlanarizer. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_SUBGRAPH_PLANARIZER_H -#define OGDF_SUBGRAPH_PLANARIZER_H - -#include -#include -#include -#include -#include - - -namespace ogdf -{ - -//! The planarization approach for crossing minimization. -/** - * This crossing minimization module represents a customizable implementation - * of the planarization approach. This approach consists of two phases. - * In the first phase, a planar subgraph is computed, and in the second - * phase, the remaining edges are re-inserted one-by-one, each time with - * as few crossings as possible; the crossings are then replaced by dummy - * nodes of degree four, resulting in a planarized representation of the - * graph. - * - * Both steps, the computation of the planar subgraph and the re-insertion - * of a single edge, are implemented using module options. Additionaly, - * the second phase can be repeated several times, each time with a randomly - * permuted order of the edges to be re-inserted, and taking the solution - * with the least crossings. This can improve the quality of the solution - * significantly. More details on the planarization approach can be found in - * - * C. Gutwenger, P. Mutzel: An Experimental Study of Crossing - * Minimization Heuristics. 11th International Symposium on %Graph - * Drawing 2003, Perugia (GD '03), LNCS 2912, pp. 13-24, 2004. - * - *

    Optional parameters

    - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    permutationsint1 - * The number of permutations the (complete) edge insertion phase is repeated. - *
    setTimeoutbooltrue - * If set to true, the time limit is also passed to submodules; otherwise, - * a timeout might be checked late when a submodule requires a lot of runtime. - *
    - * - *

    %Module options

    - * The various phases of the algorithm can be exchanged by setting - * module options allowing flexible customization. The algorithm provides - * the following module options: - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    subgraphPlanarSubgraphModuleFastPlanarSubgraph - * The module for the computation of the planar subgraph. - *
    inserterEdgeInsertionModuleVariableEmbeddingInserter - * The module used for edge insertion. The edges not contained in the planar - * subgraph are re-inserted one-by-one, each with as few crossings as possible. - *
    -*/ -class OGDF_EXPORT SubgraphPlanarizer : public CrossingMinimizationModule, public Logger -{ - class CrossingStructure - { - public: - CrossingStructure() : m_numCrossings(0) { } - void init(PlanRep &PG, int weightedCrossingNumber); - void restore(PlanRep &PG, int cc); - - int numberOfCrossings() const { return m_numCrossings; } - int weightedCrossingNumber() const { return m_weightedCrossingNumber; } - const SListPure &crossings(edge e) const { return m_crossings[e]; } - - private: - int m_numCrossings; - int m_weightedCrossingNumber; - EdgeArray > m_crossings; - }; - -protected: - //! Implements the algorithm call. - virtual ReturnType doCall(PlanRep &PG, - int cc, - const EdgeArray &cost, - const EdgeArray &forbid, - const EdgeArray &subgraphs, - int& crossingNumber); - -public: - //! Creates an instance of subgraph planarizer. - SubgraphPlanarizer(); - - //! Sets the module option for the computation of the planar subgraph. - void setSubgraph(PlanarSubgraphModule *pSubgraph) { - m_subgraph.set(pSubgraph); - } - - //! Sets the module option for the edge insertion module. - void setInserter(EdgeInsertionModule *pInserter) { - m_inserter.set(pInserter); - } - - //! Returns the number of permutations. - int permutations() { return m_permutations; } - - //! Sets the number of permutations to \a p. - void permutations(int p) { m_permutations = p; } - - //! Returns the current setting of options setTimeout. - bool setTimeout() { return m_setTimeout; } - - //! Sets the option setTimeout to \a b. - void setTimeout(bool b) { m_setTimeout = b; } - -private: - ModuleOption m_subgraph; //!< The planar subgraph algorithm. - ModuleOption m_inserter; //!< The edge insertion module. - - int m_permutations; //!< The number of permutations. - bool m_setTimeout; //!< The option for setting timeouts in submodules. -}; - -} - -#endif // OGDF_SUBGRAPH_PLANARIZER_H diff --git a/ext/OGDF/ogdf/planarity/VariableEmbeddingInserter.h b/ext/OGDF/ogdf/planarity/VariableEmbeddingInserter.h deleted file mode 100644 index b8e308325..000000000 --- a/ext/OGDF/ogdf/planarity/VariableEmbeddingInserter.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class VariablEmbeddingInserter. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_VARIABLE_EMBEDDING_INSERTER_H -#define OGDF_VARIABLE_EMBEDDING_INSERTER_H - - -#include -#include -#include - - -namespace ogdf { - -class PlanarSPQRTree; -class ExpandedGraph; -class PlaneGraphCopy; - - -class BiconnectedComponent; - - -//! Optimal edge insertion module. -/** - * The class VariableEmbeddingInserter represents the optimal edge insertion - * algorithm, which inserts a single edge with a minum number of crossings - * into a planar graph. - * - * The implementation is based on the following publication: - * - * Carsten Gutwenger, Petra Mutzel, Rene Weiskircher: Inserting an Edge into - * a Planar %Graph. Algorithmica 41(4), pp. 289-308, 2005. - */ -class OGDF_EXPORT VariableEmbeddingInserter : public EdgeInsertionModule -{ -public: - //! Creates an instance of variable embedding edge inserter. - VariableEmbeddingInserter(); - - ~VariableEmbeddingInserter() { } - - /** - * \brief Calls only the postprocessing; assumes that all edges in \a origEdges are already inserted into \a PG. - * - * @param PG is the input planarized representation and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a PG) that have to be inserted. - * \return the status of the result. - */ - ReturnType callPostprocessing(PlanRep &PG, const List &origEdges) { - return doCallPostprocessing(PG, origEdges, false, 0, 0, 0); - } - - - /** - * @name Optional parameters - * @{ - */ - - //! Sets the remove-reinsert postprocessing method. - void removeReinsert(RemoveReinsertType rrOption) { - m_rrOption = rrOption; - } - - //! Returns the current setting of the remove-reinsert postprocessing method. - RemoveReinsertType removeReinsert() const { - return m_rrOption; - } - - - //! Sets the option percentMostCrossed to \a percent. - /** - * This option determines the portion of most crossed edges used if the remove-reinsert - * method is set to #rrMostCrossed. This portion is number of edges * percentMostCrossed() / 100. - */ - void percentMostCrossed(double percent) { - m_percentMostCrossed = percent; - } - - //! Returns the current setting of option percentMostCrossed. - double percentMostCrossed() const { - return m_percentMostCrossed; - } - - /** @} - * @name Further information - * @{ - */ - - //! Returns the number of runs performed by the remove-reinsert method after the algorithm has been called. - int runsPostprocessing() const { - return m_runsPostprocessing; - } - - //! @} - -private: - //! Implements the algorithm call. - ReturnType doCall( - PlanRep &PG, // planarized representation - const List &origEdges, // original edge to be inserted - bool forbidCrossingGens, // frobid crossings between gen's - const EdgeArray *costOrig, // pointer to array of cost of original edges; if pointer is 0 all costs are 1 - const EdgeArray *forbiddenEdgeOrig, // pointer to array deciding - // which original edges are forbidden to cross; if pointer is - // is 0 no edges are explicitly forbidden to cross - const EdgeArray *edgeSubGraph); // pointer to array of SubGraphInformation - // used in Simultaneous Drawing - - ReturnType doCallPostprocessing( - PlanRep &PG, // planarized representation - const List &origEdges, // original edge to be inserted - bool forbidCrossingGens, // frobid crossings between gen's - const EdgeArray *costOrig, // pointer to array of cost of original edges; if pointer is 0 all costs are 1 - const EdgeArray *forbiddenEdgeOrig, // pointer to array deciding - // which original edges are forbidden to cross; if pointer is - // is 0 no edges are explicitly forbidden to cross - const EdgeArray *edgeSubGraph); // pointer to array of SubGraphInformation - - edge crossedEdge(adjEntry adj) const; - int costCrossed(edge eOrig) const; - - bool m_forbidCrossingGens; - const EdgeArray *m_costOrig; - const EdgeArray *m_forbiddenEdgeOrig; - const EdgeArray *m_edgeSubgraph; - Graph::EdgeType m_typeOfCurrentEdge; - - void insert(node s, node t, SList &eip); - void blockInsert(const BiconnectedComponent &G, - node s, - node t, - List &L); - - bool dfsVertex(node v, int parent); - bool dfsComp(int i, node parent, node &repT); - - PlanRep *m_pPG; - node m_s, m_t; - edge m_st; - SList *m_pEip; - - static int m_bigM; // used for SimDraw - - NodeArray > m_compV; - Array > m_nodeB; - Array > m_edgeB; - NodeArray m_GtoBC; - - bool pathSearch(node v, edge parent, List &path); - void buildSubpath(node v, - edge eIn, - edge eOut, - List &L, - ExpandedGraph &Exp, - node s, - node t); - edge insertEdge(node v, node w, Graph &Exp, - NodeArray &GtoExp, List &nodesG); - - node m_v1, m_v2; - - RemoveReinsertType m_rrOption; //!< The remove-reinsert method. - double m_percentMostCrossed; //!< The portion of most crossed edges considered. - - int m_runsPostprocessing; //!< Runs of remove-reinsert method. -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarity/VariableEmbeddingInserter2.h b/ext/OGDF/ogdf/planarity/VariableEmbeddingInserter2.h deleted file mode 100644 index 20e2609b3..000000000 --- a/ext/OGDF/ogdf/planarity/VariableEmbeddingInserter2.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class VariableEmbeddingInserter2. - * - * \author Carsten Gutwenger
    Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_VARIABLE_EMBEDDING_INSERTER_2_H -#define OGDF_VARIABLE_EMBEDDING_INSERTER_2_H - - -#include - - -namespace ogdf { - -class OGDF_EXPORT BCandSPQRtrees; -class OGDF_EXPORT ExpandedGraph2; - - -//--------------------------------------------------------- -// VariableEmbeddingInserter2 -// edge insertion module that inserts each edge optimally -// into a given embedding. -//--------------------------------------------------------- -class OGDF_EXPORT VariableEmbeddingInserter2 : public EdgeInsertionModule -{ -public: - // construction - VariableEmbeddingInserter2(); - // destruction - virtual ~VariableEmbeddingInserter2() { } - - // - // options - // - - // sets remove-reinsert option (postprocessing) - // possible values: (see EdgeInsertionModule) - // rrNone, rrInserted, rrMostCrossed, rrAll - void removeReinsert(RemoveReinsertType rrOption) { - m_rrOption = rrOption; - } - - // returns remove-reinsert option - RemoveReinsertType removeReinsert() const { - return m_rrOption; - } - - - // sets the portion of most crossed edges used if remove-reinsert option - // is set to rrMostCrossed - // this portion no. of edges * percentMostCrossed() / 100 - void percentMostCrossed(double percent) { - m_percentMostCrossed = percent; - } - - // returns option percentMostCrossed - double percentMostCrossed() const { - return m_percentMostCrossed; - } - - - // returns the number of runs performed by the postprocessing - // after algoithm has been called - int runsPostprocessing() const { - return m_runsPostprocessing; - } - -private: - // performs actual call - ReturnType doCall( - PlanRep &PG, // planarized representation - const List &origEdges, // original edge to be inserted - bool forbidCrossingGens, // frobid crossings between gen's - const EdgeArray *costOrig, // pointer to array of cost of original edges; if pointer is 0 all costs are 1 - const EdgeArray *forbiddenEdgeOrig); // pointer to array deciding - // which original edges are forbidden to cross; if pointer - // is 0 no edges are explicitly forbidden to cross - - edge crossedEdge(adjEntry adj) const; - int costCrossed(edge eOrig) const; - - bool m_forbidCrossingGens; - const EdgeArray *m_costOrig; - const EdgeArray *m_forbiddenEdgeOrig; - Graph::EdgeType m_typeOfCurrentEdge; - - void insert(edge eOrig, SList &eip); - void blockInsert(node s, node t, List &L); - - PlanRep *m_pPG; - - BCandSPQRtrees *m_pBC; - - void buildSubpath(node v, - node vPred, - node vSucc, - List &L, - ExpandedGraph2 &Exp, - node s, - node t); - edge insertEdge(node v, node w, Graph &Exp, - NodeArray &GtoExp, List &nodesG); - - - // options - RemoveReinsertType m_rrOption; - double m_percentMostCrossed; - - // results - int m_runsPostprocessing; - -}; // class VariableEmbeddingInserter2 - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/BiconnectedShellingOrder.h b/ext/OGDF/ogdf/planarlayout/BiconnectedShellingOrder.h deleted file mode 100644 index 907a66981..000000000 --- a/ext/OGDF/ogdf/planarlayout/BiconnectedShellingOrder.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares the class BiconnectedShellingOrder... - * - * ...which computes a shelling order for a biconnected planar graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_BICONNECTED_SHELLING_ORDER_H -#define OGDF_BICONNECTED_SHELLING_ORDER_H - - -#include - - -namespace ogdf { - -/** - * \brief Computation of the shelling order for biconnected graphs. - * - * \pre The input graph has to be simple (no multi-edges, no self-loops), - * planar and biconnected. - */ -class OGDF_EXPORT BiconnectedShellingOrder : public ShellingOrderModule -{ -public: - //! Creates a biconnected shelling order module. - BiconnectedShellingOrder() { - m_baseRatio = 0.33; - } - -protected: - //! The actual implementation of the module call. - virtual void doCall(const Graph &G, - adjEntry adj, - List &partition); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/FPPLayout.h b/ext/OGDF/ogdf/planarlayout/FPPLayout.h deleted file mode 100644 index 6b77c441e..000000000 --- a/ext/OGDF/ogdf/planarlayout/FPPLayout.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the Fraysseix, Pach, Pollack Algorithm (FPPLayout) - * algorithm. - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FPP_LAYOUT_H -#define OGDF_FPP_LAYOUT_H - -#include -#include - -namespace ogdf -{ - -/** - * The class FPPLayout represents the layout algorithm by - * de Fraysseix, Pach, Pollack [DPP90]. This algorithm draws a planar graph G - * straight-line without crossings. G must not contain self-loops or multiple - * edges. The grid layout size is (2n-4) * (n-2) for a graph with - * n nodes (n ≥ 3). - * The algorithm runs in three phases. In the first phase, the graph is - * augmented by adding new artificial edges to get a triangulated plane graph. - * Then, a so-called shelling order (also called canonical ordering) - * for triangulated planar graphs is computed. In the third phase the vertices - * are placed incrementally according to the shelling order. - */ -class OGDF_EXPORT FPPLayout : public PlanarGridLayoutModule { -public: - FPPLayout(); - -private: - void doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding ); - - void computeOrder( - const GraphCopy &G, - NodeArray &num, - NodeArray &e_wp, - NodeArray &e_wq, - adjEntry e_12, - adjEntry e_2n, - adjEntry e_n1 ); - - void computeCoordinates( - const GraphCopy &G, - IPoint &boundingBox, - GridLayout &gridLayout, - NodeArray &num, - NodeArray &e_wp, - NodeArray &e_wq ); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/MMCBBase.h b/ext/OGDF/ogdf/planarlayout/MMCBBase.h deleted file mode 100644 index e6eb92609..000000000 --- a/ext/OGDF/ogdf/planarlayout/MMCBBase.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of base class for certain Mixed-Model - * crossings beautifier. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MMCB_BASE_H -#define OGDF_MMCB_BASE_H - - - -#include - - -namespace ogdf { - -/** - * \brief common base class for MMCBDoubleGrid and MMCBLocalStretch. - * - * MMCBBase contains the common functionality shared by the two Mixed-Model - * crossings beautifier MMCBDoubleGrid and MMCBLocalStretch. - */ -class OGDF_EXPORT MMCBBase : public MixedModelCrossingsBeautifierModule -{ -public: - //! Constructor (does nothing). - MMCBBase() { } - - ~MMCBBase() { } - -protected: - static void insertBend(GridLayout &gl, edge e, node v, int x, int y); - static void copyOn(int old_a[] , int new_a[]); - static int workOn(GridLayout &gl, node v); -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/MMCBDoubleGrid.h b/ext/OGDF/ogdf/planarlayout/MMCBDoubleGrid.h deleted file mode 100644 index a60aaeb3b..000000000 --- a/ext/OGDF/ogdf/planarlayout/MMCBDoubleGrid.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a Mixed-Model crossings beautifier - * that uses grid doubling. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MMCB_DOUBLE_GRID_H -#define OGDF_MMCB_DOUBLE_GRID_H - - - -#include - - -namespace ogdf { - - -/** - * \brief Crossings beautifier using grid doubling. - */ -class OGDF_EXPORT MMCBDoubleGrid : public MMCBBase -{ -public: - //! Creates an instance of the crossings beautifier module. - MMCBDoubleGrid() { } - - ~MMCBDoubleGrid() { } - -protected: - //! Implements the module call. - void doCall(const PlanRep &PG, GridLayout &gl, const List &L); -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/MMCBLocalStretch.h b/ext/OGDF/ogdf/planarlayout/MMCBLocalStretch.h deleted file mode 100644 index 922f67e4f..000000000 --- a/ext/OGDF/ogdf/planarlayout/MMCBLocalStretch.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a Mixed-Model crossings beautifier - * that local stretching. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MMCB_LOCAL_STRETCH_H -#define OGDF_MMCB_LOCAL_STRETCH_H - - - -#include - - -namespace ogdf { - - -/** - * \brief Crossings beautifier using a local stretch strategy. - */ -class OGDF_EXPORT MMCBLocalStretch : public MMCBBase -{ -public: - //! Creates an instance of the crossings beautifier. - MMCBLocalStretch() { } - - ~MMCBLocalStretch() { } - -protected: - //! Implements the module call. - void doCall(const PlanRep &PG, GridLayout &gl, const List &L); -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/MixedModelLayout.h b/ext/OGDF/ogdf/planarlayout/MixedModelLayout.h deleted file mode 100644 index 059bb34b2..000000000 --- a/ext/OGDF/ogdf/planarlayout/MixedModelLayout.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of Mixed-Model layout algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIXED_MODEL_LAYOUT_H -#define OGDF_MIXED_MODEL_LAYOUT_H - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -/** - * \brief Implementation of the Mixed-Model layout algorithm. - * - * The class MixedModelLayout represents the Mixed-Model layout algorithm - * by Gutwenger and Mutzel, which is based upon ideas by Kant. In - * particular, Kant's algorithm has been changed concerning the placement - * phase and the vertex boxes, and it has been generalized to work for - * connected planar graphs. - * - * This algorithm draws a d-planar graph \a G on a grid such that every - * edge has at most three bends and the minimum angle between two - * edges is at least 2/\a d radians. \a G must not contain self-loops - * or multiple edges. The grid size is at most (2n-6) * - * (3/2n-7/2), the number of bends is at most 5n-15, and - * every edge has length O(n), where \a G has n nodes. - * - * The algorithm runs in several phases. In the preprocessing phase, - * vertices with degree one are temporarily deleted and the graph is - * being augmented to a biconnected planar graph using a planar biconnectivity - * augmentation module. Then, a shelling order for biconnected plane - * graphs is computed. In the next step, boxes around each - * vertex are defined in such a way that the incident edges appear - * regularly along the box. Finally, the coordinates of the vertex boxes - * are computed taking the degree-one vertices into account. - * - * The implementation used in MixedModelLayout is based on the following - * publication: - * - * C. Gutwenger, P. Mutzel: Planar Polyline Drawings with Good Angular - * Resolution. 6th International Symposium on %Graph - * Drawing 1998, Montreal (GD '98), LNCS 1547, pp. 167-182, 1998. - * - *

    Precondition

    - * The input graph needs to be planar and simple (i.e., no self-loops and no - * multiple edges). - * - *

    %Module options

    - * Instances of type MixedModelLayout provide the following module options: - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    augmenterAugmentationModulePlanarAugmentation - * Augments the graph by adding edges to obtain a planar graph with - * a certain connectivity (e.g., biconnected or triconnected). - *
    embedderEmbedderModuleSimpleEmbedder - * Planar embedding algorithm applied after planar augmentation. - *
    shellingOrderShellingOrderModuleBiconnectedShellingOrder - * The algorithm to compute a shelling order. The connectivity assured - * by the planar augmentation module has to be sufficient for the shelling - * order module! - *
    crossingsBeautifierMixedModelCrossingsBeautifierModuleMMDummyCrossingsBeautifier - * The crossing beautifier is applied as preprocessing to dummy nodes - * in the graph that actually represent crossings. Such nodes arise when - * using the mixed-model layout algorithm in the planarization approach (see - * PlanarizationGridLayout). By default, crossings might look weird, since they - * are not drawn as two crossing horizontal and vertical lines; the other available - * crossings beautifier correct this. - *
    - * - *

    Running Time

    - * The computation of the layout takes time O(n), where n is - * the number of nodes of the input graph. - */ -class OGDF_EXPORT MixedModelLayout : public GridLayoutPlanRepModule -{ -public: - //! Constructs an instance of the Mixed-Model layout algorithm. - MixedModelLayout(); - - virtual ~MixedModelLayout() { } - - /** - * @name Module options - * @{ - */ - - /** - * \brief Sets the augmentation module. - * - * The augmentation module needs to make sure that the graph gets the - * connectivity required for calling the shelling order module. - */ - void setAugmenter(AugmentationModule *pAugmenter) { - m_augmenter.set(pAugmenter); - } - - //! Sets the shelling order module. - void setShellingOrder(ShellingOrderModule *pOrder) { - m_compOrder.set(pOrder); - } - - //! Sets the crossings beautifier module. - void setCrossingsBeautifier(MixedModelCrossingsBeautifierModule *pBeautifier) { - m_crossingsBeautifier.set(pBeautifier); - } - - //! Sets the module option for the graph embedding algorithm. - void setEmbedder(EmbedderModule *pEmbedder) { - m_embedder.set(pEmbedder); - } - - //! @} - -protected: - //! Implements the algorithm call. - void doCall( - PlanRep &PG, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding); - -private: - ModuleOption m_embedder; //!< The planar embedder module. - ModuleOption m_augmenter; //!< The augmentation module. - ModuleOption m_compOrder; //!< The shelling order module. - ModuleOption m_crossingsBeautifier; //!< The crossings beautifier module. -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/PlanarDrawLayout.h b/ext/OGDF/ogdf/planarlayout/PlanarDrawLayout.h deleted file mode 100644 index fe956ea3c..000000000 --- a/ext/OGDF/ogdf/planarlayout/PlanarDrawLayout.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * $Revision: 2547 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 22:05:45 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarDrawLayout which represents - * a planar straight-line drawing algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLANAR_DRAW_LAYOUT_H -#define OGDF_PLANAR_DRAW_LAYOUT_H - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - class ShellingOrder; - -/** - * \brief Implementation of the Planar-Draw layout algorithm. - * - * The class PlanarDrawLayout implements a straight-line drawing algorithm - * for planar graphs. It draws a planar graph on a grid of size at - * most (n-2) * (n-2) without edge crossings. - * - * The algorithm runs in several phases. In the first phase, - * the graph is augmented by adding edges to achieve a certain connectivity - * (e.g., biconnected or triconnected). Then, a shelling order of the - * the resulting graph is computed. Both phases are implemented by using - * module options, so you can replace them with different implementations. - * However, you have to make sure, that the connectivity achieved by the - * augmentation module is sufficient for the shelling order module (or the - * input graph already has the required connectivity). - * - * The implementation used in PlanarDrawLayout is an improved version of - * the following publication: - * - * M. Chrobak, G. Kant: Convex Grid Drawings of 3-connected Planar - * Graphs. International Journal of Computational Geometry and Applications - * 7(3), pp. 211-223, 1997. - * - *

    Precondition

    - * The input graph needs to be planar and simple (i.e., no self-loops and no - * multiple edges). - * - *

    Optional parameters

    - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    sizeOptimizationbooltrue - * If this option is set to true, the algorithm tries to reduce the - * size of the resulting grid layout. - *
    sideOptimizationboolfalse - * If this option is set to true, slopes different from +1, 0, -1 - * are allowed on the contour for reducing the resulting grid size. - *
    baseRatiodouble0.33 - * This option specifies the maximal number of nodes placed on the base line. - * The algorithm tries to place as many nodes as possible on the base - * line, but takes at most max(2, \a baseRatio * size of external face) many. - *
    - * - *

    %Module options

    - * Instances of type PlanarDrawLayout provide the following module options: - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    augmenterAugmentationModulePlanarAugmentation - * Augments the graph by adding edges to obtain a planar graph with - * a certain connectivity (e.g., biconnected or triconnected). - *
    embedderEmbedderModuleSimpleEmbedder - * Planar embedding algorithm applied after planar augmentation. - *
    shellingOrderShellingOrderModuleBiconnectedShellingOrder - * The algorithm to compute a shelling order. The connectivity assured - * by the planar augmentation module has to be sufficient for the shelling - * order module! - *
    - * - *

    Running Time

    - * The computation of the layout takes time O(n), where n is - * the number of nodes of the input graph. - */ -class OGDF_EXPORT PlanarDrawLayout : public PlanarGridLayoutModule -{ -public: - //! Constructs an instance of the Planar-Draw layout algorithm. - PlanarDrawLayout(); - - ~PlanarDrawLayout() { } - - - /** - * @name Optional parameters - * @{ - */ - - /** - * \brief Returns the current setting of option sizeOptimization. - * - * If this option is set to true, the algorithm tries to reduce the - * size of the resulting grid layout. - */ - bool sizeOptimization() const { return m_sizeOptimization; } - - //! Sets the option sizeOptimization to \a opt. - void sizeOptimization(bool opt) { m_sizeOptimization = opt; } - - /** - * \brief Returns the current setting of option sideOptimization. - * - * If this option is set to true, slopes different from +1, 0, -1 - * are allowed on the contour for reducing the resulting grid size. - */ - bool sideOptimization() const { return m_sizeOptimization; } - - //! Sets the option sideOptimization to \a opt. - void sideOptimization(bool opt) { m_sizeOptimization = opt; } - - /** - * \brief Returns the current setting of option baseRatio. - * - * This option specifies the maximal number of nodes placed on the base line. - * The algorithm tries to place as many nodes as possible on the base - * line, but takes at most max(2, \a baseRatio * size of external face) many. - */ - double baseRatio() const { return m_baseRatio; } - - //! Sets the option baseRatio to \a ratio. - void baseRatio(double ratio) { m_baseRatio = ratio; } - - - /** @} - * @name Module options - * @{ - */ - - /** - * \brief Sets the augmentation module. - * - * The augmentation module needs to make sure that the graph gets the - * connectivity required for calling the shelling order module. - */ - void setAugmenter(AugmentationModule *pAugmenter) { - m_augmenter.set(pAugmenter); - } - - //! Sets the shelling order module. - void setShellingOrder(ShellingOrderModule *pOrder){ - m_computeOrder.set(pOrder); - } - - //! Sets the module option for the graph embedding algorithm. - void setEmbedder(EmbedderModule *pEmbedder) { - m_embedder.set(pEmbedder); - } - - //! @} - -private: - bool m_sizeOptimization; //!< The option for allowing arbitrary slopes. - bool m_sideOptimization; //!< The option for size optimization. - double m_baseRatio; //!< The option for specifying the base ratio. - - ModuleOption m_embedder; //!< The planar embedder module. - ModuleOption m_augmenter; //!< The augmentation module. - ModuleOption m_computeOrder; //!< The shelling order module. - - // computes grid layout for graph G - void doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding); - - void computeCoordinates(const Graph &G, - ShellingOrder &order, - NodeArray &x, - NodeArray &y); - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/PlanarStraightLayout.h b/ext/OGDF/ogdf/planarlayout/PlanarStraightLayout.h deleted file mode 100644 index 1c9e5def6..000000000 --- a/ext/OGDF/ogdf/planarlayout/PlanarStraightLayout.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * $Revision: 2547 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 22:05:45 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PlanarStraightLayout which represents - * a planar straight-line drawing algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_PLANAR_STRAIGHT_LAYOUT_H -#define OGDF_PLANAR_STRAIGHT_LAYOUT_H - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - class ShellingOrder; - -/** - * \brief Implementation of the Planar-Straight layout algorithm. - * - * The class PlanarStraightLayout implements a straight-line drawing algorithm - * for planar graphs. It draws a planar graph on a grid of size at - * most (2n-4) * (n-2) without edge crossings. - * - * The algorithm runs in several phases. In the first phase, - * the graph is augmented by adding edges to achieve a certain connectivity - * (e.g., biconnected or triconnected). Then, a shelling order of the - * the resulting graph is computed. Both phases are implemented by using - * module options, so you can replace them with different implementations. - * However, you have to make sure, that the connectivity achieved by the - * augmentation module is sufficient for the shelling order module (or the - * input graph already has the required connectivity). - * - * The implementation used in PlanarStraightLayout is an improved version of - * an algorithm presented in: - * - * Goos Kant: Drawing Planar Graphs Using the Canonical Ordering. - * Algorithmica 16(1), pp. 4-32, 1996. - * - *

    Precondition

    - * The input graph needs to be planar and simple (i.e., no self-loops and no - * multiple edges). - * - *

    Optional parameters

    - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    sizeOptimizationbooltrue - * If this option is set to true, the algorithm tries to reduce the - * size of the resulting grid layout. - *
    baseRatiodouble0.33 - * This option specifies the maximal number of nodes placed on the base line. - * The algorithm tries to place as many nodes as possible on the base - * line, but takes at most max(2, \a baseRatio * size of external face) many. - *
    - * - *

    %Module options

    - * Instances of type PlanarDrawLayout provide the following module options: - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    augmenterAugmentationModulePlanarAugmentation - * Augments the graph by adding edges to obtain a planar graph with - * a certain connectivity (e.g., biconnected or triconnected). - *
    embedderEmbedderModuleSimpleEmbedder - * Planar embedding algorithm applied after planar augmentation. - *
    shellingOrderShellingOrderModuleBiconnectedShellingOrder - * The algorithm to compute a shelling order. The connectivity assured - * by the planar augmentation module has to be sufficient for the shelling - * order module! - *
    - * - *

    Running Time

    - * The computation of the layout takes time O(n), where n is - * the number of nodes of the input graph. - */ -class OGDF_EXPORT PlanarStraightLayout : public PlanarGridLayoutModule -{ -public: - //! Constructs an instance of the Planar-Straight layout algorithm. - PlanarStraightLayout(); - - ~PlanarStraightLayout() { } - - - /** - * @name Optional parameters - * @{ - */ - - /** - * \brief Returns the current setting of option sizeOptimization. - * - * If this option is set to true, the algorithm tries to reduce the - * size of the resulting grid layout. - */ - bool sizeOptimization() const { return m_sizeOptimization; } - - //! Sets the option sizeOptimization to \a opt. - void sizeOptimization(bool opt) { m_sizeOptimization = opt; } - - /** - * \brief Returns the current setting of option baseRatio. - * - * This option specifies the maximal number of nodes placed on the base line. - * The algorithm tries to place as many nodes as possible on the base - * line, but takes at most max(2, \a baseRatio * size of external face) many. - */ - double baseRatio() const { return m_baseRatio; } - - //! Sets the option baseRatio to \a ratio. - void baseRatio(double ratio) { m_baseRatio = ratio; } - - - /** @} - * @name Module options - * @{ - */ - - /** - * \brief Sets the augmentation module. - * - * The augmentation module needs to make sure that the graph gets the - * connectivity required for calling the shelling order module. - */ - void setAugmenter(AugmentationModule *pAugmenter) { - m_augmenter.set(pAugmenter); - } - - //! Sets the shelling order module. - void setShellingOrder(ShellingOrderModule *pOrder){ - m_computeOrder.set(pOrder); - } - - //! Sets the module option for the graph embedding algorithm. - void setEmbedder(EmbedderModule *pEmbedder) { - m_embedder.set(pEmbedder); - } - - //! @} - -private: - bool m_sizeOptimization; //!< The option for size optimization. - double m_baseRatio; //!< The option for specifying the base ratio. - - ModuleOption m_embedder; //!< The planar embedder module. - ModuleOption m_augmenter; //!< The augmentation module. - ModuleOption m_computeOrder; //!< The shelling order module. - - void doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding); - - void computeCoordinates(const Graph &G, - ShellingOrder &lmc, - NodeArray &x, - NodeArray &y); - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/SchnyderLayout.h b/ext/OGDF/ogdf/planarlayout/SchnyderLayout.h deleted file mode 100644 index e81799825..000000000 --- a/ext/OGDF/ogdf/planarlayout/SchnyderLayout.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the Schnyder Layout Algorithm (SchnyderLayout) - * algorithm. - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SCHNYDER_LAYOUT_H -#define OGDF_SCHNYDER_LAYOUT_H - -#include -#include -#include - -namespace ogdf { - -/** - * The class SchnyderLayout represents the layout algorithm by - * Schnyder [Sch90]. This algorithm draws a planar graph G - * straight-line without crossings. G must not contain self-loops or - * multiple edges. - * The grid layout size is (n − 2) × (n − 2) for a graph with - * n nodes (n ≥ 3). - * The algorithm runs in three phases. In the first phase, the graph is - * augmented by adding new artificial edges to get a triangulated plane graph. - * Then, a partition of the set of interior edges in three trees - * (also called Schnyder trees) with special orientation properties is derived. - * In the third step, the actual coordinates are computed. - */ -class OGDF_EXPORT SchnyderLayout : public PlanarGridLayoutModule { - -public: - SchnyderLayout(); - -protected: - void doCall(const Graph &G, adjEntry adjExternal, GridLayout &gridLayout, - IPoint &boundingBox, bool fixEmbedding); - -private: - void contract(Graph& G, node a, node b, node c, List& L); - - void realizer( - GraphCopy& G, - const List& L, - node a, - node b, - node c, - EdgeArray& rValues, - GraphCopy& T); - - void subtreeSizes( - EdgeArray& rValues, - int i, - node r, - NodeArray& size); - - void prefixSum( - EdgeArray& rValues, - int i, - node r, - const NodeArray& val, - NodeArray& sum); - - void schnyderEmbedding( - GraphCopy& GC, - GridLayout &gridLayout, - adjEntry adjExternal); -}; - - -} // end namespace ogdf - - -#endif //define diff --git a/ext/OGDF/ogdf/planarlayout/ShellingOrder.h b/ext/OGDF/ogdf/planarlayout/ShellingOrder.h deleted file mode 100644 index 94c6b30e8..000000000 --- a/ext/OGDF/ogdf/planarlayout/ShellingOrder.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares classes ShellingOrderSet and ShellingOrder. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SHELLING_ORDER_H -#define OGDF_SHELLING_ORDER_H - - -#include - - -namespace ogdf { - - -/** - * \brief The node set in a shelling order of a graph. - */ -class OGDF_EXPORT ShellingOrderSet : public Array -{ -public: - //! Creates an empty shelling order set. - ShellingOrderSet() : Array() - { - m_leftVertex = m_rightVertex = 0; - m_leftAdj = m_rightAdj = 0; - } - - //! Creates a shelling order set for \a l nodes. - /** - * @param l is the number of nodes in the set. - * @param adjL points to the left-node of the set. - * @param adjR points to the right-node of the set. - */ - ShellingOrderSet(int l, adjEntry adjL = 0, adjEntry adjR = 0) : Array(1,l) - { - m_leftVertex = (adjL != 0) ? adjL->twinNode() : 0; - m_rightVertex = (adjR != 0) ? adjR->twinNode() : 0; - m_leftAdj = adjL; - m_rightAdj = adjR; - } - - // destructor - ~ShellingOrderSet() { } - - - //! Returns the left-node of the set. - node left() const { - return m_leftVertex; - } - - //! Returns the right-node of the set. - node right() const { - return m_rightVertex; - } - - //! Returns the adjacency entry pointing from z1 to the left node (or 0 if no such node). - adjEntry leftAdj() const { - return m_leftAdj; - } - - //! Returns the adjacency entry pointing from \a zp to the right node (or 0 if no such node). - adjEntry rightAdj() const { - return m_rightAdj; - } - - //! Returns true iff the adjacency entry to the left-node exists. - bool hasLeft() const { - return m_leftAdj != 0; - } - - //! Returns true iff the adjacency entry to the right-node exists. - bool hasRight() const { - return m_rightAdj != 0; - } - - //! Sets the left-node to \a cl. - void left(node cl) { - m_leftVertex = cl; - } - - //! Sets the right-node to \a cr. - void right (node cr) { - m_rightVertex = cr; - } - - //! Sets the adjacency entry pointing to the left-node to \a adjL. - void leftAdj(adjEntry adjL) { - m_leftAdj = adjL; - } - - //! Sets the adjacency entry pointing to the right-node to \a adjR. - void rightAdj(adjEntry adjR) { - m_rightAdj = adjR; - } - - //! Returns the length of the order set, i.e., the number of contained nodes. - int len() const { - return high(); - } - - //! Returns the i-th node in the order set from left (the leftmost node has index 1). - node operator[] (const int i) const { - return Array::operator[](i); - } - - //! Returns the i-th node in the order set from left (the leftmost node has index 1). - node& operator[] (const int i) { - return Array::operator[](i); - } - - //! Assignment operator. - void operator= (const ShellingOrderSet& S) { - Array::operator= (S); - left (S.left()); - right (S.right()); - leftAdj (S.leftAdj()); - rightAdj(S.rightAdj()); - } - -private: - node m_leftVertex; //!< the left-node of the set. - node m_rightVertex; //!< the right-node of the set. - adjEntry m_leftAdj; //!< the adjacency entry pointing to the left-node. - adjEntry m_rightAdj; //!< the adjacency entry pointing to the right-node. -}; - - - - -/** - * \brief The shelling order of a graph. - */ -class OGDF_EXPORT ShellingOrder -{ -public: - - //! Creates an empty shelling order. - ShellingOrder() { - m_pGraph = 0; - } - - //ShellingOrder(const Graph &G, const List &partition); - - - ~ShellingOrder() { } - - - - //! Returns the graph associated with the shelling order. - const Graph& getGraph() const { - return *m_pGraph; - } - - //! Returns the number of sets in the node partition. - int length() const { - return m_V.high(); - } - - //! Returns the length of the i-th order set Vi. - int len(int i) const { - return m_V[i].len(); - } - - //! Returns the j-th node of the i-th order set Vi. - node operator() (int i, int j) const { - return (m_V[i])[j]; - } - - //! Returns the i-th set V_i - const ShellingOrderSet& operator[](int i) const { - return m_V[i]; - } - - //! Returns the left-node of the i-th set Vi. - node left (int i) const { - return m_V[i].left(); - } - - //! Returns the right-node of the i-th set Vi. - node right (int i) const { - return m_V[i].right(); - } - - //! Returns the rank of node v, where rank(v) = i iff v is contained in Vi. - int rank (node v) const { - return m_rank[v]; - } - - - /** - * \brief Initializes the shelling order for graph \a G with a given node partition. - * @param G is the associated graph. - * @param partition is the node partition. - */ - void init(const Graph &G, const List &partition); - - /** - * \brief Initializes the shelling order for graph \a G with a given node partition and transforms it into a leftmost order. - * @param G is the associated graph. - * @param partition is the node partition. - */ - void initLeftmost(const Graph &G, const List &partition); - - - void push(int k, node v, node tgt); - - friend class CompOrderBic; - -private: - const Graph *m_pGraph; //!< the associated graph. - Array m_V; //!< the node partition. - NodeArray m_rank; //!< the rank of nodes. -}; - - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/planarlayout/TriconnectedShellingOrder.h b/ext/OGDF/ogdf/planarlayout/TriconnectedShellingOrder.h deleted file mode 100644 index 7b780f308..000000000 --- a/ext/OGDF/ogdf/planarlayout/TriconnectedShellingOrder.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares the class TriconnectedShellingOrder... - * - * ...which computes a shelling order for a triconnected planar graph. - * - * \author - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_TRICONNECTED_SHELLING_ORDER_H -#define OGDF_TRICONNECTED_SHELLING_ORDER_H - - -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// Computation of a shelling order for a triconnected and -// simple (no multi-edges, no self-loops) planar graph -//--------------------------------------------------------- -class OGDF_EXPORT TriconnectedShellingOrder : public ShellingOrderModule -{ -public: - TriconnectedShellingOrder() { - m_baseRatio = 0.33; - } - -protected: - // does the actual computation; must be overridden by derived classes - // the computed order is returned in partition - virtual void doCall(const Graph &G, - adjEntry adj, - List &partition); - -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/SimDraw.h b/ext/OGDF/ogdf/simultaneous/SimDraw.h deleted file mode 100644 index 857276c08..000000000 --- a/ext/OGDF/ogdf/simultaneous/SimDraw.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Base class for simultaneous drawing. - * - * \author Michael Schulz and Daniel Lueckerath - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_SIM_DRAW_H -#define OGDF_SIM_DRAW_H - -#include -#include - -namespace ogdf -{ - - //! The Base class for simultaneous graph drawing. - /** - * This class provides functions for simultaneous graph drawing, - * such as adding new subgraphs. - * - * It is possible to store up to 32 basicgraphs in one instance of the class. - * The basic graph membership for all edges is stored via - * GraphAttributes::edgeSubgraph. - * Several functions are outsourced in corresponding manipulator modules. - */ - - class OGDF_EXPORT SimDraw - { - friend class SimDrawManipulatorModule; - friend class SimDrawCaller; - friend class SimDrawColorizer; - friend class SimDrawCreator; - friend class SimDrawCreatorSimple; - - public: - //! Types for node comparison - enum CompareBy { - index, //!< nodes are compared by their indices - label //!< nodes are compared by their labels - }; - - private: - Graph m_G; //!< the underlying graph - GraphAttributes m_GA; //!< the underlying graphattributes - CompareBy m_compareBy; //!< compare mode - NodeArray m_isDummy; //!< dummy nodes may be colored differently - - - public: - //! constructs empty simdraw instance - /** - * GraphAttributes::edgeSubGraph is activated. - * No other attributes are active. - */ - SimDraw(); - - - //! returns graph - const Graph &constGraph() const { return m_G; } - //! returns graph - Graph &constGraph() { return m_G; } - //! returns graphattributes - const GraphAttributes &constGraphAttributes() const { return m_GA; } - //! returns graphattributes - GraphAttributes &constGraphAttributes() { return m_GA; } - - //! empty graph - void clear() { m_G.clear(); } - - //! returns compare mode - const CompareBy &compareBy() const { return m_compareBy; } - //! returns compare mode - /* - * The usage of comparison by label makes only sense if the - * attribute nodeLabel is activated and labels are set properly. - */ - CompareBy &compareBy() { return m_compareBy; } - - //! returns true if node \a v is marked as dummy - /** - * All dummy node features are introduced for usage when running - * callSubgraphPlanarizer of SimDrawCaller. - */ - const bool &isDummy(node v) const { return m_isDummy[v]; } - //! returns true if node \a v is marked as dummy - bool &isDummy(node v) { return m_isDummy[v]; } - //! returns true if node \a v is a cost zero dummy node - bool isPhantomDummy(node v) const - { - return((isDummy(v)) && (!isProperDummy(v))); - } - //! returns true if node \a v is a cost greater zero dummy node - bool isProperDummy(node v) const; - - //! returns number of nodes - int numberOfNodes() const { return m_G.numberOfNodes(); } - //! returns number of dummy nodes - int numberOfDummyNodes() const; - //! returns number of phantom dummy nodes - int numberOfPhantomDummyNodes() const; - //! returns number of proper dummy nodes - int numberOfProperDummyNodes() const; - - //! checks whether instance is a consistent SimDraw instance - bool consistencyCheck() const; - - //! calculates maximum number of input graphs - /** - * Subgraphs are numbered from 0 to 31. - * This method returns the number of the maximal used subgraph. - * If the graph is empty, the function returns -1. - */ - int maxSubGraph() const; - - //! returns number of BasicGraphs in m_G - /** - * This function uses maxSubGraph to return the number of - * basic graphs contained in m_G. - * If the graph is empty, the function returns 0. - */ - int numberOfBasicGraphs() const; - - //! calls GraphAttributes::readGML - void readGML(const char *fileName) { m_GA.readGML(m_G, fileName); } - //! calls GraphAttributes::writeGML - void writeGML(const char *fileName) const { m_GA.writeGML(fileName); } - - //! returns graph consisting of all edges and nodes from SubGraph \a i - const Graph getBasicGraph(int i) const; - //! returns graphattributes associated with basic graph \a i - /** - * Supported attributes are: - * nodeGraphics, edgeGraphics, edgeLabel, nodeLabel, nodeId, - * edgeIntWeight and edgeColor. - */ - void getBasicGraphAttributes(int i, GraphAttributes &GA, Graph &G); - - //! adds new GraphAttributes to m_G - /** - * If the number of subgraphs in m_G is less than 32, this - * function will add the new GraphAttributes \a GA to m_G - * and return true. - * Otherwise this function returns false. - * The function uses the current compare mode. - */ - bool addGraphAttributes(const GraphAttributes & GA); - - //! adds the graph g to the instance m_G - /** - * If the number of subgraphs in m_G is less than 32 and - * m_compareBy is set to index, this function will add graph - * \a G to m_G and return true. - * Otherwise this function returns false. - */ - bool addGraph(const Graph & G); - - //! gives access to new attribute if not already given - void addAttribute(long attr) - { - if(!(m_GA.attributes() & attr)) - m_GA.initAttributes(attr); - } - - private: - //! compares two nodes \a v and \a w by their ids - bool compareById(node v, node w) const { return (v->index() == w->index()); } - - //! compares two nodes \a v and \a w by their labels - /** - * This method only works, if attribute nodeLabel is activated - * and set properly. - * Otherwise it is recommended to use compareById. - */ - bool compareByLabel(const GraphAttributes &vGA, node v, - const GraphAttributes &wGA, node w) const - { - return(vGA.labelNode(v) == wGA.labelNode(w)); - } - - //! compares two nodes \a v and \a w by compare mode stored in m_compareBy - /** - * This method checks whether m_compareBy was set to index or label and - * uses the corresponding compare method. - */ - bool compare(const GraphAttributes &vGA, node v, - const GraphAttributes &wGA, node w) const; - - }; - -} - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/SimDrawCaller.h b/ext/OGDF/ogdf/simultaneous/SimDrawCaller.h deleted file mode 100644 index 206cb728e..000000000 --- a/ext/OGDF/ogdf/simultaneous/SimDrawCaller.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers variety of possible algorithm calls for simultaneous - * drawing. - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_SIMDRAW_CALLER_H -#define OGDF_SIMDRAW_CALLER_H - -#include - -namespace ogdf -{ - - //! Calls modified algorithms for simdraw instances - /** - * Runs special algorithms suitable for simultaneous drawing - * on current SimDraw instance. The algorithms take - * care of all necessary GraphAttributes activations and - * take over calculated coordinates and dummy nodes. - * - * A typical use of SimDrawCaller involves a predefined SimDraw - * instance on which SimDrawCaller works. - * \code - * SimDraw SD; - * ... - * SimDrawCaller SDC(SD); - * SDC.callSubgraphPlanarizer(); - * \endcode - */ - class OGDF_EXPORT SimDrawCaller : public SimDrawManipulatorModule - { - - private: - EdgeArray *m_esg; //!< saves edgeSubGraph data - - //! updates m_esg - /** - * Should be called whenever graph changed and current - * basic graph membership is needed. - */ - void updateESG(); - - public: - //! constructor - SimDrawCaller(SimDraw &SD); - - //! runs SugiyamaLayout with modified SplitHeuristic - /** - * Runs special call of SugiyamaLayout using - * SugiyamaLayout::setSubgraphs(). - * Saves node coordinates and dummy node bends in current - * simdraw instance. - * - * Uses TwoLayerCrossMinSimDraw object to perform crossing - * minimization. The default is SplitHeuristic. - * - * Automatically activates GraphAttributes::nodeGraphics.\n - * Automatically activates GraphAttributes::edgeGraphics. - */ - void callSugiyamaLayout(); - - //! runs UMLPlanarizationLayout with modified inserter - /** - * Runs UMLPlanarizationLayout with callSimDraw and retransfers - * node coordinates and dummy node bend to current simdraw - * instance. - * - * Automatically activates GraphAttributes::nodeGraphics.\n - * Automatically activates GraphAttributes::edgeGraphics. - */ - void callUMLPlanarizationLayout(); - - //! runs SubgraphPlanarizer with modified inserter - /** - * Runs SubgraphPlanarizer on connected component \a cc with simdraw - * call. Integer edge costs of GraphAttributes are used - * (1 for each edge if not available). - * - * Modifies graph by inserting dummy nodes for each crossing. - * All dummy nodes are marked as dummy. - * (Method SimDrawColorizer::addColorNodeVersion is recommended - * for visualizing dummy nodes.) - * - * No layout is calculated. The result is a planar graph. - */ - int callSubgraphPlanarizer(int cc = 0, int numberOfPermutations = 1); - - }; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/SimDrawColorizer.h b/ext/OGDF/ogdf/simultaneous/SimDrawColorizer.h deleted file mode 100644 index 026a5730f..000000000 --- a/ext/OGDF/ogdf/simultaneous/SimDrawColorizer.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers colorizer for SimDraw. - * - * \author Michael Schulz and Tobias Dehling - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifndef OGDF_SIMDRAW_COLORIZER_H -#define OGDF_SIMDRAW_COLORIZER_H - -#include - -namespace ogdf -{ - - //! Adds color to a graph - /** SimDrawColorizer adds colors to the edges (and nodes) of a simdraw - * instance. The underlying color scheme sets the used colors. - * Some color schemes are only usable for a small number of basic graphs. - * - * A typical use of SimDrawColorizer involves a predefined SimDraw - * instance on which SimDrawColorizer works. - * \code - * SimDraw SD; - * SimDrawColorizer SDC(SD); - * [...] - * SDC.addColor(); - * [...] - * \endcode - */ - class OGDF_EXPORT SimDrawColorizer : public SimDrawManipulatorModule - { - - public: - //! types for colorschemes - enum colorScheme - { - none, //!< <= 32 different colors - bluYel, //!< blue and yellow <= 2 colors - redGre, //!< red and green <= 2 colors - bluOra, //!< blue and orange <= 2 colors - teaLil, //!< teal and purple <= 2 colors - redBluYel, //!< red, blue and yellow <= 3 colors - greLilOra //!< green, purple and orange <= 3 colors - }; - - private: - //! stores the current colorscheme - colorScheme m_colorScheme; - - public: - //! constructor assigns default color scheme - SimDrawColorizer(SimDraw &SD) : SimDrawManipulatorModule(SD) - { m_colorScheme = none; } - - //! returns current color scheme - const colorScheme &ColorScheme() const { return m_colorScheme; } - - //! assigns a new color scheme - colorScheme &ColorScheme() { return m_colorScheme; } - - //! adds color to a graph including nodes - void addColorNodeVersion(); - - //! adds some color to a graph - void addColor(); - - public: - //! Manages the various color schemes - /** - * Color schemes are used within SimDrawColorizer to chose - * different colors for the basic graph visualizations. - * It is used directly within SimDrawColorizer. - * - * \code - * SimDraw SD; - * SimDrawColorizer SDC(SD); - * [...] - * SDC.ColorScheme() = SimDrawColorizer::redGre; - * SDC.addColor(); - * [...] - * \endcode - * - * CAUTION: Some color schemes are only valid for a small - * number (e.g. two or three) of basic graphs. The default color - * scheme can be used for up to 32 basic graphs. - */ - class SimDrawColorScheme - { - private: - //! stores the current colorscheme (set by constructor) - colorScheme m_intScheme; - - //! red color component - /** stores the values of the red color component for every graph - * according to colorscheme - */ - int *red; - - //! green color component - /** stores the values of the green color component for every graph - * according to colorscheme - */ - int *green; - - //! blue color component - /** stores the values of the blue color component for every graph - * according to colorscheme - */ - int *blue; - - public: - //! constructor - SimDrawColorScheme (enum colorScheme colorScm, int numberOfGraphs); - - //! destructor - ~SimDrawColorScheme(); - - //! joins the different color components together - String getColor(int subGraphBits, int numberOfGraphs); - - //! sets the color component arrays according to colorschemeXS - void assignColScm(int numberOfGraphs); - }; // SimDrawColorScheme - - }; // SimDrawColorizer - -} - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/SimDrawCreator.h b/ext/OGDF/ogdf/simultaneous/SimDrawCreator.h deleted file mode 100644 index 3b30b9445..000000000 --- a/ext/OGDF/ogdf/simultaneous/SimDrawCreator.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers variety of possible SimDraw creations. - * - * \author Michael Schulz and Daniel Lueckerath - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_SIMDRAW_CREATOR_H -#define OGDF_SIMDRAW_CREATOR_H - -#include - -namespace ogdf -{ - //! Creates variety of possible SimDraw creations - /** - * This class is used for creating simdraw instances. - * Possible features include reading a graph, randomly modifying - * or clearing the edgeSubgraph value and changing the subGraphBits. - */ - - class OGDF_EXPORT SimDrawCreator : public SimDrawManipulatorModule - { - - public: - //! constructor - SimDrawCreator(SimDraw &SD) : SimDrawManipulatorModule(SD) {} - - //! returns SubGraphBits from edge e - unsigned int &SubGraphBits(edge e) { return m_GA->subGraphBits(e); } - - //! returns SubGraphBits from edge e - const unsigned int &SubGraphBits(edge e) const { return m_GA->subGraphBits(e); } - - //! reads a Graph - void readGraph(const Graph &G) { *m_G = G; } - - //! randomly chose edgeSubGraph value for two graphs - /** - * Assigns random edgeSubGraph values to all edges to create - * a SimDraw instance consisting of two basic graphs. - * Each edge in m_G has a chance of \a doubleESGProbability (in Percent) - * to belong to two SubGraphs. - * Otherwise it has equal chance to belong to either basic graph. - */ - void randomESG2(int doubleESGProbability = 50); - - //! randomly chose edgeSubGraph value for three graphs - /** - * Assigns random edgeSubGraph values to all edges to create - * a SimDraw instance consisting of three basic graphs. - * Each edge in m_G has a chance of \a doubleESGProbabilit (in Percent) - * to belong to two basic graphs and a chance of \a tripleESGProbability - * (in Percent) to belong to three basic graphs. - */ - void randomESG3(int doubleESGProbability = 50, int tripleESGProbability = 25); - - //! randomly chose edgeSubGraph value for graphNumber graphs - /** - * Assigns random edgeSubGraph values to all edges to create - * a SimDraw instance consisting of \a graphNumber basic graphs. - * Each edge has an equal chance for each SubGraphBit - value. - */ - void randomESG(int graphNumber); - - //! clears edgeSubGraph value - /** - * This method clears all SubGraph values from m_G. - * After this function all edges belong to no basic graph. - * CAUTION: All edges need to be reset their edgeSubGraph value - * for maintaining consistency. - */ - void clearESG(); - - //! randomly creates a simdraw instance - /** - * This method creates a random graph with \a numberOfNodes nodes, - * \a numberOfEdges edges. It is transfered into a simdraw instance with - * \a numberOfBasicGraphs basic graphs. - * - * randomSimpleGraph from graph_generators.h is used to - * create a random graph. Furthermore randomESG is used on this graph - * to generate \a numberOfBasicGraphs basic graphs. - */ - void createRandom(int numberOfNodes, int numberOfEdges, int numberOfBasicGraphs); - - }; - -} - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/SimDrawCreatorSimple.h b/ext/OGDF/ogdf/simultaneous/SimDrawCreatorSimple.h deleted file mode 100644 index f1feb0d14..000000000 --- a/ext/OGDF/ogdf/simultaneous/SimDrawCreatorSimple.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers simple SimDraw creations. - * - * \author Michael Schulz and Daniel Lueckerath - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_SIMDRAW_CREATOR_SIMPLE_H -#define OGDF_SIMDRAW_CREATOR_SIMPLE_H - -#include - -namespace ogdf -{ - //! Offers predefined SimDraw creations. - /** - * This class offers some predefined SimDraw creations, such as - * an instance of two outerplanar graphs from Brass et al. (WADS'03) - * or an instance of a path and a planar graph from Erten and Kobourov - * (GD'04). - */ - - class OGDF_EXPORT SimDrawCreatorSimple : public SimDrawCreator - { - - public: - //! constructor - SimDrawCreatorSimple(SimDraw &SD) : SimDrawCreator(SD) {} - - //! creates pair-of-tree instance from Geyer, Kaufmann, Vrto (GD'05) - void createTrees_GKV05(int n); - - //! creates instance of a path and a planar graph from Erten and Kobourov (GD'04) - void createPathPlanar_EK04(); - - //! creates K5 instance from Erten and Kobourov (GD'04) - void createK5_EK04(); - - //!creates K5 instance from Gassner et al. (WG'06) - void createK5_GJPSS06(); - - //!creates instance of two outerplanar graphs from Brass et al. (WADS'03) - void createOuterplanar_BCDEEIKLM03(); - - //!creates instance from Kratochvil (GD'98) - void createKrat98(int N, int nodeNumber); - - //! creates instance with numberofBasic*2 outer, - //! numberOfParallels*numberOfBasic inner Nodes and one Root. - void createWheel(int numberOfParallels, int numberOfbasic); - - //! creates simultaneously planar simultaneous graph with n+1 basic graphs. - void createExpo(int n); - }; - -} - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/SimDrawManipulatorModule.h b/ext/OGDF/ogdf/simultaneous/SimDrawManipulatorModule.h deleted file mode 100644 index 18a399bc6..000000000 --- a/ext/OGDF/ogdf/simultaneous/SimDrawManipulatorModule.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * $Revision: 2528 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 23:05:08 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Module for simdraw manipulator classes - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_SIMDRAW_MANIPULATOR_MODULE_H -#define OGDF_SIMDRAW_MANIPULATOR_MODULE_H - -#include - -namespace ogdf -{ - //! Interface for simdraw manipulators - /** - * To avoid class SimDraw to become too large, several functions - * have been outsourced. These are systematically - * grouped in creation methods (SimDrawCreator), algorithm calls - * (SimDrawCaller) and coloring methods (SimDrawColorizer). - * - * A manipulator instance always needs a SimDraw instance (base instance) - * to work on. The base instance is linked by pointers, - * thus a change within the base instance after initializing does - * not cause trouble: - * \code - * SimDraw SD; - * SimDrawCreatorSimple SDCr(SD); - * SimDrawColorizer SDCo(SD); - * SDCr.createTrees_GKV05(4); - * SimDrawCaller SDCa(SD); - * SDCa.callUMLPlanarizationLayout(); - * SDCo.addColor(); - * \endcode - */ - class OGDF_EXPORT SimDrawManipulatorModule - { - - protected: - //! pointer to current simdraw instance - SimDraw *m_SD; - - //! pointer to current graph - Graph *m_G; - - //! pointer to current graphattributes - GraphAttributes *m_GA; - - public: - //! default constructor - /** creates its own simdraw instance - */ - SimDrawManipulatorModule(); - - //! constructor - SimDrawManipulatorModule(SimDraw &SD) { init(SD); } - - //! initializing base instance - void init(SimDraw &SD); - - //! returns base instance - const SimDraw &constSimDraw() const { return *m_SD; } - }; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/simultaneous/TwoLayerCrossMinSimDraw.h b/ext/OGDF/ogdf/simultaneous/TwoLayerCrossMinSimDraw.h deleted file mode 100644 index 0cc5e9bee..000000000 --- a/ext/OGDF/ogdf/simultaneous/TwoLayerCrossMinSimDraw.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of interface for two-layer crossing - * minimization algorithms for Simultaneous Drawing. - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_TWO_LAYER_CROSS_MIN_SIMDRAW_H -#define OGDF_TWO_LAYER_CROSS_MIN_SIMDRAW_H - - -#include - - -namespace ogdf { - - - class OGDF_EXPORT TwoLayerCrossMinSimDraw : public TwoLayerCrossMin - { - public: - //! Initializes a two-layer crossing minimization module. - TwoLayerCrossMinSimDraw() : TwoLayerCrossMin() { } - - /** - * \brief Performs crossing minimization for level \a L. - * - * @param L is the level in the hierarchy on which nodes are permuted; the - * neighbor level (fixed level) is determined by the hierarchy. - * @param esg points to an edge array which specifies to which subgraphs - * an edge belongs; there are up to 32 possible subgraphs each of which - * is represented by a bit of an unsigned int. - */ - virtual void call(Level &L, const EdgeArray *esg) = 0; - }; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/tree/RadialTreeLayout.h b/ext/OGDF/ogdf/tree/RadialTreeLayout.h deleted file mode 100644 index 27c209bd2..000000000 --- a/ext/OGDF/ogdf/tree/RadialTreeLayout.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of linear time layout algorithm for free - * trees (class RadialTreeLayout). - * - * Based on chapter 3.1.1 Radial Drawings of Graph Drawing by - * Di Battista, Eades, Tamassia, Tollis. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_RADIAL_TREE_LAYOUT_H -#define OGDF_RADIAL_TREE_LAYOUT_H - -#include -#include - - -namespace ogdf { - - -//! The radial tree layout algorithm. -/** - *

    Optional parameters

    - * Radial tree layout provides the following optional parameters. - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    levelDistancedouble50.0 - * The minimal vertical distance required between levels. - *
    connectedComponentDistancedouble50.0 - * The minimal horizontal distance required between trees in the forest. - *
    rootSelection #RootSelectionType #rootIsCenter - * Specifies how to select the root of the tree. - *
    -*/ -class OGDF_EXPORT RadialTreeLayout : public LayoutModule -{ -public: - //! Selection strategies for root of the tree. - enum RootSelectionType { - rootIsSource, //!< Select a source in the graph. - rootIsSink, //!< Select a sink in the graph. - rootIsCenter //!< Select the center of the tree. - }; - -private: - double m_levelDistance; //!< The minimal distance between levels. - double m_connectedComponentDistance; //!< The minimal distance between trees. - - RootSelectionType m_selectRoot; //!< Specifies how to determine the root. - - node m_root; //!< The root of the tree. - - int m_numLevels; //!< The number of levels (root is on level 0). - NodeArray m_level; //!< The level of a node. - NodeArray m_parent; //!< The parent of a node (0 if root). - NodeArray m_leaves; //!< The weighted number of leaves in subtree. - Array > m_nodes; //!< The nodes at a level. - - NodeArray m_angle; //!< The angle of node center (for placement). - NodeArray m_wedge; //!< The wedge reserved for subtree. - - NodeArray m_diameter; //!< The diameter of a circle bounding a node. - Array m_width; //!< The width of a circle. - - Array m_radius; //!< The width of a level. - double m_outerRadius; //!< The radius of circle bounding the drawing. - - struct Group - { - RadialTreeLayout *m_data; - - bool m_leafGroup; - SListPure m_nodes; - double m_sumD; - double m_sumW; - double m_leftAdd; - double m_rightAdd; - - Group(RadialTreeLayout *data, node v) { - m_data = data; - m_leafGroup = (v->degree() == 1); - m_nodes.pushBack(v); - m_sumD = m_data->diameter()[v] + m_data->levelDistance(); - m_sumW = m_data->leaves()[v]; - m_leftAdd = m_rightAdd = 0.0; - } - - bool isSameType(node v) const { - return (m_leafGroup == (v->degree() == 1)); - } - - void append(node v) { - m_nodes.pushBack(v); - m_sumD += m_data->diameter()[v] + m_data->levelDistance(); - m_sumW += m_data->leaves()[v]; - } - - double add() const { return m_leftAdd + m_rightAdd; } - node leftVertex () const { return m_nodes.front(); } - node rightVertex() const { return m_nodes.back (); } - }; - - class Grouping : public List - { - public: - void computeAdd(double &D, double &W); - }; - - NodeArray m_grouping; - -public: - //! Creates an instance of radial tree layout and sets options to default values. - RadialTreeLayout(); - - //! Copy constructor. - RadialTreeLayout(const RadialTreeLayout &tl); - - // destructor - ~RadialTreeLayout(); - - //! Assignment operator. - RadialTreeLayout &operator=(const RadialTreeLayout &tl); - - //! Calls the algorithm for graph attributes \a GA. - /** - * The algorithm preserve the order of children which is given by - * the adjacency lists. - * - * \pre The graph is a tree. - * @param GA represents the input graph and is assigned the computed layout. - */ - void call(GraphAttributes &GA); - - - // option that determines the minimal vertical distance - // required between levels - - //! Returns the option levelDistance. - double levelDistance() const { return m_levelDistance; } - - //! Sets the option levelDistance to \a x. - void levelDistance(double x) { m_levelDistance = x; } - - // option that determines the minimal horizontal distance - // required between trees in the forest - - //! Returns the option connectedComponentDistance. - double connectedComponentDistance() const { return m_connectedComponentDistance; } - - //! Sets the option connectedComponentDistance to \a x. - void connectedComponentDistance(double x) { m_connectedComponentDistance = x; } - - // option that determines if the root is on the top or on the bottom - - //! Returns the option rootSelection. - RootSelectionType rootSelection() const { return m_selectRoot; } - - //! Sets the option rootSelection to \a sel. - void rootSelection(RootSelectionType sel) { m_selectRoot = sel; } - - const NodeArray &diameter() const { return m_diameter; } - const NodeArray &leaves() const { return m_leaves; } - -private: - void FindRoot(const Graph &G); - void ComputeLevels(const Graph &G); - void ComputeDiameters(GraphAttributes &AG); - void ComputeAngles(const Graph &G); - void ComputeCoordinates(GraphAttributes &AG); - void ComputeGrouping(int i); - - OGDF_NEW_DELETE -}; - -} // end namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/tree/TreeLayout.h b/ext/OGDF/ogdf/tree/TreeLayout.h deleted file mode 100644 index 5c6c401af..000000000 --- a/ext/OGDF/ogdf/tree/TreeLayout.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * $Revision: 2583 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-12 01:02:21 +0200 (Do, 12. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of linear time layout algorithm for trees - * (TreeLayout) based on Walker's algorithm. - * - * \author Christoph Buchheim - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_TREE_LAYOUT_H -#define OGDF_TREE_LAYOUT_H - -#include -#include - -namespace ogdf { - -/** - * \brief The tree layout algorithm. - * - * The class TreeLayout represents the improved version of the tree layout - * algorithm by Walker presented in: - * - * Christoph Buchheim, Michael Jünger, Sebastian Leipert: Drawing - * rooted trees in linear time. Software: Practice and Experience 36(6), - * pp. 651-665, 2006. - * - * The algorithm also allows to lay out a forest, i.e., a collection of trees. - * - *

    Optional parameters

    - * Tree layout provides various optional parameters. - * - * - * - * - * - * - * - * - * - * - * - *
    OptionTypeDefaultDescription - *
    siblingDistancedouble20.0 - * The horizontal spacing between adjacent sibling nodes. - *
    subtreeDistancedouble20.0 - * The horizontal spacing between adjacent subtrees. - *
    levelDistancedouble50.0 - * The vertical spacing between adjacent levels. - *
    treeDistancedouble50.0 - * The horizontal spacing between adjacent trees in a forest. - *
    orthogonalLayoutboolfalse - * Determines whether edges are routed in an orthogonal - * or straight-line fashion. - *
    orientation #Orientation #topToBottom - * Determines if the tree is laid out in a top-to-bottom, - * bottom-to-top, left-to-right, or right-to-left fashion. - *
    selectRoot #RootSelectionType #rootIsSource - * Determines how to select the root of the tree(s). Possible - * selection strategies are to take a (unique) source or sink in - * the graph, or to use the coordinates and to select the topmost - * node for top-to-bottom orientation, etc. - *
    - * - * The spacing between nodes is determined by the siblingDistance, - * subtreeDistance, levelDistance, and treeDistance. - * The layout style is determined by orthogonalLayout and - * orientation; the root of the tree is selected according to - * th eselection strategy given by selectRoot. - */ -class OGDF_EXPORT TreeLayout : public LayoutModule { -public: - //! Determines how to select the root of the tree. - enum RootSelectionType { - rootIsSource, //!< Select a source in the graph. - rootIsSink, //!< Select a sink in the graph. - rootByCoord //!< Use the coordinates, e.g., select the topmost node if orientation is topToBottom. - }; - -private: - double m_siblingDistance; //!< The minimal distance between siblings. - double m_subtreeDistance; //!< The minimal distance between subtrees. - double m_levelDistance; //!< The minimal distance between levels. - double m_treeDistance; //!< The minimal distance between trees. - - bool m_orthogonalLayout; //!< Option for orthogonal style (yes/no). - Orientation m_orientation; //!< Option for orientation of tree layout. - RootSelectionType m_selectRoot; //!< Option for how to determine the root. - - NodeArray m_number; //!< Consecutive numbers for children. - - NodeArray m_parent; //!< Parent node, 0 if root. - NodeArray m_leftSibling; //!< Left sibling, 0 if none. - NodeArray m_firstChild; //!< Leftmost child, 0 if leaf. - NodeArray m_lastChild; //!< Rightmost child, 0 if leaf. - NodeArray m_thread; //!< Thread, 0 if none. - NodeArray m_ancestor; //!< Actual highest ancestor. - - NodeArray m_preliminary; //!< Preliminary x-coordinates. - NodeArray m_modifier; //!< Modifier of x-coordinates. - NodeArray m_change; //!< Change of shift applied to subtrees. - NodeArray m_shift; //!< Shift applied to subtrees. - - SListPure m_reversedEdges; //!< List of temporarily removed edges. - Graph *m_pGraph; //!< The input graph. - -public: - //! Creates an instance of tree layout and sets options to default values. - TreeLayout(); - - //! Copy constructor. - TreeLayout(const TreeLayout &tl); - - // destructor - ~TreeLayout(); - - - /** - * @name Algorithm call - * @{ - */ - - /** - * \brief Calls tree layout for graph attributes \a GA. - * - * \pre The graph is a tree. - * - * The order of children is given by the adjacency lists; - * the successor of the unique in-edge of a non-root node - * leads to its leftmost child; the leftmost child of the root - * is given by its first adjacency entry. - * @param GA is the input graph and will also be assigned the layout information. - */ - void call(GraphAttributes &GA); - - /** - * \brief Calls tree layout for graph attributes \a GA. - * - * \pre The graph is a tree. - * - * Sorts the adjacency entries according to the positions of adjacent - * vertices in \a GA. - * @param GA is the input graph and will also be assigned the layout information. - * @param G is the graph associated with \a GA. - */ - void callSortByPositions(GraphAttributes &GA, Graph &G); - - - /** @} - * @name Optional parameters - * @{ - */ - - //! Returns the the minimal required horizontal distance between siblings. - double siblingDistance() const { return m_siblingDistance; } - - //! Sets the the minimal required horizontal distance between siblings to \a x. - void siblingDistance(double x) { m_siblingDistance = x; } - - //! Returns the minimal required horizontal distance between subtrees. - double subtreeDistance() const { return m_subtreeDistance; } - - //! Sets the minimal required horizontal distance between subtrees to \a x. - void subtreeDistance(double x) { m_subtreeDistance = x; } - - //! Returns the minimal required vertical distance between levels. - double levelDistance() const { return m_levelDistance; } - - //! Sets the minimal required vertical distance between levels to \a x. - void levelDistance(double x) { m_levelDistance = x; } - - //! Returns the minimal required horizontal distance between trees in the forest. - double treeDistance() const { return m_treeDistance; } - - //! Sets the minimal required horizontal distance between trees in the forest to \a x. - void treeDistance(double x) { m_treeDistance = x; } - - //! Returns whether orthogonal edge routing style is used. - bool orthogonalLayout() const { return m_orthogonalLayout; } - - //! Sets the option for orthogonal edge routing style to \a b. - void orthogonalLayout(bool b) { m_orthogonalLayout = b; } - - //! Returns the option that determines the orientation of the layout. - Orientation orientation() const { return m_orientation; } - - //! Sets the option that determines the orientation of the layout to \a orientation. - void orientation(Orientation orientation) { m_orientation = orientation; } - - //! Returns the option that determines how the root is selected. - RootSelectionType rootSelection() const { return m_selectRoot; } - - //! Sets the option that determines how the root is selected to \a rootSelection. - void rootSelection(RootSelectionType rootSelection) { m_selectRoot = rootSelection; } - - - /** @} - * @name Operators - * @{ - */ - - //! Assignment operator. - TreeLayout &operator=(const TreeLayout &tl); - - //! @} - -private: - class AdjComparer; - - void adjustEdgeDirections(Graph &G, node v, node parent); - void setRoot(GraphAttributes &AG, Graph &tree); - void undoReverseEdges(GraphAttributes &AG); - - // initialize all node arrays and - // compute the tree structure from the adjacency lists - // - // returns the root node - void initializeTreeStructure(const Graph &tree, List &roots); - - // delete all node arrays - void deleteTreeStructure(); - - // returns whether node v is a leaf - int isLeaf(node v) const; - - // returns the successor of node v on the left/right contour - // returns 0 if there is none - node nextOnLeftContour(node v) const; - node nextOnRightContour(node v) const; - - // recursive bottom up traversal of the tree for computing - // preliminary x-coordinates - void firstWalk(node subtree,const GraphAttributes &AG,bool upDown); - - // space out the small subtrees on the left hand side of subtree - // defaultAncestor is used for all nodes with obsolete m_ancestor - void apportion( - node subtree, - node &defaultAncestor, - const GraphAttributes &AG, - bool upDown); - - // recursive top down traversal of the tree for computing final - // x-coordinates - void secondWalkX(node subtree, double modifierSum, GraphAttributes &AG); - void secondWalkY(node subtree, double modifierSum, GraphAttributes &AG); - - // compute y-coordinates and edge shapes - void computeYCoordinatesAndEdgeShapes(node root,GraphAttributes &AG); - void computeXCoordinatesAndEdgeShapes(node root,GraphAttributes &AG); - - void findMinX(GraphAttributes &AG, node root, double &minX); - void findMinY(GraphAttributes &AG, node root, double &minY); - void findMaxX(GraphAttributes &AG, node root, double &maxX); - void findMaxY(GraphAttributes &AG, node root, double &maxY); - void shiftTreeX(GraphAttributes &AG, node root, double shift); - void shiftTreeY(GraphAttributes &AG, node root, double shift); -}; - -} // end namespace ogdf - -#endif - diff --git a/ext/OGDF/ogdf/upward/DominanceLayout.h b/ext/OGDF/ogdf/upward/DominanceLayout.h deleted file mode 100644 index 6214c8767..000000000 --- a/ext/OGDF/ogdf/upward/DominanceLayout.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of dominance layout algorithm. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//*** -// Dominance Drawing Method. see "Graph Drawing" by Di Battista et al. -//*** - - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_DOMINANCE_LAYOUT_H -#define OGDF_DOMINANCE_LAYOUT_H - - -#include -#include -#include -#include -#include -#include -#include - -namespace ogdf { - - -class OGDF_EXPORT DominanceLayout : public LayoutModule -{ -public: - - DominanceLayout() { - m_grid_dist = 1; - // set default module - m_upPlanarizer.set(new SubgraphUpwardPlanarizer()); - - m_angle = 45.0 / 180.0 * Math::pi; - - } - - virtual void call(GraphAttributes &GA); - - void layout(GraphAttributes &GA, const UpwardPlanRep &UPROrig); - - void setUpwardPlanarizer(UpwardPlanarizerModule *upPlanarizer) { - m_upPlanarizer.set(upPlanarizer); - } - - void setMinGridDistance(int dist) {m_grid_dist = dist;} - - - -private: - - double m_angle; //rotate angle to obtain an upward drawing; default is 45° - - NodeArray firstout; - NodeArray lastout; - NodeArray firstin; - NodeArray lastin; - - int m_R; - int m_L; - - // list of nodes sorted by their x and y coordinate. - List xNodes; - List yNodes; - - //coordinate in preliminary layout - NodeArray xPreCoord; - NodeArray yPreCoord; - - //final coordinate of the nodes of the UPR - NodeArray xCoord; - NodeArray yCoord; - - - //min grid distance - int m_grid_dist; - - ModuleOption m_upPlanarizer; // upward planarizer - - void labelX(const UpwardPlanRep &UPR, node v, int &count); - - void labelY(const UpwardPlanRep &UPR, node v, int &count); - - void compact(const UpwardPlanRep &UPR, GraphAttributes &GA); - - void findTransitiveEdges(const UpwardPlanRep &UPR, List &edges); - -}; - - -}//namespace - -#endif diff --git a/ext/OGDF/ogdf/upward/ExpansionGraph.h b/ext/OGDF/ogdf/upward/ExpansionGraph.h deleted file mode 100644 index 160471dcf..000000000 --- a/ext/OGDF/ogdf/upward/ExpansionGraph.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class ExpansionGraph... - * - * ...which represents the expansion graph of each biconnected - * component of a given digraph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_EXPANSION_GRAPH_H -#define OGDF_EXPANSION_GRAPH_H - - -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// ExpansionGraph -// represents expansion graph of each biconnected component -// of a given digraph, i.e., each vertex v with in- and outdegree -// greater than 1 is expanded into two vertices x and y connected -// by an edge x->y such that all incoming edges are moved from -// v to x and all outgoing edges from v to y -//--------------------------------------------------------- -class OGDF_EXPORT ExpansionGraph : public Graph -{ -public: - // constructor - ExpansionGraph(const Graph &G); - - // number of biconnected components of G - int numberOfBCs() const { - return m_component.high()+1; - } - - // returns number of bic. component containing edge e - int componentNumber(edge e) const { - return m_compNum[e]; - } - - void setComponentNumber(edge e, int i) { - m_compNum[e] = i; - } - - // returns list of edges contained in component i - const SListPure &component(int i) const { - return m_component[i]; - } - - // returns list of components containing vertex v - const SList &adjacentComponents(node v) const { - return m_adjComponents[v]; - } - - - // original node of node v - // Precond.: v is a node in the expansion graph - node original(node v) const { - return m_vOrig[v]; - } - - node representative(node v) const { - node vOrig = m_vOrig[v]; - return (vOrig != 0) ? vOrig : m_vRep[v]; - } - - node copy(node vG) const { - return m_vCopy[vG]; - } - - // original edge of edge e - // Precond.: e is a edge in the expansion graph - edge original(edge e) const { - return m_eOrig[e]; - } - - // sets the original node of vCopy to vOriginal - void setOriginal(node vCopy, node vOriginal) { - m_vOrig[vCopy] = vOriginal; - } - - - // initializes to the expansion graph of the i-th biconnected component - // of G - void init(int i); - - // initializes to the expansion graph of G - // advantage is that the vertices in the created copy are created in the - // order in which the corresponding originals appear in the list of nodes - // in G and therefore mostly have the same indices - // mainly for debbugging purposes - void init(const Graph &G); - -private: - node getCopy(node vOrig) { - node vCopy = m_vCopy[vOrig]; - if (vCopy == 0) { - vCopy = newNode(); - m_vOrig[m_vCopy[vOrig] = vCopy] = vOrig; - } - return vCopy; - } - - EdgeArray m_compNum; // component of edge e - Array > m_component; // edges in i-th biconnected comp. - NodeArray > m_adjComponents; // components containing v - NodeArray m_vCopy; // copy of original vertex - NodeArray m_vOrig; // original vertex of copy - NodeArray m_vRep; - EdgeArray m_eOrig; // original edge of copy -}; // class ExpansionGraph - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/upward/FUPSSimple.h b/ext/OGDF/ogdf/upward/FUPSSimple.h deleted file mode 100644 index 5c5856b02..000000000 --- a/ext/OGDF/ogdf/upward/FUPSSimple.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of the FastPlanarSubgraph. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_FUPS_SIMPLE_H -#define OGDF_FUPS_SIMPLE_H - - -#include - - -namespace ogdf { - - -class OGDF_EXPORT FUPSSimple : public FUPSModule{ - -public: - //! Creates an instance of feasible subgraph algorithm. - FUPSSimple() : m_nRuns(0) { } - - // destructor - ~FUPSSimple() { } - - - // options - - //! Sets the number of randomized runs to \a nRuns. - void runs (int nRuns) { - m_nRuns = nRuns; - } - - //! Returns the current number of randomized runs. - int runs() const { - return m_nRuns; - } - - - //! return a adjEntry of node v which right face is f. Be Carefully! The adjEntry is not always unique. - adjEntry getAdjEntry(const CombinatorialEmbedding &Gamma, node v, face f) - { - adjEntry adj = 0; - forall_adj(adj, v) { - if (Gamma.rightFace(adj) == f) - break; - } - - OGDF_ASSERT(Gamma.rightFace(adj) == f); - - return adj; - } - -protected: - - /** - * \brief Computes a feasible upward planar subgraph of the input graph. - * - * @param UPR represents the feasible upward planar subgraph after the call. \a UPR has to be initialzed as a - * UpwardPlanRep of the input connected graph G and is modified to obtain the upward planar subgraph. - * The subgraph is represented as an upward planar representation. - * @param delEdges is the deleted edges in order to obtain the subgraph. The edges are edges of the original graph G. - * \return the status of the result. - */ - virtual Module::ReturnType doCall(UpwardPlanRep &UPR, - List &delEdges); - - -private: - - int m_nRuns; //!< The number of runs for randomization. - - void computeFUPS(UpwardPlanRep &UPR, - List &delEdges); - - //! Compute a (random) span tree of the input sT-Graph. - /* - * @param GC The Copy of the input graph G. - * @param &delEdges The deleted edges (edges of G). - * @param random compute a random span tree - * @multisource true, if the original graph got multisources. In this case, the incident edges of - * the source are allways included in the span tree - */ - void getSpanTree(GraphCopy &GC, List &delEdges, bool random); - - /* - * Function use by geSpannTree to compute the spannig tree. - */ - void dfs_visit(const Graph &G, edge e, NodeArray &visited, EdgeArray &treeEdges, bool random); - - // construct a merge graph with repsect to gamma and its test acyclicity - bool constructMergeGraph(GraphCopy &M, // copy of the original graph, muss be embedded - adjEntry adj_orig, // the adjEntry of the original graph, which right face is the ext. Face and adj->theNode() is the source - const List &del_orig); // deleted edges -}; - -} -#endif diff --git a/ext/OGDF/ogdf/upward/FaceSinkGraph.h b/ext/OGDF/ogdf/upward/FaceSinkGraph.h deleted file mode 100644 index 7a0b18869..000000000 --- a/ext/OGDF/ogdf/upward/FaceSinkGraph.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class FaceSinkGraph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FACE_SINK_GRAPH_H -#define OGDF_FACE_SINK_GRAPH_H - - -#include -#include -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT FaceSinkGraph : public Graph -{ -public: - //! constructor (we assume that the original graph is connected!) - FaceSinkGraph(const ConstCombinatorialEmbedding &E, node s); - - //! default constructor (dummy) - FaceSinkGraph() : m_pE(0) { } - - - void init(const ConstCombinatorialEmbedding &E, node s); - - - //! return a reference to the original graph G - const Graph &originalGraph() const { - return *m_pE; - } - - //! returns a reference to the embedding E of the original graph G - const ConstCombinatorialEmbedding &originalEmbedding() const { - return *m_pE; - } - - //! returns the sink-switch in G corresponding to node v in the face-sink - //! graph, 0 if v corresponds to a face - node originalNode(node v) const { - return m_originalNode[v]; - } - - //! returns the face in E corresponding to node v in the face-sink - //! graph, 0 if v corresponds to a sink-switch - face originalFace(node v) const { - return m_originalFace[v]; - } - - // returns true iff node v in the face-sink graph corresponds to a - // face in E containing the source - bool containsSource(node v) const { - return m_containsSource[v]; - } - - - - - //! returns the list of faces f in E such that there exists an upward-planar - //! drawing realizing E with f as external face - //! a node v_T in tree T is returned as representative. v_T is 0 if no possible external face exists. - node possibleExternalFaces(SList &externalFaces) { - node v_T = checkForest(); - if (v_T != 0) - gatherExternalFaces(m_T,0,externalFaces); - return v_T; - } - - - node faceNodeOf(edge e) { - return dfsFaceNodeOf(m_T,0, - m_pE->rightFace(e->adjSource()),m_pE->rightFace(e->adjTarget())); - } - - - node faceNodeOf(face f) { - return dfsFaceNodeOf(m_T,0,f,0); - } - - - //! augments G to an st-planar graph (original implementation) - /** introduces also new nodes into G corresponding to face-nodes in face sink graph) - */ - void stAugmentation( - node h, // node corresponding to external face - Graph &G, // original graph (not const) - SList &augmentedNodes, // list of augmented nodes - SList &augmentedEdges); // list of augmented edges - - //! augments G to an st-planar graph - /** (introduces only one new node as super sink into G) - */ - void stAugmentation( - node h, // node corresponding to external face - Graph &G, // original graph (not const) - node &superSink, // super sink - SList &augmentedEdges); // list of augmented edges - - //! compute the sink switches of all faces. - // the ext. face muss be set - void sinkSwitches(FaceArray< List > &faceSwitches); - - - -private: - //! constructs face-sink graph - void doInit(); - - //! performs dfs-traversal and checks for backwards edges - bool dfsCheckForest( - node v, // current node - node parent, // its parent in tree - NodeArray &visited, // not already visited ? - // number of internal vertices of G in current tree - int &nInternalVertices); - - //! builds list of possible external faces - /** all faces in tree T containing - * the single source s) by a dfs traversal of T - */ - void gatherExternalFaces( - node v, // current node - node parent, // its parent - SList &externalFaces); // returns list of possible external faces - - node dfsFaceNodeOf(node v, node parent,face f1, face f2); - - node dfsStAugmentation( - node v, // current node - node parent, // its parent - Graph &G, // original graph (not const) - SList &augmentedNodes, // list of augmented nodes - SList &augmentedEdges); // list of augmented edges - - node dfsStAugmentation( - node v, // current node - node parent, // its parent - Graph &G, // original graph (not const) - SList &augmentedEdges); // list of augmented edges - - - //! associated embedding of graph G - const ConstCombinatorialEmbedding *m_pE; - node m_source; //!< the single source - node m_T; //!< representative of unique tree T - - NodeArray m_originalNode; //!< original node in G - NodeArray m_originalFace; //!< original face in E - NodeArray m_containsSource; //!< contains face node the source ? - - /* - //! traverse the face sink tree and compute the sink witches of each internal faces - void dfsFST(node v, //current node - node parent, //parent of v - FaceArray< List > &faceSwitches, - NodeArray &visited); - */ - - //! checks if the face-sink graph is a forest with - //! 1) there is exactly one tree T containing no internal vertex of G - //! 2) all other trees contain exactly one internal vertex of G - //! a node in tree T is returned as representative - node checkForest(); - - - //! return a adjEntry of node v which right face is f. Be Carefully! The adjEntry is not always unique. - adjEntry getAdjEntry(node v, face f); - - -}; // class FaceSinkGraph - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/upward/FeasibleUpwardPlanarSubgraph.h b/ext/OGDF/ogdf/upward/FeasibleUpwardPlanarSubgraph.h deleted file mode 100644 index 4d095507e..000000000 --- a/ext/OGDF/ogdf/upward/FeasibleUpwardPlanarSubgraph.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class FeasibleUpwardPlanarSubgraph which - * computes an feasible upward planar subgraph and a feasible upward embedding. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_FEASIBLE_UPWARD_PLANAR_SUBGRAPH_H -#define OGDF_FEASIBLE_UPWARD_PLANAR_SUBGRAPH_H - - - -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT FeasibleUpwardPlanarSubgraph : public Module -{ -public: - // construction - FeasibleUpwardPlanarSubgraph() { } - // destruction - ~FeasibleUpwardPlanarSubgraph() { } - - // Computes a feasible upward planar subgraph fups with feasible a - // embedding gamma. - ReturnType call( - Graph &G, // connected single source graph - GraphCopy &Fups, // the feasible upward planar subgraph - adjEntry &extFaceHandle, // the right face of this adjEntry is the ext. face of the embedded fups - List &delEdges, // the list of deleted edges (original edges) - bool multisources, // true, if the original input graph has multi sources - // and G is an tranformed single source graph (by introducing a super source) - int runs); // number of runs - - // Computes a feasible upward planar subgraph fups with feasible a - // embedding gamma. - ReturnType call( - const Graph &G, - GraphCopy &Fups, - adjEntry &extFaceHandle, - List &delEdges, - bool multisources); - - // construct a merge graph with repsect to gamma and its test acyclicity - bool constructMergeGraph( - GraphCopy &M, // copy of the original graph, muss be embedded - adjEntry adj_orig, // the adjEntry of the original graph, which right face is the ext. Face and adj->theNode() is the source - const List &del_orig); // deleted edges - - - //! return a adjEntry of node v which right face is f. Be Carefully! The adjEntry is not always unique. - adjEntry getAdjEntry(const CombinatorialEmbedding &Gamma, node v, face f) - { - adjEntry adj = 0; - forall_adj(adj, v) { - if (Gamma.rightFace(adj) == f) - break; - } - - OGDF_ASSERT(Gamma.rightFace(adj) == f); - - return adj; - } - -private: - - //! Compute a (random) span tree of the input sT-Graph. - /* - * @param GC The input graph. - * @param &delEdges The deleted edges (original edges). - * @param random compute a random span tree - * @multisource true, if the original graph got multisources. In this case, the incident edges of - * the source are allways included in the span tree - */ - void getSpanTree(GraphCopy &GC, List &delEdges, bool random, bool multisources); - - /* - * Function use by geSpannTree to compute the spannig tree. - */ - void dfs_visit(const Graph &G, edge e, NodeArray &visited, EdgeArray &treeEdges, bool random); - - - - -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/upward/FixedEmbeddingUpwardEdgeInserter.h b/ext/OGDF/ogdf/upward/FixedEmbeddingUpwardEdgeInserter.h deleted file mode 100644 index a23990204..000000000 --- a/ext/OGDF/ogdf/upward/FixedEmbeddingUpwardEdgeInserter.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief declaration of class FixedEmbeddingInserter - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FIXED_EMBEDDING_UPWARD_EDGE_INSERTER_H -#define OGDF_FIXED_EMBEDDING_UPWARD_EDGE_INSERTER_H - - - -#include -#include -#include - - - - -namespace ogdf { - - - -//! Edge insertion module that inserts each edge optimally into a fixed embedding. -class OGDF_EXPORT FixedEmbeddingUpwardEdgeInserter : public UpwardEdgeInserterModule -{ -public: - //! Creates an instance of fixed-embedding edge inserter. - FixedEmbeddingUpwardEdgeInserter() {} - - ~FixedEmbeddingUpwardEdgeInserter() { } - - -private: - - bool isUpwardPlanar(Graph &G) - { - UpwardPlanarModule upMod; - return upMod.upwardPlanarityTest(G); - } - - /** - * @param UPR is the input upward planarized representation of a FUPS and will also receive the result. - * @param origEdges is the list of original edges (edges in the original graph - * of \a UPR) that have to be inserted. - * @param costOrig points to an edge array containing the costs of original edges; edges in - * \a UPR without an original edge have zero costs. - * @param forbiddenEdgeOrig points to an edge array indicating if an original edge is - * forbidden to be crossed. - */ - virtual ReturnType doCall(UpwardPlanRep &UPR, - const List &origEdges, - const EdgeArray *costOrig = 0, - const EdgeArray *forbiddenEdgeOrig = 0 - ); - - - ReturnType insertAll(UpwardPlanRep &UPR, - List &toInsert, - EdgeArray &cost); - - - //! compute a list of static locked edges, i.e. eges which a priory cannot included in a feasible insertion path. - void staticLock(UpwardPlanRep &UPR, EdgeArray &locked, const List &origEdges, edge e_orig); - - //! compute a list of dynamic locked edges - void dynamicLock(UpwardPlanRep &UPR, EdgeArray &locked, face f, adjEntry e_cur); - - void nextFeasibleEdges(UpwardPlanRep &UPR, List &nextEdges, face f, adjEntry e_cur, EdgeArray &locked, bool heuristic); - - //! compute the minimal feasible insertion path - void minFIP(UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path) { getPath(UPR, origEdges, cost, e_orig, path, false); } - - - - //! compute a constraint feasible insertion path usig heuristic. - void constraintFIP(UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path) { getPath(UPR, origEdges, cost, e_orig, path, true); } - - //! compute an insertion path - void getPath(UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path, - bool heuristic); - - - //! mark the edges which are dominates by node v - void markUp(const Graph &G, node v, EdgeArray &markedEdges); - - - //! mark the edges which dominate node v - void markDown(const Graph &G, node v, EdgeArray &markedEdges); - - //! compute the feasible edges of the face f with respect to e - void feasibleEdges(UpwardPlanRep &UPR, - face f, // current face - adjEntry adj, // current adjEntry, right face muss be f - EdgeArray &locked, // we compute the dyn. locked edges on the fly with respect to e - List &feasible, // the list of feasible edges in f with respect to e - bool heuristic); - - //! return true if current insertion path is contraint feasible - bool isConstraintFeasible(UpwardPlanRep &UPR, - const List &orig_edges, - edge e_orig, - adjEntry adjCurrent, - adjEntry adjNext, // the next adjEntry of the current insertion path - EdgeArray &predAdj //Array to reconstruction the insertion path - ); - - - //! return true if current insertion path is contraint feasible - bool isConstraintFeasible(UpwardPlanRep &UPR, - List &origEdges, - edge e_orig, - SList &path); - - -}; - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/upward/FixedUpwardEmbeddingInserter.h b/ext/OGDF/ogdf/upward/FixedUpwardEmbeddingInserter.h deleted file mode 100644 index 619abc427..000000000 --- a/ext/OGDF/ogdf/upward/FixedUpwardEmbeddingInserter.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * $Revision: 2555 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 12:12:10 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class FeasibleUpwardPlanarSubgraph which - * computes an feasible upward planar subgraph and a feasible upward embedding. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_FIXED_UPWARD_EMBEDDING_INSERTER_H -#define OGDF_FIXED_UPWARD_EMBEDDING_INSERTER_H - - - -#include -#include -#include -#include - - -namespace ogdf { - - -class OGDF_EXPORT FixedUpwardEmbeddingInserter : public Module -{ -public: - // construction - FixedUpwardEmbeddingInserter(); - - // destruction - ~FixedUpwardEmbeddingInserter(){ } - - // Insert all edges in UPR - Module::ReturnType call(UpwardPlanRep &UPR, List origEdges, EdgeArray &cost); - - bool isUpwardPlanar(Graph &G) - { - UpwardPlanarModule upMod; - return upMod.upwardPlanarityTest(G); - } - -private: - - const int infty; - - //! compute a list of static locked edges, i.e. eges which a priory cannot included in a feasible insertion path. - void staticLock(UpwardPlanRep &UPR, EdgeArray &locked, const List &origEdges, edge e_orig); - - //! compute a list of dynamic locked edges - void dynamicLock(UpwardPlanRep &UPR, EdgeArray &locked, face f, adjEntry e_cur); - - void nextFeasibleEdges(UpwardPlanRep &UPR, List &nextEdges, face f, adjEntry e_cur, EdgeArray &locked); - - //! compute the minimal feasible insertion path - void minFIP(UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path) { getPath(UPR, origEdges, cost, e_orig, path, false); } - - - - //! compute a constraint feasible insertion path usig heuristic. - void constraintFIP(UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path) { getPath(UPR, origEdges, cost, e_orig, path, true); } - - //! compute an insertion path - void getPath(UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path, - bool heuristic); - - - //! mark the edges which are dominates by node v - void markUp(const Graph &G, node v, EdgeArray &markedEdges); - - - //! mark the edges which dominate node v - void markDown(const Graph &G, node v, EdgeArray &markedEdges); - - //! compute the feasible edges of the face f with respect to e - void feasibleEdges(UpwardPlanRep &UPR, - face f, // current face - adjEntry adj, // current adjEntry, right face muss be f - EdgeArray &locked, // we compute the dyn. locked edges on the fly with respect to e - List feasible // the list of feasible edges in f with respect to e - ); - - //! return true if current insertion path is contraint feasible - bool isConstraintFeasible(UpwardPlanRep &UPR, - const List &orig_edges, - edge e_orig, - adjEntry adj, // the last adjEntry of the insertion path - EdgeArray &predAdj //Array to reconstruction the insertion path - ); - - - //! return true if current insertion path is contraint feasible - bool isConstraintFeasible(UpwardPlanRep &UPR, - List &origEdges, - edge e_orig, - SList &path); - -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/upward/LayerBasedUPRLayout.h b/ext/OGDF/ogdf/upward/LayerBasedUPRLayout.h deleted file mode 100644 index f500a5538..000000000 --- a/ext/OGDF/ogdf/upward/LayerBasedUPRLayout.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of upward planarization layout algorithm. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_LAYER_BASED_UPR_LAYOUT_H -#define OGDF_LAYER_BASED_UPR_LAYOUT_H - - - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - -class OrderComparer -{ -public: - OrderComparer(const UpwardPlanRep &_UPR, Hierarchy &_H); - - // if vH1 and vH2 are placed on the same layer and node vH1 has to drawn on the lefthand side of vH2 (according to UPR) then return true; - bool less(node vH1, node vH2) const ; - -private: - const UpwardPlanRep &UPR; - Hierarchy &H; - NodeArray dfsNum; - //EdgeArray outEdgeOrder; - mutable NodeArray crossed; - - //traverse with dfs using edge order from left to right and compute the dfs number. - void dfs_LR( edge e, - NodeArray &visited, - NodeArray &dfsNum, - int &num); - - //return true if vUPR1 is on the lefthand side of vUPR2 according to UPR. - bool left(node vUPR1, - List chain1, //if vUPR1 is associated with a long edge dummy vH1, then chain1 contain vH1 - node vUPR2 , - List chain2 // if vUPR2 is associated with a long edge dummy vH2, then chain2 contain vH2 - ) const; - - //return true if vUPR1 is on the lefthand side of vUPR2 according to UPR. - // pred.: source or target of both edge muss identical - bool left(edge e1UPR, edge e2UPR) const; - - //return true if vUPR1 is on the lefthand side of vUPR2 according to UPR. - // use only by method less for the case when both node vH1 and vH2 are long-edge dummies. - // level: the current level of the long-edge dummies - bool left(List &chain1, List &chain2, int level) const; - - //return true if there is a node above vUPR with rank level or lower - bool checkUp(node vUPR, int level) const; -}; - - -class OGDF_EXPORT LayerBasedUPRLayout : public UPRLayoutModule -{ -public: - - // constructor: sets options to default values - LayerBasedUPRLayout() - { - // set default value - FastHierarchyLayout *fhl = new FastHierarchyLayout(); - fhl->nodeDistance(40.0); - fhl->layerDistance(40.0); - fhl->fixedLayerDistance(true); - m_layout.set(fhl); - OptimalRanking *opRank = new OptimalRanking(); - opRank->separateMultiEdges(false); - m_ranking.set(opRank); - m_numLevels = 0; - m_maxLevelSize = 0; - } - - // destructor - ~LayerBasedUPRLayout() { } - - // returns the number of crossings in the layout after the algorithm - // has been applied - int numberOfCrossings() const { return m_crossings; } - - // module option for the computation of the final layout - void setLayout(HierarchyLayoutModule *pLayout) { - m_layout.set(pLayout); - } - - - void setRanking(RankingModule *pRanking) { - m_ranking.set(pRanking); - } - - //! Use only the 3. phase of Sugiyama' framework for layout. - void UPRLayoutSimple(const UpwardPlanRep &UPR, GraphAttributes &AG); - - //! Return the number of layers/levels. Not implemented if use methode callSimple(..). - int numberOfLayers() { return m_numLevels; } - - //! Return the max. number of elements on a layer. Not implemented if use methode callSimple(..). - int maxLayerSize() { return m_maxLevelSize; } - -protected : - - /* - * @param UPR is the upward planarized representation of the input graph. - * @param AG has to be assigned the hierarchy layout. - */ - virtual void doCall(const UpwardPlanRep &UPR, GraphAttributes &AG); - - int m_crossings; - - ModuleOption m_ranking; - - ModuleOption m_layout; - - - struct RankComparer { - Hierarchy *H; - bool less(node v1, node v2) const { - return (H->rank(v1) < H->rank(v2)); - } - }; - - -private: - - // compute a ranking of the nodes of UPR. - // Precond. a ranking module muss be set - void computeRanking(const UpwardPlanRep &UPR, NodeArray &rank); - - - //! rearanging the position of the sources in order to reduce some crossings. - void postProcessing_sourceReorder(Hierarchy &H, List &sources); - - - //! reduce the long edge dummies (LED) - void postProcessing_reduceLED(Hierarchy &H, List &sources) { - forall_listiterators(node, it, sources) - postProcessing_reduceLED(H, *it); - } - - void postProcessing_reduceLED(Hierarchy &H, node vH); - - void post_processing_reduce(Hierarchy &H, int &i, node s, int minIdx, int maxIdx, NodeArray &markedNodes); - - //! mark all the nodes dominated by sH. (Help method for postProcessing_reduceLED() ) - void postProcessing_markUp(Hierarchy &H, node sH, NodeArray &markedNodes); - - - //! delete level i of H. - void post_processing_deleteLvl(Hierarchy &H, int i); - - //! delete the interval [beginIdx,endIdx] on the level j. - void post_processing_deleteInterval(Hierarchy &H, int beginIdx, int endIdx, int &j); - - //! insert the interval [beginIdx,endIdx] of level i-1 to level i at position pos. - void post_processing_CopyInterval(Hierarchy &H, int i, int beginIdx, int endIdx, int pos); - - int m_numLevels; - int m_maxLevelSize; - - - - //------------------------ UPRLayoutSimple methods -------------------------------------------- - void callSimple(GraphAttributes &AG, adjEntry adj //left most edge of the source - ); - - // needed for UPRLayoutSimple - void dfsSortLevels( - adjEntry adj1, - const NodeArray &rank, - Array > &nodes); - - // needed for UPRLayoutSimple - void longestPathRanking(const Graph &G, NodeArray &rank); - - -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/upward/SubgraphUpwardPlanarizer.h b/ext/OGDF/ogdf/upward/SubgraphUpwardPlanarizer.h deleted file mode 100644 index 12b2f2a8f..000000000 --- a/ext/OGDF/ogdf/upward/SubgraphUpwardPlanarizer.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - - /** \file - * \brief Declaration of class SubgraphPlanarizer. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_SUBGRAPH_UPWARD_PLANARIZER_H -#define OGDF_SUBGRAPH_UPWARD_PLANARIZER_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf -{ - - -class OGDF_EXPORT SubgraphUpwardPlanarizer : public UpwardPlanarizerModule -{ - -public: - //! Creates an instance of subgraph planarizer. - SubgraphUpwardPlanarizer() - { - m_runs = 1; - //set default module - m_subgraph.set(new FUPSSimple()); - m_inserter.set(new FixedEmbeddingUpwardEdgeInserter()); - m_acyclicMod.set(new GreedyCycleRemoval()); - } - - //! Sets the module option for the computation of the feasible upward planar subgraph. - void setSubgraph(FUPSModule *FUPS) { - m_subgraph.set(FUPS); - } - - //! Sets the module option for the edge insertion module. - void setInserter(UpwardEdgeInserterModule *pInserter) { - m_inserter.set(pInserter); - } - - //! Sets the module option for acyclic subgraph module. - void setAcyclicSubgraphModule(AcyclicSubgraphModule *acyclicMod) { - m_acyclicMod.set(acyclicMod); - } - - int runs() {return m_runs;} - void runs(int n) {m_runs = n;} - -protected: - - virtual ReturnType doCall(UpwardPlanRep &UPR, - const EdgeArray &cost, - const EdgeArray &forbid); - - ModuleOption m_subgraph; //!< The upward planar subgraph algorithm. - ModuleOption m_inserter; //!< The edge insertion module. - ModuleOption m_acyclicMod; //! &biComps); - - //! traversion the BTree and merge the component to a common graph - void dfsMerge(const GraphCopy &GC, - BCTree &BC, - NodeArray &biComps, - NodeArray &uprs, - UpwardPlanRep &UPR_res, - node parent_BC, - node current_BC, - NodeArray &nodesDone); - - - //! add UPR to UPR_res. - void merge(const GraphCopy &GC, - UpwardPlanRep &UPR_res, - const GraphCopy &block, - UpwardPlanRep &UPR - ); -}; - -} - -#endif diff --git a/ext/OGDF/ogdf/upward/UpwardPlanRep.h b/ext/OGDF/ogdf/upward/UpwardPlanRep.h deleted file mode 100644 index 368d183fb..000000000 --- a/ext/OGDF/ogdf/upward/UpwardPlanRep.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a base class for planar representations - * of graphs and cluster graphs. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UPWARDPLANREP_H -#define OGDF_UPWARDPLANREP_H - - -#include - -#include - -//class SubgraphUpwardPlanarizer; - - - -namespace ogdf { - - -/** - * \brief Upward planarized representations (of a connected component) of a graph. - * The upward planarization representation is a single source single sink graph. - * The single source is s_hat and the single sink is t_hat. - * s_hat is connected with the sources of the original graph. This muss be done before - * creating of a instance of UpwardPlanRep. The super sink t_hat is contructed in this class. - * For technical reason we contruct a sink t and connect the sink of the original graph - * with t. Then we connect t with t_hat. The edge (t,t_hat) is called the external face handle. - * Because the right face of the adjEntry of this edge should be the external face. - */ -class OGDF_EXPORT UpwardPlanRep : public GraphCopy -{ -public: - - friend class SubgraphUpwardPlanarizer; - - //debug only - //friend class FixedEmbeddingUpwardEdgeInserter; - - /* @{ - * \brief Creates a planarized representation with respect to \a Gamma. - * Gamma muss be an upward planar embedding with a fixed ext. face - * Precondition: the graph is a single source graph - */ - - UpwardPlanRep(const CombinatorialEmbedding &Gamma); //upward planar embedding with a fixed ext. face - - UpwardPlanRep(const GraphCopy &GC, // muss be upward embedded and single source - adjEntry adj_ext); // the right face of this adjEntry is the external face - - //! copy constructor - UpwardPlanRep(const UpwardPlanRep &UPR); - - //! standart constructor - UpwardPlanRep(): GraphCopy(), isAugmented(false), t_hat(0), s_hat(0), extFaceHandle(0), crossings(0) // multisources(false) - { - m_Gamma.init(*this); - m_isSinkArc.init(*this, false); - m_isSourceArc.init(*this, false); - } - - virtual ~UpwardPlanRep() {} - - //! same as insertEdgePath, but assumes that the graph is embedded - void insertEdgePathEmbedded( - edge eOrig, - SList crossedEdges, - EdgeArray &cost); - - //! convert to a single source single sink graph (result is not necessary a st-graph!). - // pred. the graph muss be a sinlge source graph - // We construct node t and connect the sink-switches with t. The new arcs are sSinkArc. - // For simplicity we construct an additional edge (t,t_hat) (the extFaceArc), where t_hat is the super sink. - void augment(); - - //! return true if graph is augmented to a single source single sink graph - bool augmented() const { return isAugmented; } - - //! return the upward planar embedding - const CombinatorialEmbedding & getEmbedding() const {return m_Gamma;} - - CombinatorialEmbedding & getEmbedding() {return m_Gamma;} - - node getSuperSink() const {return t_hat;} - - node getSuperSource() const {return s_hat;} - - int numberOfCrossings() const {return crossings;} - - //! Assignment operator. - UpwardPlanRep &operator=(const UpwardPlanRep ©); - - bool isSinkArc(edge e) const {return m_isSinkArc[e];} - - bool isSourceArc(edge e) const {return m_isSourceArc[e];} - - //! 0 if node v is not a sink switch (not the top sink switch !!) of an internal face. - //! else v is sink-switch of the right face of the adjEntry. - adjEntry sinkSwitchOf(node v) {return m_sinkSwitchOf[v];} - - // return the adjEntry of v which right face is f. - adjEntry getAdjEntry(const CombinatorialEmbedding &Gamma, node v, face f) const { - adjEntry adj; - forall_adj(adj, v) { - if (Gamma.rightFace(adj) == f) - break; - } - - OGDF_ASSERT(Gamma.rightFace(adj) == f); - - return adj; - } - - //return the left in edge of node v. - adjEntry leftInEdge(node v) const - { - if (v->indeg() == 0) - return 0; - adjEntry adj; - forall_adj(adj, v) { - if (adj->theEdge()->target() == v && adj->cyclicSucc()->theEdge()->source() == v) - break; - } - return adj; - } - - //*************************** debug ******************************** - void outputFaces (const CombinatorialEmbedding &embedding) const { - cout << endl << "Face UPR " << endl; - face f; - forall_faces(f, embedding) { - cout << "face " << f->index() << ": "; - adjEntry adjNext = f->firstAdj(); - do { - cout << adjNext->theEdge() << "; "; - adjNext = adjNext->faceCycleSucc(); - } while(adjNext != f->firstAdj()); - cout << endl; - } - if (embedding.externalFace() != 0) - cout << "ext. face of the graph is: " << embedding.externalFace()->index() << endl; - else - cout << "no ext. face set." << endl; - } - - - -protected: - - bool isAugmented; //!< the UpwardPlanRep is augmented to a single source and single sink graph - - CombinatorialEmbedding m_Gamma; //! < embedding og this UpwardPlanRep - - node t_hat; //!< the super sink - - node s_hat; //!< the super source - - // sinkArk are edges which are added to transform the original graph to single sink graph. - // note: the extFaceHandle is a sink arc. - EdgeArray m_isSinkArc; - - // source arc are edges which are added to transform the original graph to a single source graph - EdgeArray m_isSourceArc; - - // 0 if node v is not a non-top-sink-switch of a internal face. - // else v is (non-top) sink-switch of f (= right face of adjEntry). - NodeArray m_sinkSwitchOf; - - adjEntry extFaceHandle; // the right face of this adjEntry is always the ext. face - - int crossings; - - -private: - void computeSinkSwitches(); - - //! only for planarizer !!! - void initMe(); - - void copyMe(const UpwardPlanRep &UPR); - - void removeSinkArcs(SList &crossedEdges); - - void constructSinkArcs(face f, node t); - -};//UpwardPlanRep - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/upward/UpwardPlanarModule.h b/ext/OGDF/ogdf/upward/UpwardPlanarModule.h deleted file mode 100644 index efb1397d7..000000000 --- a/ext/OGDF/ogdf/upward/UpwardPlanarModule.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class UpwardPlanarModule, which implements - * the upward-planarity testing and embedding algorithm for - * single-source digraphs by Bertolazzi et al. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UPWARD_PLANAR_MODULE_H -#define OGDF_UPWARD_PLANAR_MODULE_H - - -#include -#include -#include - - -namespace ogdf { - - class OGDF_EXPORT SPQRTree; - class OGDF_EXPORT Skeleton; - class OGDF_EXPORT StaticPlanarSPQRTree; - class OGDF_EXPORT ExpansionGraph; - class OGDF_EXPORT FaceSinkGraph; - -//--------------------------------------------------------- -// UpwardPlanarModule -//--------------------------------------------------------- -class OGDF_EXPORT UpwardPlanarModule -{ -public: - // constructor - UpwardPlanarModule() { } - - - //------------------------------ - // general single-source graphs - - // tests if single-source digraph G is upward planar - bool upwardPlanarityTest(Graph &G) { - NodeArray > adjacentEdges; - return doUpwardPlanarityTest(G,false,adjacentEdges); - } - - // tests if single-source digraph G is upward planar and, if true, - // constructs an upward-planar embeding of G - bool upwardPlanarEmbed(Graph &G) - { - NodeArray > adjacentEdges(G); - if(doUpwardPlanarityTest(G,true,adjacentEdges) == false) - return false; - SList augmentedNodes; - SList augmentedEdges; - doUpwardPlanarityEmbed(G,adjacentEdges,false,augmentedNodes,augmentedEdges); - return true; - } - - // tests if single-source digraph G is upward planar and, if true, - // augments G to a planar st-digraph - bool upwardPlanarAugment(Graph &G, - SList &augmentedNodes, - SList &augmentedEdges) - { - NodeArray > adjacentEdges(G); - if(doUpwardPlanarityTest(G,true,adjacentEdges) == false) - return false; - doUpwardPlanarityEmbed(G,adjacentEdges,true,augmentedNodes,augmentedEdges); - return true; - } - - // tests if single-source digraph G is upward planar and, if true, - // augments G to a planar st-digraph - bool upwardPlanarAugment(Graph &G, - node &superSink, - SList &augmentedEdges) - { - NodeArray > adjacentEdges(G); - if(doUpwardPlanarityTest(G,true,adjacentEdges) == false) - return false; - doUpwardPlanarityEmbed(G,adjacentEdges,true,superSink,augmentedEdges); - return true; - } - - // tests if single-source digraph G is upward planar and, if true, - // augments G to a planar st-digraph - bool upwardPlanarAugment(Graph &G) - { - node superSink; - SList augmentedEdges; - return upwardPlanarAugment(G,superSink,augmentedEdges); - } - - - // -------------------------------- - // embedded single-source digraphs - - // tests if embedded single-source digraph G can be drawn upward-planar - // realizing the given embedding and returns in externalFaces the set - // of faces which can be choosen as external face - bool testEmbeddedBiconnected( - const Graph &G, // embedded input graph - const ConstCombinatorialEmbedding &E, // embedding - SList &externalFaces); // possible external faces - - // tests if embedded single-source digraph G can be drawn upward-planar - // realizing the given embedding and augments G to a planar st-digraph - bool testAndAugmentEmbedded( - Graph &G, // embedded input graph - SList &augmentedNodes, // augmented nodes - SList &augmentedEdges);// augmented edges - - bool testAndAugmentEmbedded( - Graph &G, // embedded input graph - node &superSink, // super sink - SList &augmentedEdges);// augmented edges - - -private: - - struct DegreeInfo { - int m_indegSrc; - int m_outdegSrc; - int m_indegTgt; - int m_outdegTgt; - }; - - // classes defined and used in UpwardPlanarModule.cpp - class OGDF_EXPORT SkeletonInfo; - class ConstraintRooting; - - - // returns the single-source if present, 0 otherwise - node getSingleSource(const Graph &G); - - //----------------------------------------------------------- - // the following functions perform actual testing, embedding, - // and augmenting - - // test and compute adjacency lists of embedding - bool doUpwardPlanarityTest( - Graph &G, - bool embed, - NodeArray > &adjacentEdges); - - // embed and compute st-augmentation (original implementation - inserts - // also new nodes corresponding to faces into G) - void doUpwardPlanarityEmbed( - Graph &G, - NodeArray > &adjacentEdges, - bool augment, - SList &augmentedNodes, - SList &augmentedEdges); - - // embed and compute st-augmentation (new implementation - inserts only - // one new node into G which is the super sink) - void doUpwardPlanarityEmbed( - Graph &G, - NodeArray > &adjacentEdges, - bool augment, - node &superSink, - SList &augmentedEdges); - - // performs the actual test (and computation of sorted adjacency lists) for - // each biconnected component - bool testBiconnectedComponent( - ExpansionGraph &exp, - node sG, - int parentBlock, - bool embed, - NodeArray > &adjacentEdges); - - - //------------------------------- - // computatation of st-skeletons - - // compute sT-skeletons - // test for upward-planarity, build constraints for rooting, and find a - // rooting of the tree satisfying all constraints - // returns true iff such a rooting exists - edge directSkeletons( - SPQRTree &T, - NodeArray &skInfo); - - // precompute information: in-/outdegrees in pertinent graph, contains - // pertinent graph the source? - void computeDegreesInPertinent( - const SPQRTree &T, - node s, - NodeArray &skInfo, - node vT); - - - //------------------------ - // embedding of skeletons - - bool initFaceSinkGraph(const Graph &M, SkeletonInfo &skInfo); - - void embedSkeleton( - Graph &G, - StaticPlanarSPQRTree &T, - NodeArray &skInfo, - node vT, - bool extFaceIsLeft); - - - //-------------------------- - // assigning sinks to faces - - void assignSinks( - FaceSinkGraph &F, - face extFace, - NodeArray &assignedFace); - - node dfsAssignSinks( - FaceSinkGraph &F, - node v, // current node - node parent, // its parent - NodeArray &assignedFace); - - - //------------------------------ - // for testing / debugging only - - bool checkDegrees( - SPQRTree &T, - node s, - NodeArray &skInfo); - - bool virtualEdgesDirectedEqually(const SPQRTree &T); - - - -}; // class UpwardPlanarModule - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/ogdf/upward/UpwardPlanarSubgraphSimple.h b/ext/OGDF/ogdf/upward/UpwardPlanarSubgraphSimple.h deleted file mode 100644 index db87e417d..000000000 --- a/ext/OGDF/ogdf/upward/UpwardPlanarSubgraphSimple.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class UpwardPlanarSubgraphSimple which - * computes an upward planar subgfraph by using UpwardPlanarModule. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_UPWARD_PLANAR_SUBGRAPH_SIMPLE_H -#define OGDF_UPWARD_PLANAR_SUBGRAPH_SIMPLE_H - - - - -#include -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// UpwardPlanarSubgraphSimple -// implements a maximal planar subgraph algorithm using -// planarity testing -//--------------------------------------------------------- -class OGDF_EXPORT UpwardPlanarSubgraphSimple : public UpwardPlanarSubgraphModule -{ -public: - // construction - UpwardPlanarSubgraphSimple() { } - // destruction - ~UpwardPlanarSubgraphSimple() { } - - // computes set of edges delEdges, which have to be deleted - // in order to get a planar subgraph; edges in preferedEdges - // should be contained in planar subgraph - void call(const Graph &G, List &delEdges); - - void call(GraphCopy &GC, List &delEdges); - - -private: - bool checkAcyclic( - GraphCopySimple &graphAcyclicTest, - SList > &tmpAugmented); - - void dfsBuildSpanningTree( - node v, - SListPure &treeEdges, - NodeArray &visited); - -}; - - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/ogdf/upward/UpwardPlanarizationLayout.h b/ext/OGDF/ogdf/upward/UpwardPlanarizationLayout.h deleted file mode 100644 index 206db76d6..000000000 --- a/ext/OGDF/ogdf/upward/UpwardPlanarizationLayout.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of upward planarization layout algorithm. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_UPWARD_PLANARIZATION_LAYOUT_H -#define OGDF_UPWARD_PLANARIZATION_LAYOUT_H - - - -#include -#include -#include -#include -#include -#include -#include -#include - - - -namespace ogdf { - - - -class OGDF_EXPORT UpwardPlanarizationLayout : public LayoutModule -{ -public: - - // constructor: sets options to default values - UpwardPlanarizationLayout() - { - m_cr_nr = 0; - // set default module - m_layout.set(new LayerBasedUPRLayout()); - m_UpwardPlanarizer.set(new SubgraphUpwardPlanarizer()); - } - - // destructor - ~UpwardPlanarizationLayout() { } - - - // calls the algorithm for attributed graph AG - // returns layout information in AG - void call(GraphAttributes &AG) - { - UpwardPlanRep UPR; - UPR.createEmpty(AG.constGraph()); - m_UpwardPlanarizer.get().call(UPR); - m_layout.get().call(UPR, AG); - m_cr_nr = UPR.numberOfCrossings(); - m_numLevels = m_layout.get().numberOfLevels; - } - - - // module option for the computation of the final layout - void setUPRLayout(UPRLayoutModule *pLayout) { - m_layout.set(pLayout); - } - - - void setUpwardPlanarizer(UpwardPlanarizerModule *pUpwardPlanarizer) { - m_UpwardPlanarizer.set(pUpwardPlanarizer); - } - - // returns the number of crossings in the layout after the algorithm - // has been applied - int numberOfCrossings() const { return m_cr_nr; } - - int numberOfLevels() const { return m_numLevels; } - -protected: - - int m_cr_nr; - - int m_numLevels; - - ModuleOption m_UpwardPlanarizer; - - ModuleOption m_layout; -}; - - -} - -#endif diff --git a/ext/OGDF/ogdf/upward/VisibilityLayout.h b/ext/OGDF/ogdf/upward/VisibilityLayout.h deleted file mode 100644 index bf55b99d8..000000000 --- a/ext/OGDF/ogdf/upward/VisibilityLayout.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * $Revision: 2524 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-03 09:54:22 +0200 (Tue, 03 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of visibility layout algorithm. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//*** -// Visibility Layout Method. see "Graph Drawing" by Di Battista et al. -//*** - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_VISIBILITY_LAYOUT_H -#define OGDF_VISIBILITY_LAYOUT_H - -#include -#include -#include -#include -#include -#include -#include - -namespace ogdf { - - -class OGDF_EXPORT VisibilityLayout : public LayoutModule -{ -public: - - VisibilityLayout() { - m_grid_dist = 1; - // set default module - m_upPlanarizer.set(new SubgraphUpwardPlanarizer()); - } - - virtual void call(GraphAttributes &GA); - - void layout(GraphAttributes &GA, const UpwardPlanRep &UPROrig); - - void setUpwardPlanarizer(UpwardPlanarizerModule *upPlanarizer) { - m_upPlanarizer.set(upPlanarizer); - } - - void setMinGridDistance(int dist) {m_grid_dist = dist;} - - - -private: - - //min grid distance - int m_grid_dist; - - Graph D; // the dual graph of the UPR - node s_D; // super source of D - node t_D; // super sink f D - - //node segment of the visibility representation - struct NodeSegment { - int y; //y coordinate - int x_l; // left x coordinate - int x_r; // right x coordiante - }; - - // edge segment of the visibility representation - struct EdgeSegment { - int y_b; // bottom y coordinate - int y_t; // top y coordinate - int x; // x coordiante - }; - - //mapping node to node segment of visibility presentation - NodeArray nodeToVis; - - //mapping edge to edge segment of visibility presentation - EdgeArray edgeToVis; - - FaceArray faceToNode; - NodeArray leftFace_node; - NodeArray rightFace_node; - EdgeArray leftFace_edge; - EdgeArray rightFace_edge; - - ModuleOption m_upPlanarizer; // upward planarizer - - void constructDualGraph(UpwardPlanRep &UPR); - - void constructVisibilityRepresentation(UpwardPlanRep &UPR); - - -}; - - -}//namespace - -#endif diff --git a/ext/OGDF/src/augmentation/DfsMakeBiconnected.cpp b/ext/OGDF/src/augmentation/DfsMakeBiconnected.cpp deleted file mode 100644 index 375f804d7..000000000 --- a/ext/OGDF/src/augmentation/DfsMakeBiconnected.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements a simple, dfs-based algorithm for - * biconnectivity augmentation. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - -void DfsMakeBiconnected::doCall(Graph &G, List &L) -{ - makeBiconnected(G,L); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/augmentation/PlanarAugmentation.cpp b/ext/OGDF/src/augmentation/PlanarAugmentation.cpp deleted file mode 100644 index 011bdcb05..000000000 --- a/ext/OGDF/src/augmentation/PlanarAugmentation.cpp +++ /dev/null @@ -1,1446 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief planar biconnected augmentation approximation algorithm - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -#include -#include -#include - - -// for debug-outputs -//#define PLANAR_AUGMENTATION_DEBUG - -// for checking planarity directly after inserting a new edge -// and additional planarity tests after each augmentation round -//#define PLANAR_AUGMENTATION_DEBUG_PLANARCHECK - - -namespace ogdf { - - -/******************************************************** - * - * implementation of class PALabel - * - *******************************************************/ - -void PALabel::removePendant(node pendant) -{ - if (m_pendants.size() > 0){ - ListIterator it = m_pendants.begin(); - for (; it.valid(); ++it) - if ((*it) == pendant){ - m_pendants.del(it); - break; - } - } -} - - -/******************************************************** - * - * implementation of class PlanarAugmentation - * - *******************************************************/ - - -// ---------------------------------------------------- -// doCall -// -// ---------------------------------------------------- -void PlanarAugmentation::doCall(Graph& g, List& L) -{ - m_nPlanarityTests = 0; - - L.clear(); - m_pResult = &L; - - m_pGraph = &g; - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "Graph G has no self loops = " << isLoopFree(*m_pGraph) << endl; - cout << "Graph G is planar = " << isPlanar(*m_pGraph)<< endl; - cout << "Graph G is connected = " << isConnected(*m_pGraph) << endl; - cout << "Graph G is biconnected = " << isBiconnected(*m_pGraph) << endl; - #endif - - // create the bc-tree - if (m_pGraph->numberOfNodes() > 1){ - - if (!isConnected(*m_pGraph)){ - if(m_pGraph->numberOfEdges() == 0){ - // one edge is required - m_pResult->pushBack(m_pGraph->newEdge(m_pGraph->firstNode(), m_pGraph->firstNode()->succ())); - } - - makeConnectedByPendants(); - } - - m_pBCTree = new DynamicBCTree(*m_pGraph); - - // init the m_adjNonChildren-NodeArray with all adjEntries of the bc-tree - m_adjNonChildren.init(m_pBCTree->m_B); - - node v; - adjEntry adj; - forall_nodes(v, m_pBCTree->bcTree()){ - if (v->firstAdj() != 0){ - m_adjNonChildren[v].pushFront(v->firstAdj()); - adj = v->firstAdj()->cyclicSucc(); - while (adj != v->firstAdj()){ - m_adjNonChildren[v].pushBack(adj); - adj = adj->cyclicSucc(); - } - } - } - m_isLabel.init(m_pBCTree->bcTree(), 0); - m_belongsTo.init(m_pBCTree->bcTree(), 0); - - // call main function - augment(); - } -} - - - -// ---------------------------------------------------- -// makeConnectedByPendants() -// -// makes graph connected by inserting edges between -// nodes of pendants of the connected components -// -// ---------------------------------------------------- -void PlanarAugmentation::makeConnectedByPendants() -{ - DynamicBCTree bcTreeTemp(*m_pGraph, true); - - NodeArray components; - components.init(*m_pGraph, 0); - - int compCnt = connectedComponents(*m_pGraph, components); - - List getConnected; - - Array compConnected(compCnt); - for (int i=0; idegree() == 0){ - // found a seperated node that will be connected - getConnected.pushBack(v); - compConnected[components[v]] = true; - } - } - - forall_nodes(v, *m_pGraph){ - if ((compConnected[components[v]] == false) && (bcTreeTemp.bcproper(v)->degree() <= 1)){ - // found a node that will be connected - getConnected.pushBack(v); - compConnected[components[v]] = true; - } - } - - ListIterator it = getConnected.begin(); - ListIterator itBefore = getConnected.begin(); - while (it.valid()){ - if (it != itBefore){ - // insert edge between it and itBefore - m_pResult->pushBack(m_pGraph->newEdge(*it, *itBefore)); - itBefore++; - } - it++; - } -} - - - -// ---------------------------------------------------- -// augment() -// -// the main augmentation function -// -// ---------------------------------------------------- -void PlanarAugmentation::augment() -{ - node v, rootPendant = 0; - - // first initialize the list of pendants - forall_nodes(v, m_pBCTree->bcTree()){ - if (v->degree() == 1){ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "augment(): found pendant with index " << v->index(); - #endif - if (m_pBCTree->parent(v) == 0){ - rootPendant = v; - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << " is root! (also inserted into pendants-list!)" << endl << flush; - #endif - } - else{ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << endl << flush; - #endif - } - m_pendants.pushBack(v); - } - } - - if (rootPendant != 0){ - // the root of the bc-tree is also a pendant - // this has to be changed - - node bAdjNode = rootPendant->firstAdj()->twinNode(); - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "augment(): changing root in bc-tree because root is a pendant!" << endl << flush; - cout << "augment(): index of old root = " << rootPendant->index() << ", new root = " << bAdjNode->index() << endl << flush; - #endif - - // modify the bc-tree-structure - modifyBCRoot(rootPendant, bAdjNode); - } - - // call reduceChain for all pendants - if (m_pendants.size() > 1){ - ListIterator it = m_pendants.begin(); - for (; it.valid(); ++it){ - reduceChain((*it)); - } - } - - // it can appear that reduceChain() inserts some edges - // in case of non-planarity (paPlanarity) - // so there are new pendants and obsolete pendants - // the obsolete pendants are collected in m_pendantsToDel - if (m_pendantsToDel.size() > 0){ - ListIterator delIt = m_pendantsToDel.begin(); - for (; delIt.valid(); delIt = m_pendantsToDel.begin()){ - deletePendant(*delIt); - m_pendantsToDel.del(delIt); - } - } - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "augment(): after reduceChain() for every pendant:" << endl; - cout << " #labels = " << m_labels.size() << endl; - cout << " #pendants = " << m_pendants.size() << endl << endl; - cout << "STARTING MAIN LOOP:" << endl; - cout << endl << flush; - #endif - - // main loop - while(!m_labels.empty()){ - // foundMatching indicates if there are 2 labels that can be connected - bool foundMatching; - // labels first and second are going to be computed by findMatching - // and foundMatching=true or foundMatching=false - // first is always != 0 after findMatching(...) - pa_label first, second = 0; - - foundMatching = findMatching(first, second); - - // no matching labels were found - if (!foundMatching){ - - // we have only one label - if (m_labels.size() == 1){ - - if (m_pendants.size() > 1) - //m_labels.size() == 1 && m_pendants.size() > 1 - // join the pendants of this label - joinPendants(first); - else{ - //m_labels.size() == 1 && m_pendants.size() == 1 - connectInsideLabel(first); - } - } - else{ - // m_labels.size() > 1 - - if (first->size() == 1){ - // m_labels.size() > 1 && first->size() == 1 - // connect the - connectInsideLabel(first); - } - else{ - // m_labels.size() > 1 && first->size() > 1 - // so connect all pendants of label first - joinPendants(first); - } - } - } - else{ - - // foundMatching == true - connectLabels(first, second); - } - - // output after each round: - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << endl << "augment(): output after one round:" << endl; - cout << " #labels = " << m_labels.size() << endl; - cout << " #pendants = " << m_pendants.size() << endl; - #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK - cout << "graph is planar == " << isPlanar(*m_pGraph) << endl; - cout << "graph is biconnected == " << isBiconnected(*m_pGraph) << endl; - #endif - cout << endl << flush; - - ListIterator labelIt = m_labels.begin(); - int pos = 1; - for (; labelIt.valid(); labelIt++){ - cout << "pos " << pos << ": "; - if ((m_isLabel[(*labelIt)->parent()]).valid()) - cout << " OK, parent-index = " << (*labelIt)->parent()->index() - << ", size = " << (*labelIt)->size() << endl << flush; - else - cout << " ERROR, parent-index = " << (*labelIt)->parent()->index() - << ", size = " << (*labelIt)->size()<< endl << flush; - - pos++; - } - cout << endl << flush; - #endif - // : output after each round - - }//main loop - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << endl << "FINISHED MAIN LOOP" << endl << endl; - cout << "# planarity tests = " << m_nPlanarityTests << endl; - #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARITY - cout << "resulting Graph is biconnected = " << isBiconnected(*m_pGraph) << endl; - cout << "resulting Graph is planar = " << isPlanar(*m_pGraph) << endl; - #endif - cout << endl << flush; - #endif - - terminate(); -} - - - -// ---------------------------------------------------- -// reduceChain(node p, label labelOld) -// -// finds the "parent" (->label) for a pendant p of the BC-Tree -// and creates a new label or inserts the pendant to another -// label -// reduceChain can also insert edges in case of paPlanarity -// -// ---------------------------------------------------- -void PlanarAugmentation::reduceChain(node p, pa_label labelOld) -{ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "reduceChain(" << p->index() << ")"; - #endif - - // parent = parent of p in the BC-Tree - // if p is the root, then parent == 0 - node parent = m_pBCTree->DynamicBCTree::parent(p); - - // last is going to be the last cutvertex in the computation of followPath() - node last; - paStopCause stopCause; - - // traverse from parent to the root of the bc-tree and check several - // conditions. last is going to be the last cutvertex on this path - stopCause = followPath(parent, last); - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << ", stopCause == "; - switch(stopCause){ - case paPlanarity: - cout << "paPlanarity" << endl << flush; - break; - case paCDegree: - cout << "paCDegree" << endl << flush; - break; - case paBDegree: - cout << "paBDegree" << endl << flush; - break; - case paRoot: - cout << "paRoot" << endl << flush; - break; - } - #endif - - - if (stopCause == paPlanarity){ - node adjToCutP = adjToCutvertex(p); - node adjToCutLast = adjToCutvertex(m_pBCTree->DynamicBCTree::parent(last), last); - - // computes path in bc-tree between bcproper(adjToCutP) and bcproper(adjToCutLast) - SList& path = m_pBCTree->findPath(adjToCutP, adjToCutLast); - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "reduceChain(): inserting edge between " << adjToCutP->index() - << " and " << adjToCutLast->index() << endl << flush; - #endif - - // create new edge - edge e = m_pGraph->newEdge(adjToCutP, adjToCutLast); - - // insert the edge into the result-list - m_pResult->pushBack(e); - - // update the bc-Tree with new edge - m_pBCTree->updateInsertedEdge(e); - - // find the new arised pendant - node newPendant = m_pBCTree->find(p); - - if (newPendant != p){ - // delete the old pendant - // cannot delete the pendant immediatly - // because that would affect the outer loop in augment() - m_pendantsToDel.pushBack(p); - // insert the new arised pendant - // at the front of m_pendants becuse that doesn't affect the outer loop in augment() - m_pendants.pushFront(newPendant); - } - - // updating m_adjNonChildren - updateAdjNonChildren(newPendant, path); - - // check if newPendant is the new root of the bc-tree - if (m_pBCTree->DynamicBCTree::parent(newPendant) == 0){ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "reduceChain(): new arised pendant is the new root of the bc-tree, it has degree " - << m_pBCTree->m_bNode_degree[newPendant] << endl << flush; - #endif - - node newRoot = (*(m_adjNonChildren[newPendant].begin()))->twinNode(); - - // modify bc-tree-structure - modifyBCRoot(newPendant, newRoot); - } - - delete(&path); - - // delete label if necessary - if (labelOld != 0){ - deleteLabel(labelOld); - } - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "reduceChain(): calling reduceChain() with newPendant = " << newPendant->index() << endl << flush; - #endif - - // call reduceChain with the new arised pendant - reduceChain(newPendant); - } - - pa_label l; - - if (stopCause == paCDegree || stopCause == paRoot){ - - if (labelOld != 0){ - if (labelOld->head() == last){ - // set the stop-cause - labelOld->stopCause(stopCause); - } - else - deleteLabel(labelOld); - } - - if (m_isLabel[last].valid()){ - // l is the label that last is the head of - l = *(m_isLabel[last]); - // add the actual pendant p to l - addPendant(p, l); - // set the stop-cause - l->stopCause(stopCause); - } - else{ - newLabel(last, p, stopCause); - } - } - - if (stopCause == paBDegree){ - if (labelOld != 0){ - if (labelOld->head() != last){ - deleteLabel(labelOld); - newLabel(last, p, paBDegree); - } - else{ - labelOld->stopCause(paBDegree); - } - } - else{ - newLabel(last, p, paBDegree); - } - } -} // reduceChain() - - - -// ---------------------------------------------------- -// followPath(node v, node &last) -// -// traverses the BC-Tree upwards from v -// (v is always a parent of a pendant) -// last becomes the last cutvertex before we return -// -// ---------------------------------------------------- -paStopCause PlanarAugmentation::followPath(node v, node& last) -{ - last = 0; - node bcNode = m_pBCTree->find(v); - - if (m_pBCTree->typeOfBNode(bcNode) == BCTree::CComp){ - last = bcNode; - } - - while (bcNode != 0){ - int deg = m_pBCTree->m_bNode_degree[bcNode]; - - if (deg > 2){ - if (m_pBCTree->typeOfBNode(bcNode) == BCTree::CComp){ - last = bcNode; - return paCDegree; - } - else - return paBDegree; - } - - // deg == 2 (case deg < 2 cannot occur) - if (m_pBCTree->typeOfBNode(bcNode) == BCTree::CComp){ - last = bcNode; - } - else{ - // bcNode is a BComp and degree is 2 - if (m_pBCTree->numberOfNodes(bcNode) > 4){ - // check planarity if number of nodes > 4 - // because only than a K5- or k33-Subdivision can be included - - node adjBCNode = 0; - - bool found = false; - SListIterator childIt = m_adjNonChildren[bcNode].begin(); - while (!found && childIt.valid()){ - if (m_pBCTree->find((*childIt)->twinNode()) != last){ - found = true; - adjBCNode = m_pBCTree->find((*childIt)->twinNode()); - } - childIt++; - } - - // get nodes in biconnected-components graph of m_pBCTree - node hNode = m_pBCTree->m_bNode_hRefNode[last]; - node hNode2 = m_pBCTree->m_bNode_hRefNode[adjBCNode]; - - // check planarity for corresponding graph-nodes of hNode and hNode2 - if (!planarityCheck(m_pBCTree->m_hNode_gNode[hNode], - m_pBCTree->m_hNode_gNode[hNode2])){ - return paPlanarity; - } - } - } - // iterate to parent node - bcNode = m_pBCTree->DynamicBCTree::parent(bcNode); - } - // reached the bc-tree-root - return paRoot; -} - - - -// ---------------------------------------------------- -// planarityCheck(node v1, node v2) -// -// checks planarity for the new edge (v1, v2) -// v1 and v2 are nodes in the original graph -// -// ---------------------------------------------------- -bool PlanarAugmentation::planarityCheck(node v1, node v2) -{ - // first simple tests - if (v1 == v2){ - return true; - } - - // check if edge (v1, v2) already exists - if (v1->firstAdj()->twinNode() == v2){ - return true; - } - adjEntry adjTest = v1->firstAdj()->cyclicSucc(); - while (adjTest != v1->firstAdj()){ - if (v1->firstAdj()->twinNode() == v2){ - return true; - } - adjTest = adjTest->cyclicSucc(); - } - - // test planarity for edge (v1, v2) - edge e = m_pGraph->newEdge(v1, v2); - - m_nPlanarityTests++; - - bool planar = planarEmbed(*m_pGraph); - - // finally delete the edge - m_pGraph->delEdge(e); - - return planar; -} - - - -// ---------------------------------------------------- -// adjToCutvertex(node v, node cutvertex) -// -// returns the vertex in the original graph that -// belongs to v (B-Component in the BC-Graph and pendant) -// and is adjacent to the cutvertex (also node of the BC-Graph) -// if cutvertex == 0 then the cutvertex of the parent of v -// is considered -// -// ---------------------------------------------------- -node PlanarAugmentation::adjToCutvertex(node v, node cutvertex) -{ - node nodeAdjToCutVertex; - - if (cutvertex == 0){ - - // set nodeAdjToCutVertex to the node in the original graph, - // that corresponds to the parent (c-component) of v in the bc-tree - nodeAdjToCutVertex = m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hParNode[v]]; - - // adj = adjEntry at the cutvertex - adjEntry adj = nodeAdjToCutVertex->firstAdj(); - - while (m_pBCTree->DynamicBCTree::bcproper(adj->twinNode()) != v) - adj = adj->cyclicSucc(); - - nodeAdjToCutVertex = adj->twinNode(); - - } - else{ - // set nodeAdjToCutVertex to the node in the original graph, - // corresponding to the cutvertex in the bc-tree - nodeAdjToCutVertex = m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hRefNode[cutvertex]]; - - // adj = adjEntry at the cutvertex - adjEntry adj = nodeAdjToCutVertex->firstAdj(); - - bool found = false; - - if (m_pBCTree->bComponent(nodeAdjToCutVertex, adj->twinNode()) == v){ - found = true; - nodeAdjToCutVertex = adj->twinNode(); - } - else{ - adj = adj->cyclicSucc(); - while ((!found) && (adj != nodeAdjToCutVertex->firstAdj())){ - if (m_pBCTree->bComponent(nodeAdjToCutVertex, adj->twinNode()) == v){ - nodeAdjToCutVertex = adj->twinNode(); - found = true; - } - adj = adj->cyclicSucc(); - } - } - } - return nodeAdjToCutVertex; -} - - - -// ---------------------------------------------------- -// findLastBefore(node pendant, node ancestor) -// -// returns the last vertex before ancestor -// on the path from pendant to ancestor -// -// ---------------------------------------------------- -node PlanarAugmentation::findLastBefore(node pendant, node ancestor) -{ - node bcNode = pendant; - while ((bcNode) && (m_pBCTree->DynamicBCTree::parent(bcNode) != ancestor)) - bcNode = m_pBCTree->DynamicBCTree::parent(bcNode); - - if (!bcNode){ - // should never occur - return 0; - } - - return bcNode; -} - - - -// ---------------------------------------------------- -// deletePendant(node p) -// -// deletes pendant p from the list of all pendants -// deletes p also from the label it belongs to -// -// ---------------------------------------------------- -void PlanarAugmentation::deletePendant(node p, bool removeFromLabel) -{ - ListIterator mPendantsIt = m_pendants.begin(); - - bool deleted = false; - while (!deleted && mPendantsIt.valid()){ - ListIterator itSucc = mPendantsIt.succ(); - if ((*mPendantsIt) == p){ - m_pendants.del(mPendantsIt); - deleted = true; - } - mPendantsIt = itSucc; - } - - if ((removeFromLabel) && (m_belongsTo[p] != 0)){ - (m_belongsTo[p])->removePendant(p); - m_belongsTo[p] = 0; - } -} - - - -// ---------------------------------------------------- -// removeAllPendants(label& l) -// -// deletes a label -// and - if desired - removes the pendants belonging to l -// -// ---------------------------------------------------- -void PlanarAugmentation::removeAllPendants(pa_label& l) -{ - while (l->size() > 0){ - m_belongsTo[l->getFirstPendant()] = 0; - l->removeFirstPendant(); - } -} - - - -// ---------------------------------------------------- -// addPendant(pa_label& l, node pendant) -// -// adds a pendant p to a label l -// re-inserts also l to m_labels -// -// ---------------------------------------------------- -void PlanarAugmentation::addPendant(node p, pa_label& l) -{ - m_belongsTo[p] = l; - l->addPendant(p); - - node newParent = m_pBCTree->find(l->parent()); - - m_labels.del(m_isLabel[l->parent()]); - m_isLabel[newParent] = insertLabel(l); -} - - - -// ---------------------------------------------------- -// joinPendants(pa_label& l) -// -// connects all pendants of the label -// -// ---------------------------------------------------- -void PlanarAugmentation::joinPendants(pa_label& l) -{ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "joinPendants(): l->size()==" << l->size() << endl << flush; - #endif - - node pendant1 = l->getFirstPendant(); - // delete pendant from m_pendants but not from the label it belongs to - deletePendant(pendant1, false); - - SList newEdges; - - // traverse through pendant-list and connect them - ListIterator pendantIt = (l->m_pendants).begin(); - while (pendantIt.valid()){ - - if (*pendantIt != pendant1){ - - // delete pendant from m_pendants but not from the label it belongs to - deletePendant(*pendantIt, false); - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "joinPendants(): connectPendants: " << pendant1->index() - << " and " << (*pendantIt)->index() << endl << flush; - #endif - - // connect pendants and insert edge in newEdges - newEdges.pushBack(connectPendants(pendant1, *pendantIt)); - - // iterate pendant1 - pendant1 = *pendantIt; - } - pendantIt++; - } - - // update new edges - updateNewEdges(newEdges); - - removeAllPendants(l); - - SListIterator edgeIt = newEdges.begin(); - node newBlock = (m_pBCTree->DynamicBCTree::bcproper(*edgeIt)); - if (m_pBCTree->m_bNode_degree[newBlock] == 1){ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "joinPendants(): new block " << newBlock->index() << " has degree 1 " << endl << flush; - #endif - - m_belongsTo[newBlock] = l; - addPendant(newBlock, l); - m_pendants.pushBack(newBlock); - - } - else{ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "joinPendants(): new block has degree " << m_pBCTree->m_bNode_degree[newBlock] << endl << flush; - #endif - deleteLabel(l); - } -} - - - -// ---------------------------------------------------- -// connectInsideLabel(label& l) -// -// connects the only pendant of l with -// a computed "ancestor" -// -// ---------------------------------------------------- -void PlanarAugmentation::connectInsideLabel(pa_label& l) -{ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectInsideLabel(): l->size() == " << l->size() << ", parent = " << l->parent()->index() - << ", head = " << l->head()->index() << endl << flush; - #endif - - node head = l->head(); - node pendant = l->getFirstPendant(); - - node ancestor = m_pBCTree->DynamicBCTree::parent(head); - - node v1 = adjToCutvertex(pendant); - - // check if head is the root of the BC-Tree - if (ancestor == 0){ - node wrongAncestor = findLastBefore(pendant, head); - - SListIterator adjIt = m_adjNonChildren[head].begin(); - bool found = false; - while ((!found) && (adjIt.valid())){ - - if (m_pBCTree->find((*adjIt)->twinNode()) != wrongAncestor){ - ancestor = m_pBCTree->find((*adjIt)->twinNode()); - found = true; - } - adjIt++; - } - } - - node v2 = adjToCutvertex(ancestor, head); - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectInsideLabel(): inserting edge between " << v1->index() << " and " << v2->index() << endl << flush; - #endif - - SList newEdges; - edge e = m_pGraph->newEdge(v1, v2); - newEdges.pushFront(e); - - #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK - if (!isPlanar(*m_pGraph)) - cout << "connectInsideLabel(): CRITICAL ERROR!!! inserted non-planar edge!!! (in connectInsideLabel())" << endl << flush; - #endif - - updateNewEdges(newEdges); - - node newBlock = m_pBCTree->DynamicBCTree::bcproper(e); - - // delete label l, and also the pendant - deleteLabel(l); - - if (m_pBCTree->m_bNode_degree[newBlock] == 1){ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectInsideLabel(): new block " << newBlock->index() << " has degree 1... calling reduceChain() "; - #endif - m_pendants.pushBack(newBlock); - if ((m_belongsTo[newBlock] != 0) && (m_belongsTo[newBlock]->size() == 1)){ - reduceChain(newBlock, m_belongsTo[newBlock]); - } - else{ - reduceChain(newBlock); - // it can appear that reduceChain() inserts some edges - // so there are new pendants and obsolete pendants - // the obsolete pendants are collected in m_pendantsToDel - if (m_pendantsToDel.size() > 0){ - ListIterator delIt = m_pendantsToDel.begin(); - for (; delIt.valid(); delIt = m_pendantsToDel.begin()){ - deletePendant(*delIt); - m_pendantsToDel.del(delIt); - } - } - } - } -} - - - -// ---------------------------------------------------- -// connectPendants(node pendant1, node pendant2) -// -// connects the two pendants with a new edge -// -// ---------------------------------------------------- -edge PlanarAugmentation::connectPendants(node pendant1, node pendant2) -{ - node v1 = adjToCutvertex(pendant1); - node v2 = adjToCutvertex(pendant2); - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectPendants(): inserting edge between " << v1->index() << " and " << v2->index() << endl << flush; - #endif - - edge e = m_pGraph->newEdge(v1, v2); - - #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK - if (!(isPlanar(*m_pGraph))) - cout << "connectLabels(): CRITICAL ERROR in connectPendants: inserted edge is not planar!!!" << endl << flush; - #endif - - return e; -} - - - -// ---------------------------------------------------- -// insertLabel(pa_label l) -// -// inserts a label l at the correct position in the list -// -// ---------------------------------------------------- -ListIterator PlanarAugmentation::insertLabel(pa_label l) -{ - if (m_labels.size() == 0){ - return m_labels.pushFront(l); - } - else{ - ListIterator it = m_labels.begin(); - while (it.valid() && ((*it)->size() > l->size())){ - it++; - } - if (!it.valid()) - return m_labels.pushBack(l); - else - return m_labels.insert(l, it, before); - } -} - - - -// ---------------------------------------------------- -// deleteLabel(pa_label& l, bool removePendants) -// -// deletes a label -// and - if desired - removes the pendants belonging to l -// -// ---------------------------------------------------- -void PlanarAugmentation::deleteLabel(pa_label& l, bool removePendants) -{ - ListIterator labelIt = m_isLabel[l->parent()]; - - m_labels.del(labelIt); - m_isLabel[l->parent()] = 0; - - ListIterator pendantIt = (l->m_pendants).begin(); - while (pendantIt.valid()){ - m_belongsTo[*pendantIt] = 0; - pendantIt++; - } - - if (removePendants){ - pendantIt = (l->m_pendants).begin(); - while (pendantIt.valid()){ - - ListIterator mPendantsIt = m_pendants.begin(); - - bool deleted = false; - while (!deleted && mPendantsIt.valid()){ - ListIterator itSucc = mPendantsIt.succ(); - if ((*mPendantsIt) == *pendantIt){ - m_pendants.del(mPendantsIt); - deleted = true; - } - mPendantsIt = itSucc; - } - pendantIt++; - } - } - - delete(l); - l = 0; -} - - - -// ---------------------------------------------------- -// connectLabels(pa_label first, pa_label second); -// -// connects the pendants of first with the pendants -// of second. -// first.size() >= second.size() -// -// ---------------------------------------------------- -void PlanarAugmentation::connectLabels(pa_label first, pa_label second) -{ - ListIterator pendantIt; - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectLabels(), first->size()=="<< first->size() << " , second->size()==" - << second->size() << endl << flush; - - pendantIt = (first->m_pendants).begin(); - cout << "connectLabels(): label first = "; - for (; pendantIt.valid(); pendantIt++){ - cout << (*pendantIt)->index() << ", "; - } - pendantIt = (second->m_pendants).begin(); - cout << " || " << endl << "label second = "; - for (; pendantIt.valid(); pendantIt++){ - cout << (*pendantIt)->index() << ", "; - } - cout << endl << flush; - #endif - - SList newEdges; - pendantIt = (second->m_pendants).begin(); - - // stores the pendants of label first that were connected - // because first.size() => second.size() - SList getConnected; - node v2; - int n = 0; - - while (pendantIt.valid()){ - v2 = first->getPendant(n); - getConnected.pushBack(v2); - newEdges.pushBack(connectPendants(v2, *pendantIt)); - - #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK - if (!(isPlanar(*m_pGraph))) - cout << "connectLabels(): CRITICAL ERROR: inserted edge is not planar!!!" << endl << flush; - #endif - - n++; - pendantIt++; - } - - updateNewEdges(newEdges); - deleteLabel(second); - - node newBlock = m_pBCTree->DynamicBCTree::bcproper(newEdges.front()); - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectLabels(): newBlock->index() == " << newBlock->index() << ", degree == " - << m_pBCTree->m_bNode_degree[newBlock] << endl << flush; - #endif - - SListIterator pendantIt2 = getConnected.begin(); - while (pendantIt2.valid()){ - - //first->removePendant(*pendantIt2); - deletePendant(*pendantIt2); - - pendantIt2++; - } - - if (first->size() != 0){ - m_labels.del(m_isLabel[first->parent()]); - m_isLabel[m_pBCTree->find(first->parent())] = insertLabel(first); - - pendantIt = (first->m_pendants).begin(); - for (; pendantIt.valid(); pendantIt++){ - m_belongsTo[m_pBCTree->find(*pendantIt)] = first; - } - } - else{ // first->size() == 0 - deleteLabel(first); - } - - if (m_pBCTree->m_bNode_degree[newBlock] == 1){ - - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectLabels(): m_bNode_degree[" << newBlock->index() << "] == 1... calling reduceChain()" << endl << flush; - #endif - - m_pendants.pushBack(newBlock); - - if ((m_belongsTo[newBlock] != 0) && (m_belongsTo[newBlock]->size() == 1)){ - reduceChain(newBlock, m_belongsTo[newBlock]); - } - else{ - reduceChain(newBlock); - - // it can appear that reduceChain() inserts some edges - // so there are new pendants and obsolete pendants - // the obsolete pendants are collected in m_pendantsToDel - if (m_pendantsToDel.size() > 0){ - ListIterator delIt = m_pendantsToDel.begin(); - for (; delIt.valid(); delIt = m_pendantsToDel.begin()){ - deletePendant(*delIt); - m_pendantsToDel.del(delIt); - } - } - } - } - else{ - #ifdef PLANAR_AUGMENTATION_DEBUG - cout << "connectLabels(): newBlock is no new pendant ! degree == " << m_pBCTree->m_bNode_degree[newBlock] << endl << flush; - #endif - } -} - - - -// ---------------------------------------------------- -// newLabel(node cutvertex, node block, paStopCause whyStop) -// -// creates a new label and inserts it into m_labels -// -// ---------------------------------------------------- -pa_label PlanarAugmentation::newLabel(node cutvertex, node p, paStopCause whyStop) -{ - pa_label l = OGDF_NEW PALabel(0, cutvertex, whyStop); - l->addPendant(p); - m_belongsTo[p] = l; - m_isLabel[cutvertex] = m_labels.pushBack(l); - return l; -} - - - -// ---------------------------------------------------- -// findMatching(pa_label& first, pa_label& second) -// -// trys to find two matching labels -// first will be the label with max. size that has -// a matching label -// -// ---------------------------------------------------- -bool PlanarAugmentation::findMatching(pa_label& first, pa_label& second) -{ - first = m_labels.front(); - second = 0; - pa_label l = 0; - - ListIterator it = m_labels.begin(); - while (it.valid()){ - second = *it; - - if (second != first){ - if ( (l != 0) && (second->size() < l->size()) ){ - second = l; - return true; - } - - if (l != 0){ - - if ( connectCondition(second, first) - && planarityCheck(m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hRefNode[second->head()]], - m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hRefNode[first->head()]]) ) - { - return true; - } - } - else{ // l == 0 - - if ( planarityCheck(m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hRefNode[second->head()]], - m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hRefNode[first->head()]]) ){ - if (connectCondition(second, first)){ - return true; - } - l = second; - } - } - } - it++; - } - - if (!l) - return false; - - second = l; - return true; -} - - - -// ---------------------------------------------------- -// connectCondition(pa_label a, pa_label b) -// -// checks the connect-condition for label a and b -// -// ---------------------------------------------------- -bool PlanarAugmentation::connectCondition(pa_label a, pa_label b) -{ - bool found = false; - - if ( (a->isBLabel()) && (b->size() == 1) ){ - found = true; - } - - int deg1 = m_pBCTree->m_bNode_degree[m_pBCTree->find(a->head())] - b->size() +1; - int deg2 = m_pBCTree->m_bNode_degree[m_pBCTree->find(b->head())] - b->size() +1; - - if ((deg1 > 2) && (deg2 > 2)){ - return true; - } - if ((deg1 > 2) || (deg2 > 2)){ - if (found){ - return true; - } - else - found = true; - } - SList *path = m_pBCTree->findPathBCTree(a->head(), b->head()); - SListIterator it = path->begin(); - node bcNode; - - for (; it.valid(); it++){ - bcNode = m_pBCTree->find(*it); - - if ((bcNode != a->parent()) && (bcNode != b->parent())){ - if (m_pBCTree->m_bNode_degree[bcNode] > 2){ - if (found) { - delete path; - return true; - } else - found = true; - } - if ((m_pBCTree->typeOfBNode(bcNode) == BCTree::BComp) - && (m_pBCTree->m_bNode_degree[bcNode] > 3)) - { - delete path; - return true; - } - } - } - - delete path; - return !found; -} - - - -// ---------------------------------------------------- -// updateAdjNonChildren() -// -// update of m_adjNonChildren -// newBlock is the node all nodes on path now belong to -// -// ---------------------------------------------------- -void PlanarAugmentation::updateAdjNonChildren(node newBlock, SList& path) -{ - SListIterator pathIt = path.begin(); - - SListIterator childIt = m_adjNonChildren[newBlock].begin(); - SListIterator prevIt = m_adjNonChildren[newBlock].begin(); - // first update m_adjNonChildren[newBlock] by deleting wrong adjEntries - while (childIt.valid()){ - if (m_pBCTree->find((*childIt)->twinNode()) == newBlock){ - if (childIt == m_adjNonChildren[newBlock].begin()){ - m_adjNonChildren[newBlock].popFront(); - childIt = m_adjNonChildren[newBlock].begin(); - prevIt = m_adjNonChildren[newBlock].begin(); - } - else{ - childIt = prevIt; - m_adjNonChildren[newBlock].delSucc(prevIt); - childIt++; - } - } - else{ - prevIt = childIt; - childIt++; - } - } - - // now run through list of all path-nodes - // and update m_adjNonChildren[pathIt] if they do not belong to another bc-node - // or insert adjEntries to m_adjNonChildren[newBlock] - while (pathIt.valid()){ - - if (*pathIt != newBlock){ - if (*pathIt == m_pBCTree->find(*pathIt)){ - - childIt = m_adjNonChildren[*pathIt].begin(); - prevIt = m_adjNonChildren[*pathIt].begin(); - - while (childIt.valid()){ - if (m_pBCTree->find((*childIt)->twinNode()) == (*pathIt)){ - if (childIt == m_adjNonChildren[*pathIt].begin()){ - m_adjNonChildren[*pathIt].popFront(); - childIt = m_adjNonChildren[*pathIt].begin(); - prevIt = m_adjNonChildren[*pathIt].begin(); - } - else{ - childIt = prevIt; - m_adjNonChildren[*pathIt].delSucc(prevIt); - childIt++; - } - } - else{ - prevIt = childIt; - childIt++; - } - } - } - else{ // (*pathIt != m_pBCTree->find(*pathIt)) - childIt = m_adjNonChildren[*pathIt].begin(); - - while (childIt.valid()){ - if (m_pBCTree->find((*childIt)->twinNode()) != newBlock){ - // found a child of *pathIt, that has an adjacent bc-node - // that doesn't belong to newBlock - m_adjNonChildren[newBlock].pushBack(*childIt); - } - childIt++; - } - m_adjNonChildren[*pathIt].clear(); - } - } - pathIt++; - } -} - - - -// ---------------------------------------------------- -// updateBCRoot() -// -// modifys the root of the bc-tree -// -// ---------------------------------------------------- -void PlanarAugmentation::modifyBCRoot(node oldRoot, node newRoot) -{ - // status before updates: - // m_pBCTree->m_bNode_hRefNode[oldRoot] = 0 - // m_pBCTree->m_bNode_hParNode[oldRoot] = 0 - - // m_pBCTree->m_bNode_hRefNode[newRoot] = single isolated vertex in b-comp-graph of this c-comp - // m_pBCTree->m_bNode_hParNode[newRoot] = cutvertex in b-comp-graph corresponding to rootPendant - - // updates: - // for the old root: - m_pBCTree->m_bNode_hRefNode[oldRoot] = m_pBCTree->m_bNode_hParNode[newRoot]; - m_pBCTree->m_bNode_hParNode[oldRoot] = m_pBCTree->m_bNode_hRefNode[newRoot]; - - // for the new root: - // m_pBCTree->m_bNode_hRefNode[newRoot] = no update required; - m_pBCTree->m_bNode_hParNode[newRoot] = 0; -} - - - -// ---------------------------------------------------- -// updateNewEdges(const SList &newEdges) -// -// updates the bc-tree-structure and m_adjNonChildren, -// also adds all edges of newEdges to m_pResult -// -// ---------------------------------------------------- -void PlanarAugmentation::updateNewEdges(const SList &newEdges) -{ - SListConstIterator edgeIt = newEdges.begin(); - while (edgeIt.valid()){ - m_pResult->pushBack(*edgeIt); - - SList& path = m_pBCTree->findPath((*edgeIt)->source(), (*edgeIt)->target()); - - m_pBCTree->updateInsertedEdge(*edgeIt); - node newBlock = m_pBCTree->DynamicBCTree::bcproper(*edgeIt); - - updateAdjNonChildren(newBlock, path); - - if ((m_pBCTree->parent(newBlock) == 0) - && (m_pBCTree->m_bNode_degree[newBlock] == 1)) { - // the new block is a pendant and also the new root of the bc-tree - node newRoot = 0; - newRoot = (*(m_adjNonChildren[newBlock].begin()))->twinNode(); - modifyBCRoot(newBlock, newRoot); - } //if ((m_pBCTree->parent(newBlock) == 0) && (m_pBCTree->m_bNode_degree[newBlock] == 1)) - - delete(&path); - edgeIt++; - } // while (edgeIt.valid) -} - - - -// ---------------------------------------------------- -// terminate() -// -// cleanup before finish -// -// ---------------------------------------------------- -void PlanarAugmentation::terminate() -{ - while (m_labels.size() > 0){ - pa_label l = m_labels.popFrontRet(); - delete (l); - } - - m_pendants.clear(); - node v; - forall_nodes(v, m_pBCTree->m_B) - m_adjNonChildren[v].clear(); - - delete(m_pBCTree); -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/augmentation/PlanarAugmentationFix.cpp b/ext/OGDF/src/augmentation/PlanarAugmentationFix.cpp deleted file mode 100644 index 2f1419860..000000000 --- a/ext/OGDF/src/augmentation/PlanarAugmentationFix.cpp +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief planar biconnected augmentation algorithm with fixed - * embedding - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -#include -#include -#include -#include -#include - - -// for debug-outputs -//#define PLANAR_AUGMENTATION_FIX_DEBUG - -// for additional planarity checks after each "round" -//#define PLANAR_AUGMENTATION_FIX_DEBUG_PLANARCHECK - - -namespace ogdf { - - -/******************************************************** - * - * implementation of class PlanarAugmentationFix - * - *******************************************************/ - -// ---------------------------------------------------- -// doCall -// -// ---------------------------------------------------- -void PlanarAugmentationFix::doCall(Graph& g, List& L) -{ - L.clear(); - m_pResult = &L; - - m_pGraph = &g; - m_pEmbedding = new CombinatorialEmbedding(*m_pGraph); - - NodeArray activeNodes(*m_pGraph, false); - List activeNodesList; - - face actFace; - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "original graph:" << endl << flush; - node n; - forall_nodes(n, *m_pGraph){ - cout << n->index() << ": "; - adjEntry nAdj; - forall_adj(nAdj, n) - cout << nAdj << " "; - cout << endl << flush; - } - #endif - - List faces; - - forall_faces(actFace, *m_pEmbedding){ - faces.pushBack(actFace); - } - - m_eCopy.init(*m_pGraph, 0); - m_graphCopy.createEmpty(*m_pGraph); - - while (faces.size() > 0){ - actFace = faces.popFrontRet(); - - adjEntry adjOuterFace = 0; - - adjEntry adjFirst = actFace->firstAdj(); - if (m_pEmbedding->leftFace(adjFirst) != actFace) - adjFirst = adjFirst->twin(); - - adjEntry adjFace = adjFirst; - - if (m_pEmbedding->numberOfFaces() == 1){ - // we just have only one face (this is the outer face) - adjOuterFace = adjFace; - } - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "======================" << endl - << "face " << actFace->index() <<":" << endl - << adjFace->theNode()->index() << "(" << adjFace << ")"<< ", "; - #endif - - activeNodesList.pushBack(adjFace->theNode()); - activeNodes[adjFace->theNode()] = true; - adjFace = adjFace->twin()->cyclicSucc(); - - bool augmentationRequired = false; - - while (adjFace != adjFirst){ - if ((adjOuterFace == 0) && (m_pEmbedding->leftFace(adjFace) != m_pEmbedding->rightFace(adjFace))) - adjOuterFace = adjFace; - - if (activeNodes[adjFace->theNode()] == false){ - activeNodesList.pushBack(adjFace->theNode()); - activeNodes[adjFace->theNode()] = true; - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << adjFace->theNode()->index() << "(" << adjFace << ")"<< ", "; - #endif - } - else{ - augmentationRequired = true; - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << adjFace->theNode()->index() << "(" << adjFace << ")(nc), "; - #endif - } - - adjFace = adjFace->twin()->cyclicSucc(); - } - - if (augmentationRequired){ - m_graphCopy.createEmpty(*m_pGraph); - m_graphCopy.initByActiveNodes(activeNodesList, activeNodes, m_eCopy); - m_graphCopy.setOriginalEmbedding(); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << " graphCopy:" << endl << flush; - forall_nodes(n, m_graphCopy){ - cout << n->index() << "(" << (m_graphCopy.original(n))->index() << "):" << flush; - adjEntry nAdj; - forall_adj(nAdj, n){ - cout << nAdj << "(" << nAdj->theEdge() << "[" << nAdj->index() << "]) " << flush; - } - cout << endl << flush; - } - #endif - - adjEntry adjOuterFaceCopy = (m_graphCopy.copy(adjOuterFace->theEdge()))->adjSource(); - if (adjOuterFaceCopy->theNode() != m_graphCopy.copy(adjOuterFace->theNode())) - adjOuterFaceCopy = adjOuterFaceCopy->twin(); - - augment(adjOuterFaceCopy); - - } - else{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << endl << flush; - #endif - } - - - edge e; - // set all entries in activeNodes to default value false - // for next iteration - ListIterator anIt = activeNodesList.begin(); - while (anIt.valid()){ - activeNodes[*anIt] = false; - forall_adj_edges(e, *anIt) - m_eCopy[e] = 0; - anIt++; - } - activeNodesList.clear(); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "======================" << endl << flush; - #endif - - } - - delete m_pEmbedding; - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - if (isBiconnected(*m_pGraph)) - cout << " graph is biconnected" << endl << flush; - else - cout << " graph is NOT biconnected!!!" << endl << flush; - - if (pisPlanar(*m_pGraph)) - cout << " graph is planar" << endl << flush; - else - cout << " graph is NOT planar!!!" << endl << flush; - #endif -} - - - -// ---------------------------------------------------- -// augment() -// -// the main augmentation function -// -// ---------------------------------------------------- -void PlanarAugmentationFix::augment(adjEntry adjOuterFace) -{ - CombinatorialEmbedding* actComb = new CombinatorialEmbedding(m_graphCopy); - m_pActEmbedding = actComb; - - DynamicBCTree* actBCTree = new DynamicBCTree(m_graphCopy); - m_pBCTree = actBCTree; - - m_pActEmbedding->setExternalFace(m_pActEmbedding->rightFace(adjOuterFace)); - - node bFaceNode = m_pBCTree->bcproper(adjOuterFace->theEdge()); - - m_isLabel.init(m_pBCTree->bcTree(), 0); - m_belongsTo.init(m_pBCTree->bcTree(), 0); - m_belongsToIt.init(m_pBCTree->bcTree(), 0); - - List pendants; - - node v; - node root; - - // init pendants - forall_nodes(v, m_pBCTree->bcTree()){ - if (m_pBCTree->parent(v) == 0){ - root = v; - } - if (v->degree() == 1){ - // pendant - if (v != bFaceNode){ - pendants.pushBack(v); - } - } - } - - if (root != bFaceNode){ - // change root of the bc-tree to the b-node that includes the actual face - modifyBCRoot(root, bFaceNode); - } - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << " augment(): pendants:" << flush; - forall_nodes(v, m_pBCTree->bcTree()){ - if (m_pBCTree->parent(v) == 0){ - cout << "[root: " << v->index() << flush; - if (m_pBCTree->typeOfBNode(v) == BCTree::BComp) - cout << "(b)], " << flush; - else - cout << "(c)], " << flush; - } - if (v->degree() == 1){ - // pendant - if (v != bFaceNode){ - cout << v->index() << ", " << flush; - } - else - cout << v->index() << "(is root), " << flush; - } - } - cout << endl << flush; - #endif - - m_actBCRoot = bFaceNode; - m_labels.clear(); - - // call reduceChain for all pendants - ListIterator itPendant = pendants.begin(); - while (itPendant.valid()){ - reduceChain(*itPendant); - itPendant++; - } - - // main augmentation loop - while (m_labels.size() > 0){ - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << endl - << " *-----------------------------------" << endl - << " * augment(): #labels : " << m_labels.size() << endl << flush; - - ListIterator labelIt = m_labels.begin(); - ListIterator pendantIt; - int lNr = 1; - while (labelIt.valid()){ - cout << " * label in list with position " << lNr << " : " << flush; - pendantIt = ((*labelIt)->m_pendants).begin(); - while (pendantIt.valid()){ - cout << (*pendantIt)->index() << " " << flush; - pendantIt++; - } - cout << endl << flush; - lNr++; - labelIt++; - } - cout << " *-----------------------------------" << endl << endl << flush; - #endif - - - if (m_labels.size() == 1){ - connectSingleLabel(); - } - else{ - node pendant1, pendant2; - adjEntry adjV1, adjV2; - bool foundMatching = findMatching(pendant1, pendant2, adjV1, adjV2); - if (!foundMatching) - findMatchingRev(pendant1, pendant2, adjV1, adjV2); - - connectPendants(pendant1, pendant2, adjV1, adjV2); - } - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG_PLANARCHECK - if (isPlanar(m_graphCopy)) - cout << " graphCopy is planar" << endl << flush; - else{ - cout << " graphCopy is NOT planar!!!" << endl << flush;; - } - #endif - } // main loop - - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG_PLANARCHECK - if (isBiconnected(m_graphCopy)) - cout << " graphCopy is biconnected" << endl << flush; - else{ - cout << " graphCopy is NOT biconnected!!!" << endl << flush; - } - - if (isPlanar(m_graphCopy)) - cout << " graphCopy is planar" << endl << flush; - else{ - cout << " graphCopy is NOT planar!!!" << endl << flush; - } - #endif - - m_pActEmbedding = 0; - m_pBCTree = 0; - delete(actComb); - delete(actBCTree); -} - - - -// ---------------------------------------------------- -// reduceChain() -// -// ---------------------------------------------------- -void PlanarAugmentationFix::reduceChain(node p) -{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "reduceChain() " << p->index(); - if (m_pBCTree->typeOfBNode(p) == BCTree::BComp) - cout << "[b]"<< flush; - else - cout << "[c]"<< flush; - #endif - - // parent = parent of p in the BC-Tree - // if p is the root, then parent == 0 - node parent = m_pBCTree->DynamicBCTree::parent(p); - - // last is going to be the last cutvertex in the computation of followPath() - node last; - paStopCause stopCause; - - // traverse from parent to the root of the bc-tree and check several - // conditions. last is going to be the last cutvertex on this path - stopCause = followPath(parent, last); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << ", stopCause == "; - switch(stopCause){ - case paPlanarity: - // cannot occur - break; - case paCDegree: - cout << "paCDegree "; - break; - case paBDegree: - cout << "paBDegree "; - break; - case paRoot: - cout << "paRoot "; - break; - } - #endif - - pa_label l; - - if (stopCause == paCDegree || stopCause == paRoot){ - - if (m_isLabel[last].valid()){ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "reduceChain(): add " << p->index() << " to another label" << endl << flush; - #endif - // l is the label that last is the head of - l = *(m_isLabel[last]); - // add the actual pendant p to l - addPendant(p, l); - // set the stop-cause - l->stopCause(stopCause); - } - else{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "reduceChain(): creating a new label with pendant " << p->index() << endl << flush; - #endif - newLabel(last, 0, p, stopCause); - } - } - else{ - // stopCause == paBDegree - parent = m_pBCTree->parent(last); - - if (m_isLabel[parent].valid()){ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "reduceChain(): add " << p->index() << " to another label" << endl << flush; - #endif - l = *(m_isLabel[parent]); - addPendant(p, l); - } - else{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "reduceChain(): creating a new label with pendant " << p->index() << endl << flush; - #endif - newLabel(last, parent, p, paBDegree); - } - } -} - - - -// ---------------------------------------------------- -// followPath(node v, node& last) -// -// ---------------------------------------------------- -paStopCause PlanarAugmentationFix::followPath(node v, node& last) -{ - last = 0; - node bcNode = m_pBCTree->find(v); - - if (m_pBCTree->typeOfBNode(bcNode) == BCTree::CComp){ - last = bcNode; - } - - while (bcNode != 0){ - int deg = m_pBCTree->m_bNode_degree[bcNode]; - - if (deg > 2){ - if (m_pBCTree->typeOfBNode(bcNode) == BCTree::CComp){ - last = bcNode; - return paCDegree; - } - else{ - if (m_pBCTree->DynamicBCTree::parent(bcNode) == 0) - return paRoot; - else - return paBDegree; - } - } - - if (m_pBCTree->typeOfBNode(bcNode) == BCTree::CComp){ - last = bcNode; - } - - // iterate to parent node - bcNode = m_pBCTree->DynamicBCTree::parent(bcNode); - } - return paRoot; -} - - - -// ---------------------------------------------------- -// findMatching(node& pendant1, node& pendant2,...) -// -// ---------------------------------------------------- -bool PlanarAugmentationFix::findMatching(node& pendant1, node& pendant2, adjEntry& adjV1, adjEntry& adjV2) -{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "findMatching()" << endl << flush; - #endif - - pa_label l = m_labels.front(); - pendant2 = 0; - adjV1 = adjV2 = 0; - pendant1 = m_pBCTree->find(l->getFirstPendant()); - node pendantFirst = pendant1; - - node cutV = m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hParNode[pendant1]]; - adjEntry adj = cutV->firstAdj(); - if (m_pBCTree->DynamicBCTree::bcproper(adj->theEdge()) == pendant1){ - while (m_pBCTree->DynamicBCTree::bcproper(adj->twinNode()) == pendant1){ - adjV1 = adj->twin(); - adj = adj->cyclicSucc(); - } - } - else{ - while (m_pBCTree->DynamicBCTree::bcproper(adj->twinNode()) != pendant1) - adj = adj->cyclicPred(); - adjV1 = adj->twin(); - adj = adj->cyclicSucc(); - } - - // adjV1 is the very adjEntry that belongs to pendant1, points to the cutvertex - // and is the rightmost adjEntry with this properties - adjV1 = adjV1->cyclicPred(); - - bool loop = true; - bool found = false; - - node cutvBFNode = 0; - bool dominatingTree = false; - - while (loop){ - - if (m_pBCTree->typeOfGNode(adj->theNode()) == BCTree::CutVertex){ - if (!dominatingTree){ - if ((adj->theNode() == cutvBFNode)){ - dominatingTree = true; - } - else{ - if ((cutvBFNode == 0) && (m_pBCTree->DynamicBCTree::bcproper(adj->theEdge()) == m_actBCRoot)) - cutvBFNode = adj->theNode(); - } - } - } - else{ - node actPendant = m_pBCTree->DynamicBCTree::bcproper(adj->theNode()); - - if ((m_pBCTree->m_bNode_degree[actPendant] == 1) && (actPendant != m_actBCRoot) && (actPendant != pendant1)){ - - if (m_belongsTo[actPendant] == l){ - // found pendant of same label - adjV1 = adj->cyclicPred(); - pendant1 = actPendant; - l->m_pendants.del(m_belongsToIt[pendant1]); - m_belongsToIt[pendant1] = l->m_pendants.pushFront(pendant1); - if (dominatingTree){ - cutvBFNode = 0; - } - } - else{ - // found pendant of different label - if (dominatingTree){ - // we have a dominating tree - if (cutvBFNode != 0){ - // corrupt situation - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "findMatching(): found dominating tree: corrupt situation " << endl << flush; - #endif - - pendant1 = pendantFirst; - loop = false; - found = false; - } - else{ - // correct situation - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "findMatching(): found dominating tree: correct situation " << endl << flush; - #endif - - adjV2 = adj->cyclicPred(); - pendant2 = actPendant; - loop = false; - found = true; - } - } - else{ - // no dominating tree - adjV2 = adj->cyclicPred(); - pendant2 = actPendant; - loop = false; - found = true; - } - } - } - } - - adj = adj->twin()->cyclicSucc(); - } - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "findMatching() finished with found == "<< found << endl << flush; - #endif - - return (found); -} - - - -// ---------------------------------------------------- -// findMatchingRev(node& pendant1, node& pendant2,...) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::findMatchingRev(node& pendant1, node& pendant2, adjEntry& adjV1, adjEntry& adjV2) -{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "findMatchingRev() " << endl << flush; - #endif - - pa_label l = m_belongsTo[pendant1]; - pendant2 = 0; - adjV1 = adjV2 = 0; - - - node cutV = m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hParNode[pendant1]]; - adjEntry adj = cutV->firstAdj(); - if (m_pBCTree->DynamicBCTree::bcproper(adj->theEdge()) == pendant1){ - while (m_pBCTree->DynamicBCTree::bcproper(adj->theEdge()) == pendant1){ - adjV1 = adj->twin(); - adj = adj->cyclicPred(); - } - } - else{ - while (m_pBCTree->DynamicBCTree::bcproper(adj->theEdge()) != pendant1) - adj = adj->cyclicSucc(); - adjV1 = adj->twin(); - adj = adj->cyclicPred(); - } - - bool loop = true; - - while (loop){ - - if (m_pBCTree->typeOfGNode(adj->theNode()) == BCTree::Normal){ - - node actPendant = m_pBCTree->DynamicBCTree::bcproper(adj->theNode()); - - if (m_pBCTree->m_bNode_degree[actPendant] == 1){ - - if (m_belongsTo[actPendant] == l){ - // found pendant of same label - adjV1 = adj; - pendant1 = actPendant; - l->m_pendants.del(m_belongsToIt[pendant1]); - m_belongsToIt[pendant1] = l->m_pendants.pushBack(pendant1); - } - else{ - // found pendant of different label - adjV2 = adj; - pendant2 = actPendant; - loop = false; - } - - } - } - - adj = adj->twin()->cyclicPred(); - } -} - - - -// ---------------------------------------------------- -// connectPendants(...) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::connectPendants(node pendant1, node pendant2, adjEntry adjV1, adjEntry adjV2) -{ - edge newEdgeCopy = m_pActEmbedding->splitFace(adjV1, adjV2); - - adjEntry adjOrigV1 = (m_graphCopy.original(adjV1->theEdge()))->adjSource(); - if (adjOrigV1->theNode() != m_graphCopy.original(adjV1->theNode())) - adjOrigV1 = adjOrigV1->twin(); - - adjEntry adjOrigV2 = (m_graphCopy.original(adjV2->theEdge()))->adjSource(); - if (adjOrigV2->theNode() != m_graphCopy.original(adjV2->theNode())) - adjOrigV2 = adjOrigV2->twin(); - - edge newEdgeOrig = m_pEmbedding->splitFace(adjOrigV1, adjOrigV2); - m_pResult->pushBack(newEdgeOrig); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "connectPendants(" << pendant1->index() << ", " << pendant2->index() << ", " << adjV1 << ", " << adjV2 << ")" << endl << flush; - cout << " leads to edge " << newEdgeCopy << endl << flush; - cout << " and new edge in the orig. " << newEdgeOrig << endl << flush; - #endif - - m_pBCTree->updateInsertedEdge(newEdgeCopy); - m_graphCopy.setEdge(newEdgeOrig, newEdgeCopy); - - pa_label l1 = m_belongsTo[pendant1]; - pa_label l2 = m_belongsTo[pendant2]; - - deletePendant(pendant1); - deletePendant(pendant2); - - if (l2->size() > 0){ - if (l2->size() == 1){ - node pendant = l2->getFirstPendant(); - deleteLabel(l2); - reduceChain(pendant); - } - else{ - removeLabel(l2); - insertLabel(l2); - } - } - else - deleteLabel(l2); - - if (l1->size() > 0){ - if (l1->size() == 1){ - node pendant = l1->getFirstPendant(); - deleteLabel(l1); - reduceChain(pendant); - } - else{ - removeLabel(l1); - insertLabel(l1); - } - } - else - deleteLabel(l1); - - m_actBCRoot = m_pBCTree->find(m_actBCRoot); - - node bcNode = m_pBCTree->DynamicBCTree::bcproper(newEdgeCopy); - if ((bcNode != pendant1) && (bcNode != pendant2) && (m_pBCTree->m_bNode_degree[bcNode] == 1) - && (bcNode != m_actBCRoot)) - reduceChain(bcNode); -} - - - -// ---------------------------------------------------- -// connectSingleLabel(...) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::connectSingleLabel() -{ - pa_label l = m_labels.front(); - node pendant1 = l->getFirstPendant(); - - adjEntry adj; - node cutV = m_pBCTree->m_hNode_gNode[m_pBCTree->m_bNode_hParNode[pendant1]]; - adjEntry adjRun = cutV->firstAdj(); - m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()); - - if (m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()) == pendant1){ - while (m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()) == pendant1){ - adj = adjRun->twin(); - adjRun = adjRun->cyclicSucc(); - } - } - else{ - while (m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()) != pendant1) - adjRun = adjRun->cyclicPred(); - adj = adjRun->twin(); - adjRun = adjRun->cyclicSucc(); - } - - adjEntry adjFirst = adj; - adj = adj->cyclicPred(); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - bool singleEdgePendant = false; - if (adj == adj->cyclicSucc()) - singleEdgePendant = true; - - cout << "connectSinlgeLabel(): cutv=" << cutV << ", adj=" << adj << ", adjRun=" << adjRun << "(pred=" << adjRun->cyclicPred() <<")" - << ", adjFirst=" << adjFirst << ", singleEdgePendant=" << singleEdgePendant << endl << flush; - #endif - - bool connectLeft = false; - bool connectRight = false; - node adjBNode = 0; - node lastConnectedPendant = 0; - - if (l->size() > 1){ - - node cutvBFNode = 0; - bool loop = true; - - adjBNode = m_pBCTree->bcproper(adj->theEdge()); - - // first connect pendants "on the right" of the first pendant - while (loop){ - - if (m_pBCTree->typeOfGNode(adjRun->theNode()) == BCTree::CutVertex){ - if ((adjRun->theNode() == cutvBFNode)){ - loop = false; - } - else{ - if ((cutvBFNode == 0) && (m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()) == m_actBCRoot)) - cutvBFNode = adjRun->theNode(); - } - } - else{ - node actPendant = m_pBCTree->DynamicBCTree::bcproper(adjRun->theNode()); - - if ((m_pBCTree->m_bNode_degree[actPendant] == 1) - && (actPendant != m_pBCTree->find(adjBNode)) - && (actPendant != lastConnectedPendant) - && (actPendant != m_actBCRoot)){ - - if (!connectRight) - connectRight = true; - - lastConnectedPendant = actPendant; - adjRun = adjRun->cyclicPred(); - - edge newEdgeCopy = m_pActEmbedding->splitFace(adj, adjRun); - - adjEntry adjOrigV1 = (m_graphCopy.original(adj->theEdge()))->adjSource(); - if (adjOrigV1->theNode() != m_graphCopy.original(adj->theNode())) - adjOrigV1 = adjOrigV1->twin(); - adjEntry adjOrigV2 = (m_graphCopy.original(adjRun->theEdge()))->adjSource(); - if (adjOrigV2->theNode() != m_graphCopy.original(adjRun->theNode())) - adjOrigV2 = adjOrigV2->twin(); - - edge newEdgeOrig = m_pEmbedding->splitFace(adjOrigV1, adjOrigV2); - m_pResult->pushBack(newEdgeOrig); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "connectSingleLabel(): splitFace (on the right) with " << adj << " and " << adjRun << endl << flush; - cout << " leads to edge " << newEdgeCopy << endl << flush; - cout << " newEdge in the orig. graph " << newEdgeOrig << endl << flush; - #endif - - m_graphCopy.setEdge(newEdgeOrig, newEdgeCopy); - adjRun = adjRun->cyclicSucc()->cyclicSucc(); - } - } - adjRun = adjRun->twin()->cyclicSucc(); - } // while (loop) - - // now connect pendants "on the left" of the first pendant - adjRun = adjFirst->twin(); - while (m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()) == pendant1) - adjRun = adjRun->cyclicPred(); - adj = adjRun->cyclicSucc()->twin(); - - cutvBFNode = 0; - loop = true; - - while (loop){ - - if (m_pBCTree->typeOfGNode(adjRun->theNode()) == BCTree::CutVertex){ - if ((adjRun->theNode() == cutvBFNode)){ - loop = false; - } - else{ - if ((cutvBFNode == 0) && (m_pBCTree->DynamicBCTree::bcproper(adjRun->theEdge()) == m_actBCRoot)) - cutvBFNode = adjRun->theNode(); - } - } - else{ - node actPendant = m_pBCTree->DynamicBCTree::bcproper(adjRun->theNode()); - if ((m_pBCTree->m_bNode_degree[actPendant] == 1) - && (actPendant != m_pBCTree->find(adjBNode)) - && (actPendant != lastConnectedPendant) - && (actPendant != m_actBCRoot)){ - - if (!connectLeft) - connectLeft = true; - - lastConnectedPendant = actPendant; - edge newEdgeCopy = m_pActEmbedding->splitFace(adj, adjRun); - - adjEntry adjOrigV1 = (m_graphCopy.original(adj->theEdge()))->adjSource(); - if (adjOrigV1->theNode() != m_graphCopy.original(adj->theNode())) - adjOrigV1 = adjOrigV1->twin(); - adjEntry adjOrigV2 = (m_graphCopy.original(adjRun->theEdge()))->adjSource(); - if (adjOrigV2->theNode() != m_graphCopy.original(adjRun->theNode())) - adjOrigV2 = adjOrigV2->twin(); - - edge newEdgeOrig = m_pEmbedding->splitFace(adjOrigV1, adjOrigV2); - m_pResult->pushBack(newEdgeOrig); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "connectSingleLabel(): splitFace (on the left) with " << adj << " and " << adjRun << endl << flush; - cout << " leads to edge " << newEdgeCopy << endl << flush; - cout << " newEdge in the orig. graph " << newEdgeOrig << endl << flush; - #endif - - m_graphCopy.setEdge(newEdgeOrig, newEdgeCopy); - adj = adj->cyclicSucc(); - } - } - - adjRun = adjRun->twin()->cyclicPred(); - } - } - - adjRun = adj->cyclicSucc(); - - while (m_pBCTree->DynamicBCTree::bcproper(adjRun->theNode()) != m_pBCTree->find(m_actBCRoot)){ - adjRun = adjRun->twin()->cyclicSucc(); - } - adjRun = adjRun->cyclicPred(); - - edge newEdgeCopy = m_pActEmbedding->splitFace(adj, adjRun); - - adjEntry adjOrigV1 = (m_graphCopy.original(adj->theEdge()))->adjSource(); - if (adjOrigV1->theNode() != m_graphCopy.original(adj->theNode())) - adjOrigV1 = adjOrigV1->twin(); - adjEntry adjOrigV2 = (m_graphCopy.original(adjRun->theEdge()))->adjSource(); - if (adjOrigV2->theNode() != m_graphCopy.original(adjRun->theNode())) - adjOrigV2 = adjOrigV2->twin(); - - edge newEdgeOrig = m_pEmbedding->splitFace(adjOrigV1, adjOrigV2); - m_pResult->pushBack(newEdgeOrig); - - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "connectSingleLabel(): splitFace (last edge) with " << adj << " and " << adjRun << endl << flush; - cout << " leads to edge " << newEdgeCopy << endl << flush; - cout << " newEdge in the orig. graph " << newEdgeOrig << endl << flush; - #endif - - m_graphCopy.setEdge(newEdgeOrig, newEdgeCopy); - - deleteLabel(l); -} - - - -// ---------------------------------------------------- -// newLabel(...) -// -// ---------------------------------------------------- -pa_label PlanarAugmentationFix::newLabel(node cutvertex, node parent, node pendant, paStopCause whyStop) -{ - pa_label l; - l = OGDF_NEW PALabel(parent, cutvertex, whyStop); - - m_belongsTo[pendant] = l; - m_belongsToIt[pendant] = (l->m_pendants).pushBack(pendant); - - if (parent != 0) - m_isLabel[parent] = m_labels.pushBack(l); - else - m_isLabel[cutvertex] = m_labels.pushBack(l); - - return l; -} - - - -// ---------------------------------------------------- -// deleteLabel(...) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::deleteLabel(pa_label& l, bool removePendants){ - ListIterator labelIt = m_isLabel[l->parent()]; - - m_labels.del(labelIt); - m_isLabel[l->parent()] = 0; - - ListIterator pendantIt = (l->m_pendants).begin(); - while (pendantIt.valid()){ - m_belongsTo[*pendantIt] = 0; - m_belongsToIt[*pendantIt] = 0; - pendantIt++; - } - - delete(l); - l = 0; -} - - - -// ---------------------------------------------------- -// removeLabel(...) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::removeLabel(pa_label& l){ - ListIterator labelIt = m_isLabel[l->parent()]; - - m_labels.del(labelIt); -} - - - -// ---------------------------------------------------- -// addPendant(pa_label& l, node pendant) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::addPendant(node p, pa_label& l) -{ - m_belongsTo[p] = l; - m_belongsToIt[p] = (l->m_pendants).pushBack(p); - - node newParent = m_pBCTree->find(l->parent()); - - m_labels.del(m_isLabel[l->parent()]); - m_isLabel[newParent] = insertLabel(l); -} - - - -// ---------------------------------------------------- -// deletePendant(node pendant) -// -// ---------------------------------------------------- -void PlanarAugmentationFix::deletePendant(node pendant){ - (m_belongsTo[pendant])->removePendant(m_belongsToIt[pendant]); - m_belongsTo[pendant] = 0; - m_belongsToIt[pendant] = 0; -} - - - -// ---------------------------------------------------- -// insertLabel(pa_label l) -// -// ---------------------------------------------------- -ListIterator PlanarAugmentationFix::insertLabel(pa_label l) -{ - if (m_labels.size() == 0){ - return m_labels.pushFront(l); - } - else{ - ListIterator it = m_labels.begin(); - while (it.valid() && ((*it)->size() > l->size())){ - it++; - } - if (!it.valid()) - return m_labels.pushBack(l); - else - return m_labels.insert(l, it, before); - } -} - - - -// ---------------------------------------------------- -// modifyBCRoot() -// -// ---------------------------------------------------- -void PlanarAugmentationFix::modifyBCRoot(node oldRoot, node newRoot) -{ - #ifdef PLANAR_AUGMENTATION_FIX_DEBUG - cout << "modifyBCRoot()" << endl << flush; - #endif - - SList *path = m_pBCTree->findPathBCTree(oldRoot, newRoot); - SListIterator it = path->begin(); - SListIterator it2 = path->begin(); - - while (it.valid()){ - if (it2 != it){ - changeBCRoot((*it2), (*it)); - } - - it2 = it; - it++; - } - - delete path; -} - - - -// ---------------------------------------------------- -// changeBCRoot() -// -// ---------------------------------------------------- -void PlanarAugmentationFix::changeBCRoot(node oldRoot, node newRoot) -{ - // for the old root: - m_pBCTree->m_bNode_hRefNode[oldRoot] = m_pBCTree->m_bNode_hParNode[newRoot]; - m_pBCTree->m_bNode_hParNode[oldRoot] = m_pBCTree->m_bNode_hRefNode[newRoot]; - - // for the new root: - // m_pBCTree->m_bNode_hRefNode[newRoot] = no update required; - m_pBCTree->m_bNode_hParNode[newRoot] = 0; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/CliqueFinder.cpp b/ext/OGDF/src/basic/CliqueFinder.cpp deleted file mode 100644 index 1ea37562c..000000000 --- a/ext/OGDF/src/basic/CliqueFinder.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of a heuristical method to find cliques - * in a given input graph. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - -#ifdef OGDF_DEBUG -#include -#endif -#include -#include - - -namespace ogdf { - - -//constructor -CliqueFinder::CliqueFinder(const Graph &G) : m_pGraph(&G), m_pCopy(0), - m_minDegree(2), - m_numberOfCliques(0), - m_postProcess(ppSimple), - m_callByList(false), - m_pList(0), - m_density(100) -{ - try { - m_pCopy = new GraphCopy(G); - m_copyCliqueNumber.init(*m_pCopy, -1); - m_usedNode.init(*m_pCopy, false); - } - catch (...) - { - OGDF_THROW(InsufficientMemoryException); - } -}//constructor - -CliqueFinder::~CliqueFinder() -{ - if (m_pCopy != 0) - { - //we have to uninitialize the nodearray before destroying - //the graph - m_copyCliqueNumber.init(); - m_usedNode.init(); - - delete m_pCopy; - } -}//destructor - - - -//--------------------------------------------------- -//calls -//--------------------------------------------------- -//Call with NodeArray, each clique will be assigned a -//different number, each node gets the number of the -//clique it is contained in, -1 if not a clique member -void CliqueFinder::call(NodeArray &cliqueNumber) -{ - m_callByList = false; - m_pList = 0; - //First find the cliques: doCall - doCall(m_minDegree); - //Then set the result: setResults(cliqueNumber); - setResults(cliqueNumber); - -}//call - -//call with list of node lists, on return these lists contain -//the nodes in each clique that is found -void CliqueFinder::call(List< List > &cliqueLists) -{ - m_callByList = true; - m_pList = &cliqueLists; - m_pList->clear(); - - //First find the cliques: doCall - doCall(m_minDegree); - //setresult is called in doCall for every treated component - - m_pList = 0; -}//call - - -//--------------------------------------------------------- -//actual call -//minDegree default 2, all other nodes are skipped -//only high values have an impact because we only -//work on triconnected components, skipping all low -//degree nodes (but we make the test graphcopy biconnected -//afterwards) -void CliqueFinder::doCall(int minDegree) -{ - //--------------------------------------------- - //initialize structures and check preconditions - //--------------------------------------------- - m_copyCliqueNumber.init(*m_pCopy, -1); - m_usedNode.init(*m_pCopy, false); - makeParallelFreeUndirected(*m_pCopy); //it doesnt make sense to count loops - makeLoopFree(*m_pCopy); //or parallel edges - - m_numberOfCliques = 0; - //We first indentify the biconnected components of - //the graph to allow the use of the SPQR-tree data - //Structure. Latter then separates the different - //triconnected components on which we finally work - - //TODO: delete all copy nodes with degree < minDegree - - int nodeNum = m_pGraph->numberOfNodes(); - //TODO: change for non-cliques, where this is not necessary - if (nodeNum < minDegree) return; //nothing to find for cliques - - //------------------------------------------------------- - //Special cases: - //Precondition for SPQR-trees: graph has at least 3 nodes - //or 2 nodes and at least 3 edges - //TODO: check this after makebiconnected - - //---------------------------- - //set values for trivial cases - if (nodeNum < 3) - { - //only set numbers for the special case - if (nodeNum == 2) - { - if (m_pGraph->numberOfEdges() >= 1) //> 2) - { - node w = m_pCopy->firstNode(); - m_copyCliqueNumber[w] = 0; - w = w->succ(); - m_copyCliqueNumber[w] = 0; - } - else - { - if (minDegree == 0) - { - node w = m_pCopy->firstNode(); - m_copyCliqueNumber[w] = 0; - w = w->succ(); - m_copyCliqueNumber[w] = 1; - }//if no mindegree - - } - }//if two nodes - else if ( (nodeNum == 1) && (minDegree <= 0)) - m_copyCliqueNumber[m_pCopy->firstNode()] = 0; - - return; - }//graph too small - - OGDF_ASSERT(m_pCopy != 0) - - //save the original edges - EdgeArray originalEdge(*m_pCopy, true); - List added; - - - //we make the copy biconnected, this keeps the triconnected - //components - - - //------------------------------------------------------------- - //store the original node degrees: - //afterwards we want to be able to sort the nodes corresponding - //to their real degree, not the one with the additional - //connectivity edges - NodeArray realDegree(*m_pCopy, -1);//no isolated nodes exist here - //relative degree, number of high degree neighbours - NodeArray relDegree(*m_pCopy, 0);//no isolated nodes exist here - node v; - forall_nodes(v, *m_pCopy) - { - realDegree[v] = v->degree(); - if (v->degree() > 0) - { - adjEntry adRun = v->firstAdj(); - while (adRun) - { - adjEntry succ = adRun->succ(); - if (adRun->twinNode()->degree() >= minDegree) - relDegree[v]++; - adRun = succ; - }//while - }//if not isolated - - }//forallnodes - - makeBiconnected(*m_pCopy, added); - - //TODO: We can decrease node degrees by the number of adjacent - //low degree nodes to sort them only by number of relevant connections - //PARTIALLY DONE: relDegree - - //storing the component number, there are no isolated nodes now - EdgeArray component(*m_pCopy); - - StaticSPQRTree spqrTree(*m_pCopy); - - //Return if there are no R-nodes - if (spqrTree.numberOfRNodes() == 0) - { - //TODO:set node numbers for cliques - //that are not triconnected - //each edge is a min. clique for mindegree 1 - //each triangle for mindegree 2? - - return; - }//if - - //the degree of the original node - //within the triconnected component - NodeArray ccDegree(*m_pCopy, 0); - - forall_nodes(v, spqrTree.tree()) - { - //we search for dense subgraphs in R-Nodes - //heuristics: - //sort the nodes by their degree within the component - //in descending order, then start cliques by initializing - //them with the first node and checking the remaining, - //starting new cliques with nodes that don't fit in the - //existing cliques (stored in cliqueList) - - if (spqrTree.typeOf(v) == SPQRTree::RNode) - { - //retrieve the skeleton - Skeleton &s = spqrTree.skeleton(v); - node w; - Graph &skeletonG = s.getGraph(); - - //list of cliques - List< List* > cliqueList; - - //we insert all nodes into a list to sort them - List sortList; - - //save the usable edges within the triconnected component - EdgeArray usableEdge(*m_pCopy, false); - - //derive the degree of the original node - //within the triconnected component - forall_nodes(w, skeletonG) - { - node vOrig = s.original(w); - - edge eSkel; - forall_adj_edges(eSkel, w) - { - edge goodEdge = s.realEdge(eSkel); - bool isGoodEdge = goodEdge != 0; - if (isGoodEdge) isGoodEdge = m_pCopy->original(goodEdge) != 0; - //if (s.realEdge(eSkel)) - if (isGoodEdge) - { - ccDegree[vOrig]++; - usableEdge[goodEdge] = true; - } - }//foralladjedges - - sortList.pushBack(vOrig); - - }//forall_nodes - - //sort the nodes corresponding to their degree - NodeComparer ncomp(ccDegree, false); - sortList.quicksort(ncomp); - - ListIterator itNode = sortList.begin(); - - while(itNode.valid()) - { - - //hier erst vergleichen, ob Knoten Grad > aktcliquengroesse, - //dann ob mit clique verbunden - //alternativ koennte man stattdessen fuer jeden gewaehlten - //Knoten nur noch seine Nachbarn als Kandidaten zulassen - //hier sollte man mal ein paar Strategien testen, z.B. - //streng nach Listenordnung vorgehen oder eine "Breitensuche" - //vom Startknoten aus.. - node vCand = *itNode; - - //node can appear in several 3connected components - if (m_usedNode[vCand]) - { - itNode++; - continue; - }//if already used - - //if there are only "small" degree nodes left, we stop - //if (vCand->degree() < minDegree) - if (ccDegree[vCand] < minDegree) - break; - - //------------------------------------------------ - //successively check the node against the existing - //clique candidates - - //run through the clique candidates to find a matching - //node set - bool setFound = false; - ListIterator< List* > itCand = cliqueList.begin(); - while (itCand.valid()) - { - - //in the case of cliques, the node needs min degree - //greater or equal to current clique size - //TODO: adapt to dense subgraphs - bool isCand = false; - if (m_density == 100) - isCand = (vCand->degree() >= (*itCand)->size()); - else isCand = (vCand->degree() >= ceil(m_density*(*itCand)->size()/100.0)); - if (isCand) - { - //TODO: insert adjacency oracle here to speed - //up the check? - //TODO: check if change from clique to dense subgraph criterion - //violates some preconditions for our search - if (allAdjacent(vCand, (*itCand))) - { - OGDF_ASSERT(m_usedNode[*itNode] == false) - (*itCand)->pushBack(*itNode); - setFound = true; - m_usedNode[(*itNode)] = true; - - //bubble sort the clique after insertion of the node - //while size > predsize swap positions - ListIterator< List* > itSearch = itCand.pred(); - if (itSearch.valid()) - { - while (itSearch.valid() && - ( (*itCand)->size() > (*itSearch)->size()) ) - { - itSearch--; - } - //If valid, move behind itSearch, else move to front - if (!itSearch.valid()) - cliqueList.moveToFront(itCand); - else cliqueList.moveToSucc(itCand, itSearch); - }//if valid - - break; - }//if node fits into node set - }//if sufficient degree - //hier kann man mit else breaken, wenn Liste immer sortiert ist - - itCand++; - }//while clique candidates - - //create a new candidate if necessary - if (!setFound) - { - List* cliqueCandidate = OGDF_NEW List(); - itCand = cliqueList.pushBack(cliqueCandidate); - OGDF_ASSERT(m_usedNode[*itNode] == false) - cliqueCandidate->pushBack(*itNode); - m_usedNode[(*itNode)] = true; - - }//if no candidate yet - - itNode++; - }//while valid - - //TODO: cliquelist vielleicht durch einen member ersetzen - //und nicht das delete vergessen! -#ifdef OGDF_DEBUG - int numC1 = cliqueList.size(); - - int nodeNum = 0; - ListIterator< List* > itDeb = cliqueList.begin(); - while (itDeb.valid()) - { - if ( (*itDeb)->size() > minDegree ) - nodeNum = nodeNum +(*itDeb)->size(); - itDeb++; - } - checkCliques(cliqueList, false); - double realTime; - ogdf::usedTime(realTime); -#endif - postProcessCliques(cliqueList, usableEdge); -#ifdef OGDF_DEBUG - realTime = ogdf::usedTime(realTime); - - int nodeNum2 = 0; - itDeb = cliqueList.begin(); - while (itDeb.valid()) - { - if ( (*itDeb)->size() > minDegree ) - nodeNum2 = nodeNum2 +(*itDeb)->size(); - itDeb++; - } - if (nodeNum2 > nodeNum) - { - cout<<"\nAnzahl Cliquen vor PP: "<* > itCand = cliqueList.begin(); - while (itCand.valid()) - { - if ( (*itCand)->size() <= minDegree ) break; - - ListIterator itV = (*itCand)->begin(); - while (itV.valid()) - { - node u = (*itV); - OGDF_ASSERT(m_copyCliqueNumber[u] == -1) - m_copyCliqueNumber[u] = m_numberOfCliques; - itV++; - }//while clique nodes - m_numberOfCliques++; - itCand++; - }//while - //TODO: only set numbers if return value is not a list - //of clique node lists - setResults(cliqueList); - - //free the allocated memory - ListIterator< List* > itCl = cliqueList.begin(); - while (itCl.valid()) - { - delete (*itCl); - itCl++; - }//while - - //debug - //GraphAttributes AG(skeletonG); - //char *ch = new char[50]; - //sprintf(ch, "c:\\temp\\ogdl\\skeleton%d.gml",j++); - //AG.writeGML(ch); - //delete ch - - - }//if - }//forallnodes - -}//docall - -//revisits cliques that are bad candidates and rearranges them, -//using only edges with usableeEdge == true -void CliqueFinder::postProcessCliques( - List< List* > &cliqueList, - EdgeArray &usableEdge) -{ - //TODO:hier aufpassen, das man nicht Knoten ausserhalb des - //R-Knotens nimmt - if (m_postProcess == ppNone) return; - - //------------------------------------------------------ - //we run over all leftover nodes and try to find cliques - List leftOver; - - //list of additional cliques - List< List* > cliqueAdd; - - //----------------------------------- - //First we check the nodes set by the - //heuristic for dense subgraphs - //best would be to reinsert them immediatedly after - //each found subgraph to allow reuse - ListIterator< List* > itCand = cliqueList.begin(); - if (m_density != 100) - while (itCand.valid()) - { - if ((*itCand)->size() > m_minDegree) - { - NodeArray inList(*m_pCopy, false); - ListIterator itNode = (*itCand)->begin(); - while (itNode.valid()) - { - inList[*itNode] = true; - itNode++; - }//while - - itNode = (*itCand)->begin(); - while (itNode.valid()) - { - int adCount = 0; //counts number of nodes adj. to *itNode in itCand - //check if inGraph degree is high enough - //and allow reuse otherwise - adjEntry adE = (*itNode)->firstAdj(); - for (int i = 0; i < (*itNode)->degree(); i++) - { - if (usableEdge[adE->theEdge()]) - { - if (inList[adE->twinNode()]) - adCount++; - } - adE = adE->cyclicSucc(); - }//for - - //now delete nodes if connectivity to small - if (DIsLess(adCount, ceil(((*itCand)->size()-1)*m_density/100.0))) - { - leftOver.pushBack(*itNode); - m_usedNode[*itNode] = false; - inList[*itNode] = false; - ListIterator itDel = itNode; - itNode++; - (*itCand)->del(itDel); - continue; - } - itNode++; - }//while - - }//if - else break; - itCand++; - }//while - - - itCand = cliqueList.begin(); - while (itCand.valid()) - { - if ((*itCand)->size() <= m_minDegree) - { - while (!((*itCand)->empty())) - { - node v = (*itCand)->popFrontRet(); - leftOver.pushBack(v); - m_usedNode[v] = false; - OGDF_ASSERT(!m_usedNode[v]) - OGDF_ASSERT(m_copyCliqueNumber[v] == -1) - }//while nodes - ListIterator< List* > itDel = itCand; - delete (*itDel); - itCand++; - cliqueList.del(itDel);//del - //Todo: remove empty lists here - continue; - }//if - - itCand++; - }//while lists - - //now we have all left over nodes in list leftOver - //vorsicht: wenn wir hier evaluate benutzen, duerfen wir - //nicht Knoten hinzunehmen, die schon in Cliquen benutzt sind - NodeArray value(*m_pCopy); - NodeComparer cmp(value, false); - ListIterator itNode = leftOver.begin(); - while (itNode.valid()) - { - node vVal = (*itNode); - value[vVal] = evaluate(vVal, usableEdge); - itNode++; - }//while - - leftOver.quicksort(cmp); - - //-------------------------------------------------- - //now start a new search at the most qualified nodes - //TODO: Option: wieviele? - itNode = leftOver.begin(); - while (itNode.valid()) - { - //some nodes can already be assigned in earlier iterations - if (m_usedNode[*itNode]) - { - itNode++; - continue; - }//if already used - - //TODO: hier an dense subgraphs anpassen - - //TODO: this is inefficient because we already - //ran through the neighbourhood - //this is the same loop as in evaluate and - //should not be run twice, but its not efficient - //to save the neighbour degree values for every - //run of evaluate - //############################## - NodeArray neighbour(*m_pCopy, false); - NodeArray neighbourDegree(*m_pCopy, 0); - adjEntry adj1; - node v = *itNode; - OGDF_ASSERT(!m_usedNode[v]) - forall_adj(adj1, v) - { - if (!usableEdge[adj1->theEdge()]) continue; - node w = adj1->twinNode(); - if (!m_usedNode[w]) neighbour[w] = true; - }//foralladj - - List *neighbours = new List(); - //this loop counts every triangle (two times) - //TODO: man kann besser oben schon liste neighbours fuellen - //und hier nur noch darueber laufen - forall_adj(adj1, v) - { - //if (!usableEdge[adj1->theEdge()]) continue; - node w = adj1->twinNode(); - //if (m_usedNode[w]) continue; //dont use paths over other cliques - if (!neighbour[w]) continue; - OGDF_ASSERT(!m_usedNode[w]) - adjEntry adj2; - - OGDF_ASSERT(m_copyCliqueNumber[w] == -1) - neighbours->pushBack(w); - neighbourDegree[w]++; //connected to v - - forall_adj(adj2, w) - { - if (!usableEdge[adj2->theEdge()]) continue; - node u = adj2->twinNode(); - if (m_usedNode[u]) continue; //dont use paths over other cliques - if (neighbour[u]) - { - neighbourDegree[w]++; - }//if - }//foralladj - }//foralladj - //############################## - - //--------------------------------------------- - //now we have a (dense) set of nodes and we can - //delete the nodes with the smallest degree up - //to a TODO certain amount - cmp.init(neighbourDegree); - neighbours->quicksort(cmp); - - //neighbours->clear(); - findClique(v, *neighbours); - /* - ListIterator itDense = neighbours->rbegin(); - while (itDense.valid()) - { - //TODO: hier die Bedingung an Dichte statt - //Maximalgrad - //removes all possible but one clique around v - if (neighbourDegree[*itDense] < neighbours->size()) - neighbours->del(itDense); - - - itDense--; - }//while - */ - - //hier noch usenode setzen und startknoten hinzufuegen - //we found a dense subgraph - if (neighbours->size() >= m_minDegree) - { - OGDF_ASSERT(allAdjacent(v, neighbours)) - neighbours->pushFront(v); - - ListIterator itUsed = neighbours->begin(); - while (itUsed.valid()) - { - OGDF_ASSERT(m_usedNode[*itUsed] == false) - //TODO: hier gleich die liste checken - m_usedNode[(*itUsed)] = true; - itUsed++; - }//while - cliqueAdd.pushBack(neighbours); -#ifdef OGDF_DEBUG - OGDF_ASSERT(cliqueOK(neighbours)) -#endif - }//if - else - { - ListIterator itUsed = neighbours->begin(); - while (itUsed.valid()) - { - ListIterator itDel = itUsed; - //delete (*itDel); - itUsed++; - neighbours->del(itDel); - //neighbours->remove(itDel); - }//while - //neighbours->clear(); - delete neighbours; //hier vielleicht clear? - } - - itNode++; - }//while - - cliqueList.conc(cliqueAdd); - -}//postprocess - -int CliqueFinder::evaluate(node v, EdgeArray &usableEdge) -{ - int value = 0; - //Simple version: run through the neighbourhood of - //every node and try to find a triangle path back - //(triangles over neighbours are mandatory for cliques) - //we run through the neighbourhood of v up to depth - //2 and check if we can reach v again - //erst mal die einfache Variante ohne Zwischenspeicherung - //der Ergebnisse fuer andere Knoten - //TODO: Geht das auch effizienter als mit Nodearray? - NodeArray neighbour(*m_pCopy, false); - adjEntry adj1; - forall_adj(adj1, v) - { - if (!usableEdge[adj1->theEdge()]) continue; - node w = adj1->twinNode(); - if (!m_usedNode[w]) neighbour[w] = true; - }//foralladj - - //this loop counts every triangle (twice) - forall_adj(adj1, v) - { - if (!usableEdge[adj1->theEdge()]) continue; - adjEntry adj2; - node w = adj1->twinNode(); - if (m_usedNode[w]) continue; //dont use paths over other cliques - forall_adj(adj2, w) - { - if (!usableEdge[adj2->theEdge()]) continue; - node u = adj2->twinNode(); - if (m_usedNode[u]) continue; //dont use paths over other cliques - if (neighbour[u]) - { - value++; - }//if - }//foralladj - }//foralladj - return value; -}//evaluate - -//searchs for a clique around node v in list neighbours -//runs through list and performs numRandom additional -//random runs, permuting the sequence -//the result is returned in the list neighbours -void CliqueFinder::findClique( - node v, - List &neighbours, - int numRandom) -{ - //TODO:should be realdegree - if (v->degree() < m_minDegree) neighbours.clear(); - List clique; //used to check clique criteria - OGDF_ASSERT(!m_usedNode[v]) - clique.pushBack(v); //mandatory - //we could assume that neighbours are always neighbours - //of v and push the first node. too, here - ListIterator itNode = neighbours.begin(); - while (itNode.valid()) - { - if ( ((*itNode)->degree() < clique.size()) || - ((*itNode)->degree() < m_minDegree) ) - { - ListIterator itDel = itNode; - //delete (*itDel); - itNode++; - neighbours.del(itDel); //remove - - continue; - } - if (allAdjacent((*itNode), &clique)) - { - clique.pushBack((*itNode)); - itNode++; - } - else - { - ListIterator itDel = itNode; - itNode++; - neighbours.del(itDel); - } - - }//while - //we can stop if the degree is smaller than the clique size - int k; - for (k = 0; k & cliqueNum) -{ - //Todo: Assert that cliqueNum is an array on m_pGraph - //set the clique numbers for the original nodes, -1 if not - //member of a clique - node v; - - forall_nodes(v, *m_pGraph) - { - node w = m_pCopy->copy(v); - OGDF_ASSERT(w) - cliqueNum[v] = m_copyCliqueNumber[w]; - - }//forallnodes -}//setresults - -//set results values from copy node lists to original node -void CliqueFinder::setResults(List< List* > &cliqueLists) -{ - if (!m_callByList) return; - if (!m_pList) return; - - //m_pList->clear(); //componentwise - //run through the clique lists - ListIterator< List* > it = cliqueLists.begin(); - while (it.valid()) - { - List l_list; //does this work locally? - //run through the cliques - ListIterator itNode = (*it)->begin(); - while(itNode.valid()) - { - node u = m_pCopy->original((*itNode)); - if (u) - l_list.pushBack(u); - itNode++; - }//while - - m_pList->pushBack(l_list); - it++; - }//while -}//setresults - -//same as above -void CliqueFinder::setResults(List< List > &cliqueLists) -{ - //run through the clique lists - ListIterator< List > it = cliqueLists.begin(); - while (it.valid()) - { - //run through the cliques - ListIterator itNode = (*it).begin(); - while(itNode.valid()) - { - itNode++; - }//while - - it++; - }//while -}//setresults - -//Graph must be parallelfree -//checks if v is adjacent to (min. m_density percent of) all nodes in vList -inline bool CliqueFinder::allAdjacent(node v, List* vList) -{ - int threshold = int(ceil(max(1.0, ceil((vList->size()*m_density/100.0))))); - //we do not want to run into some rounding error if m_density == 100 - if (m_density == 100) {if (v->degree() < vList->size()) return false;} - else if (DIsLess(v->degree(), threshold)) return false; - if (vList->size() == 0) return true; - int adCount = 0; - //Check: can the runtime be improved, e.g. by an adjacency oracle - //or by running degree times through the list? - NodeArray inList(*m_pCopy, false);//(v->graphOf()), false); - ListIterator it = vList->begin(); - while (it.valid()) - { - inList[(*it)] = true; - it++; - }//while - - adjEntry adE = v->firstAdj(); - for (int i = 0; i < v->degree(); i++) - { - if (inList[adE->twinNode()]) - adCount++; - adE = adE->cyclicSucc(); - }//for - - //we do not want to run into some rounding error if m_density == 100 - if (m_density == 100) { if (adCount == vList->size()) return true;} - else if (DIsGreaterEqual(adCount, threshold)) - return true; - - return false; -}//allAdjacent - -//----------------------------------------------------------------------------- -//Debug - -//check - -void CliqueFinder::checkCliques(List< List* > &cliqueList, bool sizeCheck) -{ - //check if size is ok and if all nodes are mutually connected - ListIterator< List* > itList = cliqueList.begin(); - - while (itList.valid()) - { - if (sizeCheck) - { - OGDF_ASSERT((*itList)->size()> m_minDegree) - } - OGDF_ASSERT(cliqueOK((*itList))) - - itList++; - }//while - -}//checkCliques - -bool CliqueFinder::cliqueOK(List *clique) -{ - bool result = true; - NodeArray connect(*m_pCopy, 0); - ListIterator itV = clique->begin(); - - while (itV.valid()) - { - adjEntry adj1; - forall_adj(adj1, (*itV)) - { - connect[adj1->twinNode()]++; - - }//foralladj - itV++; - }//while - itV = clique->begin(); - while (itV.valid()) - { - if (m_density == 100) - { - if (connect[(*itV)] < (clique->size()-1)) - return false; - } - else - { - //due to the current heuristics, we can not guarantee any - //value - //TODO:postprocess and delete all "bad" nodes - //double minVal = (clique->size()-1)*m_density/100.0; - //if (DIsLess(connect[(*itV)], minVal)) - // return false; - } - itV++; - }//while - - return result; -}//cliqueOK - - -//output -#ifdef OGDF_DEBUG -void CliqueFinder::writeGraph(Graph &G, NodeArray &cliqueNumber, const String &fileName) -{ - GraphAttributes AG(G, GraphAttributes::nodeGraphics | GraphAttributes::nodeColor | - GraphAttributes::nodeLabel); - node v; - //char *hexString = new char[7]; - String colorString; - forall_nodes(v, G) - { - colorString = "#"; - char s1[8]; - char s2[8]; - char s3[8]; - int num = cliqueNumber[v]; - int col1, col2, col3; - if (num != -1) - { - col1 = abs(((num * 191) + 123) % 256); - col2 = abs(((num * 131) + 67) % 256); - col3 = abs(((num * 7) + 17) % 256); - } - else col1 = col2 = col3 = 0; - - ogdf::sprintf(s1,8,"%02X",col1);//s1[2] = '0'; - ogdf::sprintf(s2,8,"%02X",col2);//s2[2] = '0'; - ogdf::sprintf(s3,8,"%02X",col3);//s3[2] = '0'; - ////String st1 - colorString+=s1[0];colorString+=s1[1]; - colorString+=s2[0];colorString+=s2[1]; - colorString+=s3[0];colorString+=s3[1]; - AG.colorNode(v) = colorString; - AG.labelNode(v).sprintf("%d", num); - - }//forall_nodes - - AG.writeGML(fileName); - - //delete hexString; -} -#endif - -}//namespace ogdf diff --git a/ext/OGDF/src/basic/CombinatorialEmbedding.cpp b/ext/OGDF/src/basic/CombinatorialEmbedding.cpp deleted file mode 100644 index d344396e0..000000000 --- a/ext/OGDF/src/basic/CombinatorialEmbedding.cpp +++ /dev/null @@ -1,630 +0,0 @@ -/* - * $Revision: 2555 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 12:12:10 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class CombinatorialEmbedding - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -#define MIN_FACE_TABLE_SIZE (1 << 4) - - -namespace ogdf { - -ConstCombinatorialEmbedding::ConstCombinatorialEmbedding() -{ - m_cpGraph = 0; - m_externalFace = 0; - m_nFaces = m_faceIdCount = 0; - m_faceArrayTableSize = MIN_FACE_TABLE_SIZE; -} - - -ConstCombinatorialEmbedding::ConstCombinatorialEmbedding(const Graph &G) : - m_cpGraph(&G), m_rightFace(G,0) -{ - computeFaces(); -} - -ConstCombinatorialEmbedding::ConstCombinatorialEmbedding( - const ConstCombinatorialEmbedding &C) - : m_cpGraph(C.m_cpGraph), m_rightFace(*C.m_cpGraph,0) -{ - computeFaces(); - - if(C.m_externalFace == 0) - m_externalFace = 0; - else - m_externalFace = m_rightFace[C.m_externalFace->firstAdj()]; -} - -ConstCombinatorialEmbedding &ConstCombinatorialEmbedding::operator=( - const ConstCombinatorialEmbedding &C) -{ - init(*C.m_cpGraph); - - if(C.m_externalFace == 0) - m_externalFace = 0; - else - m_externalFace = m_rightFace[C.m_externalFace->firstAdj()]; - - return *this; -} - -void ConstCombinatorialEmbedding::init(const Graph &G) -{ - m_cpGraph = &G; - m_rightFace.init(G,0); - computeFaces(); -} - - -void ConstCombinatorialEmbedding::init() -{ - m_cpGraph = 0; - m_externalFace = 0; - m_nFaces = m_faceIdCount = 0; - m_faceArrayTableSize = MIN_FACE_TABLE_SIZE; - m_rightFace.init(); - m_faces.clear(); - - reinitArrays(); -} - - -void ConstCombinatorialEmbedding::computeFaces() -{ - m_externalFace = 0; // no longer valid! - m_faceIdCount = 0; - m_faces.clear(); - - m_rightFace.fill(0); - - node v; - forall_nodes(v,*m_cpGraph) { - adjEntry adj; - forall_adj(adj,v) { - if (m_rightFace[adj]) continue; - -#ifdef OGDF_DEBUG - face f = OGDF_NEW FaceElement(this,adj,m_faceIdCount++); -#else - face f = OGDF_NEW FaceElement(adj,m_faceIdCount++); -#endif - - m_faces.pushBack(f); - - adjEntry adj2 = adj; - do { - m_rightFace[adj2] = f; - f->m_size++; - adj2 = adj2->faceCycleSucc(); - } while (adj2 != adj); - } - } - - m_nFaces = m_faceIdCount; - m_faceArrayTableSize = Graph::nextPower2(MIN_FACE_TABLE_SIZE,m_faceIdCount); - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -face ConstCombinatorialEmbedding::createFaceElement(adjEntry adjFirst) -{ - if (m_faceIdCount == m_faceArrayTableSize) { - m_faceArrayTableSize <<= 1; - for(ListIterator it = m_regFaceArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_faceArrayTableSize); - } - } - -#ifdef OGDF_DEBUG - face f = OGDF_NEW FaceElement(this,adjFirst,m_faceIdCount++); -#else - face f = OGDF_NEW FaceElement(adjFirst,m_faceIdCount++); -#endif - - m_faces.pushBack(f); - m_nFaces++; - - return f; -} - - -edge CombinatorialEmbedding::split(edge e) -{ - face f1 = m_rightFace[e->adjSource()]; - face f2 = m_rightFace[e->adjTarget()]; - - edge e2 = m_pGraph->split(e); - - m_rightFace[e->adjSource()] = m_rightFace[e2->adjSource()] = f1; - f1->m_size++; - m_rightFace[e->adjTarget()] = m_rightFace[e2->adjTarget()] = f2; - f2->m_size++; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return e2; -} - - -void CombinatorialEmbedding::unsplit(edge eIn, edge eOut) -{ - face f1 = m_rightFace[eIn->adjSource()]; - face f2 = m_rightFace[eIn->adjTarget()]; - - --f1->m_size; - --f2->m_size; - - if (f1->m_adjFirst == eOut->adjSource()) - f1->m_adjFirst = eIn->adjSource(); - - if (f2->m_adjFirst == eIn->adjTarget()) - f2->m_adjFirst = eOut->adjTarget(); - - m_pGraph->unsplit(eIn,eOut); -} - - -node CombinatorialEmbedding::splitNode(adjEntry adjStartLeft, adjEntry adjStartRight) -{ - face fL = leftFace(adjStartLeft); - face fR = leftFace(adjStartRight); - - node u = m_pGraph->splitNode(adjStartLeft,adjStartRight); - - adjEntry adj = adjStartLeft->cyclicPred(); - - m_rightFace[adj] = fL; - ++fL->m_size; - m_rightFace[adj->twin()] = fR; - ++fR->m_size; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return u; -} - - -node CombinatorialEmbedding::contract(edge e) -{ - // Since we remove face e, we also remove adjSrc and adjTgt. - // We make sure that node of them is stored as first adjacency - // entry of a face. - adjEntry adjSrc = e->adjSource(); - adjEntry adjTgt = e->adjTarget(); - - face fSrc = m_rightFace[adjSrc]; - face fTgt = m_rightFace[adjTgt]; - - if(fSrc->m_adjFirst == adjSrc) { - adjEntry adj = adjSrc->faceCycleSucc(); - fSrc->m_adjFirst = (adj != adjTgt) ? adj : adj->faceCycleSucc(); - } - - if(fTgt->m_adjFirst == adjTgt) { - adjEntry adj = adjTgt->faceCycleSucc(); - fTgt->m_adjFirst = (adj != adjSrc) ? adj : adj->faceCycleSucc(); - } - - node v = m_pGraph->contract(e); - --fSrc->m_size; - --fTgt->m_size; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return v; -} - - -edge CombinatorialEmbedding::splitFace(adjEntry adjSrc, adjEntry adjTgt) -{ - OGDF_ASSERT(m_rightFace[adjSrc] == m_rightFace[adjTgt]) - OGDF_ASSERT(adjSrc != adjTgt) - - edge e = m_pGraph->newEdge(adjSrc,adjTgt); - - face f1 = m_rightFace[adjTgt]; - face f2 = createFaceElement(adjSrc); - - adjEntry adj = adjSrc; - do { - m_rightFace[adj] = f2; - f2->m_size++; - adj = adj->faceCycleSucc(); - } while (adj != adjSrc); - - f1->m_adjFirst = adjTgt; - f1->m_size += (2 - f2->m_size); - m_rightFace[e->adjSource()] = f1; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return e; -} - -//special version of the above function doing a pushback of the new edge -//on the adjacency list of v making it possible to insert new degree 0 -//nodes into a face -edge CombinatorialEmbedding::splitFace(node v, adjEntry adjTgt) -{ - adjEntry adjSrc = v->lastAdj(); - edge e = 0; - bool degZ = v->degree() == 0; - if (degZ) { - e = m_pGraph->newEdge(v, adjTgt); - } - else - { - OGDF_ASSERT(m_rightFace[adjSrc] == m_rightFace[adjTgt]) - OGDF_ASSERT(adjSrc != adjTgt) - e = m_pGraph->newEdge(adjSrc,adjTgt); //could use ne(v,ad) here, too - } - - face f1 = m_rightFace[adjTgt]; - //if v already had an adjacent edge, we split the face in two faces - int subSize = 0; - if (!degZ) - { - face f2 = createFaceElement(adjSrc); - - adjEntry adj = adjSrc; - do - { - m_rightFace[adj] = f2; - f2->m_size++; - adj = adj->faceCycleSucc(); - } while (adj != adjSrc); - subSize = f2->m_size; - }//if not zero degree - else - { - m_rightFace[e->adjTarget()] = f1; - } - - f1->m_adjFirst = adjTgt; - f1->m_size += (2 - subSize); - m_rightFace[e->adjSource()] = f1; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return e; -}//splitface -//-- -//----------------- -//incremental stuff -//special version of the above function doing a pushback of the new edge -//on the adjacency list of v making it possible to insert new degree 0 -//nodes into a face, end node v -edge CombinatorialEmbedding::splitFace(adjEntry adjSrc, node v) -{ - adjEntry adjTgt = v->lastAdj(); - edge e = 0; - bool degZ = v->degree() == 0; - if (degZ) - { - e = m_pGraph->newEdge(adjSrc, v); - } - else - { - OGDF_ASSERT(m_rightFace[adjSrc] == m_rightFace[adjTgt]) - OGDF_ASSERT(adjSrc != adjTgt) - e = m_pGraph->newEdge(adjSrc, adjTgt); //could use ne(v,ad) here, too - } - - face f1 = m_rightFace[adjSrc]; - //if v already had an adjacent edge, we split the face in two faces - int subSize = 0; - if (!degZ) - { - face f2 = createFaceElement(adjTgt); - - adjEntry adj = adjTgt; - do - { - m_rightFace[adj] = f2; - f2->m_size++; - adj = adj->faceCycleSucc(); - } while (adj != adjTgt); - subSize = f2->m_size; - }//if not zero degree - else - { - m_rightFace[e->adjSource()] = f1; - } - - f1->m_adjFirst = adjSrc; - f1->m_size += (2 - subSize); - m_rightFace[e->adjTarget()] = f1; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return e; -}//splitface - -//update face information after inserting a merger ith edge e in a copy graph -void CombinatorialEmbedding::updateMerger(edge e, face fRight, face fLeft) -{ - //two cases: a single face/two faces - fRight->m_size++; - fLeft->m_size++; - m_rightFace[e->adjSource()] = fRight; - m_rightFace[e->adjTarget()] = fLeft; - //check for first adjacency entry - if (fRight != fLeft) - { - fRight->m_adjFirst = e->adjSource(); - fLeft->m_adjFirst = e->adjTarget(); - }//if -}//updateMerger - -//-- - - -face CombinatorialEmbedding::joinFaces(edge e) -{ - OGDF_ASSERT(e->graphOf() == m_pGraph); - - // get the two faces adjacent to e - face f1 = m_rightFace[e->adjSource()]; - face f2 = m_rightFace[e->adjTarget()]; - - OGDF_ASSERT(f1 != f2); - - // we will reuse the largest face and delete the other one - if (f2->m_size > f1->m_size) - swap(f1,f2); - - // the size of the joined face is the sum of the sizes of the two faces - // f1 and f2 minus the two adjacency entries of e - f1->m_size += f2->m_size - 2; - - // If the stored (first) adjacency entry of f1 belongs to e, we must set - // it to the next entry in the face, because we will remove it by deleting - // edge e - if (f1->m_adjFirst->theEdge() == e) - f1->m_adjFirst = f1->m_adjFirst->faceCycleSucc(); - - // each adjacency entry in f2 belongs now to f1 - adjEntry adj1 = f2->firstAdj(), adj = adj1; - do { - m_rightFace[adj] = f1; - } while((adj = adj->faceCycleSucc()) != adj1); - - m_pGraph->delEdge(e); - - m_faces.del(f2); - --m_nFaces; - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return f1; -} - - -void CombinatorialEmbedding::reverseEdge(edge e) -{ - // reverse edge in graph - m_pGraph->reverseEdge(e); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -void CombinatorialEmbedding::moveBridge(adjEntry adjBridge, adjEntry adjBefore) -{ - OGDF_ASSERT(m_rightFace[adjBridge] == m_rightFace[adjBridge->twin()]); - OGDF_ASSERT(m_rightFace[adjBridge] != m_rightFace[adjBefore]); - - face fOld = m_rightFace[adjBridge]; - face fNew = m_rightFace[adjBefore]; - - adjEntry adjCand = adjBridge->faceCycleSucc(); - - int sz = 0; - adjEntry adj; - for(adj = adjBridge->twin(); adj != adjCand; adj = adj->faceCycleSucc()) { - if(fOld->m_adjFirst == adj) - fOld->m_adjFirst = adjCand; - m_rightFace[adj] = fNew; - ++sz; - } - - fOld->m_size -= sz; - fNew->m_size += sz; - - edge e = adjBridge->theEdge(); - if(e->source() == adjBridge->twinNode()) - m_pGraph->moveSource(e, adjBefore, after); - else - m_pGraph->moveTarget(e, adjBefore, after); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -void CombinatorialEmbedding::removeDeg1(node v) -{ - OGDF_ASSERT(v->degree() == 1); - - adjEntry adj = v->firstAdj(); - face f = m_rightFace[adj]; - - if(f->m_adjFirst == adj || f->m_adjFirst == adj->twin()) - f->m_adjFirst = adj->faceCycleSucc(); - f->m_size -= 2; - - m_pGraph->delNode(v); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -void CombinatorialEmbedding::clear() -{ - m_pGraph->clear(); - - m_faces.clear(); - - m_nFaces = m_faceIdCount = 0; - m_faceArrayTableSize = MIN_FACE_TABLE_SIZE; - m_externalFace = 0; - - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -face ConstCombinatorialEmbedding::chooseFace() const -{ - if (m_nFaces == 0) return 0; - - int k = ogdf::randomNumber(0,m_nFaces-1); - face f = firstFace(); - while(k--) f = f->succ(); - - return f; -} - - -face ConstCombinatorialEmbedding::maximalFace() const -{ - if (m_nFaces == 0) return 0; - - face fMax = firstFace(); - int max = fMax->size(); - - for(face f = fMax->succ(); f != 0; f = f->succ()) - { - if (f->size() > max) { - max = f->size(); - fMax = f; - } - } - - return fMax; -} - - -ListIterator ConstCombinatorialEmbedding:: - registerArray(FaceArrayBase *pFaceArray) const -{ - return m_regFaceArrays.pushBack(pFaceArray); -} - - -void ConstCombinatorialEmbedding::unregisterArray( - ListIterator it) const -{ - m_regFaceArrays.del(it); -} - - -void ConstCombinatorialEmbedding::reinitArrays() -{ - ListIterator it = m_regFaceArrays.begin(); - for(; it.valid(); ++it) - (*it)->reinit(m_faceArrayTableSize); -} - - -bool ConstCombinatorialEmbedding::consistencyCheck() -{ - if (m_cpGraph->consistencyCheck() == false) - return false; - - if(m_cpGraph->representsCombEmbedding() == false) - return false; - - AdjEntryArray visited(*m_cpGraph,false); - int nF = 0; - - face f; - forall_faces(f,*this) { -#ifdef OGDF_DEBUG - if (f->embeddingOf() != this) - return false; -#endif - - nF++; - - adjEntry adj = f->firstAdj(), adj2 = adj; - int sz = 0; - do { - sz++; - if (visited[adj2] == true) - return false; - - visited[adj2] = true; - - if (m_rightFace[adj2] != f) - return false; - - adj2 = adj2->faceCycleSucc(); - } while(adj2 != adj); - - if (f->size() != sz) - return false; - } - - if (nF != m_nFaces) - return false; - - node v; - forall_nodes(v,*m_cpGraph) { - adjEntry adj; - forall_adj(adj,v) { - if (visited[adj] == false) - return false; - } - } - - return true; -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/Constraint.cpp b/ext/OGDF/src/basic/Constraint.cpp deleted file mode 100644 index 022fda814..000000000 --- a/ext/OGDF/src/basic/Constraint.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class Constraint, which is a base - * class for classes responsible for specifying and storing - * drawing constraints. - * - * \author PG478 - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "ogdf/basic/Constraints.h" -#include -#include - - -namespace ogdf { - - -bool Constraint::buildFromOgml(XmlTagObject* constraintTag, Hashing * nodes) -{ - return true; -} - -bool Constraint::storeToOgml(int id, ostream & os, int indentStep) -{ - return true; -} - -/* -void Constraint::generateIndent(char ** indent, const int & indentSize) -{ - // free memory block (INFO: indent must point to an array of chars or to NULL) - delete [] *indent; - // instantiate array of chars - *indent = new char[indentSize + 1]; - // if memory couldn't be allocated, we throw an exception - if (!*indent) { - OGDF_THROW(InsufficientMemoryException); // don't use regular throw! - } - // fill char array - for(int i = 0; i < indentSize; ++i) { - (*indent)[i] = INDENTCHAR; - } - // terminate string - (*indent)[indentSize] = '\0'; -}*/ - -} //end namespace ogdf diff --git a/ext/OGDF/src/basic/ConstraintManager.cpp b/ext/OGDF/src/basic/ConstraintManager.cpp deleted file mode 100644 index 50205bb6d..000000000 --- a/ext/OGDF/src/basic/ConstraintManager.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class ConstraintManager that handles - * drawing constraints. - * - * \author PG478 - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//#include -#include -//#include -//#include -//#include - -namespace ogdf { - -Constraint *ConstraintManager::createConstraintByName(const Graph &G, String *name) -{ -// if ((*name) == "Anchor") return new AnchorConstraint(G); else -// if ((*name) == "Alignment") return new AlignmentConstraint(G,0.0); else -// if ((*name) == "Sequence") return new SequenceConstraint(G,true); else - return NULL; -} - -String ConstraintManager::getClassnameOfConstraint(Constraint *c) { -// if (c->getType()==AnchorConstraint::getStaticType()) return "Anchor"; -// if (c->getType()==AlignmentConstraint::getStaticType()) return "Alignment"; -// if (c->getType()==SequenceConstraint::getStaticType()) return "Sequence"; - return ""; -} - -} diff --git a/ext/OGDF/src/basic/DisjointSets.cpp b/ext/OGDF/src/basic/DisjointSets.cpp deleted file mode 100644 index 0a6e779c6..000000000 --- a/ext/OGDF/src/basic/DisjointSets.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of disjoint sets data structures (union-find functionality). - * - * \author Andrej Dudenhefner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - -const char *linkOptionNames[] = {"Naive Link","Link by Index","Link by Size","Link by Rank"}; -const char *compressionOptionNames[] = {"Path Compression","Path Splitting","Path Halving","Reversal of Type 0","Reversal of Type 1","Collapsing","No Compression"}; -const char *interleavingOptionNames[] = {"No Interleavintg","Rem Splicing","Tarjan and van Leeuwen","Interleaved Reversal of Type 0", "Interleaved Path Splitting Path Compression"}; - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/DualGraph.cpp b/ext/OGDF/src/basic/DualGraph.cpp deleted file mode 100644 index e656e7bd8..000000000 --- a/ext/OGDF/src/basic/DualGraph.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of dual graph - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf{ - -// Computes combinatorial embedding of dual graph -// Precondition: CE must be combinatorial embedding of connected planar graph -DualGraph::DualGraph(CombinatorialEmbedding &CE) -{ - m_primalEmbedding = &CE; - Graph &primalGraph = CE.getGraph(); - init(*(new Graph)); - Graph &dualGraph = getGraph(); - - m_dualNode.init(CE); - m_dualEdge.init(primalGraph); - m_dualFace.init(primalGraph); - m_primalNode.init(*this); - m_primalFace.init(dualGraph); - m_primalEdge.init(dualGraph); - - // create dual nodes - face f; - forall_faces(f, CE) - { - node vDual = dualGraph.newNode(); - m_dualNode[f] = vDual; - m_primalFace[vDual] = f; - } - - // create dual edges - edge e; - forall_edges(e, primalGraph) - { - adjEntry aE = e->adjSource(); - node vDualSource = m_dualNode[CE.rightFace(aE)]; - node vDualTarget = m_dualNode[CE.leftFace(aE)]; - edge eDual = dualGraph.newEdge(vDualSource, vDualTarget); - m_primalEdge[eDual] = e; - m_dualEdge[e] = eDual; - } - - // sort adjElements of every dual node corresponding to dual embedding - EdgeArray visited(dualGraph, false); // needed for self-loops - forall_faces(f, CE) - { - node vDual = m_dualNode[f]; - adjEntry aePrimal = f->firstAdj(); - List aeList; - do - { - edge eDual = m_dualEdge[aePrimal->theEdge()]; - adjEntry aeDual = eDual->adjSource(); - if((aeDual->theNode()!=vDual) || (eDual->isSelfLoop() && visited[eDual])) - aeDual = eDual->adjTarget(); - aeList.pushBack( aeDual ); - visited[eDual] = true; // only needed for self-loops - aePrimal = aePrimal->faceCycleSucc(); - } - while(aePrimal != f->firstAdj()); - dualGraph.sort(vDual, aeList); - } - - // calculate dual faces and links to corresponding primal nodes - computeFaces(); - node v; - forall_nodes(v, primalGraph) - { - edge ePrimal = v->firstAdj()->theEdge(); - edge eDual = m_dualEdge[ePrimal]; - face fDual = rightFace(eDual->adjSource()); - if(ePrimal->source()==v) - fDual = leftFace(eDual->adjSource()); - m_dualFace[v] = fDual; - m_primalNode[fDual] = v; - } -} - -// Destructor -DualGraph::~DualGraph() -{ - clear(); - delete m_cpGraph; -} - -} diff --git a/ext/OGDF/src/basic/EdgeComparer.cpp b/ext/OGDF/src/basic/EdgeComparer.cpp deleted file mode 100644 index 3ed68daa0..000000000 --- a/ext/OGDF/src/basic/EdgeComparer.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of EdgeComparer. - * - * Compare edges on base of node layout position, - * clockwise ordering - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - - -//compares outgoing adjEntries -int EdgeComparer::compare(const adjEntry &e1, const adjEntry &e2) const -{ - //identify if the edges meet at a common point, otherwise - //sort by index (stable) - //are the adjentries sourceentries (edges outgoing) ? - bool sAdj1 = (e1 == e1->theEdge()->adjSource()); - bool sAdj2 = (e2 == e2->theEdge()->adjSource()); - //generic nodes/edges - node s1 = (m_PR ? m_PR->original(e1->theNode()) : e1->theNode()); - node s2 = (m_PR ? m_PR->original(e2->theNode()) : e2->theNode()); - edge ed1 = (m_PR ? m_PR->original(e1->theEdge()) : e1->theEdge()); - edge ed2 = (m_PR ? m_PR->original(e2->theEdge()) : e2->theEdge()); - node t1 = (m_PR ? m_PR->original(e1->twinNode()) : e1->twinNode()); - node t2 = (m_PR ? m_PR->original(e2->twinNode()) : e2->twinNode()); - - //a: adjentry node(s) - //b: twin nodes - - double x1a, x1b, x2a, x2b, y1a, y1b, y2a, y2b; - - //debug stuff - //bool output = false; - //if ( ( (s1->degree() == 5) || (s2->degree() == 5)) && - // ( (m_AG->type(ed1)== Graph::generalization) || - // (m_AG->type(ed2)== Graph::generalization))) - //{ - // output = true; - //} - - x1a = m_AG->x(s1); - x2a = m_AG->x(s2); - y1a = m_AG->y(s1); - y2a = m_AG->y(s2); - - - //meet check not yet implemented, assume same start point - OGDF_ASSERT(!((!DIsEqual(x1a,x2a)) && (!(DIsEqual(y1a,y2a)))) || (s1 != s2)) - - //check if we have bends without representation node - //use them as second end point - const DPolyline &bends1 = m_AG->bends(ed1); - const DPolyline &bends2 = m_AG->bends(ed2); - - ListConstIterator it1; - ListConstIterator it2; - - bool hasBends1 = bends1.size() > 0; - bool hasBends2 = bends2.size() > 0; - - if (hasBends1) - { - if (sAdj1) - it1 = bends1.begin(); - else it1 = bends1.rbegin(); - - x1b = (*it1).m_x; - y1b = (*it1).m_y; - } - else - { - x1b = m_AG->x(t1); - y1b = m_AG->y(t1); - } - if (hasBends2) - { - if (sAdj2) - it2 = bends2.begin(); - else it2 = bends2.rbegin(); - - x2b = (*it2).m_x; - y2b = (*it2).m_y; - } - else - { - x2b = m_AG->x(t2); - y2b = m_AG->y(t2); - } - //special condition: if we have parallel segments, e.g. merger edges, - //we don't use the bend position - if (hasBends1 && hasBends2) - { - bool end1 = false; - //try to run over the bends / edge endpoint to differing points - while ( (x1b == x2b) && (y1b == y2b) && (x1a == x2a) && (y1a == y2a) ) - { - //move one step further - if (it1.valid()) - { - if (sAdj1) it1++; - else it1--; - } - if (it2.valid()) - { - if (sAdj2) it2++; - else it2--; - } - - if (it1.valid()) - { - x1b = (*it1).m_x; - y1b = (*it1).m_y; - } - else - { - x1b = m_AG->x(t1); - y1b = m_AG->y(t1); - end1 = true; - } - if (it2.valid()) - { - x2b = (*it2).m_x; - y2b = (*it2).m_y; - } - else - { - x2b = m_AG->x(t2); - y2b = m_AG->y(t2); - //stop searching at both endpoints - if (end1) break; - } - }//while same endpoints - } - - //now we have all the points necessary to sort - //double dx1, dx2, dy1, dy2; - //dx1 = x1b - x1a; - //dx2 = x2b - x2a; - //dy1 = y1b - y1a; - //dy2 = y2b - y2a; - - //debug - /* - ofstream f("c:\\Temp\\Karsten\\ASorting.txt", ios::app); - - f << "\nEntries at node: " << s1->index() <<"\n"; - f << "Compare " << s1->index() <<"->"<index() << " " <type(ed1)<<" , \n" - << s2->index() <<"->"<index() << " " <type(ed1)<< "\n"; - - f << "Resultat: "<<-orientation(DPoint(x1a, y1a), - DPoint(x1b, y1b), - DPoint(x2b, y2b)) << "\n"; - */ - - //hier rueckgabe Vergleich e1->id, e2->id, falls nicht selber knoten - //... - //clockwise ist -, counterclockwise ist + - //in AGD alle +! - //return -compareVectors(dx1, dy1, dx2, dy2); - //HIER fuer debuggen -davor - - if (s1 == s2) - { - node uvw = s1->firstAdj()->twinNode(); - edge ed3 = s1->firstAdj()->theEdge(); - const DPolyline &bends3 = m_AG->bends(ed3); - DPoint dp; - //as we use different comparison points for edges - //at different compares, we have to assure that - //we always have the same position of a edge's comparison - //point compared to our reference vector - // - // - // xxxxxxx - // | | |l l = Mess-Vektor - // x | x l - // | l - // |-------o - //-- - //workaround: wir kreisen, bis wir nicht auf einer Generalisierung - //liegen. Das muss nicht immer moeglich sein und selbst dann koennen - //Assoziationen uebereinander liegen. - //Oder: Wir gehen immer bis zum zweiten Knick (immer diff bei merger) - if (bends3.size()>0) - { - if (bends3.size()>1) - { - ListConstIterator itb; - if (s1->firstAdj()==ed3->adjSource()) - { - itb = bends3.begin(); - itb++; - dp = (*itb); - } - else - { - itb = bends3.rbegin(); - itb--; - dp = (*itb); - } - }//if >= 2 bends, e.g. merger - else - { - if (s1->firstAdj()==ed3->adjSource()) - dp = bends3.front(); - else dp = bends3.back(); - } - } - //-- - else - dp = DPoint(m_AG->x(uvw)-2, m_AG->y(uvw)+1); - double w1 = angle(DPoint(x1a, y1a), dp, DPoint(x1b, y1b)); - double w2 = angle(DPoint(x1a, y1a), dp, DPoint(x2b, y2b)); - OGDF_ASSERT(w1 >= 0 && (w2 >= 0)) - - //workaround shortcut (can be inserted above) - if (ed1 == ed3) - return 1; //Reference edge is first edge - if (ed2 == ed3) - return -1; - -/*debug stuff - if (output) - { - ofstream fout("c:\\temp\\ogdl\\EComp.txt",ios::app); - fout << "Knoten an Position "<type(ed1)<< - " Winkel: "<type(ed2)<< - " Winkel: "<w2?"NEIN":"Vielleicht")) <<"\n"; - - }//output -*/ - if (w1 < w2) - return 1; - else if (w1 > w2) return -1; - else return 0; - } - else return orientation(DPoint(x1a, y1a), - DPoint(x1b, y1b), - DPoint(x2b, y2b)) ; -}//compare - - -bool EdgeComparer::before(const DPoint u, const DPoint v, const DPoint w) const -{ - /* - double dx1 = v.m_x - u.m_x; - double dx2 = w.m_x - u.m_x; - double dy1 = v.m_y - u.m_y; - double dy2 = w.m_y - u.m_y; - - return (compareVectors(dx1, dy1, dx2, dy2) < 0); - */ - return orientation(u, v, w) > 0; -} -//orientation of two vectors uv, uw: -//does v lie to the left of the line through u and w? -//returns 1 if v lies to the left, -1 if to the right -//and 0 if the points are colinear -//Is based on the sign of the determinant of a matrix -//defined by the point coordinates -//respects the flipping of y axis!! -//TODO: shift into geometric -int EdgeComparer::orientation( - const DPoint u, - const DPoint v, - const DPoint w) const -{ - double plus1 = v.m_x*w.m_y; - double plus2 = w.m_x*u.m_y; - double plus3 = u.m_x*v.m_y; - double minus1 = v.m_x*u.m_y; - double minus2 = w.m_x*v.m_y; - double minus3 = u.m_x*w.m_y; - - double E = plus1 + plus2 + plus3 - minus1 - minus2 - minus3; - - if ( E > 0 ) return 1; - if ( E < 0 ) return -1; - return 0; - -}//orientation - - -//counterclockwise with respect to their angle to the x-axis -int EdgeComparer::compareVectors(const double& x1, - const double& y1, - const double& x2, - const double& y2) const -{ - if (x1 == x2 && y1 == y2) return 0; - if (x1 == 0 && y1 == 0) return -1; - if (x2 == 0 && y2 == 0) return +1; - // vectors are distinct and non-zero - - int sy1 = signOf(y1); int sy2 = signOf(y2); - - int upper1 = ( sy1 != 0 ? sy1 : signOf(x1) ); - int upper2 = ( sy2 != 0 ? sy2 : signOf(x2) ); - - if ( upper1 == upper2 ) return signOf(x2*y1 - x1*y2); - - return upper2 - upper1; -}//comparevectors - - -//computes angle between vectors -double EdgeComparer::angle(DPoint p, DPoint q, DPoint r) const -{ - double dx1 = q.m_x - p.m_x, dy1 = q.m_y - p.m_y; - double dx2 = r.m_x - p.m_x, dy2 = r.m_y - p.m_y; - - //two vertices on the same place! - if ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)) - return 0.0; - - double norm = (dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2); - - double cosphi = (dx1*dx2+dy1*dy2) / sqrt(norm); - - if (cosphi >= 1.0 ) return 0; if (cosphi <= -1.0 ) return Math::pi; - - double phi = acos(cosphi); - - if (dx1*dy2 < dy1*dx2) phi = -phi; - - if (phi < 0) phi += 2*Math::pi; - - return phi; -}//angle - - - -}//namespace ogdf diff --git a/ext/OGDF/src/basic/EdgeComparerSimple.cpp b/ext/OGDF/src/basic/EdgeComparerSimple.cpp deleted file mode 100644 index 687ebdeef..000000000 --- a/ext/OGDF/src/basic/EdgeComparerSimple.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of EdgeComparerSimple. - * - * Compare incident edges of a node based on the position of - * the last bend point or the position of the adjacent node - * given by the GraphAttributes - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -namespace ogdf { - - -int EdgeComparerSimple::compare(const adjEntry &e1, const adjEntry &e2) const -{ - // set true if the algorithm should consider the bend-points - bool useBends = true; - - double xP1, xP2, yP1, yP2; - - DPolyline poly = m_AG->bends(e1->theEdge()); - ListIterator it; - DPoint pE1, pE2; - - if ((useBends) && (poly.size() > 2)){ - it = poly.begin(); - - while (it.valid()){ - it++; - } - - if (e1->theEdge()->source() == basis){ - it = poly.begin(); - it++; - } - else{ - it = poly.rbegin(); - it--; - } - pE1 = *it; - } - else{ - pE1.m_x = m_AG->x((e1->twinNode())); - pE1.m_y = m_AG->y((e1->twinNode())); - } - - poly = m_AG->bends(e2->theEdge()); - if ((useBends) && (poly.size() > 2)){ - it = poly.begin(); - - while (it.valid()){ - it++; - } - - if (e2->theEdge()->source() == basis){ - it = poly.begin(); - it++; - } - else{ - it = poly.rbegin(); - it--; - } - pE2 = *it; - } - else{ - pE2.m_x = m_AG->x((e2->twinNode())); - pE2.m_y = m_AG->y((e2->twinNode())); - } - - - xP1 = -(m_AG->x(basis)) + (pE1.m_x); - yP1 = -(m_AG->y(basis)) + (pE1.m_y); - - xP2 = -(m_AG->x(basis)) + (pE2.m_x); - yP2 = -(m_AG->y(basis)) + (pE2.m_y); - - if ((yP1 >= 0) && (yP2 < 0)) - return 1; - if ((yP1 < 0) && (yP2 >= 0)) - return -1; - if ((yP1 >= 0) && (yP2 >= 0)){ - - if ((xP1 >= 0) && (xP2 < 0)) - return -1; - if ((xP1 < 0) && (xP2 >= 0)) - return 1; - - xP1 = xP1 / (sqrt(xP1*xP1 + yP1*yP1)); - xP2 = xP2 / (sqrt(xP2*xP2 + yP2*yP2)); - if (xP1 > xP2) - return -1; - else - return 1; - } - if ((yP1 < 0) && (yP2 < 0)){ - - if ((xP1 >= 0) && (xP2 < 0)) - return 1; - if ((xP1 < 0) && (xP2 >= 0)) - return -1; - - xP1 = xP1 / (sqrt(xP1*xP1 + yP1*yP1)); - xP2 = xP2 / (sqrt(xP2*xP2 + yP2*yP2)); - if (xP1 > xP2) - return 1; - else - return -1; - } - - return 0; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/basic/Graph.cpp b/ext/OGDF/src/basic/Graph.cpp deleted file mode 100644 index a84745005..000000000 --- a/ext/OGDF/src/basic/Graph.cpp +++ /dev/null @@ -1,1481 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Graph class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - - -#define MIN_NODE_TABLE_SIZE (1 << 4) -#define MIN_EDGE_TABLE_SIZE (1 << 4) - - -namespace ogdf { - -Graph::Graph() -{ - m_nNodes = m_nEdges = m_nodeIdCount = m_edgeIdCount = 0; - m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE; - m_edgeArrayTableSize = MIN_EDGE_TABLE_SIZE; -} - - -Graph::Graph(const Graph &G) -{ - m_nNodes = m_nEdges = m_nodeIdCount = m_edgeIdCount = 0; - copy(G); - m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE,m_nodeIdCount); - m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE,m_edgeIdCount); -} - - -Graph::~Graph() -{ - ListIterator itVNext; - for(ListIterator itV = m_regNodeArrays.begin(); - itV.valid(); itV = itVNext) - { - itVNext = itV.succ(); - (*itV)->disconnect(); - } - - ListIterator itENext; - for(ListIterator itE = m_regEdgeArrays.begin(); - itE.valid(); itE = itENext) - { - itENext = itE.succ(); - (*itE)->disconnect(); - } - - ListIterator itAdjNext; - for(ListIterator itAdj = m_regAdjArrays.begin(); - itAdj.valid(); itAdj = itAdjNext) - { - itAdjNext = itAdj.succ(); - (*itAdj)->disconnect(); - } - - for (node v = m_nodes.begin(); v; v = v->succ()) { - v->m_adjEdges.~GraphList(); - } -} - - -Graph &Graph::operator=(const Graph &G) -{ - clear(); copy(G); - m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE,m_nodeIdCount); - m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE,m_edgeIdCount); - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return *this; -} - - -void Graph::assign(const Graph &G, NodeArray &mapNode, - EdgeArray &mapEdge) -{ - clear(); - copy(G,mapNode,mapEdge); - m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE,m_nodeIdCount); - m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE,m_edgeIdCount); - reinitArrays(); -} - - -void Graph::construct(const Graph &G, NodeArray &mapNode, - EdgeArray &mapEdge) -{ - copy(G,mapNode,mapEdge); - m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE,m_nodeIdCount); - m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE,m_edgeIdCount); -} - - -void Graph::copy(const Graph &G, NodeArray &mapNode, - EdgeArray &mapEdge) -{ - if (G.m_nNodes == 0) return; - - mapNode.init(G,0); - - node vG; - forall_nodes(vG,G) { - node v = mapNode[vG] = pureNewNode(); - v->m_indeg = vG->m_indeg; - v->m_outdeg = vG->m_outdeg; - } - - if (G.m_nEdges == 0) return; - - mapEdge.init(G,0); - - edge e, eC; - forall_edges(e,G) { - m_edges.pushBack(eC = mapEdge[e] = - OGDF_NEW EdgeElement( - mapNode[e->source()],mapNode[e->target()],m_edgeIdCount)); - - eC->m_adjSrc = OGDF_NEW AdjElement(eC,m_edgeIdCount<<1); - (eC->m_adjTgt = OGDF_NEW AdjElement(eC,(m_edgeIdCount<<1)|1)) - ->m_twin = eC->m_adjSrc; - eC->m_adjSrc->m_twin = eC->m_adjTgt; - m_edgeIdCount++; - } - m_nEdges = G.m_nEdges; - - EdgeArray mark(G,false); - - forall_nodes(vG,G) { - node v = mapNode[vG]; - GraphList &adjEdges = vG->m_adjEdges; - for (AdjElement *adjG = adjEdges.begin(); adjG; adjG = adjG->succ()) { - int id = adjG->m_edge->index(); - edge eC = mapEdge[id]; - - adjEntry adj; - if (eC->isSelfLoop()) { - if (mark[id]) - adj = eC->m_adjTgt; - else { - adj = eC->m_adjSrc; - mark[id] = true; - } - } else - adj = (v == eC->m_src) ? eC->m_adjSrc : eC->m_adjTgt; - - v->m_adjEdges.pushBack(adj); - adj->m_node = v; - } - } -} - - -void Graph::copy(const Graph &G) -{ - NodeArray mapNode; - EdgeArray mapEdge; - copy(G,mapNode,mapEdge); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -void Graph::constructInitByNodes( - const Graph &G, - const List &nodes, - NodeArray &mapNode, - EdgeArray &mapEdge) -{ - // clear - for (node v = m_nodes.begin(); v; v = v->succ()) { - v->m_adjEdges.~GraphList(); - } - - m_nodes.clear(); - m_edges.clear(); - - m_nNodes = m_nEdges = m_nodeIdCount = m_edgeIdCount = 0; - m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE; - - - // list of edges adjacent to nodes in nodes - SListPure edges; - - // create nodes and assemble list of edges - ListConstIterator itG; - for(itG = nodes.begin(); itG.valid(); ++itG) { - node vG = *itG; - node v = mapNode[vG] = pureNewNode(); - - v->m_indeg = vG->m_indeg; - v->m_outdeg = vG->m_outdeg; - - adjEntry adjG; - forall_adj(adjG,vG) { - // corresponding adjacency entries differ by index modulo 2 - // the following conditions makes sure that each edge is - // added only once to edges - if ((adjG->m_id & 1) == 0) - edges.pushBack(adjG->m_edge); - } - } - - // create edges - SListConstIterator it; - for(it = edges.begin(); it.valid(); ++it) - { - edge eG = *it; - node v = mapNode[eG->source()]; - node w = mapNode[eG->target()]; - - edge eC = mapEdge[eG] = OGDF_NEW EdgeElement(v, w, m_edgeIdCount); - m_edges.pushBack(eC); - - eC->m_adjSrc = OGDF_NEW AdjElement(eC, m_edgeIdCount<<1); - (eC->m_adjTgt = OGDF_NEW AdjElement(eC, (m_edgeIdCount<<1)|1)) - ->m_twin = eC->m_adjSrc; - eC->m_adjSrc->m_twin = eC->m_adjTgt; - ++m_edgeIdCount; - ++m_nEdges; - } - - EdgeArray mark(G,false); - for(itG = nodes.begin(); itG.valid(); ++itG) { - node vG = *itG; - node v = mapNode[vG]; - - GraphList &adjEdges = vG->m_adjEdges; - for (AdjElement *adjG = adjEdges.begin(); adjG; adjG = adjG->succ()) { - int id = adjG->m_edge->index(); - edge eC = mapEdge[id]; - - adjEntry adj; - if (eC->isSelfLoop()) { - if (mark[id]) - adj = eC->m_adjTgt; - else { - adj = eC->m_adjSrc; - mark[id] = true; - } - } else - adj = (v == eC->m_src) ? eC->m_adjSrc : eC->m_adjTgt; - - v->m_adjEdges.pushBack(adj); - adj->m_node = v; - } - } - -/* - AdjElement *adjSrc = OGDF_NEW AdjElement(v); - - v->m_adjEdges.pushBack(adjSrc); - //v->m_outdeg++; - - AdjElement *adjTgt = OGDF_NEW AdjElement(w); - - w->m_adjEdges.pushBack(adjTgt); - //w->m_indeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - adjTgt->m_id = (adjSrc->m_id = m_edgeIdCount << 1) | 1; - edge e = OGDF_NEW EdgeElement(v,w,adjSrc,adjTgt,m_edgeIdCount++); - - ++m_nEdges; - m_edges.pushBack(e); - - mapEdge[eG] = adjSrc->m_edge = adjTgt->m_edge = e; - }*/ - - // set size of associated arrays and reinitialize all (we have now a - // completely new graph) - m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE,m_nodeIdCount); - m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE,m_edgeIdCount); - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -//------------------ -//mainly a copy of the above code, remerge this again -void Graph::constructInitByActiveNodes( - const List &nodes, - const NodeArray &activeNodes, - NodeArray &mapNode, - EdgeArray &mapEdge) -{ - // clear - for (node v = m_nodes.begin(); v; v = v->succ()) { - v->m_adjEdges.~GraphList(); - } - - m_nodes.clear(); - m_edges.clear(); - - m_nNodes = m_nEdges = m_nodeIdCount = m_edgeIdCount = 0; - m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE; - - - // list of edges adjacent to nodes in nodes - SListPure edges; - - // create nodes and assemble list of edges - //NOTE: nodes is a list of ACTIVE nodes - ListConstIterator itG; - for(itG = nodes.begin(); itG.valid(); ++itG) { - node vG = *itG; - node v = mapNode[vG] = pureNewNode(); - - //we cannot assign the original degree, as there - //may be edges to non-active nodes - //v->m_indeg = vG->m_indeg; - //v->m_outdeg = vG->m_outdeg; - - int inCount = 0; - int outCount = 0; - adjEntry adjG; - forall_adj(adjG,vG) - { - // coresponding adjacency entries differ by index modulo 2 - // the following conditions makes sure that each edge is - // added only once to edges - if (activeNodes[adjG->m_edge->opposite(vG)]) - { - if ((adjG->m_id & 1) == 0) - { - edges.pushBack(adjG->m_edge); - }//if one time - if (adjG->m_edge->source() == vG) outCount++; - else inCount++; - }//if opposite active - }//foralladj - v->m_indeg = inCount; - v->m_outdeg = outCount; - }//for nodes - - // create edges - SListConstIterator it; - for(it = edges.begin(); it.valid(); ++it) - { - edge eG = *it; - node v = mapNode[eG->source()]; - node w = mapNode[eG->target()]; - - AdjElement *adjSrc = OGDF_NEW AdjElement(v); - - v->m_adjEdges.pushBack(adjSrc); - //v->m_outdeg++; - - AdjElement *adjTgt = OGDF_NEW AdjElement(w); - - w->m_adjEdges.pushBack(adjTgt); - //w->m_indeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - adjTgt->m_id = (adjSrc->m_id = m_edgeIdCount << 1) | 1; - edge e = OGDF_NEW EdgeElement(v,w,adjSrc,adjTgt,m_edgeIdCount++); - - ++m_nEdges; - m_edges.pushBack(e); - - mapEdge[eG] = adjSrc->m_edge = adjTgt->m_edge = e; - } - - // set size of associated arrays and reinitialize all (we have now a - // completely new graph) - m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE,m_nodeIdCount); - m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE,m_edgeIdCount); - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -}//constructinitbyactivenodes - -//------------------ - - - -node Graph::newNode() -{ - ++m_nNodes; - if (m_nodeIdCount == m_nodeArrayTableSize) { - m_nodeArrayTableSize <<= 1; - for(ListIterator it = m_regNodeArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_nodeArrayTableSize); - } - } - -#ifdef OGDF_DEBUG - node v = OGDF_NEW NodeElement(this,m_nodeIdCount++); -#else - node v = OGDF_NEW NodeElement(m_nodeIdCount++); -#endif - - m_nodes.pushBack(v); - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->nodeAdded(v); - - return v; -} - - -//what about negative index numbers? -node Graph::newNode(int index) -{ - ++m_nNodes; - - if(index >= m_nodeIdCount) { - m_nodeIdCount = index+1; - - if(index >= m_nodeArrayTableSize) { - m_nodeArrayTableSize = nextPower2(m_nodeArrayTableSize,index); - for(ListIterator it = m_regNodeArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_nodeArrayTableSize); - } - } - } - -#ifdef OGDF_DEBUG - node v = OGDF_NEW NodeElement(this,index); -#else - node v = OGDF_NEW NodeElement(index); -#endif - - m_nodes.pushBack(v); - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->nodeAdded(v); - return v; -} - - -node Graph::pureNewNode() -{ - ++m_nNodes; - -#ifdef OGDF_DEBUG - node v = OGDF_NEW NodeElement(this,m_nodeIdCount++); -#else - node v = OGDF_NEW NodeElement(m_nodeIdCount++); -#endif - - m_nodes.pushBack(v); - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->nodeAdded(v); - return v; -} - - -// IMPORTANT: -// The indices of the two adjacency entries pointing to an edge differ -// only in the last bit (adjSrc/2 == adjTgt/2) -// -// This can be useful sometimes in order to avoid visiting an edge twice. -edge Graph::createEdgeElement(node v, node w, adjEntry adjSrc, adjEntry adjTgt) -{ - if (m_edgeIdCount == m_edgeArrayTableSize) { - m_edgeArrayTableSize <<= 1; - - for(ListIterator it = m_regEdgeArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_edgeArrayTableSize); - } - - for(ListIterator itAdj = m_regAdjArrays.begin(); - itAdj.valid(); ++itAdj) - { - (*itAdj)->enlargeTable(m_edgeArrayTableSize << 1); - } - } - - adjTgt->m_id = (adjSrc->m_id = m_edgeIdCount << 1) | 1; - edge e = OGDF_NEW EdgeElement(v,w,adjSrc,adjTgt,m_edgeIdCount++); - m_edges.pushBack(e); - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->edgeAdded(e); - return e; -} - - -edge Graph::newEdge(node v, node w, int index) -{ - OGDF_ASSERT(v != 0 && w != 0); - OGDF_ASSERT(v->graphOf() == this && w->graphOf() == this); - - ++m_nEdges; - - AdjElement *adjSrc = OGDF_NEW AdjElement(v); - - v->m_adjEdges.pushBack(adjSrc); - v->m_outdeg++; - - AdjElement *adjTgt = OGDF_NEW AdjElement(w); - - w->m_adjEdges.pushBack(adjTgt); - w->m_indeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - if(index >= m_edgeIdCount) { - m_edgeIdCount = index+1; - - if(index >= m_edgeArrayTableSize) { - m_edgeArrayTableSize = nextPower2(m_edgeArrayTableSize,index); - - for(ListIterator it = m_regEdgeArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_edgeArrayTableSize); - } - - for(ListIterator itAdj = m_regAdjArrays.begin(); - itAdj.valid(); ++itAdj) - { - (*itAdj)->enlargeTable(m_edgeArrayTableSize << 1); - } - } - } - - adjTgt->m_id = (adjSrc->m_id = index/*m_edgeIdCount*/ << 1) | 1; - edge e = OGDF_NEW EdgeElement(v,w,adjSrc,adjTgt,index); - m_edges.pushBack(e); - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->edgeAdded(e); - return adjSrc->m_edge = adjTgt->m_edge = e; -} - - -edge Graph::newEdge(node v, node w) -{ - OGDF_ASSERT(v != 0 && w != 0); - OGDF_ASSERT(v->graphOf() == this && w->graphOf() == this); - - ++m_nEdges; - - AdjElement *adjSrc = OGDF_NEW AdjElement(v); - - v->m_adjEdges.pushBack(adjSrc); - v->m_outdeg++; - - AdjElement *adjTgt = OGDF_NEW AdjElement(w); - - w->m_adjEdges.pushBack(adjTgt); - w->m_indeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - edge e = createEdgeElement(v,w,adjSrc,adjTgt); - - return adjSrc->m_edge = adjTgt->m_edge = e; -} - - -edge Graph::newEdge(adjEntry adjStart, adjEntry adjEnd, Direction dir) -{ - OGDF_ASSERT(adjStart != 0 && adjEnd != 0) - OGDF_ASSERT(adjStart->graphOf() == this && adjEnd->graphOf() == this); - - ++m_nEdges; - - node v = adjStart->theNode(), w = adjEnd->theNode(); - - AdjElement *adjTgt = OGDF_NEW AdjElement(w); - AdjElement *adjSrc = OGDF_NEW AdjElement(v); - - if(dir == ogdf::after) { - w->m_adjEdges.insertAfter(adjTgt,adjEnd); - v->m_adjEdges.insertAfter(adjSrc,adjStart); - } else { - w->m_adjEdges.insertBefore(adjTgt,adjEnd); - v->m_adjEdges.insertBefore(adjSrc,adjStart); - } - - w->m_indeg++; - v->m_outdeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - edge e = createEdgeElement(v,w,adjSrc,adjTgt); - - return adjSrc->m_edge = adjTgt->m_edge = e; -} - -edge Graph::newEdge(node v, adjEntry adjEnd) -{ - OGDF_ASSERT(v != 0 && adjEnd != 0) - OGDF_ASSERT(v->graphOf() == this && adjEnd->graphOf() == this); - - ++m_nEdges; - - node w = adjEnd->theNode(); - - AdjElement *adjTgt = OGDF_NEW AdjElement(w); - - w->m_adjEdges.insertAfter(adjTgt,adjEnd); - w->m_indeg++; - - AdjElement *adjSrc = OGDF_NEW AdjElement(v); - - v->m_adjEdges.pushBack(adjSrc); - v->m_outdeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - edge e = createEdgeElement(v,w,adjSrc,adjTgt); - - return adjSrc->m_edge = adjTgt->m_edge = e; -}//newedge -//copy of above function with edge ending at v -edge Graph::newEdge(adjEntry adjStart, node v) -{ - OGDF_ASSERT(v != 0 && adjStart != 0) - OGDF_ASSERT(v->graphOf() == this && adjStart->graphOf() == this); - - ++m_nEdges; - - node w = adjStart->theNode(); - - AdjElement *adjSrc = OGDF_NEW AdjElement(w); - - w->m_adjEdges.insertAfter(adjSrc, adjStart); - w->m_outdeg++; - - AdjElement *adjTgt = OGDF_NEW AdjElement(v); - - v->m_adjEdges.pushBack(adjTgt); - v->m_indeg++; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - edge e = createEdgeElement(w,v,adjSrc,adjTgt); - - return adjSrc->m_edge = adjTgt->m_edge = e; -}//newedge - - -void Graph::move(edge e, - adjEntry adjSrc, - Direction dirSrc, - adjEntry adjTgt, - Direction dirTgt) -{ - OGDF_ASSERT(e->graphOf() == this); - OGDF_ASSERT(adjSrc->graphOf() == this && adjTgt->graphOf() == this); - OGDF_ASSERT(adjSrc != e->m_adjSrc && adjSrc != e->m_adjTgt); - OGDF_ASSERT(adjTgt != e->m_adjSrc && adjTgt != e->m_adjTgt); - - node v = adjSrc->m_node, w = adjTgt->m_node; - adjEntry adj1 = e->m_adjSrc, adj2 = e->m_adjTgt; - e->m_src->m_adjEdges.move(adj1,v->m_adjEdges,adjSrc,dirSrc); - e->m_tgt->m_adjEdges.move(adj2,w->m_adjEdges,adjTgt,dirTgt); - - e->m_src->m_outdeg--; - e->m_tgt->m_indeg--; - - adj1->m_node = e->m_src = v; - adj2->m_node = e->m_tgt = w; - - v->m_outdeg++; - w->m_indeg++; -} - - -void Graph::moveTarget(edge e, node v) -{ - OGDF_ASSERT(e->graphOf() == this); - OGDF_ASSERT(v->graphOf() == this); - - adjEntry adj = e->m_adjTgt; - e->m_tgt->m_adjEdges.move(adj,v->m_adjEdges); - - e->m_tgt->m_indeg--; - adj->m_node = e->m_tgt = v; - v->m_indeg++; -} - -void Graph::moveTarget(edge e, adjEntry adjTgt, Direction dir) -{ - node v = adjTgt->theNode(); - - OGDF_ASSERT(e->graphOf() == this); - OGDF_ASSERT(v->graphOf() == this); - - adjEntry adj = e->m_adjTgt; - e->m_tgt->m_adjEdges.move(adj,v->m_adjEdges, adjTgt, dir); - - e->m_tgt->m_indeg--; - adj->m_node = e->m_tgt = v; - v->m_indeg++; -} - -// By Leipert -void Graph::moveSource(edge e, node v) -{ - OGDF_ASSERT(e->graphOf() == this); - OGDF_ASSERT(v->graphOf() == this); - - adjEntry adj = e->m_adjSrc; - e->m_src->m_adjEdges.move(adj,v->m_adjEdges); - - e->m_src->m_outdeg--; - adj->m_node = e->m_src = v; - v->m_outdeg++; -} - -void Graph::moveSource(edge e, adjEntry adjSrc, Direction dir) -{ - node v = adjSrc->theNode(); - - OGDF_ASSERT(e->graphOf() == this); - OGDF_ASSERT(v->graphOf() == this); - - adjEntry adj = e->m_adjSrc; - e->m_src->m_adjEdges.move(adj,v->m_adjEdges, adjSrc, dir); - - e->m_src->m_outdeg--; - adj->m_node = e->m_src = v; - v->m_outdeg++; -} - -edge Graph::split(edge e) -{ - OGDF_ASSERT(e != 0 && e->graphOf() == this); - - ++m_nEdges; - - node u = newNode(); - u->m_indeg = u->m_outdeg = 1; - - adjEntry adjTgt = OGDF_NEW AdjElement(u); - adjTgt->m_edge = e; - adjTgt->m_twin = e->m_adjSrc; - e->m_adjSrc->m_twin = adjTgt; - - // adapt adjacency entry index to hold invariant - adjTgt->m_id = e->m_adjTgt->m_id; - - u->m_adjEdges.pushBack(adjTgt); - - adjEntry adjSrc = OGDF_NEW AdjElement(u); - adjSrc->m_twin = e->m_adjTgt; - u->m_adjEdges.pushBack(adjSrc); - - int oldId = e->m_adjTgt->m_id; - edge e2 = createEdgeElement(u,e->m_tgt,adjSrc,e->m_adjTgt); - resetAdjEntryIndex(e->m_adjTgt->m_id,oldId); - - e2->m_adjTgt->m_twin = adjSrc; - e->m_adjTgt->m_edge = adjSrc->m_edge = e2; - - e->m_tgt = u; - e->m_adjTgt = adjTgt; - return e2; -} - - -void Graph::unsplit(node u) -{ - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj()->theEdge(); - - if (eIn->target() != u) - swap(eIn,eOut); - - unsplit(eIn,eOut); -} - - - -void Graph::unsplit(edge eIn, edge eOut) -{ - node u = eIn->target(); - - // u must be a node with exactly one incoming edge eIn and one outgoing - // edge eOut - OGDF_ASSERT(u->graphOf() == this && u->indeg() == 1 && - u->outdeg() == 1 && eOut->source() == u); - - // none of them is a self-loop! - OGDF_ASSERT(eIn->isSelfLoop() == false && eOut->isSelfLoop() == false); - - // we reuse these adjacency entries - adjEntry adjSrc = eIn ->m_adjSrc; - adjEntry adjTgt = eOut->m_adjTgt; - - eIn->m_tgt = eOut->m_tgt; - - // adapt adjacency entry index to hold invariant - resetAdjEntryIndex(eIn->m_adjTgt->m_id,adjTgt->m_id); - adjTgt->m_id = eIn->m_adjTgt->m_id; // correct id of adjacency entry! - - eIn->m_adjTgt = adjTgt; - - adjSrc->m_twin = adjTgt; - adjTgt->m_twin = adjSrc; - - adjTgt->m_edge = eIn; - - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->edgeDeleted(eOut); - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->nodeDeleted(u); - // remove structures that are no longer used - m_edges.del(eOut); - m_nodes.del(u); - --m_nNodes; - --m_nEdges; - -} - - -void Graph::delNode(node v) -{ - OGDF_ASSERT(v != 0 && v->graphOf() == this) - - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->nodeDeleted(v); - - --m_nNodes; - - GraphList &adjEdges = v->m_adjEdges; - AdjElement *adj; - while((adj = adjEdges.begin()) != 0) - delEdge(adj->m_edge); - - m_nodes.del(v); -} - - -void Graph::delEdge(edge e) -{ - OGDF_ASSERT(e != 0 && e->graphOf() == this) - - // notify all registered observers - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) (*it)->edgeDeleted(e); - - --m_nEdges; - - node src = e->m_src, tgt = e->m_tgt; - - src->m_adjEdges.del(e->m_adjSrc); - src->m_outdeg--; - tgt->m_adjEdges.del(e->m_adjTgt); - tgt->m_indeg--; - - m_edges.del(e); -} - - -void Graph::clear() -{ - //tell all structures to clear their graph-initialized data - for(ListIterator it = m_regStructures.begin(); - it.valid(); ++it) - { - (*it)->cleared(); - }//for - for (node v = m_nodes.begin(); v; v = v->succ()) { - v->m_adjEdges.~GraphList(); - } - - m_nodes.clear(); - m_edges.clear(); - - m_nNodes = m_nEdges = m_nodeIdCount = m_edgeIdCount = 0; - m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE; - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -void Graph::reverseEdge(edge e) -{ - OGDF_ASSERT(e != 0 && e->graphOf() == this) - node &src = e->m_src, &tgt = e->m_tgt; - - swap(src,tgt); - swap(e->m_adjSrc,e->m_adjTgt); - src->m_outdeg++; src->m_indeg--; - tgt->m_outdeg--; tgt->m_indeg++; -} - - -void Graph::reverseAllEdges() -{ - for (edge e = m_edges.begin(); e; e = e->succ()) - reverseEdge(e); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); -} - - -void Graph::reverseAdjEdges() -{ - node v; - forall_nodes(v,*this) - reverseAdjEdges(v); -} - - -node Graph::chooseNode() const -{ - if (m_nNodes == 0) return 0; - int k = ogdf::randomNumber(0,m_nNodes-1); - node v = firstNode(); - while(k--) v = v->succ(); - return v; -} - - -edge Graph::chooseEdge() const -{ - if (m_nEdges == 0) return 0; - int k = ogdf::randomNumber(0,m_nEdges-1); - edge e = firstEdge(); - while(k--) e = e->succ(); - return e; -} - - -edge Graph::searchEdge(node v, node w) const -{ - OGDF_ASSERT(v != 0 && v->graphOf() == this) - OGDF_ASSERT(w != 0 && w->graphOf() == this) - adjEntry adj; - forall_adj(adj,v) { - if(adj->twinNode() == w) return adj->twin()->theEdge(); - } - return 0; -} - - -void Graph::hideEdge(edge e) -{ - OGDF_ASSERT(e != 0 && e->graphOf() == this) - --m_nEdges; - - node src = e->m_src, tgt = e->m_tgt; - - src->m_adjEdges.delPure(e->m_adjSrc); - src->m_outdeg--; - tgt->m_adjEdges.delPure(e->m_adjTgt); - tgt->m_indeg--; - - m_edges.move(e, m_hiddenEdges); -} - - -void Graph::restoreEdge(edge e) -{ - ++m_nEdges; - - node v = e->m_src; - v->m_adjEdges.pushBack(e->m_adjSrc); - ++v->m_outdeg; - - node w = e->m_tgt; - w->m_adjEdges.pushBack(e->m_adjTgt); - ++w->m_indeg; - - m_hiddenEdges.move(e, m_edges); -} - - -void Graph::restoreAllEdges() -{ - edge e, ePrev; - for(e = m_hiddenEdges.rbegin(); e != 0; e = ePrev) { - ePrev = e->pred(); - restoreEdge(e); - } -} - - -int Graph::genus() const -{ - if (m_nNodes == 0) return 0; - - int nIsolated = 0; - node v; - forall_nodes(v,*this) - if (v->degree() == 0) ++nIsolated; - - NodeArray component(*this); - int nCC = connectedComponents(*this,component); - - AdjEntryArray visited(*this,false); - int nFaceCycles = 0; - - forall_nodes(v,*this) { - adjEntry adj1; - forall_adj(adj1,v) { - if (visited[adj1]) continue; - - adjEntry adj = adj1; - do { - visited[adj] = true; - adj = adj->faceCycleSucc(); - } while (adj != adj1); - - ++nFaceCycles; - } - } - - return (m_nEdges - m_nNodes - nIsolated - nFaceCycles + 2*nCC) / 2; -} - - -ListIterator Graph::registerArray( - NodeArrayBase *pNodeArray) const -{ - return m_regNodeArrays.pushBack(pNodeArray); -} - - -ListIterator Graph::registerArray( - EdgeArrayBase *pEdgeArray) const -{ - return m_regEdgeArrays.pushBack(pEdgeArray); -} - - -ListIterator Graph::registerArray( - AdjEntryArrayBase *pAdjArray) const -{ - return m_regAdjArrays.pushBack(pAdjArray); -} - -ListIterator Graph::registerStructure( - GraphObserver *pStructure) const -{ - return m_regStructures.pushBack(pStructure); -}//registerstructure - - -void Graph::unregisterArray(ListIterator it) const -{ - m_regNodeArrays.del(it); -} - - -void Graph::unregisterArray(ListIterator it) const -{ - m_regEdgeArrays.del(it); -} - - -void Graph::unregisterArray(ListIterator it) const -{ - m_regAdjArrays.del(it); -} - -void Graph::unregisterStructure(ListIterator it) const -{ - m_regStructures.del(it); -} - -void Graph::reinitArrays() -{ - ListIterator itNode = m_regNodeArrays.begin(); - for(; itNode.valid(); ++itNode) - (*itNode)->reinit(m_nodeArrayTableSize); - - ListIterator itEdge = m_regEdgeArrays.begin(); - for(; itEdge.valid(); ++itEdge) - (*itEdge)->reinit(m_edgeArrayTableSize); - - ListIterator itAdj = m_regAdjArrays.begin(); - for(; itAdj.valid(); ++itAdj) - (*itAdj)->reinit(m_edgeArrayTableSize << 1); -} - -void Graph::reinitStructures() -{ - //is there a challenge? - ListIterator itGS = m_regStructures.begin(); - for (;itGS.valid(); ++itGS) - (*itGS)->reInit(); -} - - -void Graph::resetAdjEntryIndex(int newIndex, int oldIndex) -{ - ListIterator itAdj = m_regAdjArrays.begin(); - for(; itAdj.valid(); ++itAdj) - (*itAdj)->resetIndex(newIndex,oldIndex); -} - - -int Graph::nextPower2(int start, int idCount) -{ - while (start <= idCount) - start <<= 1; - - return start; -} - - -bool Graph::readGML(const char *fileName) -{ - ifstream is(fileName); - return readGML(is); -} - - -bool Graph::readGML(istream &is) -{ - GmlParser gml(is); - if (gml.error()) return false; - bool result = gml.read(*this); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return result; -} - - -void Graph::writeGML(const char *fileName) const -{ - ofstream os(fileName); - writeGML(os); -} - - -void Graph::writeGML(ostream &os) const -{ - NodeArray id(*this); - int nextId = 0; - - os << "Creator \"ogdf::Graph::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,*this) { - os << " node [\n"; - os << " id " << (id[v] = nextId++) << "\n"; - os << " ]\n"; // node - } - - edge e; - forall_edges(e,*this) { - os << " edge [\n"; - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -// read graph in LEDA format from file fileName -bool Graph::readLEDAGraph(const char *fileName) -{ - ifstream is(fileName); - return readLEDAGraph(is); -} - - -bool Graph::readToEndOfLine(istream &is) -{ - int c; - do { - if (is.eof()) return false; - c = is.get(); - } while(c != '\n'); - return true; -} - - -// read graph in LEDA format from input stream is -bool Graph::readLEDAGraph(istream &is) -{ - clear(); - - // the first three strings in the LEDA format describe the type of the - // format, of nodes and of edges. We simply ignore the additional node/ - // edge attributes - String formatType, nodeType, edgeType; - - is >> formatType; - is >> nodeType; - is >> edgeType; - - if (formatType != "LEDA.GRAPH") - return false; - - - // number of nodes - int n; - is >> n >> std::ws; - - // create n nodes and ignore n lines - Array nodes(1,n); - int i; - for(i = 1; i <= n; ++i) { - if (readToEndOfLine(is) == false) - return false; - nodes[i] = newNode(); - } - - // number of edges - int m; - is >> m; - - for(i = 1; i <= m; ++i) { - // read index of source and target node - int src, tgt; - is >> src >> tgt; - - // indices valid? - if (src < 1 || n < src || tgt < 1 || n < tgt) - return false; - - newEdge(nodes[src],nodes[tgt]); - - // ignore rest of line - if (readToEndOfLine(is) == false) - return false; - } - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - - return true; -} - - -bool Graph::consistencyCheck() const -{ - int n = 0; - node v; - forall_nodes(v,*this) { -#ifdef OGDF_DEBUG - if (v->graphOf() != this) - return false; -#endif - - n++; - int in = 0, out = 0; - - adjEntry adj; - forall_adj(adj,v) { - edge e = adj->m_edge; - if (adj->m_twin->m_edge != e) - return false; - - if (e->m_adjSrc == adj) - out++; - else if (e->m_adjTgt == adj) - in++; - else - return false; - - if (adj->m_node != v) - return false; - -#ifdef OGDF_DEBUG - if (adj->graphOf() != this) - return false; -#endif - } - - if (v->m_indeg != in) - return false; - - if (v->m_outdeg != out) - return false; - } - - if (n != m_nNodes) - return false; - - int m = 0; - edge e; - forall_edges(e,*this) { -#ifdef OGDF_DEBUG - if (e->graphOf() != this) - return false; -#endif - - m++; - if (e->m_adjSrc == e->m_adjTgt) - return false; - - if (e->m_adjSrc->m_edge != e) - return false; - - if (e->m_adjTgt->m_edge != e) - return false; - - if (e->m_adjSrc->m_node != e->m_src) - return false; - - if (e->m_adjTgt->m_node != e->m_tgt) - return false; - } - - if (m != m_nEdges) - return false; - - return true; -} - - -void Graph::resetEdgeIdCount(int maxId) -{ - m_edgeIdCount = maxId+1; - -#ifdef OGDF_DEBUG - if (ogdf::debugLevel >= int(ogdf::dlConsistencyChecks)) { - edge e; - forall_edges(e,*this) - { - // if there is an edge with higer index than maxId, we cannot - // set the edge id count to maxId+1 - if (e->index() > maxId) - OGDF_ASSERT(false); - } - } -#endif -} - - -node Graph::splitNode(adjEntry adjStartLeft, adjEntry adjStartRight) -{ - OGDF_ASSERT(adjStartLeft != 0 && adjStartRight != 0); - OGDF_ASSERT(adjStartLeft->graphOf() == this && adjStartRight->graphOf() == this); - OGDF_ASSERT(adjStartLeft->theNode() == adjStartRight->theNode()); - - node w = newNode(); - - adjEntry adj, adjSucc; - for(adj = adjStartRight; adj != adjStartLeft; adj = adjSucc) { - adjSucc = adj->cyclicSucc(); - moveAdj(adj,w); - } - - newEdge(adjStartLeft, adjStartRight, ogdf::before); - - return w; -} - - -node Graph::contract(edge e) -{ - adjEntry adjSrc = e->adjSource(); - adjEntry adjTgt = e->adjTarget(); - node v = e->source(); - node w = e->target(); - - adjEntry adjNext; - for(adjEntry adj = adjTgt->cyclicSucc(); adj != adjTgt; adj = adjNext) - { - adjNext = adj->cyclicSucc(); - - edge eAdj = adj->theEdge(); - if(w == eAdj->source()) - moveSource(eAdj, adjSrc, before); - else - moveTarget(eAdj, adjSrc, before); - } - - delNode(adjTgt->theNode()); - - return v; -} - - -void Graph::moveAdj(adjEntry adj, node w) -{ - node v = adj->m_node; - - v->m_adjEdges.move(adj,w->m_adjEdges); - adj->m_node = w; - - edge e = adj->m_edge; - if(v == e->m_src) { - --v->m_outdeg; - e->m_src = w; - ++w->m_outdeg; - } else { - --v->m_indeg; - e->m_tgt = w; - ++w->m_indeg; - } -} - - -ostream &operator<<(ostream &os, ogdf::node v) -{ - if (v) os << v->index(); else os << "nil"; - return os; -} - -ostream &operator<<(ostream &os, ogdf::edge e) -{ - if (e) os << "(" << e->source() << "," << e->target() << ")"; - else os << "nil"; - return os; -} - -ostream &operator<<(ostream &os, ogdf::adjEntry adj) -{ - if (adj) { - ogdf::edge e = adj->theEdge(); - if (adj == e->adjSource()) - os << e->source() << "->" << e->target(); - else - os << e->target() << "->" << e->source(); - } else os << "nil"; - return os; -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/basic/GraphAttributes.cpp b/ext/OGDF/src/basic/GraphAttributes.cpp deleted file mode 100644 index 6cc0c5d67..000000000 --- a/ext/OGDF/src/basic/GraphAttributes.cpp +++ /dev/null @@ -1,1256 +0,0 @@ -/* - * $Revision: 2571 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 17:25:20 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class GraphAttributes. - * - * Class GraphAttributes extends a graph by graphical attributes like - * node position, color, etc. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// GraphAttributes -// graph topology + graphical attributes -//--------------------------------------------------------- - -GraphAttributes::GraphAttributes() : m_pGraph(0), m_directed(true) { } - - - -GraphAttributes::GraphAttributes(const Graph &G, long initAttr) : - m_pGraph(&G), m_directed(true), m_attributes(0) -{ - initAttributes(m_attributes = initAttr); -} - - - -void GraphAttributes::initAttributes(long attr) -{ - m_attributes |= attr; - - //no color without graphics - OGDF_ASSERT( (m_attributes & nodeGraphics) != 0 || (m_attributes & nodeColor) == 0); - //no fill and linewithout graphics - OGDF_ASSERT( (m_attributes & nodeGraphics) != 0 || (attr & nodeStyle) == 0); - //no color without graphics - OGDF_ASSERT( (m_attributes & edgeGraphics) != 0 || (attr & edgeColor) == 0); - - if (attr & nodeGraphics) { - m_x .init(*m_pGraph,0.0); - m_y .init(*m_pGraph,0.0); - m_width .init(*m_pGraph,0.0); - m_height.init(*m_pGraph,0.0); - m_nodeShape.init(*m_pGraph,rectangle); - } - - if (attr & nodeColor) - { - m_nodeColor.init(*m_pGraph, ""); - m_nodeLine.init(*m_pGraph, ""); - } - - if (attr & nodeStyle) - { - m_nodePattern.init(*m_pGraph, bpNone); - m_nodeStyle.init(*m_pGraph, esSolid); - m_nodeLineWidth.init(*m_pGraph, 1); - //images should not be added here as nodestyle, purely experimental - //such that it fits PG code - //images: - m_imageUri.init(*m_pGraph, ""); - m_imageStyle.init(*m_pGraph, GraphAttributes::FreeScale); - m_imageAlign.init(*m_pGraph, GraphAttributes::Center); - m_imageDrawLine.init(*m_pGraph, false); - m_imageWidth.init(*m_pGraph, 0); - m_imageHeight.init(*m_pGraph, 0); - } - - if (attr & edgeGraphics) { - m_bends.init(*m_pGraph,DPolyline()); - } - - if (attr & edgeColor) - m_edgeColor.init(*m_pGraph); - - if (attr & edgeStyle) - { - m_edgeStyle.init(*m_pGraph, esSolid); - m_edgeWidth.init(*m_pGraph, 1.0); - } - - if (attr & nodeLevel) { - m_level.init(*m_pGraph,0); - } - if (attr & nodeWeight) { - m_nodeIntWeight.init(*m_pGraph,0); - } - if (attr & edgeIntWeight) { - m_intWeight.init(*m_pGraph,1); - } - if (attr & edgeDoubleWeight) { - m_doubleWeight.init(*m_pGraph,1.0); - } - if (attr & nodeLabel) { - m_nodeLabel.init(*m_pGraph); - } - if (attr & edgeLabel) { - m_edgeLabel.init(*m_pGraph); - } - if (attr & edgeType) { - m_eType.init(*m_pGraph,Graph::association);//should be Graph::standard end explicitly set - } - if (attr & nodeType) { - m_vType.init(*m_pGraph,Graph::vertex); - } - if (attr & nodeId) { - m_nodeId.init(*m_pGraph, -1); - } - if (attr & edgeArrow) { - m_edgeArrow.init(*m_pGraph, undefined); - } - if (attr & nodeTemplate) { - m_nodeTemplate.init(*m_pGraph); - } - if (attr & edgeSubGraph) { - m_subGraph.init(*m_pGraph,0); - } -} - -void GraphAttributes::destroyAttributes(long attr) -{ - m_attributes &= ~attr; - - if (attr & nodeGraphics) { - m_x .init(); - m_y .init(); - m_width .init(); - m_height.init(); - m_nodeShape.init(); - if (attr & nodeColor) - m_nodeColor.init(); - if (attr & nodeStyle) - { - m_nodePattern.init(); - m_nodeLine.init(); - m_nodeLineWidth.init(); - //should have its own trigger attribute - //images - m_imageUri.init(); - m_imageStyle.init(); - m_imageAlign.init(); - m_imageDrawLine.init(); - m_imageWidth.init(); - m_imageHeight.init(); - } - } - - if (attr & edgeGraphics) { - m_bends.init(); - } - if (attr & edgeColor) - { - m_edgeColor.init(); - } - if (attr & edgeStyle) - { - m_edgeStyle.init(); - m_edgeWidth.init(); - } - - if (attr & nodeLevel) { - m_level.init(); - } - if (attr & nodeWeight) { - m_nodeIntWeight.init(); - } - if (attr & edgeIntWeight) { - m_intWeight.init(); - } - if (attr & edgeDoubleWeight) { - m_doubleWeight.init(); - } - if (attr & nodeLabel) { - m_nodeLabel.init(); - } - if (attr & edgeLabel) { - m_edgeLabel.init(); - } - if (attr & nodeId) { - m_nodeId.init(); - } - if (attr & edgeArrow) { - m_edgeArrow.init(); - } - if (attr & nodeTemplate) { - m_nodeTemplate.init(); - } - if (attr & edgeSubGraph) { - m_subGraph.init(); - } -} - - -void GraphAttributes::init(const Graph &G, long initAttr) -{ - m_pGraph = &G; - destroyAttributes(m_attributes); - m_attributes = 0; - initAttributes(m_attributes = initAttr); -} - -void GraphAttributes::setAllWidth(double w) -{ - node v; - forall_nodes(v,*m_pGraph) - m_width[v] = w; -} - - -void GraphAttributes::setAllHeight(double h) -{ - node v; - forall_nodes(v,*m_pGraph) - m_height[v] = h; -} - - -void GraphAttributes::clearAllBends() -{ - edge e; - forall_edges(e,*m_pGraph) - m_bends[e].clear(); -} - - -bool GraphAttributes::readGML(Graph &G, const String &fileName) -{ - ifstream is(fileName.cstr()); - if (!is) - return false; // couldn't open file - - return readGML(G,is); -} - - -bool GraphAttributes::readGML(Graph &G, istream &is) -{ - GmlParser gml(is); - if (gml.error()) - return false; - - return gml.read(G,*this); -} - - -bool GraphAttributes::readRudy(Graph &G, const String &fileName) -{ - ifstream is(fileName.cstr()); - if (!is) - return false; - return readRudy(G,is); -} - - -bool GraphAttributes::readRudy(Graph &G, istream &is) -{ - if (!is) - return false; - int i; - int n, m; - int src, tgt; - double weight; - edge e; - - is >> n >> m; - - G.clear(); - Array mapToNode(0,n-1,0); - - if (attributes() & edgeDoubleWeight){ - for(i=0; i> src >> tgt >> weight; - src--; - tgt--; - if(mapToNode[src] == 0) mapToNode[src] = G.newNode(src); - if(mapToNode[tgt] == 0) mapToNode[tgt] = G.newNode(tgt); - e = G.newEdge(mapToNode[src],mapToNode[tgt]); - this->doubleWeight(e)=weight; - } - } - return true; -} - - -void GraphAttributes::writeRudy(const String &fileName) const -{ - ofstream os(fileName.cstr()); - writeRudy(os); -} - - -void GraphAttributes::writeRudy(ostream &os) const -{ - const Graph &G = this->constGraph(); - os << G.numberOfNodes() << " " << G.numberOfEdges() << endl; - - edge e; - if (attributes() & edgeDoubleWeight){ - forall_edges(e,G) { - os << (e->source()->index())+1 << " " << (e->target()->index())+1; - os << " " << this->doubleWeight(e) << endl; - } - } - else forall_edges(e,G) os << (e->source()->index())+1 << " " << (e->target()->index())+1 << endl; -} - - -const int c_maxLengthPerLine = 200; - -void GraphAttributes::writeLongString(ostream &os, const String &str) const -{ - os << "\""; - - int num = 1; - const char *p = str.cstr(); - while(*p != 0) - { - switch(*p) { - case '\\': - os << "\\\\"; - num += 2; - break; - case '\"': - os << "\\\""; - num += 2; - break; - - // ignored white space - case '\r': - case '\n': - case '\t': - break; - - default: - os << *p; - ++num; - } - - if(num >= c_maxLengthPerLine) { - os << "\\\n"; - num = 0; - } - - ++p; - } - - os << "\""; -} - - -void GraphAttributes::writeGML(const String &fileName) const -{ - ofstream os(fileName.cstr()); - writeGML(os); -} - - -void GraphAttributes::writeGML(ostream &os) const -{ - NodeArray id(*m_pGraph); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - - os << "graph [\n"; - - os << (m_directed ? " directed 1\n" : " directed 0\n"); - - node v; - forall_nodes(v,*m_pGraph) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - if (attributes() & nodeTemplate) { - os << " template "; - writeLongString(os, templateNode(v)); - os << "\n"; - } - - if (attributes() & nodeLabel) { - //os << "label \"" << labelNode(v) << "\"\n"; - os << " label "; - writeLongString(os, labelNode(v)); - os << "\n"; - } - - if (m_attributes & nodeGraphics) { - os << " graphics [\n"; - os << " x " << m_x[v] << "\n"; - os << " y " << m_y[v] << "\n"; - os << " w " << m_width[v] << "\n"; - os << " h " << m_height[v] << "\n"; - if (m_attributes & nodeColor) - { - os << " fill \"" << m_nodeColor[v] << "\"\n"; - os << " line \"" << m_nodeLine[v] << "\"\n"; - }//color - if (m_attributes & nodeStyle) - { - os << " pattern \"" << m_nodePattern[v] << "\"\n"; - os << " stipple " << styleNode(v) << "\n"; - os << " lineWidth " << lineWidthNode(v) << "\n"; - } - switch (m_nodeShape[v]) - { - case rectangle: os << " type \"rectangle\"\n"; break; - case oval: os << " type \"oval\"\n"; break; - } - os << " width 1.0\n"; - os << " ]\n"; // graphics - } - - os << " ]\n"; // node - } - - edge e; - forall_edges(e,*m_pGraph) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - if (attributes() & edgeLabel){ - os << " label "; - writeLongString(os, labelEdge(e)); - os << "\n"; - } - if (attributes() & edgeType) - os << " generalization " << type(e) << "\n"; - - if (attributes() & edgeSubGraph) - os << " subgraph " << subGraphBits(e) << "\n"; - - if (m_attributes & edgeGraphics) { - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (attributes() & GraphAttributes::edgeType) { - if (attributes() & GraphAttributes::edgeArrow) { - switch(arrowEdge(e)) { - case GraphAttributes::none: - os << " arrow \"none\"\n"; - break; - - case GraphAttributes::last: - os << " arrow \"last\"\n"; - break; - - case GraphAttributes::first: - os << " arrow \"first\"\n"; - break; - - case GraphAttributes::both: - os << " arrow \"both\"\n"; - break; - - case GraphAttributes::undefined: - // do nothing - break; - - default: - // do nothing - break; - } - } else { - if (type(e) == Graph::generalization) - os << " arrow \"last\"\n"; - else - os << " arrow \"none\"\n"; - } - - } else { // GraphAttributes::edgeType not used - if (m_directed) { - os << " arrow \"last\"\n"; - } else { - os << " arrow \"none\"\n"; - } - } - - if (attributes() & GraphAttributes::edgeStyle) - { - os << " stipple " << styleEdge(e) << "\n"; - os << " lineWidth " << edgeWidth(e) << "\n"; - }//edgestyle is gml graphlet extension!!! - if (attributes() & edgeDoubleWeight) - { - os << " weight " << doubleWeight(e) << "\n"; - } - //hier noch Unterscheidung Knotentypen, damit die Berechnung - //fuer Ellipsen immer bis zum echten Rand rechnet - const DPolyline &dpl = m_bends[e]; - if (!dpl.empty()) { - os << " Line [\n"; - - node v = e->source(); - if(dpl.front().m_x < m_x[v] - m_width[v]/2 || - dpl.front().m_x > m_x[v] + m_width[v]/2 || - dpl.front().m_y < m_y[v] - m_height[v]/2 || - dpl.front().m_y > m_y[v] + m_height[v]/2) - { - os << " point [ x " << m_x[e->source()] << " y " << - m_y[e->source()] << " ]\n"; - } - - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - os << " point [ x " << (*it).m_x << " y " << (*it).m_y << " ]\n"; - - v = e->target(); - if(dpl.back().m_x < m_x[v] - m_width[v]/2 || - dpl.back().m_x > m_x[v] + m_width[v]/2 || - dpl.back().m_y < m_y[v] - m_height[v]/2 || - dpl.back().m_y > m_y[v] + m_height[v]/2) - { - os << " point [ x " << m_x[e->target()] << " y " << - m_y[e->target()] << " ]\n"; - } - - os << " ]\n"; // Line - }//bends - - //output width and color - if ((m_attributes & edgeColor) && - (m_edgeColor[e].length() != 0)) - os << " fill \"" << m_edgeColor[e] << "\"\n"; - - os << " ]\n"; // graphics - } - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -bool GraphAttributes::readXML(Graph &G, const String &fileName) -{ - ifstream is(fileName.cstr()); - return readXML(G,is); -} - - -bool GraphAttributes::readXML(Graph &G, istream &is) -{ - // need at least these attributes - initAttributes(~m_attributes & - (nodeGraphics | edgeGraphics | nodeLabel | edgeLabel)); - - XmlParser xml(is); - if (xml.error()) return false; - - return xml.read(G,*this); -} - - - -// -// calculates the bounding box of the graph -const DRect GraphAttributes::boundingBox() const -{ - double minx, maxx, miny, maxy; - const Graph &G = constGraph(); - const GraphAttributes &AG = *this; - node v = G.firstNode(); - - if (v == 0) { - minx = maxx = miny = maxy = 0.0; - } - else { - minx = AG.x(v) - AG.width(v)/2; - maxx = AG.x(v) + AG.width(v)/2; - miny = AG.y(v) - AG.height(v)/2; - maxy = AG.y(v) + AG.height(v)/2; - - forall_nodes(v, G) { - double x1 = AG.x(v) - AG.width(v)/2; - double x2 = AG.x(v) + AG.width(v)/2; - double y1 = AG.y(v) - AG.height(v)/2; - double y2 = AG.y(v) + AG.height(v)/2; - - if (x1 < minx) minx = x1; - if (x2 > maxx) maxx = x2; - if (y1 < miny) miny = y1; - if (y2 > maxy) maxy = y2; - } - } - - edge e; - forall_edges(e, G) { - const DPolyline &dpl = AG.bends(e); - ListConstIterator iter; - for (iter = dpl.begin(); iter.valid(); ++iter) { - if ((*iter).m_x < minx) minx = (*iter).m_x; - if ((*iter).m_x > maxx) maxx = (*iter).m_x; - if ((*iter).m_y < miny) miny = (*iter).m_y; - if ((*iter).m_y > maxy) maxy = (*iter).m_y; - } - } - - return DRect(minx, miny, maxx, maxy); -} - - -// -// returns a list of all hierachies in the graph (a hierachy consists of a set of nodes) -// at least one list is returned, which is the list of all nodes not belonging to any hierachy -// this is always the first list -// the return-value of this function is the number of hierachies -int GraphAttributes::hierarchyList(List* > &list) const -{ - // list must be empty during startup - OGDF_ASSERT(list.empty()); - - const Graph &G = constGraph(); - Array processed(0, G.maxNodeIndex(), false); - node v; - edge e; - - // initialize the first list of all single nodes - List *firstList = OGDF_NEW List; - list.pushBack(firstList); - - forall_nodes(v, G) { // scan all nodes - - // skip, if already processed - if (processed[v->index()]) - continue; - - List nodeSet; // set of nodes in this hierachy, - // whose neighbours have to be processed - List *hierachy = OGDF_NEW List; // holds all nodes in this hierachy - - nodeSet.pushBack(v); // push the unprocessed node to the list - processed[v->index()] = true; // and mark it as processed - - do { // scan all neighbours of nodes in 'nodeSet' - node v = nodeSet.popFrontRet(); - hierachy->pushBack(v); // push v to the list of nodes in this hierachy - - // process all the neighbours of v, e.g. push them into 'nodeSet' - forall_adj_edges(e, v) { - if (type(e) == Graph::generalization) { - node w = e->source() == v ? e->target() : e->source(); - if (!processed[w->index()]) { - nodeSet.pushBack(w); - processed[w->index()] = true; - } - } - } - } while (!nodeSet.empty()); - - // skip adding 'hierachy', if it contains only one node - if (hierachy->size() == 1) { - firstList->conc(*hierachy); - delete hierachy; - } - else - list.pushBack(hierachy); - } - - return list.size() - 1 + (*list.begin())->size(); -} - - -// -// returns a list of all hierarchies in the graph (in this case, a hierarchy consists of a set of edges) -// list may be empty, if no generalizations are used -// the return-value of this function is the number of hierarchies with generalizations -int GraphAttributes::hierarchyList(List* > &list) const -{ - // list must be empty during startup - OGDF_ASSERT(list.empty()); - - const Graph &G = constGraph(); - Array processed(0, G.maxNodeIndex(), false); - node v; - edge e; - - forall_nodes(v, G) { // scan all nodes - - // skip, if already processed - if (processed[v->index()]) - continue; - - List nodeSet; // set of nodes in this hierarchy, - // whose neighbours have to be processed - List *hierarchy = OGDF_NEW List; // holds all edges in this hierarchy - - nodeSet.pushBack(v); // push the unprocessed node to the list - processed[v->index()] = true; // and mark it as processed - - do { // scan all neighbours of nodes in 'nodeSet' - node v = nodeSet.popFrontRet(); - - // process all the neighbours of v, e.g. push them into 'nodeSet' - forall_adj_edges(e, v) { - if (type(e) == Graph::generalization) { - node w = e->source() == v ? e->target() : e->source(); - if (!processed[w->index()]) { - nodeSet.pushBack(w); - processed[w->index()] = true; - hierarchy->pushBack(e); // push e to the list of edges in this hierarchy - } - } - } - } while (!nodeSet.empty()); - - // skip adding 'hierarchy', if it contains only one node - if (hierarchy->empty()) - delete hierarchy; - else - list.pushBack(hierarchy); - } - - return list.size(); -} - - - -void GraphAttributes::removeUnnecessaryBendsHV() -{ - edge e; - forall_edges(e,*m_pGraph) - { - DPolyline &dpl = m_bends[e]; - - if(dpl.size() < 3) - continue; - - ListIterator it1, it2, it3; - - it1 = dpl.begin(); - it2 = it1.succ(); - it3 = it2.succ(); - - do { - if(((*it1).m_x == (*it2).m_x && (*it2).m_x == (*it3).m_x) || - ((*it1).m_y == (*it2).m_y && (*it2).m_y == (*it3).m_y)) - { - dpl.del(it2); - it2 = it3; - } else { - it1 = it2; - it2 = it3; - } - - it3 = it2.succ(); - } while(it3.valid()); - } -} - - -void GraphAttributes::writeXML( - const String &fileName, - const char* delimiter, - const char* offset) const -{ - ofstream os(fileName.cstr()); - writeXML(os,delimiter,offset); -} - - -void GraphAttributes::writeXML( - ostream &os, - const char* delimiter, - const char* offset) const -{ - NodeArray id(*m_pGraph); - - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "" << delimiter; - - node v; - forall_nodes(v,*m_pGraph) { - if (m_attributes & nodeLabel) - { - os << "" << delimiter; - } - id[v] = nextId++; - - if (m_attributes & nodeGraphics) { - os << offset << " " << delimiter; - os << offset << "" << delimiter; - - } - os << "" << delimiter; - } - - edge e; - forall_edges(e,*m_pGraph) { - if (m_attributes & edgeLabel) - { - os << "source()] << "\" "; - os << "TARGET=\"" << m_nodeLabel[e->target()] << "\" "; - os << "GENERALIZATION=\"" << (m_eType[e]==Graph::generalization?1:0) << "\">" << delimiter; - } - - if (m_attributes & edgeGraphics) { - - const DPolyline &dpl = m_bends[e]; - if (!dpl.empty()) { - os << offset << "" << delimiter; -/* if (m_backward[e]) - { - os << (*dpl.rbegin()).m_x << " " << (*dpl.rbegin()).m_y << " "; - if (dpl.size() > 1) - os << (*dpl.begin()).m_x << " " << (*dpl.begin()).m_y << " "; - } - else - { -*/ - ListConstIterator iter; - for (iter = dpl.begin(); iter.valid(); ++iter) - os << offset << offset << "" << delimiter; -// if (dpl.size() > 1) -// os << ""; -// } - os << offset << "" << delimiter; - } - - } - - os << "" << delimiter; // edge - } - - os << ""; -} - -void GraphAttributes::addNodeCenter2Bends(int mode) -{ - edge e; - forall_edges(e, *m_pGraph) { - node v = e->source(); - node w = e->target(); - DPolyline &bendpoints = bends(e); - switch (mode) { - case 0 : // push center to the bends and return - bendpoints.pushFront(DPoint(x(v), y(v))); - bendpoints.pushBack (DPoint(x(w), y(w))); - break; - case 1 : // determine intersection with node and [center, last-bend-point] - bendpoints.pushFront(DPoint(x(v), y(v))); - bendpoints.pushBack (DPoint(x(w), y(w))); - case 2 : // determine intersection between node and last bend-segment - { - DPoint sp1(x(v) - width(v)/2, y(v) - height(v)/2); - DPoint sp2(x(v) - width(v)/2, y(v) + height(v)/2); - DPoint sp3(x(v) + width(v)/2, y(v) + height(v)/2); - DPoint sp4(x(v) + width(v)/2, y(v) - height(v)/2); - DLine sourceRect[4] = { - DLine(sp1, sp2), - DLine(sp2, sp3), - DLine(sp3, sp4), - DLine(sp4, sp1) - }; - - DPoint tp1(x(w) - width(w)/2, y(w) - height(w)/2); - DPoint tp2(x(w) - width(w)/2, y(w) + height(w)/2); - DPoint tp3(x(w) + width(w)/2, y(w) + height(w)/2); - DPoint tp4(x(w) + width(w)/2, y(w) - height(w)/2); - DLine targetRect[4] = { - DLine(tp1, tp2), - DLine(tp2, tp3), - DLine(tp3, tp4), - DLine(tp4, tp1) - }; - - DRect source(sp1, sp3); - DRect target(tp1, tp3); - - DPoint c1 = bendpoints.popFrontRet(); - DPoint c2 = bendpoints.popBackRet(); - - while (!bendpoints.empty() && source.contains(bendpoints.front())) - c1 = bendpoints.popFrontRet(); - while (!bendpoints.empty() && target.contains(bendpoints.back())) - c2 = bendpoints.popBackRet(); - - DPoint a1, a2; - int i; - if (bendpoints.size() == 0) { - DLine cross(c1, c2); - for (i = 0; i < 4; i++) - if (cross.intersection(sourceRect[i], a1)) break; - for (i = 0; i < 4; i++) - if (cross.intersection(targetRect[i], a2)) break; - } - else { - DLine cross1(c1, bendpoints.front()); - for (i = 0; i < 4; i++) - if (cross1.intersection(sourceRect[i], a1)) break; - DLine cross2(bendpoints.back(), c2); - for (i = 0; i < 4; i++) - if (cross2.intersection(targetRect[i], a2)) break; - } - bendpoints.pushFront(a1); - bendpoints.pushBack(a2); - break; - } - OGDF_NODEFAULT - } - bendpoints.normalize(); - } -} - -/* Methods for OGML serialization */ - -// static helper method for mapping edge styles to ogml -const char * GraphAttributes::edgeStyleToOGML(const GraphAttributes::EdgeStyle & edgeStyle) -{ - switch (edgeStyle) { - case GraphAttributes::esNoPen: - return "esNoPen"; - case GraphAttributes::esSolid: - return "esSolid"; - case GraphAttributes::esDash: - return "esDash"; - case GraphAttributes::esDot: - return "esDot"; - case GraphAttributes::esDashdot: - return "esDashdot"; - case GraphAttributes::esDashdotdot: - return "esDashdotdot"; - default: - return "esSolid"; - }//switch -} - -// static helper method for mapping image alignments to ogml -const char * GraphAttributes::imageAlignmentToOGML(const GraphAttributes::ImageAlignment &imgAlign) -{ - switch (imgAlign) { - case GraphAttributes::TopLeft: - return "topLeft"; - case GraphAttributes::TopCenter: - return "topCenter"; - case GraphAttributes::TopRight: - return "topRight"; - case GraphAttributes::CenterLeft: - return "centerLeft"; - case GraphAttributes::Center: - return "center"; - case GraphAttributes::CenterRight: - return "centerRight"; - case GraphAttributes::BottomLeft: - return "bottomLeft"; - case GraphAttributes::BottomCenter: - return "bottomCenter"; - case GraphAttributes::BottomRight: - return "bottomRight"; - default: - return "center"; - }//switch -} - - -// static helper method for mapping image style to ogml -const char * GraphAttributes::imageStyleToOGML(const GraphAttributes::ImageStyle &imgStyle) -{ - switch (imgStyle) { - case GraphAttributes::FreeScale: return "freeScale"; - case GraphAttributes::FixScale: return "fixScale"; - default: return "freeScale"; - }//switch -} - - -// static helper method for mapping brush patterns styles to ogml -const char * GraphAttributes::brushPatternToOGML(const GraphAttributes::BrushPattern & brushPattern) -{ - switch (brushPattern) { - case GraphAttributes::bpNone: - return "bpNone"; - case GraphAttributes::bpSolid: - return "bpSolid"; - case GraphAttributes::bpDense1: - return "bpDense1"; - case GraphAttributes::bpDense2: - return "bpDense2"; - case GraphAttributes::bpDense3: - return "bpDense3"; - case GraphAttributes::bpDense4: - return "bpDense4"; - case GraphAttributes::bpDense5: - return "bpDense5"; - case GraphAttributes::bpDense6: - return "bpDense6"; - case GraphAttributes::bpDense7: - return "bpDense7"; - case GraphAttributes::bpHorizontal: - return "bpHorizontal"; - case GraphAttributes::bpVertical: - return "bpVertical"; - case GraphAttributes::bpCross: - return "bpCross"; - case GraphAttributes::BackwardDiagonal: - return "BackwardDiagonal"; - case GraphAttributes::ForwardDiagonal: - return "ForwardDiagonal"; - case GraphAttributes::DiagonalCross: - return "DiagonalCross"; - default: - return "bpSolid"; - }//switch -} - - -// static helper method for exchanging X(HT)ML-tag specific chars -String GraphAttributes::formatLabel(const String& labelText) -{ - size_t length = labelText.length(); - String formattedString; - - for (size_t i = 0; i < length; ++i) { - char c = labelText[i]; - if (c == '<') { - formattedString += "<"; - } else { - if (c == '>') { - formattedString += ">"; - if ((i+1 < length) && (labelText[i+1] != '\n')) - formattedString += '\n'; - } else { - formattedString += c; - } - } - } - return formattedString; -} - -void GraphAttributes::writeSVG(const String &fileName, int fontSize, const String &fontColor) const - { - ofstream os(fileName.cstr()); - writeSVG(os, fontSize, fontColor); - } - -void GraphAttributes::writeSVG(ostream &os, int fontSize, const String &fontColor) const -{ - os.setf(ios::showpoint); - os.precision(10); - - os << "\n"; - os << " 0); - double maxX = x((*m_pGraph).firstNode()); - double maxY = y((*m_pGraph).firstNode()); - double minX = x((*m_pGraph).firstNode()); - double minY = y((*m_pGraph).firstNode()); - double nodeStrokeWidth; - - node v; - forall_nodes(v, *m_pGraph) { - if (m_attributes & nodeStyle) { - nodeStrokeWidth = lineWidthNode(v); - } else { - nodeStrokeWidth = 1.0; - } - maxX = max(maxX, x(v) + m_width[v]/2 + nodeStrokeWidth); - maxY = max(maxY, y(v) + m_height[v]/2 + nodeStrokeWidth); - minX = min(minX, x(v) - m_width[v]/2 - nodeStrokeWidth); - minY = min(minY, y(v) - m_height[v]/2 - nodeStrokeWidth); - } - - edge e; - ListConstIterator it; - double edgeStrokeWidth; - forall_edges(e, *m_pGraph) { - if (m_attributes & edgeGraphics) { - if (attributes() & GraphAttributes::edgeStyle) { - edgeStrokeWidth = edgeWidth(e); - } else { - edgeStrokeWidth = 1.0; - } - const DPolyline &dpl = m_bends[e]; - if (!dpl.empty()) { - for(it = dpl.begin(); it.valid(); ++it) { - maxX = max(maxX, (*it).m_x + edgeStrokeWidth); - maxY = max(maxY, (*it).m_y + edgeStrokeWidth); - minX = min(minX, (*it).m_x - edgeStrokeWidth); - minY = min(minY, (*it).m_y - edgeStrokeWidth); - } - } - } - } - - os << "width=\"" << (maxX - minX) << "px\" "; - os << "height=\"" << (maxY - minY) << "px\" "; - os << "viewBox=\"" << 0 << " " << 0 << " " << (maxX - minX) << " " << (maxY - minY) << "\">\n"; - - forall_edges(e, *m_pGraph) { - - const DPolyline &dpl = m_bends[e]; - if (m_attributes & edgeGraphics) { - if (!dpl.empty()) { //polyline - os << "source(); - if(dpl.front().m_x < m_x[v] - m_width[v]/2 || - dpl.front().m_x > m_x[v] + m_width[v]/2 || - dpl.front().m_y < m_y[v] - m_height[v]/2 || - dpl.front().m_y > m_y[v] + m_height[v]/2) - { - os << (m_x[e->source()] - minX) << "," << (m_y[e->source()] - minY) << " "; - } - - for(it = dpl.begin(); it.valid(); ++it) - os << ((*it).m_x - minX) << "," << ((*it).m_y - minY) << " "; - - v = e->target(); - if(dpl.back().m_x < m_x[v] - m_width[v]/2 || - dpl.back().m_x > m_x[v] + m_width[v]/2 || - dpl.back().m_y < m_y[v] - m_height[v]/2 || - dpl.back().m_y > m_y[v] + m_height[v]/2) - { - os << (m_x[e->target()] - minX) << "," << (m_y[e->target()] - minY) << " "; - } - - os << "\"/>\n"; - } else { // single line - os << "source()) - minX << "\" "; - os << "y1=\"" << y(e->source()) - minY << "\" "; - os << "x2=\"" << x(e->target()) - minX << "\" "; - os << "y2=\"" << y(e->target()) - minY<< "\" "; - - if ((m_attributes & edgeColor) && (m_edgeColor[e].length() != 0)) { - os << "stroke=\"" << m_edgeColor[e] << "\" "; - } else { - os << "stroke=\"#000000\" "; - } - - if (attributes() & GraphAttributes::edgeStyle) { - os << "stroke-width=\"" << edgeWidth(e) << "px\" "; - } - - os << "/>\n"; - } - } - } - - forall_nodes(v,*m_pGraph) { - if (m_attributes & nodeGraphics) { - switch (m_nodeShape[v]) - { - case rectangle: - os << "\n"; - - if(m_attributes & nodeLabel){ - os << "" << m_nodeLabel[v] << "\n"; - } - } - } - - os << "\n"; -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/GraphConstraints.cpp b/ext/OGDF/src/basic/GraphConstraints.cpp deleted file mode 100644 index 5229c6737..000000000 --- a/ext/OGDF/src/basic/GraphConstraints.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class GraphConstraints that handles - * drawing constraints specified for a specific graph. - * - * \author PG478 - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ -#include - -namespace ogdf { - -void GraphConstraints::nodeDeleted(node v) -{ - ListConstIterator it; - for(it = m_List.begin(); it.valid(); ++it) - { - Constraint *c = *it; - c->nodeDeleted(v); - } -} - -List GraphConstraints::getConstraintsOfType(int type) -{ - List res; - ListConstIterator it; - for(it = m_List.begin(); it.valid(); ++it) - { - Constraint *c = *it; - if (type==c->getType()) - { - if (c->isValid()) res.pushBack(c); - } - } - return res; -} - -} diff --git a/ext/OGDF/src/basic/GraphCopy.cpp b/ext/OGDF/src/basic/GraphCopy.cpp deleted file mode 100644 index cdc7f7918..000000000 --- a/ext/OGDF/src/basic/GraphCopy.cpp +++ /dev/null @@ -1,677 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of GraphCopySimple and GraphCopy classes - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// GraphCopySimple -// simple graph copies (no support for edge splitting) -//--------------------------------------------------------- - -GraphCopySimple::GraphCopySimple(const Graph &G) : m_pGraph(&G) -{ - Graph::construct(G,m_vCopy,m_eCopy); - - m_vOrig.init(*this,0); - m_eOrig.init(*this,0); - - node v; - forall_nodes(v,G) - m_vOrig[m_vCopy[v]] = v; - - edge e; - forall_edges(e,G) - m_eOrig[m_eCopy[e]] = e; -} - - -GraphCopySimple::GraphCopySimple(const GraphCopySimple &GC) -{ - NodeArray vCopy; - EdgeArray eCopy; - - Graph::construct(GC,vCopy,eCopy); - initGC(GC,vCopy,eCopy); -} - - -GraphCopySimple &GraphCopySimple::operator=(const GraphCopySimple &GC) -{ - NodeArray vCopy; - EdgeArray eCopy; - - Graph::assign(GC,vCopy,eCopy); - initGC(GC,vCopy,eCopy); - - return *this; -} - - -void GraphCopySimple::initGC(const GraphCopySimple &GC, - NodeArray &vCopy, - EdgeArray &eCopy) -{ - m_pGraph = GC.m_pGraph; - - m_vOrig.init(*this,0); m_eOrig.init(*this,0); - m_vCopy.init(*m_pGraph,0); m_eCopy.init(*m_pGraph,0); - - node v; - forall_nodes(v,GC) - m_vCopy[m_vOrig[vCopy[v]] = GC.m_vOrig[v]] = vCopy[v]; - - edge e; - forall_edges(e,GC) { - edge eOrig = GC.m_eOrig[e]; - m_eOrig[eCopy[e]] = eOrig; - if (eOrig) - m_eCopy[eOrig] = eCopy[e]; - } -} - - -//--------------------------------------------------------- -// GraphCopy -// graph copies (support for edge splitting) -//--------------------------------------------------------- - -GraphCopy::GraphCopy(const Graph &G) : m_pGraph(&G) -{ - EdgeArray eCopy; - Graph::construct(G,m_vCopy,eCopy); - - m_vOrig.init(*this,0); m_eOrig.init(*this,0); - m_eCopy.init(*m_pGraph); - m_eIterator.init(*this,0); - - node v; - forall_nodes(v,G) - m_vOrig[m_vCopy[v]] = v; - - edge e; - forall_edges(e,G) { - m_eIterator[eCopy[e]] = m_eCopy[e].pushBack(eCopy[e]); - m_eOrig[eCopy[e]] = e; - } -} - - -GraphCopy::GraphCopy(const GraphCopy &GC) -{ - NodeArray vCopy; - EdgeArray eCopy; - - Graph::construct(GC,vCopy,eCopy); - initGC(GC,vCopy,eCopy); -} - - -void GraphCopy::initGC(const GraphCopy &GC, - NodeArray &vCopy, - EdgeArray &eCopy) -{ - m_pGraph = GC.m_pGraph; - - m_vOrig.init(*this,0); m_eOrig.init(*this,0); - m_vCopy.init(*m_pGraph,0); m_eCopy.init(*m_pGraph); - m_eIterator.init(*this,0); - - node v, w; - forall_nodes(v,GC) - m_vOrig[vCopy[v]] = GC.original(v); - - edge e; - forall_edges(e,GC) - m_eOrig[eCopy[e]] = GC.original(e); - - forall_nodes(v,*this) - if ((w = m_vOrig[v]) != 0) m_vCopy[w] = v; - - forall_edges(e,*m_pGraph) { - ListConstIterator it; - for (it = GC.m_eCopy[e].begin(); it.valid(); ++it) - m_eIterator[eCopy[*it]] = m_eCopy[e].pushBack(eCopy[*it]); - } -} - - -void GraphCopy::createEmpty(const Graph &G) -{ - m_pGraph = &G; - - m_vCopy.init(G,0); - m_eCopy.init(G); - m_vOrig.init(*this,0); - m_eOrig.init(*this,0); - m_eIterator.init(*this,0); -} - - -void GraphCopy::initByNodes(const List &nodes, EdgeArray &eCopy) -{ - Graph::constructInitByNodes(*m_pGraph,nodes,m_vCopy,eCopy); - - ListConstIterator itV; - for(itV = nodes.begin(); itV.valid(); ++itV) - { - node v = *itV; - - m_vOrig[m_vCopy[v]] = v; - - adjEntry adj; - forall_adj(adj,v) { - if ((adj->index() & 1) == 0) { - edge e = adj->theEdge(); - // - // edge ec = eCopy[e]; - // - m_eIterator[eCopy[e]] = m_eCopy[e].pushBack(eCopy[e]); - m_eOrig[eCopy[e]] = e; - } - } - } - -} - -void GraphCopy::initByActiveNodes( - const List &nodes, - const NodeArray &activeNodes, - EdgeArray &eCopy) -{ - Graph::constructInitByActiveNodes(nodes, activeNodes, m_vCopy, eCopy); - - ListConstIterator itV; - for(itV = nodes.begin(); itV.valid(); ++itV) - { - node v = *itV; - - m_vOrig[m_vCopy[v]] = v; - - adjEntry adj; - forall_adj(adj,v) { - if ((adj->index() & 1) == 0) { - edge e = adj->theEdge(); - // - // edge ec = eCopy[e]; - // - OGDF_ASSERT(m_eCopy[e].size() == 0) - if (activeNodes[e->opposite(v)]) - { - m_eIterator[eCopy[e]] = m_eCopy[e].pushBack(eCopy[e]); - m_eOrig[eCopy[e]] = e; - } - } - } - } - -} - - -GraphCopy &GraphCopy::operator=(const GraphCopy &GC) -{ - NodeArray vCopy; - EdgeArray eCopy; - - Graph::assign(GC,vCopy,eCopy); - initGC(GC,vCopy,eCopy); - - return *this; -} - - -void GraphCopy::setOriginalEmbedding() -{ - node v; - forall_nodes(v, *m_pGraph) - { - if (m_vCopy[v] != 0) - { - adjEntry adjOr; - List newAdjOrder; - newAdjOrder.clear(); - - forall_adj(adjOr, v) - { - if (m_eCopy[adjOr->theEdge()].size() > 0){ - //we have outgoing adjEntries for all - //incoming and outgoing edges, check the direction - //to find the correct copy adjEntry - bool outEdge = (adjOr == (adjOr->theEdge()->adjSource())); - - OGDF_ASSERT(chain(adjOr->theEdge()).size() == 1); - edge cEdge = chain(adjOr->theEdge()).front(); - adjEntry cAdj = (outEdge ? cEdge->adjSource() : cEdge->adjTarget()); - newAdjOrder.pushBack(cAdj); - } - }//foralladj - sort(copy(v), newAdjOrder); - } - }//forallnodes -} - - -edge GraphCopy::split(edge e) -{ - edge eNew = Graph::split(e); - edge eOrig = m_eOrig[e]; - - if ((m_eOrig[eNew] = eOrig) != 0) { - m_eIterator[eNew] = m_eCopy[eOrig].insert(eNew,m_eIterator[e],after); - } - - return eNew; -} - - -void GraphCopy::unsplit(edge eIn, edge eOut) -{ - edge eOrig = m_eOrig[eOut]; - - // update chain of eOrig if eOrig exists - if (eOrig != 0) { - m_eCopy[eOrig].del(m_eIterator[eOut]); - } - - Graph::unsplit(eIn,eOut); -} - - -edge GraphCopy::newEdge(edge eOrig) -{ - OGDF_ASSERT(eOrig != 0 && eOrig->graphOf() == m_pGraph); - OGDF_ASSERT(m_eCopy[eOrig].empty()); // no support for edge splitting! - - edge e = Graph::newEdge(m_vCopy[eOrig->source()], m_vCopy[eOrig->target()]); - m_eCopy[m_eOrig[e] = eOrig].pushBack(e); - - return e; -} - -edge GraphCopy::newEdge(edge eOrig, adjEntry adjSrc, node w) -{ - OGDF_ASSERT(eOrig != 0 && eOrig->graphOf() == m_pGraph); - OGDF_ASSERT(m_eCopy[eOrig].empty()); // no support for edge splitting! - OGDF_ASSERT(w == m_vCopy[eOrig->target()]); - - edge e = Graph::newEdge(adjSrc, w); - m_eCopy[m_eOrig[e] = eOrig].pushBack(e); - - return e; -} - -edge GraphCopy::newEdge(edge eOrig, node v, adjEntry adjTgt) -{ - OGDF_ASSERT(eOrig != 0 && eOrig->graphOf() == m_pGraph); - OGDF_ASSERT(m_eCopy[eOrig].empty()); // no support for edge splitting! - OGDF_ASSERT(v == m_vCopy[eOrig->source()]); - - edge e = Graph::newEdge(v, adjTgt); - m_eCopy[m_eOrig[e] = eOrig].pushBack(e); - - return e; -} - - -//inserts edge preserving the embedding -//todo: rename adjEnd to show the symmetric character -edge GraphCopy::newEdge(node v, adjEntry adjEnd, edge eOrig, CombinatorialEmbedding &E) -{ - OGDF_ASSERT(v != 0 && adjEnd != 0) - OGDF_ASSERT(v->graphOf() == this && adjEnd->graphOf() == this); - OGDF_ASSERT(&(E.getGraph()) == this) - OGDF_ASSERT(m_eCopy[eOrig].size() == 0) - - //check which direction is correct - edge e; - if (original(v) == eOrig->source()) - e = E.splitFace(v, adjEnd); - else - e = E.splitFace(adjEnd, v); - m_eIterator[e] = m_eCopy[eOrig].pushBack(e); - m_eOrig[e] = eOrig; - - return e; -}//newedge - - -void GraphCopy::setEdge(edge eOrig, edge eCopy){ - OGDF_ASSERT(eOrig != 0 && eOrig->graphOf() == m_pGraph); - OGDF_ASSERT(eCopy != 0 && eCopy->graphOf() == this); - OGDF_ASSERT(eCopy->target() == m_vCopy[eOrig->target()]); - OGDF_ASSERT(eCopy->source() == m_vCopy[eOrig->source()]); - OGDF_ASSERT(m_eCopy[eOrig].empty()); - - m_eCopy[m_eOrig[eCopy] = eOrig].pushBack(eCopy); -} - - -void GraphCopy::insertEdgePathEmbedded( - edge eOrig, - CombinatorialEmbedding &E, - const SList &crossedEdges) -{ - m_eCopy[eOrig].clear(); - - adjEntry adjSrc, adjTgt; - SListConstIterator it = crossedEdges.begin(); - SListConstIterator itLast = crossedEdges.rbegin(); - - // iterate over all adjacency entries in crossedEdges except for first - // and last - adjSrc = *it; - for(++it; it != itLast; ++it) - { - adjEntry adj = *it; - // split edge - node u = E.split(adj->theEdge())->source(); - - // determine target adjacency entry and source adjacency entry - // in the next iteration step - adjTgt = u->firstAdj(); - adjEntry adjSrcNext = adjTgt->succ(); - - if (adjTgt != adj->twin()) - swap(adjTgt,adjSrcNext); - - // insert a new edge into the face - edge eNew = E.splitFace(adjSrc,adjTgt); - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = eOrig; - - adjSrc = adjSrcNext; - } - - // insert last edge - edge eNew = E.splitFace(adjSrc,*it); - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = eOrig; -} - - -void GraphCopy::insertEdgePath(edge eOrig, const SList &crossedEdges) -{ - node v = copy(eOrig->source()); - - SListConstIterator it; - for(it = crossedEdges.begin(); it.valid(); ++it) - { - node u = split((*it)->theEdge())->source(); - - edge eNew = newEdge(v,u); - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = eOrig; - - v = u; - } - - edge eNew = newEdge(v,copy(eOrig->target())); - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = eOrig; -} - -void GraphCopy::insertEdgePath(node srcOrig, node tgtOrig, const SList &crossedEdges) -{ - node v = copy(srcOrig); - - SListConstIterator it; - for(it = crossedEdges.begin(); it.valid(); ++it) - { - node u = split((*it)->theEdge())->source(); - - edge eNew = newEdge(v,u); - // m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = 0; - - v = u; - } - - edge eNew = newEdge(v,copy(tgtOrig)); - //m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = 0; -} - -//inserts crossing between two copy edges already in PlanRep -//returns newly introduced copy edge of crossed edge -//the crossing edge parameter is changed to allow iteration -//over an edge's crossings in the edge direction -//the parameter topDown describes he following: -// if the crossingEdge is running horizontally from left to right, -// is the crossedEdge direction top->down? -edge GraphCopy::insertCrossing( - edge& crossingEdge, - edge crossedEdge, - bool topDown) - //const SList &crossedCopies) -{ - //we first split the crossed edge - edge e = split(crossedEdge); - edge eOrig = original(crossingEdge); - adjEntry adSource = crossingEdge->adjSource(); - - //now we delete the crossing copy edge and replace it - //by two edges adjacent to the crossing vertex - //we have to consider the copy ordering of the - //original edge - //we have to keep the correct order of the adjacency entries - //because even without a combinatorial embedding, the - //ordering of the edges may already be fixed - //Problem: wie erkennt man die Reihenfolge am split? - //Man muss die Richtung der gekreuzten Kante kennen - //=>Parameter, und hier adjSource und adjTarget trennen - edge eNew1, eNew2; - if (topDown) - { - //case 1: crossingEdge runs top-down - eNew1 = newEdge(adSource, e->adjSource()); - eNew2 = newEdge(e->adjSource()->cyclicPred(), - crossingEdge->adjTarget()->cyclicPred()); - } - else - { - //case 2: crossingEdge runs bottom-up - eNew1 = newEdge(adSource, e->adjSource()->cyclicPred()); - eNew2 = newEdge(e->adjSource(), crossingEdge->adjTarget()->cyclicPred()); - }//else bottom up - //insert new edge after old entry - m_eIterator[eNew1] = m_eCopy[eOrig].insert(eNew1, m_eIterator[crossingEdge]); - m_eOrig[eNew1] = eOrig; - m_eIterator[eNew2] = m_eCopy[eOrig].insert(eNew2, m_eIterator[eNew1]); - m_eOrig[eNew2] = eOrig; - //now we delete the input copy edge - m_eCopy[eOrig].del(m_eIterator[crossingEdge]); - delEdge(crossingEdge); - crossingEdge = eNew2; - - return e;//eNew2; -} - -void GraphCopy::delCopy(edge e) -{ - edge eOrig = m_eOrig[e]; - - delEdge(e); - if (eOrig == 0) return; - - OGDF_ASSERT(m_eCopy[eOrig].size() == 1); - m_eCopy[eOrig].clear(); -} - - -void GraphCopy::delCopy(node v) -{ - node w = m_vOrig[v]; - if (w != 0) m_vCopy[w] = 0; - - adjEntry adj; - forall_adj(adj,v) - { - edge eo = m_eOrig[adj->theEdge()]; - if (eo != 0) - m_eCopy[eo].clear(); - } - - delNode(v); -} - - -void GraphCopy::removeEdgePathEmbedded( - CombinatorialEmbedding &E, - edge eOrig, - FaceSetPure &newFaces) -{ - const List &path = m_eCopy[eOrig]; - ListConstIterator it = path.begin(); - - newFaces.insert(E.joinFaces(*it)); - - for(++it; it.valid(); ++it) - { - edge e = *it; - node u = e->source(); - - newFaces.remove(E.rightFace(e->adjSource())); - newFaces.remove(E.rightFace(e->adjTarget())); - - newFaces.insert(E.joinFaces(e)); - - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj()->theEdge(); - if (eIn->target() != u) - swap(eIn,eOut); - - E.unsplit(eIn,eOut); - } - - m_eCopy[eOrig].clear(); -} - - -void GraphCopy::removeEdgePath(edge eOrig) -{ - const List &path = m_eCopy[eOrig]; - ListConstIterator it = path.begin(); - - delEdge(*it); - - for(++it; it.valid(); ++it) - { - edge e = *it; - node u = e->source(); - - delEdge(e); - - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj()->theEdge(); - if (eIn->target() != u) - swap(eIn,eOut); - - unsplit(eIn,eOut); - } - - m_eCopy[eOrig].clear(); -} - - - -bool GraphCopy::consistencyCheck() const -{ - if (Graph::consistencyCheck() == false) - return false; - - const Graph &G = *m_pGraph; - - node v, vG; - forall_nodes(vG,G) { - v = m_vCopy[vG]; -#ifdef OGDF_DEBUG - if (v && v->graphOf() != this) - return false; -#endif - if (v && m_vOrig[v] != vG) - return false; - } - - forall_nodes(v,*this) { - vG = m_vOrig[v]; -#ifdef OGDF_DEBUG - if(vG && vG->graphOf() != &G) - return false; -#endif - if (vG && m_vCopy[vG] != v) - return false; - } - - edge e, eG; - forall_edges(eG,G) { - const List &path = m_eCopy[eG]; - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - e = *it; -#ifdef OGDF_DEBUG - if (e->graphOf() != this) - return false; -#endif - if (m_eOrig[e] != eG) - return false; - } - } - - forall_edges(e,*this) { - eG = m_eOrig[e]; -#ifdef OGDF_DEBUG - if(eG && eG->graphOf() != &G) - return false; -#endif - } - - return true; -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/GridLayout.cpp b/ext/OGDF/src/basic/GridLayout.cpp deleted file mode 100644 index 6b61fe802..000000000 --- a/ext/OGDF/src/basic/GridLayout.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements classes GridLayout and GridLayoutMapped - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// GridLayout -//--------------------------------------------------------- - -IPolyline GridLayout::polyline(edge e) const -{ - IPolyline ipl = m_bends[e]; - IPoint ipStart = IPoint(m_x[e->source()],m_y[e->source()]); - IPoint ipEnd = IPoint(m_x[e->target()],m_y[e->target()]); - - if(ipl.empty() || ipStart != ipl.front()) - ipl.pushFront(ipStart); - - if(ipEnd != ipl.back() || ipl.size() < 2) - ipl.pushBack(ipEnd); - - return ipl; -} - -struct OGDF_EXPORT GridPointInfo -{ - GridPointInfo() : m_v(0), m_e(0) { } - GridPointInfo(node v) : m_v(v), m_e(0) { } - GridPointInfo(edge e) : m_v(0), m_e(e) { } - - bool operator==(const GridPointInfo &i) const { - return (m_v == i.m_v && m_e == i.m_e); - } - - bool operator!=(const GridPointInfo &i) const { - return !operator==(i); - } - - node m_v; - edge m_e; -}; - -ostream &operator<<(ostream &os, const GridPointInfo &i) -{ - if(i.m_v == 0 && i.m_e == 0) - os << "{}"; - else if(i.m_v != 0) - os << "{node " << i.m_v << "}"; - else - os << "{edge " << i.m_e << "}"; - - return os; -} - - -class IPointHashFunc { -public: - int hash(const IPoint &ip) { - return 7*ip.m_x + 23*ip.m_y; - } -}; - - -bool GridLayout::checkLayout() -{ - const Graph &G = *m_x.graphOf(); - HashArray H; - - node v; - forall_nodes(v,G) - { - IPoint ip = IPoint(m_x[v],m_y[v]); - GridPointInfo i = H[ip]; - if(i != GridPointInfo()) { - cout << "conflict of " << v << " with " << H[ip] << endl; - return false; - } - - H[ip] = GridPointInfo(v); - } - - edge e; - forall_edges(e,G) - { - const IPolyline &bends = m_bends[e]; - - ListConstIterator it; - for(it = bends.begin(); it.valid(); ++it) { - GridPointInfo i = H[*it]; - if(i != GridPointInfo()) { - cout << "conflict of bend point " << (*it) << " of edge " << e << " with " << H[*it] << endl; - return false; - } - - H[*it] = GridPointInfo(e); - } - - } - - return true; -} - -bool GridLayout::isRedundant(IPoint &p1, IPoint &p2, IPoint &p3) -{ - int dzy1 = p3.m_x - p2.m_x; - int dzy2 = p3.m_y - p2.m_y; - int dyx1 = p2.m_x - p1.m_x; - - if (dzy1 == 0) return (dyx1 == 0 || dzy2 == 0); - - int f = dyx1 * dzy2; - - return (f % dzy1 == 0 && (p2.m_y - p1.m_y) == f / dzy1); -} - -void GridLayout::compact(IPolyline &ip) -{ - if (ip.size() < 3) return; - - ListIterator it = ip.begin(); - IPoint p = *it; ++it; - for (it = it.succ(); it.valid(); ++it) { - ListIterator itPred = it.pred(); - if(p == *itPred || isRedundant(p,*itPred,*it)) { - ip.del(itPred); - } else { - p = *itPred; - } - } -} - -IPolyline GridLayout::getCompactBends(edge e) const -{ - IPolyline ipl = m_bends[e]; - - if (ipl.size() == 0) return ipl; - -#if 0 - IPoint ip_first = ipl.front(); - IPoint ip_last = ipl.back(); -#endif - - IPoint ip_src(m_x[e->source()],m_y[e->source()]); - IPoint ip_tgt(m_x[e->target()],m_y[e->target()]); - - ipl.pushFront(ip_src); - ipl.pushBack (ip_tgt); - - compact(ipl); - - ipl.popFront(); - ipl.popBack(); - -#if 0 - if (ip_first != ip_src && (ipl.empty() || ip_first != ipl.front())) - ipl.pushFront(ip_first); - if (ip_last != ip_tgt && (ipl.empty() || ip_last != ipl.back())) - ipl.pushBack(ip_last); -#endif - - return ipl; -} - - -void GridLayout::compactAllBends() -{ - const Graph &G = *m_x.graphOf(); - - edge e; - forall_edges(e,G) - m_bends[e] = getCompactBends(e); -} - -void GridLayout::remap(Layout &drawing) -{ - const Graph &G = *m_x.graphOf(); - - node v; - forall_nodes(v,G) { - drawing.x(v) = m_x[v]; - drawing.y(v) = m_y[v]; - } - -} - - -void GridLayout::computeBoundingBox(int &xmin, int &xmax, int &ymin, int &ymax) -{ - const Graph *pG = m_x.graphOf(); - - if(pG == 0 || pG->empty()) { - xmin = xmax = ymin = ymax = 0; - return; - } - - xmin = ymin = INT_MAX; - xmax = ymax = INT_MIN; - - node v; - forall_nodes(v,*pG) { - int x = m_x[v]; - if(x < xmin) xmin = x; - if(x > xmax) xmax = x; - - int y = m_y[v]; - if(y < ymin) ymin = y; - if(y > ymax) ymax = y; - } - - edge e; - forall_edges(e,*pG) { - ListConstIterator it; - for(it = m_bends[e].begin(); it.valid(); ++it) { - int x = (*it).m_x; - if(x < xmin) xmin = x; - if(x > xmax) xmax = x; - - int y = (*it).m_y; - if(y < ymin) ymin = y; - if(y > ymax) ymax = y; - } - } -} - - -int GridLayout::manhattanDistance(const IPoint &ip1, const IPoint &ip2) -{ - return abs(ip2.m_x-ip1.m_x) + abs(ip2.m_y-ip1.m_y); -} - -double GridLayout::euclideanDistance(const IPoint &ip1, const IPoint &ip2) -{ - double dx = ip2.m_x-ip1.m_x; - double dy = ip2.m_y-ip1.m_y; - - return sqrt(dx*dx + dy*dy); -} - - -int GridLayout::totalManhattanEdgeLength() const -{ - const Graph *pG = m_x.graphOf(); - int length = 0; - - edge e; - forall_edges(e,*pG) - length += manhattanEdgeLength(e); - //{ - // IPoint ip1 = IPoint(m_x[e->source()],m_y[e->source()]); - // ListConstIterator it = m_bends[e].begin(); - // for(; it.valid(); ++it) { - // length += manhattanDistance(ip1,*it); - // ip1 = *it; - // } - // length += manhattanDistance(ip1,IPoint(m_x[e->target()],m_y[e->target()])); - //} - - return length; -} - - -int GridLayout::maxManhattanEdgeLength() const -{ - const Graph *pG = m_x.graphOf(); - int length = 0; - - edge e; - forall_edges(e,*pG) - length = max( length, manhattanEdgeLength(e) ); - - return length; -} - - -int GridLayout::manhattanEdgeLength(edge e) const -{ - int length = 0; - - IPoint ip1 = IPoint(m_x[e->source()],m_y[e->source()]); - ListConstIterator it = m_bends[e].begin(); - for(; it.valid(); ++it) { - length += manhattanDistance(ip1,*it); - ip1 = *it; - } - length += manhattanDistance(ip1,IPoint(m_x[e->target()],m_y[e->target()])); - - return length; -} - - -double GridLayout::totalEdgeLength() const -{ - const Graph *pG = m_x.graphOf(); - double length = 0; - - edge e; - forall_edges(e,*pG) { - IPoint ip1 = IPoint(m_x[e->source()],m_y[e->source()]); - ListConstIterator it = m_bends[e].begin(); - for(; it.valid(); ++it) { - length += euclideanDistance(ip1,*it); - ip1 = *it; - } - length += euclideanDistance(ip1,IPoint(m_x[e->target()],m_y[e->target()])); - } - - return length; -} - - -int GridLayout::numberOfBends() const -{ - const Graph *pG = m_x.graphOf(); - int num = 0; - - edge e; - forall_edges(e,*pG) - num += m_bends[e].size(); - - return num; -} - - -//--------------------------------------------------------- -// GridLayoutMapped -//--------------------------------------------------------- - -GridLayoutMapped::GridLayoutMapped( - const PlanRep &PG, - const OrthoRep &OR, - double separation, - double cOverhang, - int fineness) : - GridLayout(PG), m_gridWidth(PG,0), m_gridHeight(PG,0), m_pPG(&PG) -{ - // determine grid mapping factor - double minDelta = separation; - - node v; - forall_nodes(v,PG) - { - node vOrig = PG.original(v); - if(vOrig == 0) continue; - - const OrthoRep::VertexInfoUML *pInfo = OR.cageInfo(v); - - for(int s = 0; s <= 3; ++s) { - const OrthoRep::SideInfoUML &si = pInfo->m_side[s]; - double size = (s & 1) ? PG.widthOrig(vOrig) : PG.heightOrig(vOrig); - if (size == 0) continue; - - if(si.m_adjGen) { - int k = max(si.m_nAttached[0],si.m_nAttached[1]); - if (k == 0) - minDelta = min(minDelta, size/2); - else - minDelta = min(minDelta, size / (2*(k + cOverhang))); - - } else { - if (si.m_nAttached[0] == 0) - minDelta = min(minDelta, size); - - else if ( !((si.m_nAttached[0] == 1) && (cOverhang == 0.0)) ) //hier cov= 0 abfangen - minDelta = min(minDelta, - size / (si.m_nAttached[0] - 1 + 2*cOverhang)); - else - minDelta = min(minDelta, size/2); - } - - } - - } - - if(0 < cOverhang && cOverhang < 1) { - /*double tryMinDelta = max(cOverhang * minDelta, separation/10000.0); - double tryMinDelta = max(cOverhang * minDelta, separation/10000.0); - if(tryMinDelta < minDelta) - minDelta = tryMinDelta;*/ - minDelta *= cOverhang; - } - - m_fMapping = fineness / minDelta; - - - // initialize grid sizes of vertices - forall_nodes(v,PG) - { - node vOrig = PG.original(v); - - if(vOrig) { - m_gridWidth [v] = toGrid(PG.widthOrig (vOrig)); - m_gridHeight[v] = toGrid(PG.heightOrig(vOrig)); - } - } -} - - -void GridLayoutMapped::remap(Layout &drawing) -{ - node v; - forall_nodes(v,*m_pPG) { - //should use toDouble here - drawing.x(v) = (m_x[v]/cGridScale) / m_fMapping; - drawing.y(v) = (m_y[v]/cGridScale) / m_fMapping; - } -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/basic/GridLayoutModule.cpp b/ext/OGDF/src/basic/GridLayoutModule.cpp deleted file mode 100644 index 31ab88239..000000000 --- a/ext/OGDF/src/basic/GridLayoutModule.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements grid mapping mechanism of class GridLayoutModule - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void GridLayoutModule::call(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - - // compute grid layout - GridLayout gridLayout(G); - doCall(G,gridLayout,m_gridBoundingBox); - - // transform grid layout to real layout - mapGridLayout(G,gridLayout,AG); -} - - -void GridLayoutModule::callGrid(const Graph &G, GridLayout &gridLayout) -{ - gridLayout.init(G); - doCall(G,gridLayout,m_gridBoundingBox); -} - - -void GridLayoutModule::mapGridLayout(const Graph &G, - GridLayout &gridLayout, - GraphAttributes &AG) -{ - double maxWidth = 0; // maximum width of columns and rows; - double yMax = 0; - - node v; - forall_nodes(v,G) { - if (AG.width (v) > maxWidth) maxWidth = AG.width (v); - if (AG.height(v) > maxWidth) maxWidth = AG.height(v); - if (gridLayout.y(v) > yMax) yMax = gridLayout.y(v); - } - - maxWidth += m_separation; - - // set position of nodes - forall_nodes(v,G) { - AG.x(v) = gridLayout.x(v) * maxWidth; - AG.y(v) = (yMax - gridLayout.y(v)) * maxWidth; - } - - // transform bend points of edges - edge e; - forall_edges(e,G) { - DPolyline &dpl = AG.bends(e); - dpl.clear(); - - IPolyline ipl = gridLayout.polyline(e); - ListConstIterator it; - for(it = ipl.begin(); it.valid(); ++it) { - const IPoint &ip = *it; - dpl.pushBack(DPoint(ip.m_x*maxWidth, (yMax-ip.m_y)*maxWidth)); - } - } -} - - -void PlanarGridLayoutModule::callFixEmbed(GraphAttributes &AG, adjEntry adjExternal) -{ - const Graph &G = AG.constGraph(); - - // compute grid layout - GridLayout gridLayout(G); - doCall(G,adjExternal,gridLayout,m_gridBoundingBox,true); - - // transform grid layout to real layout - mapGridLayout(G,gridLayout,AG); -} - - -void PlanarGridLayoutModule::callGridFixEmbed( - const Graph &G, - GridLayout &gridLayout, - adjEntry adjExternal) -{ - gridLayout.init(G); - doCall(G,adjExternal,gridLayout,m_gridBoundingBox,true); -} - - -void GridLayoutPlanRepModule::callGrid(PlanRep &PG, GridLayout &gridLayout) -{ - gridLayout.init(PG); - doCall(PG,0,gridLayout,m_gridBoundingBox,false); -} - -void GridLayoutPlanRepModule::callGridFixEmbed( - PlanRep &PG, - GridLayout &gridLayout, - adjEntry adjExternal) -{ - gridLayout.init(PG); - doCall(PG,adjExternal,gridLayout,m_gridBoundingBox,true); -} - -void GridLayoutPlanRepModule::doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) -{ - // create temporary graph copy and grid layout - PlanRep PG(G); - PG.initCC(0); // currently only for a single component! - GridLayout glPG(PG); - - // determine adjacency entry on external face of PG (if required) - if(adjExternal != 0) { - edge eG = adjExternal->theEdge(); - edge ePG = PG.copy(eG); - adjExternal = (adjExternal == eG->adjSource()) ? ePG->adjSource() : ePG->adjTarget(); - } - - // call algorithm for copy - doCall(PG,adjExternal,glPG,boundingBox,fixEmbedding); - - // extract layout for original graph - node v; - forall_nodes(v,G) { - node vPG = PG.copy(v); - gridLayout.x(v) = glPG.x(vPG); - gridLayout.y(v) = glPG.y(vPG); - } - - edge e; - forall_edges(e,G) { - IPolyline &ipl = gridLayout.bends(e); - ipl.clear(); - - ListConstIterator it; - for(it = PG.chain(e).begin(); it.valid(); ++it) - ipl.conc(glPG.bends(*it)); - } -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/basic/Hashing.cpp b/ext/OGDF/src/basic/Hashing.cpp deleted file mode 100644 index 479e384cb..000000000 --- a/ext/OGDF/src/basic/Hashing.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Hashing (class HashingBase) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - - -namespace ogdf { - -HashingBase::HashingBase(int minTableSize) -{ - m_count = 0; - init(m_minTableSize = minTableSize); -} - - -HashingBase::HashingBase(const HashingBase &H) -{ - copyAll(H); -} - - -HashingBase::~HashingBase() -{ - free(m_table); -} - - -void HashingBase::init(int tableSize) -{ - OGDF_ASSERT(tableSize >= m_minTableSize) - - m_tableSize = tableSize; - m_hashMask = tableSize-1; - m_tableSizeHigh = tableSize << 1; - m_tableSizeLow = (tableSize > m_minTableSize) ? (tableSize >> 1) : -1; - - m_table = (HashElementBase **)calloc(tableSize,sizeof(HashElementBase *)); -} - - -void HashingBase::destroyAll() -{ - HashElementBase **pList = m_table, **pListStop = m_table+m_tableSize; - - for(; pList != pListStop; ++pList) { - HashElementBase *pElement = *pList, *pNext; - for (; pElement; pElement = pNext) { - pNext = pElement->next(); - destroy(pElement); - } - } -} - - -void HashingBase::copyAll(const HashingBase &H) -{ - m_count = 0; - init(H.m_tableSize); - - HashElementBase **pList = H.m_table; - HashElementBase **pListStop = H.m_table+m_tableSize; - - for(; pList != pListStop; ++pList) { - HashElementBase *pElement = *pList; - for (; pElement; pElement = pElement->next()) - insert(H.copy(pElement)); - } -} - - -void HashingBase::clear() -{ - destroyAll(); - free(m_table); - - m_count = 0; - init(m_minTableSize); -} - - -HashingBase &HashingBase::operator=(const HashingBase &H) -{ - destroyAll(); - free(m_table); - copyAll(H); - return *this; -} - - -void HashingBase::resize(int newTableSize) -{ - HashElementBase **oldTable = m_table; - HashElementBase **oldTableStop = oldTable + m_tableSize; - - init(newTableSize); - - for(HashElementBase **pOldList = oldTable; - pOldList != oldTableStop; ++pOldList) - { - HashElementBase *pElement = *pOldList, *pNext; - for(; pElement; pElement = pNext) { - pNext = pElement->m_next; - - HashElementBase **pList = m_table + - (pElement->m_hashValue & m_hashMask); - pElement->m_next = *pList; - *pList = pElement; - } - } - - free(oldTable); -} - - -void HashingBase::insert(HashElementBase *pElement) -{ - if (++m_count == m_tableSizeHigh) - resize(m_tableSizeHigh); - - HashElementBase **pList = m_table + (pElement->m_hashValue & m_hashMask); - pElement->m_next = *pList; - *pList = pElement; -} - - -void HashingBase::del(HashElementBase *pElement) -{ - HashElementBase **pList = m_table + (pElement->m_hashValue & m_hashMask); - HashElementBase *pPrev = *pList; - - if (pPrev == pElement) { - *pList = pElement->m_next; - - } else { - while (pPrev->m_next != pElement) pPrev = pPrev->m_next; - pPrev->m_next = pElement->m_next; - } - - if (--m_count == m_tableSizeLow) - resize(m_tableSizeLow); -} - - -HashElementBase *HashingBase::firstElement(HashElementBase ***pList) const -{ - HashElementBase **pStop = m_table + m_tableSize; - for(*pList = m_table; *pList != pStop; ++(*pList)) - if (**pList) return **pList; - - return 0; -} - - -HashElementBase *HashingBase::nextElement(HashElementBase ***pList, - HashElementBase *pElement) const -{ - if ((pElement = pElement->next()) != 0) return pElement; - - HashElementBase **pStop = m_table + m_tableSize; - for(++(*pList); *pList != pStop; ++(*pList)) - if (**pList) return **pList; - - return 0; -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/Logger.cpp b/ext/OGDF/src/basic/Logger.cpp deleted file mode 100644 index d9be5a1a6..000000000 --- a/ext/OGDF/src/basic/Logger.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Logging functionality - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - -// initializers -#ifdef OGDF_DEBUG -Logger::Level Logger::m_globalloglevel = Logger::LL_DEFAULT; -Logger::Level Logger::m_minimumloglevel = Logger::LL_MINOR; -#else // RELEASE -Logger::Level Logger::m_globalloglevel = Logger::LL_ALARM; // forbid anything except alarms and forced writes -> logging is off -Logger::Level Logger::m_minimumloglevel = Logger::LL_MEDIUM; -#endif - -std::ostream* Logger::world = &std::cout; -std::ostream Logger::nirvana(NULL); - -bool Logger::m_globalstatisticmode = false; - -} - diff --git a/ext/OGDF/src/basic/Math.cpp b/ext/OGDF/src/basic/Math.cpp deleted file mode 100644 index af659c30b..000000000 --- a/ext/OGDF/src/basic/Math.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of mathematical constants, functions. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - - const double Math::pi = 3.14159265358979323846; - const double Math::pi_2 = 1.57079632679489661923; - const double Math::pi_4 = 0.785398163397448309616; - const double Math::two_pi = 2*3.14159265358979323846; - - const double Math::e = 2.71828182845904523536; - - const double Math::log_of_2 = log(2.0); - const double Math::log_of_4 = log(4.0); - - int factorials[13] = { - 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, - 3628800, 39916800, 479001600 - }; - - double factorials_d[20] = { - 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, - 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, - 1307674368000.0, 20922789888000.0, 355687428096000.0, - 6402373705728000.0, 121645100408832000.0 - }; - - int Math::binomial(int n, int k) - { - if(k>n/2) k = n-k; - if(k == 0) return 1; - int r = n; - for(int i = 2; i<=k; ++i) - r = (r * (n+1-i))/i; - return r; - } - - double Math::binomial_d(int n, int k) - { - if(k>n/2) k = n-k; - if(k == 0) return 1.0; - double r = n; - for(int i = 2; i<=k; ++i) - r = (r * (n+1-i))/i; - return r; - } - - int Math::factorial(int n) - { - if(n < 0) return 1; - if(n > 12) return INT_MAX; // not representable by int - - return factorials[n]; - } - - double Math::factorial_d(int n) - { - if(n < 0) return 1.0; - - double f = 1.0; - for(; n > 19; --n) - f *= n; - - return f * factorials_d[n]; - } - -} // namespace ogdf diff --git a/ext/OGDF/src/basic/NearestRectangleFinder.cpp b/ext/OGDF/src/basic/NearestRectangleFinder.cpp deleted file mode 100644 index 9d2da2685..000000000 --- a/ext/OGDF/src/basic/NearestRectangleFinder.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class NearestRectangleFinder - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - - -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// PairCoordId -// represents a pair of a coordinate (x or y) and the index -// of a rectangle -//--------------------------------------------------------- -struct OGDF_EXPORT NearestRectangleFinder::PairCoordId -{ - PairCoordId(double coord, int index) { - m_coord = coord; - m_index = index; - } - - PairCoordId() { } - - friend ostream &operator<<(ostream &os, const PairCoordId &p) { - os << "(" << p.m_coord << "," << p.m_index << ")"; - return os; - } - - double m_coord; - int m_index; -}; - - -//--------------------------------------------------------- -// CoordComparer -// comparer class for sorting PairCoordId according to -// decreasing coordinate -//--------------------------------------------------------- -class NearestRectangleFinder::CoordComparer -{ -public: - bool less (const PairCoordId &x, const PairCoordId &y) const { - return x.m_coord > y.m_coord; - } - bool leq (const PairCoordId &x, const PairCoordId &y) const { - return x.m_coord >= y.m_coord; - } - bool equal(const PairCoordId &x, const PairCoordId &y) const { - return x.m_coord == y.m_coord; - } -}; - - -//--------------------------------------------------------- -// YCoordComparer -// comparer class for sorting points (given by index) by -// decreasing y-coordinate -//--------------------------------------------------------- -class NearestRectangleFinder::YCoordComparer -{ -public: - YCoordComparer(const Array &point) { - m_point = &point; - } - - bool less (int x, int y) const { - return (*m_point)[x].m_y > (*m_point)[y].m_y; - } - bool leq (int x, int y) const { - return (*m_point)[x].m_y >= (*m_point)[y].m_y; - } - bool equal(int x, int y) const { - return (*m_point)[x].m_y == (*m_point)[y].m_y; - } - -private: - const Array *m_point; -}; - - - -//--------------------------------------------------------- -// NearestRectangleFinder -//--------------------------------------------------------- - -void NearestRectangleFinder::find( - const Array ®ion, - const Array &point, - Array > &nearest) -{ - const int n = region.size(); // number of rectangles - const int m = point.size(); // number of points - - List listTop; // list of max. y-coord. of rectangles - List listBottom; // list of min. y-coord. of rectangles - - // build lists listTop and listBottom ... - int i; - for(i = 0; i < n; ++i) { - const RectRegion &rect = region[i]; - listTop .pushBack(PairCoordId(rect.m_y + rect.m_height/2.0, i)); - listBottom.pushBack(PairCoordId(rect.m_y - rect.m_height/2.0, i)); - } - - // ... and sort them by decreasing coordinates - CoordComparer comparer; - listTop .quicksort(comparer); - listBottom.quicksort(comparer); - - // build array of point indices ... - Array sortedPoints(m); - for(i = 0; i < m; ++i) - sortedPoints[i] = i; - - // ... and sort them by decreasing y-coordinate - YCoordComparer yCoordComparer(point); - sortedPoints.quicksort(yCoordComparer); - - - ListPure active; // list of rectangles such that y-coord. of current - // point is contained y-projection of rectangle - - // We traverse the lists listTop and listBottom from start to end such that - // the coord. of the current entry in listTop is the first entry below p.y - // and the coord. of the current entry in listBottom is the first entry - // equal or below p.y - ListIterator nextTop = listTop .begin(); - ListIterator nextBottom = listBottom.begin(); - - - // position of a rectangle in active - Array > posInActive(n); - // list of rectangles visited for current point - BoundedStack visitedRectangles(n); - // distance of rectangle to current point (if contained in visitedRectangles) - Array distance(n); - - // the maximal distance we have to explore - // (if a rectangle lies at distance m_maxAllowedDistance, it can get - // ambigous if there are rectangles with distance <= maxDistanceVisit) - double maxDistanceVisit = m_maxAllowedDistance + m_toleranceDistance; - - // we iterate over all points by decreasing y-coordinate - for(i = 0; i < m; ++i) - { - const int nextPoint = sortedPoints[i]; - const DPoint &p = point[nextPoint]; - - // update active list - while(nextTop.valid() && (*nextTop).m_coord >= p.m_y) { - int index = (*nextTop).m_index; - posInActive[index] = active.pushBack(index); - ++nextTop; - } - - while(nextBottom.valid() && (*nextBottom).m_coord > p.m_y) { - active.del(posInActive[(*nextBottom).m_index]); - ++nextBottom; - } - - // the largest minDist value we have to consider - double minDist = maxDistanceVisit; - - // look for rectangles with minimal distance in active rectangles - // here the distance ist the distance in x-direction - ListIterator itActive; - for(itActive = active.begin(); itActive.valid(); ++itActive) - { - const RectRegion &rect = region[*itActive]; - double left = rect.m_x - rect.m_width/2.0; - double right = rect.m_x + rect.m_width/2.0; - - double xDist = 0.0; - if(p.m_x < left) - xDist = left - p.m_x; - else if (right < p.m_x) - xDist = p.m_x - right; - - if(xDist < minDist) { - minDist = xDist; - } - - visitedRectangles.push(*itActive); - distance[*itActive] = xDist; - } - - // starting at p.y, we iterate simultaniously upward and downward. - // We go upward in listBottom since these rectangles lie completely - // above p, and downward in listTop since these rectangles lie - // completely below p - ListIterator itTop = nextTop; - ListIterator itBottom = - (nextBottom.valid()) ? nextBottom.pred() : listBottom.rbegin(); - - while(itTop.valid() || itBottom.valid()) - { - if(itTop.valid()) - { - if((*itTop).m_coord < p.m_y - minDist) - itTop = ListIterator(); - else { - // determine distance between *itTop and p - const RectRegion &rect = region[(*itTop).m_index]; - double left = rect.m_x - rect.m_width/2.0; - double right = rect.m_x + rect.m_width/2.0; - - double xDist = 0.0; - if(p.m_x < left) - xDist = left - p.m_x; - else if (right < p.m_x) - xDist = p.m_x - right; - - double dist = xDist + (p.m_y - (*itTop).m_coord); - OGDF_ASSERT(dist > 0); - - if(dist < minDist) { - minDist = dist; - } - - // update visited rectangles - visitedRectangles.push((*itTop).m_index); - distance[(*itTop).m_index] = dist; - - ++itTop; - } - } - - if(itBottom.valid()) - { - if((*itBottom).m_coord > p.m_y + minDist) - itBottom = ListIterator(); - else { - // determine distance between *itBottom and p - const RectRegion &rect = region[(*itBottom).m_index]; - double left = rect.m_x - rect.m_width/2.0; - double right = rect.m_x + rect.m_width/2.0; - - double xDist = 0.0; - if(p.m_x < left) - xDist = left - p.m_x; - else if (right < p.m_x) - xDist = p.m_x - right; - - double dist = xDist + ((*itBottom).m_coord - p.m_y); - OGDF_ASSERT(dist > 0); - - if(dist < minDist) { - minDist = dist; - } - - // update visited rectangles - visitedRectangles.push((*itBottom).m_index); - distance[(*itBottom).m_index] = dist; - - --itBottom; - } - } - } - - // if the minimum found distance is outside the allowed distance - // we return an empty list for p - if(minDist > m_maxAllowedDistance) { - visitedRectangles.clear(); - - } else { - // otherwise we return all rectangles which are at most minimal - // distance plus tolerance away - double max = minDist + m_toleranceDistance; - while(!visitedRectangles.empty()) - { - int index = visitedRectangles.pop(); - if(distance[index] <= max) - nearest[nextPoint].pushBack(PairRectDist(index,distance[index])); - } - } - } -} - - -// simple version of find() which is used for correction checking -// this version only computes the nearest rectangle without considering -// maxAllowedDistance and toleranceDistance. -void NearestRectangleFinder::findSimple( - const Array ®ion, - const Array &point, - Array > &nearest) -{ - const int n = region.size(); - const int m = point.size(); - - for(int i = 0; i < m; ++i) - { - const DPoint &p = point[i]; - double minDist = DBL_MAX; - int minDistIndex = -1; - - for(int j = 0; j < n; ++j) - { - const RectRegion &rect = region[j]; - - double left = rect.m_x - rect.m_width/2.0; - double right = rect.m_x + rect.m_width/2.0; - - double xDist = 0.0; - if(p.m_x < left) - xDist = left - p.m_x; - else if (right < p.m_x) - xDist = p.m_x - right; - OGDF_ASSERT(xDist >= 0); - - double bottom = rect.m_y - rect.m_height/2.0; - double top = rect.m_y + rect.m_height/2.0; - - double yDist = 0.0; - if(p.m_y < bottom) - yDist = bottom - p.m_y; - else if (top < p.m_y) - yDist = p.m_y - top; - OGDF_ASSERT(yDist >= 0); - - double dist = xDist + yDist; - - if(dist < minDist) { - minDist = dist; - minDistIndex = j; - } - } - - //const RectRegion &rect = region[minDistIndex]; - if(minDist <= m_maxAllowedDistance) - nearest[i].pushBack(PairRectDist(minDistIndex,minDist)); - } -} - - - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/basic/PoolMemoryAllocator.cpp b/ext/OGDF/src/basic/PoolMemoryAllocator.cpp deleted file mode 100644 index a5d7cf079..000000000 --- a/ext/OGDF/src/basic/PoolMemoryAllocator.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of memory manager for more efficiently - * allocating small pieces of memory - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -struct PoolMemoryAllocator::PoolVector -{ - MemElemPtr m_pool[ePoolVectorLength]; - PoolVector *m_prev; -}; - -struct PoolMemoryAllocator::PoolElement -{ - PoolVector *m_currentVector; - MemElemPtr m_restHead; - MemElemPtr m_restTail; - __int16 m_index; - __int16 m_restCount; -}; - -struct PoolMemoryAllocator::BlockChain -{ - char m_fill[eBlockSize-sizeof(void*)]; - BlockChain *m_next; -}; - - -PoolMemoryAllocator::PoolElement PoolMemoryAllocator::s_pool[eTableSize]; -PoolMemoryAllocator::MemElemPtr PoolMemoryAllocator::s_freeVectors; -PoolMemoryAllocator::BlockChainPtr PoolMemoryAllocator::s_blocks; - -#ifdef OGDF_MEMORY_POOL_NTS -PoolMemoryAllocator::MemElemPtr PoolMemoryAllocator::s_tp[eTableSize]; -#elif defined(OGDF_NO_COMPILER_TLS) -CriticalSection *PoolMemoryAllocator::s_criticalSection; -pthread_key_t PoolMemoryAllocator::s_tpKey; -#else -CriticalSection *PoolMemoryAllocator::s_criticalSection; -OGDF_DECL_THREAD PoolMemoryAllocator::MemElemPtr PoolMemoryAllocator::s_tp[eTableSize]; -#endif - - -void PoolMemoryAllocator::init() -{ -#ifndef OGDF_MEMORY_POOL_NTS -#ifdef OGDF_NO_COMPILER_TLS - pthread_key_create(&s_tpKey,NULL); -#endif - s_criticalSection = new CriticalSection(500); -#endif - initThread(); -} - - -void PoolMemoryAllocator::initThread() { -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - pthread_setspecific(s_tpKey,calloc(eTableSize,sizeof(MemElemPtr))); -#endif -} - - -void PoolMemoryAllocator::cleanup() -{ - BlockChainPtr p = s_blocks; - while(p != 0) { - BlockChainPtr pNext = p->m_next; - free(p); - p = pNext; - } - -#ifndef OGDF_MEMORY_POOL_NTS -#ifdef OGDF_NO_COMPILER_TLS - pthread_key_delete(s_tpKey); -#endif - delete s_criticalSection; -#endif -} - - -bool PoolMemoryAllocator::checkSize(size_t nBytes) { - return nBytes < eTableSize; -} - - -void *PoolMemoryAllocator::allocate(size_t nBytes) { -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - MemElemPtr *pFreeBytes = ((MemElemPtr*)pthread_getspecific(s_tpKey))+nBytes; -#else - MemElemPtr *pFreeBytes = s_tp+nBytes; -#endif - if (OGDF_LIKELY(*pFreeBytes != 0)) { - MemElemPtr p = *pFreeBytes; - *pFreeBytes = p->m_next; - return p; - } else { - return fillPool(*pFreeBytes,__uint16(nBytes)); - } -} - - -void PoolMemoryAllocator::deallocate(size_t nBytes, void *p) { -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - MemElemPtr *pFreeBytes = ((MemElemPtr*)pthread_getspecific(s_tpKey))+nBytes; -#else - MemElemPtr *pFreeBytes = s_tp+nBytes; -#endif - MemElemPtr(p)->m_next = *pFreeBytes; - *pFreeBytes = MemElemPtr(p); -} - - -void PoolMemoryAllocator::deallocateList(size_t nBytes, void *pHead, void *pTail) { -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - MemElemPtr *pFreeBytes = ((MemElemPtr*)pthread_getspecific(s_tpKey))+nBytes; -#else - MemElemPtr *pFreeBytes = s_tp+nBytes; -#endif - MemElemPtr(pTail)->m_next = *pFreeBytes; - *pFreeBytes = MemElemPtr(pHead); -} - - -PoolMemoryAllocator::MemElemExPtr -PoolMemoryAllocator::collectGroups( - __uint16 nBytes, - MemElemPtr &pRestHead, - MemElemPtr &pRestTail, - int &nRest) -{ - int n = slicesPerBlock(nBytes); - pRestHead = 0; - -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - MemElemPtr p = ((MemElemPtr*)pthread_getspecific(s_tpKey))[nBytes]; -#else - MemElemPtr p = s_tp[nBytes]; -#endif - MemElemExPtr pStart = 0, pLast = 0; - while(p != 0) - { - int i = 0; - MemElemPtr pHead = p, pTail; - do { - pTail = p; - p = p->m_next; - } while(++i < n && p != 0); - - pTail->m_next = 0; - if(i == n) { - if(pStart == 0) - pStart = MemElemExPtr(pHead); - else - pLast->m_down = MemElemExPtr(pHead); - pLast = MemElemExPtr(pHead); - - } else { - pRestHead = pHead; - pRestTail = pTail; - nRest = i; - } - } - if (pLast) - pLast->m_down = 0; - - return pStart; -} - - -void PoolMemoryAllocator::flushPoolSmall(__uint16 nBytes) -{ - int n = slicesPerBlock(nBytes < eMinBytes ? eMinBytes : nBytes); - PoolElement &pe = s_pool[nBytes]; - -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - MemElemPtr p = ((MemElemPtr*)pthread_getspecific(s_tpKey))[nBytes]; -#else - MemElemPtr p = s_tp[nBytes]; -#endif - if(pe.m_restHead != 0) { - pe.m_restTail->m_next = p; - p = pe.m_restHead; - pe.m_restHead = 0; - } - - while(p != 0) - { - int i = 0; - MemElemPtr pHead = p, pTail; - do { - pTail = p; - p = p->m_next; - } while(++i < n && p != 0); - - if(i == n) { - incVectorSlot(pe); - pe.m_currentVector->m_pool[pe.m_index] = pHead; - - } else { - pe.m_restHead = pHead; - pe.m_restTail = pTail; - pe.m_restCount = i; - } - } -} - - -void PoolMemoryAllocator::incVectorSlot(PoolElement &pe) -{ - if(pe.m_currentVector == 0 || ++pe.m_index == ePoolVectorLength) { - if(s_freeVectors == 0) - s_freeVectors = allocateBlock(sizeof(PoolVector)); - - PoolVector *pv = (PoolVector *)s_freeVectors; - s_freeVectors = MemElemPtr(pv)->m_next; - pe.m_currentVector = pv; - pe.m_index = 0; - } -} - - -void PoolMemoryAllocator::flushPool(__uint16 nBytes) -{ -#ifndef OGDF_MEMORY_POOL_NTS - if(nBytes >= sizeof(MemElemEx)) { - MemElemPtr pRestHead, pRestTail; - int nRest; - MemElemExPtr pStart = collectGroups(nBytes, pRestHead, pRestTail, nRest); - - s_criticalSection->enter(); - PoolElement &pe = s_pool[nBytes]; - - while(pStart != 0) { - incVectorSlot(pe); - pe.m_currentVector->m_pool[pe.m_index] = MemElemPtr(pStart); - pStart = pStart->m_down; - } - if(pRestHead != 0) { - int n = slicesPerBlock(nBytes); - pRestTail->m_next = pe.m_restTail; - int nTotal = nRest + pe.m_restCount; - if(nTotal >= n) { - MemElemPtr p = pe.m_restHead; - int i = n-nRest; - while(--i > 0) - p = p->m_next; - pe.m_restHead = p->m_next; - pe.m_restCount = nTotal-n; - incVectorSlot(pe); - pe.m_currentVector->m_pool[pe.m_index] = pRestHead; - } else { - pe.m_restHead = pRestHead; - pe.m_restCount = nTotal; - } - } - s_criticalSection->leave(); - - } else { - s_criticalSection->enter(); - flushPoolSmall(nBytes); - s_criticalSection->leave(); - } -#endif -} - - -void PoolMemoryAllocator::flushPool() -{ -#ifndef OGDF_MEMORY_POOL_NTS - for(__uint16 nBytes = 1; nBytes < eTableSize; ++nBytes) { -#ifdef OGDF_NO_COMPILER_TLS - MemElemPtr p = ((MemElemPtr*)pthread_getspecific(s_tpKey))[nBytes]; -#else - MemElemPtr p = s_tp[nBytes]; -#endif - if(p != 0) - flushPool(nBytes); - } -#endif -} - - -void *PoolMemoryAllocator::fillPool(MemElemPtr &pFreeBytes, __uint16 nBytes) -{ -#ifdef OGDF_MEMORY_POOL_NTS - pFreeBytes = allocateBlock(nBytes); -#else - - s_criticalSection->enter(); - - PoolElement &pe = s_pool[nBytes]; - if(pe.m_currentVector != 0) { - pFreeBytes = pe.m_currentVector->m_pool[pe.m_index]; - if(--pe.m_index < 0) { - PoolVector *pV = pe.m_currentVector; - pe.m_currentVector = pV->m_prev; - pe.m_index = ePoolVectorLength-1; - MemElemPtr(pV)->m_next = s_freeVectors; - s_freeVectors = MemElemPtr(pV); - } - s_criticalSection->leave(); - - } else { - s_criticalSection->leave(); - pFreeBytes = allocateBlock(nBytes); - } -#endif - - MemElemPtr p = pFreeBytes; - pFreeBytes = p->m_next; - return p; -} - - -// __asm __volatile ("":::"memory") GLIBC - - -PoolMemoryAllocator::MemElemPtr -PoolMemoryAllocator::allocateBlock(__uint16 nBytes) -{ - if(nBytes < eMinBytes) - nBytes = eMinBytes; - - MemElemPtr pBlock = (MemElemPtr) malloc(eBlockSize); - - // we altogether create nSlices slices - int nWords; - int nSlices = slicesPerBlock(nBytes,nWords); - - MemElemPtr pHead = MemElemPtr(pBlock); - BlockChainPtr(pBlock)->m_next = s_blocks; - s_blocks = BlockChainPtr(pBlock); - - do { - pBlock = pBlock->m_next = pBlock+nWords; - } while(--nSlices > 1); - MemElemPtr(pBlock)->m_next = 0; - - return pHead; -} - - -size_t PoolMemoryAllocator::memoryAllocatedInBlocks() -{ -#ifndef OGDF_MEMORY_POOL_NTS - s_criticalSection->enter(); -#endif - - size_t nBlocks = 0; - for (BlockChainPtr p = s_blocks; p != 0; p = p->m_next) - ++nBlocks; - -#ifndef OGDF_MEMORY_POOL_NTS - s_criticalSection->leave(); -#endif - - return nBlocks * eBlockSize; -} - - -size_t PoolMemoryAllocator::memoryInGlobalFreeList() -{ -#ifndef OGDF_MEMORY_POOL_NTS - s_criticalSection->enter(); -#endif - - size_t bytesFree = 0; - for (int sz = 1; sz < eTableSize; ++sz) - { - const PoolElement &pe = s_pool[sz]; - PoolVector *pv = pe.m_currentVector; - for(; pv != 0; pv = pv->m_prev) - bytesFree += ePoolVectorLength*sz; - if(pe.m_restHead != 0) - bytesFree += pe.m_restCount; - } - -#ifndef OGDF_MEMORY_POOL_NTS - s_criticalSection->leave(); -#endif - - return bytesFree; -} - - -size_t PoolMemoryAllocator::memoryInThreadFreeList() -{ - size_t bytesFree = 0; - for (int sz = 1; sz < eTableSize; ++sz) - { -#if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS) - MemElemPtr p = ((MemElemPtr*)pthread_getspecific(s_tpKey))[sz]; -#else - MemElemPtr p = s_tp[sz]; -#endif - for(; p != 0; p = p->m_next) - bytesFree += sz; - } - - return bytesFree; -} - - -} diff --git a/ext/OGDF/src/basic/PreprocessorLayout.cpp b/ext/OGDF/src/basic/PreprocessorLayout.cpp deleted file mode 100644 index f9ba3e144..000000000 --- a/ext/OGDF/src/basic/PreprocessorLayout.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Preprocessor Layout simplifies Graphs for use in other Algorithms - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -PreprocessorLayout::PreprocessorLayout() -: m_randomize(false) -{ - -} - - -void PreprocessorLayout::call(GraphAttributes &GA) -{ - if (m_secondaryLayout.valid()) { - MultilevelGraph MLG(GA); - call(MLG); - MLG.exportAttributes(GA); - } -} - - -void PreprocessorLayout::call(MultilevelGraph &MLG) -{ - m_deletedEdges.clear(); - Graph * G = &(MLG.getGraph()); - - node v; - - double sqrsize; - if (m_randomize) sqrsize = 2.0*sqrt((double)G->numberOfNodes())*MLG.averageRadius(); - - forall_nodes(v, *G) { - if (MLG.radius(v) <= 0) { - MLG.radius(v, 1.0); - } - if (m_randomize) { - MLG.x(v, randomDouble( -sqrsize, sqrsize ));//-5.0, 5.0)); - MLG.y(v, randomDouble( -sqrsize, sqrsize )); - } - } - if (m_secondaryLayout.valid()) { - - call(*G, MLG); - - m_secondaryLayout.get().call(MLG.getGraphAttributes()); - MLG.updateReverseIndizes(); - - for(std::vector::iterator i = m_deletedEdges.begin(); i != m_deletedEdges.end(); i++ ) { - int index = (*i).edgeIndex; - edge temp = G->newEdge(MLG.getNode((*i).sourceIndex), MLG.getNode((*i).targetIndex), index); - MLG.weight(temp, (float)(*i).weight); - } - } -} - - -void PreprocessorLayout::call(Graph &G, MultilevelGraph &MLG) -{ - std::vector deletedEdges; - - edge e; - forall_edges(e, G) { - int index = e->index(); - if (e->source() == e->target()) { - deletedEdges.push_back(e); - m_deletedEdges.push_back(EdgeData(index, e->source()->index(), e->target()->index(), MLG.weight(e))); - } else { - adjEntry adj; - forall_adj(adj, e->source()) { - if (adj->theEdge()->index() < index && adj->twinNode() == e->target()) { - deletedEdges.push_back(e); - m_deletedEdges.push_back(EdgeData(index, e->source()->index(), e->target()->index(), MLG.weight(e))); - break; - } - } - } - } - - for (std::vector::iterator i = deletedEdges.begin(); i != deletedEdges.end(); i++) { - G.delEdge(*i); - } -} - - -} // namespace ogdf diff --git a/ext/OGDF/src/basic/String.cpp b/ext/OGDF/src/basic/String.cpp deleted file mode 100644 index 3e9dfec97..000000000 --- a/ext/OGDF/src/basic/String.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class String - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - - -#include -#include -#include -#include - - -namespace ogdf { - - -char String::s_pBuffer[OGDF_STRING_BUFFER_SIZE]; - - -String::String() -{ - m_pChar = new char[1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - m_pChar[0] = 0; - m_length = 0; -} - - -String::String(const char c) -{ - m_length = 1; - m_pChar = new char[2]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - m_pChar[0] = c; - m_pChar[1] = '\0'; -} - - -String::String(const char *str) -{ - m_length = strlen(str); - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strcpy(m_pChar,m_length+1,str); -} - - -String::String(size_t maxLen, const char *str) -{ - m_length = maxLen; - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strncpy(m_pChar, m_length+1, str, m_length); - m_pChar[m_length] = '\0'; -} - -/* -String::String(const char *format, ...) -{ - va_list argList; - va_start(argList,format); - - m_length = vsprintf(s_pBuffer,format,argList); - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - strcpy(m_pChar,s_pBuffer); -} -*/ - -String::String(const String &str) -{ - m_length = str.m_length; - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strcpy(m_pChar,m_length+1,str.m_pChar); -} - - -String::~String() -{ - delete [] m_pChar; -} - - -String &String::operator =(const String &str) -{ - if (&str == this) return *this; - - delete [] m_pChar; - - m_length = str.m_length; - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strcpy(m_pChar,m_length+1,str.m_pChar); - - return *this; -} - - -String &String::operator =(const char *str) -{ - delete [] m_pChar; - - m_length = strlen(str); - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strcpy(m_pChar,m_length+1,str); - - return *this; -} - - -String &String::operator +=(const String &str) -{ - size_t oldLength = m_length; - char *pOldChar = m_pChar; - - m_length += str.m_length; - m_pChar = new char[m_length+1]; - if (m_pChar == 0) { - delete [] pOldChar; - OGDF_THROW(InsufficientMemoryException); - } - - ogdf::strcpy(m_pChar,m_length+1,pOldChar); - ogdf::strcpy(m_pChar+oldLength,m_length+1-oldLength,str.m_pChar); - - delete [] pOldChar; - - return *this; -} - - -void String::sprintf(const char *format, ...) -{ - delete [] m_pChar; - - va_list argList; - va_start(argList,format); - - m_length = ogdf::vsprintf(s_pBuffer,OGDF_STRING_BUFFER_SIZE,format,argList); - m_pChar = new char[m_length+1]; - if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strcpy(m_pChar,m_length+1,s_pBuffer); -} - - -int String::compare (const String &x, const String &y) -{ - return strcmp(x.m_pChar, y.m_pChar); -} - - -istream& operator>>(istream& is, String &str) -{ - is >> String::s_pBuffer; - str = String::s_pBuffer; - return is; -} - -int DefHashFunc::hash(const String &key) const -{ - int hashValue = 0; - const char *pChar = key.cstr(); - - while (*pChar) - hashValue += int(*pChar++); - - return hashValue; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/System.cpp b/ext/OGDF/src/basic/System.cpp deleted file mode 100644 index c5b5fb235..000000000 --- a/ext/OGDF/src/basic/System.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * $Revision: 2633 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-18 09:09:28 +0200 (Mi, 18. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of System class. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -#ifdef __APPLE__ -#include -#include -#include -#include -#include -#include -#include -#include -#elif defined(OGDF_SYSTEM_UNIX) -#include -#endif - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) -#include -#endif - -#ifdef _MSC_VER -#include - -#elif defined(OGDF_SYSTEM_UNIX) || (defined(__MINGW32__) && !defined(__MINGW64__)) -#include -#include -#include - -static void __cpuid(int CPUInfo[4], int infoType) -{ - uint32_t a = CPUInfo[0]; - uint32_t b = CPUInfo[1]; - uint32_t c = CPUInfo[2]; - uint32_t d = CPUInfo[3]; - -#if defined(__i386__) || defined(__x86_64__) && !defined(__APPLE__) - __asm__ __volatile__ ("xchgl %%ebx,%0\n\t" - "cpuid \n\t" - "xchgl %%ebx,%0\n\t" - : "+r" (b), "=a" (a), "=c" (c), "=d" (d) - : "1" (infoType), "2" (c)); -#else - // not supported on other systems! - a = b = c = d = 0; -#endif - - CPUInfo[0] = a; - CPUInfo[1] = b; - CPUInfo[2] = c; - CPUInfo[3] = d; -} -#endif - - -namespace ogdf { - -unsigned int System::s_cpuFeatures; -int System::s_cacheSize; -int System::s_cacheLine; -int System::s_pageSize; -int System::s_numberOfProcessors; - - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) -LARGE_INTEGER System::s_HPCounterFrequency; -#endif - - -void System::init() -{ - s_cpuFeatures = 0; - s_cacheSize = 0; - s_cacheLine = 0; - - // currently not working for shared libs on Linux -#if !defined(OGDF_DLL) || !defined(OGDF_SYSTEM_UNIX) - - int CPUInfo[4] = {-1}; - __cpuid(CPUInfo, 0); - - unsigned int nIds = CPUInfo[0]; - if(nIds >= 1) - { - __cpuid(CPUInfo, 1); - - int featureInfoECX = CPUInfo[2]; - int featureInfoEDX = CPUInfo[3]; - - if(featureInfoEDX & (1 << 23)) s_cpuFeatures |= cpufmMMX; - if(featureInfoEDX & (1 << 25)) s_cpuFeatures |= cpufmSSE; - if(featureInfoEDX & (1 << 26)) s_cpuFeatures |= cpufmSSE2; - if(featureInfoECX & (1 << 0)) s_cpuFeatures |= cpufmSSE3; - if(featureInfoECX & (1 << 9)) s_cpuFeatures |= cpufmSSSE3; - if(featureInfoECX & (1 << 19)) s_cpuFeatures |= cpufmSSE4_1; - if(featureInfoECX & (1 << 20)) s_cpuFeatures |= cpufmSSE4_2; - if(featureInfoECX & (1 << 5)) s_cpuFeatures |= cpufmVMX; - if(featureInfoECX & (1 << 6)) s_cpuFeatures |= cpufmSMX; - if(featureInfoECX & (1 << 7)) s_cpuFeatures |= cpufmEST; - if(featureInfoECX & (1 << 3)) s_cpuFeatures |= cpufmMONITOR; - } - - __cpuid(CPUInfo, 0x80000000); - unsigned int nExIds = CPUInfo[0]; - - if(nExIds >= 0x80000006) { - __cpuid(CPUInfo, 0x80000006); - s_cacheLine = CPUInfo[2] & 0xff; - s_cacheSize = (CPUInfo[2] >> 16) & 0xffff; - } - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) - QueryPerformanceFrequency(&s_HPCounterFrequency); - - SYSTEM_INFO siSysInfo; - GetSystemInfo(&siSysInfo); - s_pageSize = siSysInfo.dwPageSize; - s_numberOfProcessors = siSysInfo.dwNumberOfProcessors; - -#elif defined(OGDF_SYSTEM_UNIX) && defined(__APPLE__) - unsigned long long value; - size_t size = sizeof( value ); - if (sysctlbyname("hw.pagesize", &value, &size, NULL, 0) !=-1) - s_pageSize = (int)value; - else - s_pageSize = 0; - - if (sysctlbyname("hw.ncpu", &value, &size, NULL, 0) !=-1) - s_numberOfProcessors = (int)value; - else - s_numberOfProcessors = 1; - -#elif defined(OGDF_SYSTEM_UNIX) - s_pageSize = sysconf(_SC_PAGESIZE); - s_numberOfProcessors = (int)sysconf(_SC_NPROCESSORS_CONF); - -#else - s_pageSize = 0; // just a placeholder!!! - s_numberOfProcessors = 1; // just a placeholder!!! -#endif - -#endif -} - - -#if defined(OGDF_SYSTEM_WINDOWS) || defined(__CYGWIN__) -void System::getHPCounter(LARGE_INTEGER &counter) -{ - QueryPerformanceCounter(&counter); -} - - -double System::elapsedSeconds( - const LARGE_INTEGER &startCounter, - const LARGE_INTEGER &endCounter) -{ - return double(endCounter.QuadPart - startCounter.QuadPart) - / s_HPCounterFrequency.QuadPart; -} - - -__int64 System::usedRealTime(__int64 &t) -{ - __int64 tStart = t; - t = GetTickCount(); - return t - tStart; -} - - -long long System::physicalMemory() -{ -#if !defined(__CYGWIN__) || (_WIN32_WINNT >= 0x0500) - MEMORYSTATUSEX statex; - statex.dwLength = sizeof (statex); - - GlobalMemoryStatusEx (&statex); - return statex.ullTotalPhys; -#else - MEMORYSTATUS stat; - stat.dwLength = sizeof (stat); - - GlobalMemoryStatus (&stat); - return stat.dwTotalPhys; -#endif -} - -long long System::availablePhysicalMemory() -{ -#if !defined(__CYGWIN__) || (_WIN32_WINNT >= 0x0500) - MEMORYSTATUSEX statex; - statex.dwLength = sizeof (statex); - - GlobalMemoryStatusEx (&statex); - return statex.ullAvailPhys; -#else - MEMORYSTATUS stat; - stat.dwLength = sizeof (stat); - - GlobalMemoryStatus (&stat); - return stat.dwAvailPhys; -#endif -} - -size_t System::memoryUsedByProcess() -{ - PROCESS_MEMORY_COUNTERS pmc; - GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - - return pmc.WorkingSetSize; -} - -size_t System::peakMemoryUsedByProcess() -{ - PROCESS_MEMORY_COUNTERS pmc; - GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - - return pmc.PeakWorkingSetSize; -} - -#elif __APPLE__ - -long long System::physicalMemory() -{ - unsigned long long value; - size_t size = sizeof( value ); - if (sysctlbyname("hw.memsize", &value, &size, NULL, 0) !=-1) - return value; - else - return 0; -} - -long long System::availablePhysicalMemory() -{ - unsigned long long pageSize; - long long result; - size_t size = sizeof( pageSize ); - sysctlbyname("hw.pagesize", &pageSize, &size, NULL, 0); - - vm_statistics_data_t vm_stat; - int count = ((mach_msg_type_number_t) (sizeof(vm_statistics_data_t)/sizeof(integer_t))); - host_statistics(mach_host_self(), HOST_VM_INFO, (integer_t*)&vm_stat, (mach_msg_type_number_t*)&count); - result = (unsigned long long)(vm_stat.free_count + vm_stat.inactive_count) * pageSize; - return result; -} - - -size_t System::memoryUsedByProcess() -{ - /*int pid = getpid(); - static char filename[32]; - sprintf(filename, 32, "/proc/%d/statm", pid); - - int fd = open(filename, O_RDONLY, 0); - if(fd==-1) OGDF_THROW(Exception); - - static char sbuf[256]; - sbuf[read(fd, sbuf, sizeof(sbuf) - 1)] = 0; - close(fd); - - long size, resident, share, trs, lrs, drs, dt; - sscanf(sbuf, "%ld %ld %ld %ld %ld %ld %ld", - &size, // total program size (in pages) - &resident, // number of resident set (non-swapped) pages (4k) - &share, // number of pages of shared (mmap'd) memory - &trs, // text resident set size - &lrs, // shared-lib resident set size - &drs, // data resident set size - &dt); // dirty pages - - return resident*4*1024;*/ - return 0; -} - -#else -// LINUX, NOT MAC OS -long long System::physicalMemory() -{ - return (long long)(sysconf(_SC_PHYS_PAGES)) * sysconf(_SC_PAGESIZE); -} - -long long System::availablePhysicalMemory() -{ - return (long long)(sysconf(_SC_AVPHYS_PAGES)) * sysconf(_SC_PAGESIZE); -} - -size_t System::memoryUsedByProcess() -{ - int pid = getpid(); - static char filename[32]; - sprintf(filename, 32, "/proc/%d/statm", pid); - - int fd = open(filename, O_RDONLY, 0); - if(fd==-1) OGDF_THROW(Exception); - - static char sbuf[256]; - sbuf[read(fd, sbuf, sizeof(sbuf) - 1)] = 0; - close(fd); - - long size, resident, share, trs, lrs, drs, dt; - sscanf(sbuf, "%ld %ld %ld %ld %ld %ld %ld", - &size, // total program size (in pages) - &resident, // number of resident set (non-swapped) pages (4k) - &share, // number of pages of shared (mmap'd) memory - &trs, // text resident set size - &lrs, // shared-lib resident set size - &drs, // data resident set size - &dt); // dirty pages - - return resident*4*1024; -} - -#endif - - -#ifdef OGDF_SYSTEM_WINDOWS - -size_t System::memoryAllocatedByMalloc() -{ - _HEAPINFO hinfo; - int heapstatus; - hinfo._pentry = NULL; - - size_t allocMem = 0; - while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK) - { - if(hinfo._useflag == _USEDENTRY) - allocMem += hinfo._size; - } - - return allocMem; -} - -size_t System::memoryInFreelistOfMalloc() -{ - _HEAPINFO hinfo; - int heapstatus; - hinfo._pentry = NULL; - - size_t allocMem = 0; - while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK) - { - if(hinfo._useflag == _FREEENTRY) - allocMem += hinfo._size; - } - - return allocMem; -} - -#elif __APPLE__ - -size_t System::memoryAllocatedByMalloc() -{ - return mstats().chunks_used; -} - -size_t System::memoryInFreelistOfMalloc() -{ - return mstats().chunks_free; -} -#else - -size_t System::memoryAllocatedByMalloc() -{ - return mallinfo().uordblks; -} - -size_t System::memoryInFreelistOfMalloc() -{ - return mallinfo().fordblks; -} - -#endif - -#if !defined(OGDF_SYSTEM_WINDOWS) && !defined(__CYGWIN__) -__int64 System::usedRealTime(__int64 &t) -{ - __int64 tStart = t; - timeval tv; - gettimeofday(&tv, 0); - t = __int64(tv.tv_sec) * 1000 + tv.tv_usec/1000; - return t - tStart; -} -#endif - - -size_t System::memoryAllocatedByMemoryManager() -{ - return PoolMemoryAllocator::memoryAllocatedInBlocks(); -} - -size_t System::memoryInGlobalFreeListOfMemoryManager() -{ - return PoolMemoryAllocator::memoryInGlobalFreeList(); -} - -size_t System::memoryInThreadFreeListOfMemoryManager() -{ - return PoolMemoryAllocator::memoryInThreadFreeList(); -} - - -} // namespace ogdf diff --git a/ext/OGDF/src/basic/UMLGraph.cpp b/ext/OGDF/src/basic/UMLGraph.cpp deleted file mode 100644 index 8d996db8e..000000000 --- a/ext/OGDF/src/basic/UMLGraph.cpp +++ /dev/null @@ -1,717 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of UMLGraph class - * - * \author Carsten Gutwenger, Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - -namespace ogdf { - - - -UMLGraph::UMLGraph( - Graph &G, - long initAttributes) : - GraphAttributes(G, initAttributes | edgeType | nodeType | nodeGraphics | edgeGraphics), m_pG(&G), m_cliqueCenterSize(10) -{ - m_upwardEdge.init(*this, false); - m_hierarchyParent.init(*this,0); - m_assClass.init(*this, 0); - m_associationClassModel.init(*this, 0); -} - - -UMLGraph::~UMLGraph() -{ - SListIterator it = m_assClassList.begin(); - while (it.valid()) - { - delete (*it); - it++; - }//while -}//destructor - - -void UMLGraph::insertGenMergers() -{ - if (m_pG->empty()) return; - - node v = m_pG->firstNode(), vLast = m_pG->lastNode(); //new nodes are pushed behind - //otherwise, mergers would be considered - - for( ; ; ) - { - SList inGens; - - edge e; - forall_adj_edges(e,v) - { - if (e->target() != v || type(e) != Graph::generalization) - continue; - - inGens.pushBack(e); - } - - doInsertMergers(v, inGens); - - if (v == vLast) break; - v = v->succ(); - }//while - - adjustHierarchyParents(); -} - - -void UMLGraph::adjustHierarchyParents() -{ - node v; - forall_nodes(v, *m_pG) - { - if (!m_hierarchyParent[v]) continue; - adjEntry ae; - forall_adj(ae,v) - { - if (ae->theNode() != v) - continue; - if (m_hierarchyParent[v] == m_hierarchyParent[ae->twinNode()]) //(half)brothers - m_upwardEdge[ae] = true; //the same should be for twin - - }//foralladjedges - } -}//adjustHierarchyParents - - -//inserts a merger node for generalizations hanging at v -node UMLGraph::doInsertMergers(node v, SList &inGens) -{ - node u = 0; - if (m_pG->empty()) return u; - if(inGens.size() >= 2) - { - - // create a new node representing the merge point for the generalizations - u = m_pG->newNode(); - type(u) = Graph::generalizationMerger; - - // add the edge from v to the merge point - // this edge is a generalization, but has no original edge - edge eMerge = m_pG->newEdge(u,v); - type(eMerge) = Graph::generalization; - m_mergeEdges.pushBack(eMerge); - - // We move the target node of each ingoing generalization of v to u. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - for(it = inGens.begin(); it.valid(); ++it) - { - // all edges in the list inGens must be ingoing generalizations of v - OGDF_ASSERT((*it)->target() == v && type(*it) == Graph::generalization); - - m_pG->moveTarget(*it,u); - m_hierarchyParent[(*it)->source()] = u; //set to merger - m_hierarchyParent[u] = v; - m_upwardEdge[(*it)->adjSource()] = true;//set status at source node - } - }//if ingen >= 2 - else - if (inGens.size() == 1) - { //they are not needed yet - //m_hierarchyParent[inGens.front()->source()] = v; - //m_upwardEdge[inGens.front()->adjSource()] = true;//set status at source node - }//if - return u; -}//doInsertMergers - - -void UMLGraph::undoGenMergers() -{ - SListConstIterator it; - for(it = m_mergeEdges.begin(); it.valid(); ++it) - { - edge eMerge = *it; - node u = eMerge->source(); - const DPolyline &common = bends(eMerge); - - adjEntry adj, adjSucc; - for(adj = u->firstAdj(); adj != 0; adj = adjSucc) { - adjSucc = adj->succ(); - - edge e = adj->theEdge(); - if(e->target() != u) continue; - - DPolyline &dpl = bends(e); - dpl.pushBack(DPoint(x(u),y(u))); - - ListConstIterator itDp; - for(itDp = common.begin(); itDp.valid(); ++itDp) - dpl.pushBack(*itDp); - - m_pG->moveTarget(e,eMerge->target()); - } - - m_pG->delNode(u); - } - - m_mergeEdges.clear(); -} - -//sorts the edges around all nodes of AG corresponding to the -//layout given in AG -//there is no check of the embedding afterwards because this -//method could be used as a first step of a planarization -void UMLGraph::sortEdgesFromLayout() -{ - //we order the edges around each node corresponding to - //the input embedding in the GraphAttributes layout - NodeArray > adjList(*m_pG); - - EdgeComparer* ec = new EdgeComparer(*this); - - node v; - adjEntry ae; - forall_nodes(v, *m_pG) - { - forall_adj(ae, v) - { - adjList[v].pushBack(ae); - }//forall adjacency edges - //sort the entries - adjList[v].quicksort(*ec); - m_pG->sort(v, adjList[v]); - - }//forall nodes - - delete ec; -}//sortedgesfromlayout - - -//replace each node set in cliques by a star connecting -//a new center node with all nodes in set, deletes all -//edges between nodes in set, lists need to be disjoint -//TODO: think about directly using the cliquenum array -//output of findcliques here -void UMLGraph::replaceByStar(List< List > &cliques) -{ - m_cliqueCircleSize.init(*m_pG); - m_cliqueCirclePos.init(*m_pG); - //m_cliqueEdges.init(*m_pG); - m_replacementEdge.init(*m_pG, false); - - if (cliques.empty()) return; - //we save membership of nodes in each list - NodeArray cliqueNum(*m_pG, -1); - ListIterator< List > it = cliques.begin(); - - int num = 0; - while (it.valid()) - { - ListIterator itNode = (*it).begin(); - while (itNode.valid()) - { - cliqueNum[(*itNode)] = num; - itNode++; - }//while - - num++; - it++; - }//while - - //now replace each list - it = cliques.begin(); - while (it.valid()) - { - node newCenter = replaceByStar((*it), cliqueNum); - OGDF_ASSERT(newCenter) - m_centerNodes.pushBack(newCenter); - //now we compute a circular drawing of the replacement - //and save its size and the node positions - m_cliqueCircleSize[newCenter] = circularBound(newCenter); - it++; - }//while - -}//replacebystar - -//compute a drawing of the clique around node center and save its size -//the call to circular will later be replaced by an dedicated computation -DRect UMLGraph::circularBound(node center) -{ - - //TODO: hier computecliqueposition(0,...) benutzen, rest weglassen - DRect bb; - CircularLayout cl; - Graph G; - GraphAttributes AG(G); - NodeArray umlOriginal(G); - - //TODO: we need to assure that the circular drawing - //parameters fit the drawing parameters of the whole graph - //umlgraph clique parameter members? - - OGDF_ASSERT(center->degree() > 0) - node lastNode = 0; - node firstNode = 0; - node v; - - adjEntry ae = center->firstAdj(); - do { - node w = ae->twinNode(); - v = G.newNode(); - umlOriginal[v] = w; - - if (!firstNode) firstNode = v; - AG.width(v) = width(w); - AG.height(v) = height(w); - ae = ae->cyclicSucc(); - if (lastNode != 0) G.newEdge(lastNode, v); - lastNode = v; - } while (ae != center->firstAdj()); - G.newEdge(lastNode, firstNode); - - cl.call(AG); - - forall_nodes(v, G) - { - m_cliqueCirclePos[umlOriginal[v]] = DPoint(AG.x(v), AG.y(v)); - }//forallnodes - bb = AG.boundingBox(); - - return bb; -}//circularBound - - -//computes relative positions of all nodes around center on a circle -//keeping the topological ordering of the nodes, letting the opposite -//node (to center) of the edge at firstAdj having the position at -//three o'clock (TODO: unter umstaenden hier aus gegebenen coords in -//this den Punkt auswaehlen. Aber: Was, wenn keine coords=>optional? -void UMLGraph::computeCliquePosition(node center, double rectMin) -{ - List adjNodes; - adjEntry ae = center->firstAdj(); - do - { - adjNodes.pushBack(ae->twinNode()); - ae = ae->cyclicPred(); - } while (ae != center->firstAdj()); - computeCliquePosition(adjNodes, center, rectMin); -}//computeCliquePosition - -//computes relative positions of all nodes in List cList on a minimum size -//circle (needed to compute positions with different ordering than given in *this). -//Precondition: nodes in adjNodes are adjacent to center -//first node in adjNodes is positioned to the right -void UMLGraph::computeCliquePosition(List &adjNodes, node center, double rectMin)//, const adjEntry &startAdj) -{ - DRect boundingBox; - OGDF_ASSERT(center->degree() > 0) - OGDF_ASSERT(center->degree() == adjNodes.size()) - - node v; - double radius = 0.0; - //TODO: member, parameter - //const - double minDist = 1.0; - //TODO: necessary? - double minCCDist = 20.0; - - ListIterator itNode = adjNodes.begin(); - - //-------------------------------------------------------------------------- - //for the temporary solution (scale clique to fixed rect if possible instead - //of guaranteeing the rect size in compaction) we check in advance if the sum - //of diameters plus dists fits into the given rect by heuristic estimate (biggest - //node size + radius) - if (rectMin > 0.0) - { - double rectDist = m_cliqueCenterSize; //dist to rect border todo: parameter - double rectBound = rectMin - 2.0*rectDist; - double maxSize = 0.0; - double pureSumDiameters = 0.0; - while (itNode.valid()) - { - node q =(*itNode); - double d = sqrt( - width(q)*width(q) + height(q)*height(q)); - pureSumDiameters += d; - - if (d > maxSize) maxSize = d; - - itNode++; - }//while - double totalSum = pureSumDiameters+(center->degree()-1)*minDist; - //TODO: scling, not just counting - while (totalSum/Math::pi < rectBound*0.75) - { - minDist = minDist + 1.0; - totalSum += (center->degree()-1.0); - }//while - if (minDist > 1.1) minDist -= 1.0; - //do not use larger value than cliquecentersize (used with separation) - //if (minDist > m_cliqueCenterSize) minDist = m_cliqueCenterSize; - itNode = adjNodes.begin(); - } - //temporary part ends------------------------------------------------------- - //------------------------------------------ - //first, we compute the radius of the circle - - const int n = center->degree(); - //sum of all diameters around the nodes and the max diameter radius - double sumDiameters = 0.0, maxR = 0; - //list of angles for all nodes - List angles; //node at startAdj gets 0.0 - double lastDiameter = 0.0; //temporary storage of space needed for previous node - bool first = true; - - while (itNode.valid()) - { - v =(*itNode); - double d = sqrt( - width(v)*width(v) + height(v)*height(v)); - - sumDiameters += d; - - if (d/2.0 > maxR) maxR = d/2.0; - - //save current position relative to startadj - //later on, compute angle out of these values - if (first) - { - angles.pushBack(0.0); - first = false; - } - else - { - angles.pushBack(lastDiameter+d/2.0+minDist+angles.back()); - } - lastDiameter = d/2.0; //its only half diameter... - - itNode++; - }//while - - OGDF_ASSERT(adjNodes.size() == angles.size()) - - if(n == 1) { - radius = 0; - - } else if (n == 2) { - radius = 0.5*minDist + sumDiameters / 4; - - } else { - double perimeter = (n*minDist + sumDiameters); - radius = perimeter / (2*Math::pi); - - ListIterator it = angles.begin(); - itNode = adjNodes.begin(); - while (it.valid()) - { - (*it) = (*it)*360.0/perimeter; - node w = *itNode; - double angle = Math::pi*(*it)/180.0; - m_cliqueCirclePos[w].m_x = radius*cos(angle); - m_cliqueCirclePos[w].m_y = radius*sin(angle); - itNode++; - it++; - }//while - }//if n>2 - - //now we normalize the values (start with 0.0) and - //derive the bounding box - v = adjNodes.front(); - double minX = m_cliqueCirclePos[v].m_x, - maxX = m_cliqueCirclePos[v].m_x; - double minY = m_cliqueCirclePos[v].m_y, - maxY = m_cliqueCirclePos[v].m_y; - itNode = adjNodes.begin(); - while (itNode.valid()) - { - node w = *itNode; - double wx = m_cliqueCirclePos[w].m_x; - double wy = m_cliqueCirclePos[w].m_y; - if(wx-width (w)/2.0 < minX) minX = wx-width(w)/2.0; - if(wx+width (w)/2.0 > maxX) maxX = wx+width(w)/2.0; - if(wy-height(w)/2.0 < minY) minY = wy-height(w)/2.0; - if(wy+height(w)/2.0 > maxY) maxY = wy+height(w)/2.0; - itNode++; - } - //allow distance - minX -= minCCDist; - minY -= minCCDist; - //normalize - //cout<<"\n"; - - itNode = adjNodes.begin(); - while (itNode.valid()) - { - node w = *itNode; - //cout<<"x1:"< &clique, NodeArray &cliqueNum) -{ - if (clique.empty()) return 0; - //insert an additional center node - - node center = m_pG->newNode(); - width(center) = m_cliqueCenterSize; - height(center) = m_cliqueCenterSize; -#ifdef OGDF_DEBUG -//should ask for attributes - if(m_nodeColor.valid()) - colorNode(center) = "#555555"; -#endif - //we delete all edges inzident to two clique nodes - //store all of them first in delEdges - List delEdges; -//TODO: Store edge type for all deleted edges - ListIterator it = clique.begin(); - while (it.valid()) - { - node v = (*it); - - adjEntry ad; - int numIt = cliqueNum[v]; - - forall_adj(ad, v) - { - if (cliqueNum[ad->twinNode()] == numIt) - { - if (ad->theEdge()->source() == v) - { - //m_cliqueEdges[v].pushBack(new CliqueInfo(ad->theEdge()->target(), ad->theEdge()->index())); - delEdges.pushBack(ad->theEdge()); - } - }//if - }//foralladj - - //connect center node to clique node - edge inserted = m_pG->newEdge(center, v); - this->type(inserted) = Graph::association; - m_replacementEdge[inserted] = true; - - it++; - }//while - - //now delete all edges - ListIterator itEdge = delEdges.begin(); - while (itEdge.valid()) - { - //m_pG->delEdge((*itEdge)); - m_pG->hideEdge((*itEdge)); - itEdge++; - }//while - - return center; -}//replaceByStar - -void UMLGraph::undoStars() -{ - SListIterator it = m_centerNodes.begin(); - while (it.valid()) - { - undoStar(*it, false); - it++; - }//while - - m_pG->restoreAllEdges(); - m_centerNodes.clear(); - m_replacementEdge.init(); - -}//undostars - - -//remove the center node and reinsert the deleted edges -void UMLGraph::undoStar(node center, bool restoreAllEdges) -{ - OGDF_ASSERT(center) - - //TODO: we should only restore the hidden clique edges, maybe there were - //already hidden edges and we call this for all cliques, but it is global - if (restoreAllEdges) m_pG->restoreAllEdges(); - - //remove center node - m_pG->delNode(center); - -}//undostar - -// Same as in GraphAttributes. Except: Writes red color to generalizations - -void UMLGraph::writeGML(const char *fileName) -{ - ofstream os(fileName); - writeGML(os); -} - - -void UMLGraph::writeGML(ostream &os) -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - if (attributes() & nodeLabel) - os << " label \"" << labelNode(v) << "\"\n"; - - //if (attributes() & nodeGraphics) - { - os << " graphics [\n"; - os << " x " << x(v) << "\n"; - os << " y " << y(v) << "\n"; - os << " w " << width(v) << "\n"; - os << " h " << height(v) << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - - if (type(v) == Graph::generalizationMerger) - os << " fill \"#0000A0\"\n"; - else if (type(v) == Graph::generalizationExpander) - os << " fill \"#00FF00\"\n"; - else - { - if (attributes() & nodeColor) - { - os << " fill \"" << m_nodeColor[v] << "\"\n"; - os << " line \"" << m_nodeLine[v] << "\"\n"; - }//color - else - if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - } - os << " ]\n"; // graphics - } - - os << " ]\n"; // node - } - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - if (attributes() & edgeType) - os << " generalization " << type(e) << "\n"; - - if (attributes() & edgeGraphics) { - os << " graphics [\n"; - os << " type \"line\"\n"; - if (attributes() & GraphAttributes::edgeType) { - if (type(e) == Graph::generalization) - { - os << " arrow \"last\"\n"; - if (m_upwardEdge[e->adjSource()]) - os << " fill \"#FF00FF\"\n"; - else os << " fill \"#FF0000\"\n"; - os << " width 2.0\n"; - } - else - { - if (attributes() & edgeColor) - { - // color edges, if specific color in attribut is set - os << " fill \"" << m_edgeColor[e] << "\"\n"; - } - else - if (m_upwardEdge[e->adjSource()]) - os << " fill \"#2Fff2F\"\n"; - os << " arrow \"none\"\n"; - os << " width 1.0\n"; - } - //os << " generalization " << type(e) << "\n"; - - } else { - os << " arrow \"last\"\n"; - } - - const DPolyline &dpl = bends(e); - if (!dpl.empty()) { - os << " Line [\n"; - os << " point [ x " << x(e->source()) << " y " << - y(e->source()) << " ]\n"; - - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - os << " point [ x " << (*it).m_x << " y " << (*it).m_y << " ]\n"; - - os << " point [ x " << x(e->target()) << " y " << y(e->target()) << " ]\n"; - - os << " ]\n"; // Line - } - - os << " ]\n"; // graphics - } - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/basic.cpp b/ext/OGDF/src/basic/basic.cpp deleted file mode 100644 index 38e78a9d5..000000000 --- a/ext/OGDF/src/basic/basic.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* - * $Revision: 2626 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-17 12:10:52 +0200 (Di, 17. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of basic functionality (incl. file and - * directory handling) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - -// Windows includes -#ifdef OGDF_SYSTEM_WINDOWS -#include -#if defined(_MSC_VER) && defined(UNICODE) -#undef GetFileAttributes -#undef FindFirstFile -#undef FindNextFile -#define GetFileAttributes GetFileAttributesA -#define FindFirstFile FindFirstFileA -#define WIN32_FIND_DATA WIN32_FIND_DATAA -#define FindNextFile FindNextFileA -#endif -#endif - -#ifdef __BORLANDC__ -#define _chdir chdir -#endif - -// Unix includes -#ifdef OGDF_SYSTEM_UNIX -#include -#include -#include -#include -#include -#include - -double OGDF_clk_tck = sysconf(_SC_CLK_TCK); //is long. but definig it here avoids casts... -#endif - - -#ifdef OGDF_DLL - -#ifdef OGDF_SYSTEM_WINDOWS - -#ifdef __MINGW32__ -extern "C" -#endif -BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - ogdf::PoolMemoryAllocator::init(); - ogdf::System::init(); - break; - - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - - case DLL_PROCESS_DETACH: - ogdf::PoolMemoryAllocator::cleanup(); - break; - } - return TRUE; -} - -#else - -void __attribute__ ((constructor)) my_load(void) -{ - ogdf::PoolMemoryAllocator::init(); - ogdf::System::init(); -} - -void __attribute__ ((destructor)) my_unload(void) -{ - ogdf::PoolMemoryAllocator::cleanup(); -} - -#endif - -#else - -namespace ogdf { - -//static int variables are automatically initialized with 0 -int Initialization::s_count; - -Initialization::Initialization() -{ - if (s_count++ == 0) { - ogdf::PoolMemoryAllocator::init(); - ogdf::System::init(); - } -} - -Initialization::~Initialization() -{ - if (--s_count == 0) { - ogdf::PoolMemoryAllocator::cleanup(); - } -} - -} // namespace ogdf - -#endif - - -namespace ogdf { - - // debug level (in debug build only) -#ifdef OGDF_DEBUG - DebugLevel debugLevel; -#endif - - -double usedTime(double& T) -{ - double t = T; -#ifdef OGDF_SYSTEM_WINDOWS - T = double(clock())/CLOCKS_PER_SEC; -#endif -#ifdef OGDF_SYSTEM_UNIX - struct tms now; - times (&now); - T = now.tms_utime/OGDF_clk_tck; -#endif - return T-t; -} - - -#ifdef OGDF_SYSTEM_WINDOWS - -bool isFile(const char *fileName) -{ - DWORD att = GetFileAttributes(fileName); - - if (att == 0xffffffff) return false; - return (att & FILE_ATTRIBUTE_DIRECTORY) == 0; -} - - -bool isDirectory(const char *fileName) -{ - DWORD att = GetFileAttributes(fileName); - - if (att == 0xffffffff) return false; - return (att & FILE_ATTRIBUTE_DIRECTORY) != 0; -} - - -bool changeDir(const char *dirName) -{ - return (_chdir(dirName) == 0); -} - - -void getEntriesAppend(const char *dirName, - FileType t, - List &entries, - const char *pattern) -{ - OGDF_ASSERT(isDirectory(dirName)); - - String filePattern; - filePattern.sprintf("%s\\%s", dirName, pattern); - - WIN32_FIND_DATA findData; - HANDLE handle = FindFirstFile(filePattern.cstr(), &findData); - - if (handle != INVALID_HANDLE_VALUE) - { - do { - DWORD isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); - if(isDir && ( - strcmp(findData.cFileName,".") == 0 || - strcmp(findData.cFileName,"..") == 0) - ) - continue; - - if (t == ftEntry || (t == ftFile && !isDir) || - (t == ftDirectory && isDir)) - { - entries.pushBack(findData.cFileName); - } - } while(FindNextFile(handle, &findData)); - - FindClose(handle); - } -} -#endif - -#ifdef OGDF_SYSTEM_UNIX - -bool isDirectory(const char *fname) -{ - struct stat stat_buf; - - if (stat(fname,&stat_buf) != 0) - return false; - return (stat_buf.st_mode & S_IFMT) == S_IFDIR; -} - -bool isFile(const char *fname) -{ - struct stat stat_buf; - - if (stat(fname,&stat_buf) != 0) - return false; - return (stat_buf.st_mode & S_IFMT) == S_IFREG; -} - -bool changeDir(const char *dirName) -{ - return (chdir(dirName) == 0); -} - -void getEntriesAppend(const char *dirName, - FileType t, - List &entries, - const char *pattern) -{ - OGDF_ASSERT(isDirectory(dirName)); - - DIR* dir_p = opendir(dirName); - - dirent* dir_e; - while ( (dir_e = readdir(dir_p)) != NULL ) - { - const char *fname = dir_e->d_name; - if (pattern != 0 && fnmatch(pattern,fname,0)) continue; - - String fullName; - fullName.sprintf("%s/%s", dirName, fname); - - bool isDir = isDirectory(fullName.cstr()); - if(isDir && ( - strcmp(fname,".") == 0 || - strcmp(fname,"..") == 0) - ) - continue; - - if (t == ftEntry || (t == ftFile && !isDir) || - (t == ftDirectory && isDir)) - { - entries.pushBack(fname); - } - } - - closedir(dir_p); -} -#endif - - -void getEntries(const char *dirName, - FileType t, - List &entries, - const char *pattern) -{ - entries.clear(); - getEntriesAppend(dirName, t, entries, pattern); -} - - -void getFiles(const char *dirName, - List &files, - const char *pattern) -{ - getEntries(dirName, ftFile, files, pattern); -} - - -void getSubdirs(const char *dirName, - List &subdirs, - const char *pattern) -{ - getEntries(dirName, ftDirectory, subdirs, pattern); -} - - -void getEntries(const char *dirName, - List &entries, - const char *pattern) -{ - getEntries(dirName, ftEntry, entries, pattern); -} - - -void getFilesAppend(const char *dirName, - List &files, - const char *pattern) -{ - getEntriesAppend(dirName, ftFile, files, pattern); -} - - -void getSubdirsAppend(const char *dirName, - List &subdirs, - const char *pattern) -{ - getEntriesAppend(dirName, ftDirectory, subdirs, pattern); -} - - -void getEntriesAppend(const char *dirName, - List &entries, - const char *pattern) -{ - getEntriesAppend(dirName, ftEntry, entries, pattern); -} - - - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/extended_graph_alg.cpp b/ext/OGDF/src/basic/extended_graph_alg.cpp deleted file mode 100644 index 1668bd2ce..000000000 --- a/ext/OGDF/src/basic/extended_graph_alg.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of extended graph algorithms - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -//maybe shift this to basic.h, used in cplanaredgeinserter, toos -class OrigNodePair -{ -public: - node m_src, m_tgt; -}; - -//--------------------------------------------------------- -// Methods for clustered graphs. By S.Leipert and K. Klein -//--------------------------------------------------------- - -// Recursive call for testing C-connectivity. -bool cConnectTest(ClusterGraph &C,cluster &act,NodeArray &mark,Graph &G) -{ - - ListConstIterator it; - for (it = act->cBegin(); it.valid();) - { - ListConstIterator succ = it.succ(); - cluster next = (*it); - if (!cConnectTest(C,next,mark,G)) - return false; - it = succ; - } - - ListIterator its; - for (its = act->nBegin(); its.valid(); its++) - mark[(*its)] = true; - - node v = (*(act->nBegin())); - SListPure bfs; - bfs.pushBack(v); - mark[v] = false; - - while (!bfs.empty()) - { - v = bfs.popFrontRet(); - edge e; - forall_adj_edges(e,v) - { - if (mark[e->source()]) - { - mark[e->source()] = false; - bfs.pushBack(e->source()); - } - else if (mark[e->target()]) - { - mark[e->target()] = false; - bfs.pushBack(e->target()); - } - } - } - - for (its = act->nBegin(); its.valid(); its++) - if (mark[(*its)]) - return false; - - SListPure collaps; - for (its = act->nBegin(); its.valid(); its++) - collaps.pushBack(*its); - - - C.collaps(collaps,G); - - if (act != C.rootCluster()) - C.delCluster(act); - return true; - -} - - -// true <=> C is C-connected -bool isCConnected(const ClusterGraph &C) -{ - if(C.getGraph().empty()) - return true; - - Graph G; - ClusterGraph Cp(C,G); - - - cluster root = Cp.rootCluster(); - SListPure compNodes; - NodeArray mark(G,false); - return cConnectTest(Cp,root,mark,G); -} - - -//in ClusterGraph?? -//is not yet recursive!!! -node collapseCluster(ClusterGraph& CG, cluster c, Graph& G) -{ - OGDF_ASSERT(c->cCount() == 0) - - ListIterator its; - SListPure collaps; - - //we should check here if not empty - node robinson = (*(c->nBegin())); - - for (its = c->nBegin(); its.valid(); its++) - collaps.pushBack(*its); - - CG.collaps(collaps, G); - - if (c != CG.rootCluster()) - CG.delCluster(c); - - return robinson; -} - -//returns a node of cluster c used as endpoint for inserted -//connection edges -//precondition: not empty -node getRepresentationNode(cluster c) -{ - OGDF_ASSERT(c->nCount() + c->cCount() > 0) - //improvement potential: use specific nodes that optimize connection - //process - if (c->nCount() > 0) - return (*(c->nBegin())); - - return getRepresentationNode((*(c->cBegin()))); -} - - -void recursiveConnect( - ClusterGraph& CG, - cluster act, - NodeArray& origCluster, //on CG, cluster rep. - //by collapsed node - ClusterArray& oCcluster, //cluster in orig for CG cluster - NodeArray& origNode, - Graph& G, - List& newEdges) -{ - //for non-cc clusters, add edges to make them connected - //recursively search for connection nodes (simple version: - //use first node/first node of first child (recursive) - - ListConstIterator it; - for (it = act->cBegin(); it.valid();) - { - ListConstIterator succ = it.succ(); - cluster next = (*it); - recursiveConnect(CG, next, origCluster, oCcluster, origNode, G, newEdges); - - it = succ; - } - - - //We construct a copy of the current cluster - OGDF_ASSERT(act->cCount() == 0) - Graph cG; - NodeArray vOrig(cG, 0); - NodeArray vCopy(CG, 0); //larger than necessary, hashingarray(index)? - - ListIterator its; - for (its = act->nBegin(); its.valid(); its++) - { - node vo = (*its); - node v = cG.newNode(); - vOrig[v] = vo; - vCopy[vo] = v; - - }//for - - NodeArray processed(CG, false); - for (its = act->nBegin(); its.valid(); its++) - { - node vo = (*its); - processed[vo] = true; - edge e; - forall_adj_edges(e, vo) - { - //if node in cluster and edge not yet inserted - if (vCopy[e->opposite(vo)] && !processed[e->opposite(vo)]) - //we don't care about the edge direction - cG.newEdge(vCopy[vo], vCopy[e->opposite(vo)]); - }//foralladjedges - }//for - - //connect the copy (should use improved version of makeconnected later) - List added; - makeConnected(cG, added); - - //now translate connection into clustergraph - while (!added.empty()) - { - edge eNew = added.popFrontRet(); - //allow collapse by making cluster connected - G.newEdge(vOrig[eNew->source()], vOrig[eNew->target()]); - - //maybe some of the nodes represent clusters, we have to find - //a representative - node v1 = vOrig[eNew->source()]; - node v2 = vOrig[eNew->target()]; - - //save original information - OrigNodePair np; - //already collapsed node? - np.m_src = (origCluster[v1] ? getRepresentationNode(origCluster[v1]) : origNode[v1]); - np.m_tgt = (origCluster[v2] ? getRepresentationNode(origCluster[v2]) : origNode[v2]); - newEdges.pushBack(np); - - }//if cluster was not connected - - //collapse cluster in copy and save information on the - //collapsed cluster in the nodes - cluster cOrig = oCcluster[act]; - node vNew = collapseCluster(CG, act, G); - //update info if cluster collapsed - origCluster[vNew] = cOrig; -}//recursiveConnect - - -//planarity checking version - -//we should care about the representation nodes, they should be -//good nodes, too - -//search for a node without attribute badnode (cluster: node -//with connection over cluster boundary, search for min degree -static void dfsMakeCConnected(node v, - node source, //the node vMinDeg will be connected to - NodeArray &visited, - const NodeArray &badNode, - Graph& fullGraph, //test graph - NodeArray &fullGraphCopy, - bool keepsPlanarity, //does current best keep planarity? - node &vMinDeg) //current best -{ - visited[v] = true; - - edge e; - forall_adj_edges(e,v) - { - node w = e->opposite(v); - if (!visited[w]) - { - //hier grad als erste unterscheidung: kleiner Grad besser - //dann badnode, dann planaritaet - bool better = (badNode[fullGraphCopy[vMinDeg]] || - !badNode[fullGraphCopy[w]]); - bool kPlanar = false; - - //*************************************** - //irgendeine Reihenfolge, um nicht jede moegliche - //Verbindung auf Planaritaet zu testen?? - if (source) - { - edge eP = fullGraph.newEdge( - fullGraphCopy[source], - fullGraphCopy[vMinDeg]); - - if (isPlanar(fullGraph) == true) - kPlanar = true; - - fullGraph.delEdge(eP); //only keep if finally chosen - - }//if source - - //**************************************** - better = ((better || kPlanar) && !keepsPlanarity) || (kPlanar && better); - - if (better)// && (w->degree() < vMinDeg->degree())) - vMinDeg = w; - - - dfsMakeCConnected(w, source, visited, badNode, - fullGraph, fullGraphCopy, keepsPlanarity, vMinDeg); - } - } -}//dfsMakeCConnected - - -//connect cluster represented by graph G, observe fullGraph planarity -//in nodepair selection, try to avoid badnodes -void cMakeConnected( - Graph &G, //cluster subgraph - Graph &fullGraphCopy, //copy of full graph - NodeArray &fullGraphNode, // holds node in fullgraphCopy - //corresponding to node in G cluster - NodeArray &badNode, //some attribute - List &added) -{ - added.clear(); - NodeArray visited(G,false); - - node vMinDeg, pred = 0, v; - - bool keepsPlanarity = false; - - //hier muss irgendwo bewertet werden, ob Kanten die Planaritaet - //erhalten, aber man kann nicht fuer jeden Knoten einen Test machen - forall_nodes(v,G) { - if (!visited[v]) { - vMinDeg = v; - dfsMakeCConnected(v, pred, visited, badNode, - fullGraphCopy, fullGraphNode, keepsPlanarity, vMinDeg); - if (pred) - { - added.pushBack(G.newEdge(pred,vMinDeg)); - //write current status into fullGraphCopy - fullGraphCopy.newEdge(fullGraphNode[pred], fullGraphNode[vMinDeg]); - } - pred = vMinDeg; - } - } -}//cMakeConnected - - -void recursiveCConnect( - ClusterGraph& CG, - cluster act, - NodeArray& origCluster, //on CG, cluster rep. - //by collapsed node - ClusterArray& oCcluster, //cluster in orig for CG cluster - NodeArray& origNode, - Graph& G, - Graph& fullCopy, //copy of graph G be checked for planarity - //holds corresponding nodes in fullCopy for v of G - NodeArray& copyNode, - NodeArray& badNode, //should not we used for connecting - List& newEdges) -{ - //for non-cc clusters, add edges to make them connected - //recursively search for connection nodes (simple version: - //use first node/first node of first child (recursive) - - ListConstIterator it; - for (it = act->cBegin(); it.valid();) - { - ListConstIterator succ = it.succ(); - cluster next = (*it); - recursiveCConnect(CG, next, origCluster, oCcluster, origNode, G, fullCopy, - copyNode, badNode, newEdges); - - it = succ; - } - - //****************************************** - //We construct a graph copy of the current cluster subgraph - OGDF_ASSERT(act->cCount() == 0) - Graph cG; - NodeArray vOrig(cG, 0); - NodeArray vCopy(CG, 0); //larger than necessary, hashingarray(index)? - - NodeArray vFullCopy(cG, 0);//node in planarity tested full copy - - ListIterator its; - for (its = act->nBegin(); its.valid(); its++) - { - node vo = (*its); - node v = cG.newNode(); - vOrig[v] = vo; - vCopy[vo] = v; - - vFullCopy[v] = copyNode[vo]; //save the corresponding node in working copy - //to check planarity after edge insertion - - }//for - - NodeArray processed(CG, false); - for (its = act->nBegin(); its.valid(); its++) - { - node vo = (*its); - processed[vo] = true; - edge e; - forall_adj_edges(e, vo) - { - //if node in cluster and edge not yet inserted - if (vCopy[e->opposite(vo)] && !processed[e->opposite(vo)]) - //we don't care about the edge direction - cG.newEdge(vCopy[vo], vCopy[e->opposite(vo)]); - }//foralladjedges - }//for - - //connect the copy (should use improved version of makeconnected later) - List added; - //makeConnected(cG, added); - cMakeConnected(cG, fullCopy, vFullCopy, badNode, added); - - //now translate connection into clustergraph - while (!added.empty()) - { - edge eNew = added.popFrontRet(); - //allow collapse by making cluster connected - G.newEdge(vOrig[eNew->source()], vOrig[eNew->target()]); - - //maybe some of the nodes represent clusters, we have to find - //a representative - node v1 = vOrig[eNew->source()]; - node v2 = vOrig[eNew->target()]; - - //save original information - OrigNodePair np; - //already collapsed node? - np.m_src = (origCluster[v1] ? getRepresentationNode(origCluster[v1]) : origNode[v1]); - np.m_tgt = (origCluster[v2] ? getRepresentationNode(origCluster[v2]) : origNode[v2]); - newEdges.pushBack(np); - - }//if cluster was not connected - - //collapse cluster in copy and save information on the - //collapsed cluster in the nodes - cluster cOrig = oCcluster[act]; - node vNew = collapseCluster(CG, act, G); - //update info if cluster collapsed - origCluster[vNew] = cOrig; -}//recursiveCConnect - -//***************************************************************** -/* - - - -*/ - - -//***************************************************************** - - -//second version for advanced connectivity -void cconnect( - ClusterGraph& CG, - NodeArray& origCluster, //on CG, cluster rep. by collapsed node - ClusterArray& oCcluster, //cluster in orig for CG cluster - NodeArray& origNode, - Graph& G, - List& newEdges) -{ - //We work with a copy of the graph that is checked for planarity - //for inserted cconnectivity edges - Graph fullCopy; - NodeArray fullCopyNode(G); - node v; - //check for all nodes if they have an edge adjacent crossing - //the cluster boundary, I assume this is a bad candidate for - //cconnection edges - NodeArray badNode(fullCopy, false); - - forall_nodes(v, G) - { - node w = fullCopy.newNode(); - fullCopyNode[v] = w; - edge e2; - cluster c = CG.clusterOf(v); - forall_adj_edges(e2, v) - { - node u = e2->target(); - //badnode is the case if lca(v,u) is != c(v) - cluster lca = CG.commonCluster(v, u); - if (c != lca) - { - badNode[w] = true; - break; - } - } - - }//forallnodes - - recursiveCConnect( - CG, //check cluster graph copy - CG.rootCluster(), //the whole graph - origCluster, //original cluster for collapse nodes - oCcluster, //cluster in copy - origNode, //original nodes - G, //original graph - fullCopy, //planarity checking copy of original graph G - fullCopyNode, //corresponding nodes in fullCopy - badNode, //fullCopy node attribute - newEdges); //inserted edges - -}//cconnect - - -//make a cluster graph cconnected by adding edges -//simple: just make the cluster subgraph connected -//not simple: check nodes on cluster adjacent edges -//and new edges on planarity -void makeCConnected(ClusterGraph& C, Graph& GG, List& addedEdges, bool simple) -{ - //work on copy ( is updated ) - Graph G; - NodeArray copyNode(C, 0); - ClusterArray copyCluster(C, 0); - - ClusterGraph cCopy(C, G, copyCluster, copyNode); - - NodeArray origNode(cCopy, 0); - node v; - - forall_nodes(v, GG) - origNode[copyNode[v]] = v; - - //holds information on collapsed clusters (points to original clusters) - NodeArray origCluster(cCopy, 0); - //holds copy to original cluster info - ClusterArray oCcluster(cCopy, 0); - cluster c; - forall_clusters(c, C) - oCcluster[copyCluster[c]] = c; - - List newEdges; //edges to be inserted - //recursively check clusters for connectivity and collapse - //save cluster info on collapsed nodes - - if (!simple) - cconnect(cCopy, origCluster, oCcluster, origNode, G, newEdges); - else - recursiveConnect(cCopy, cCopy.rootCluster(), origCluster, oCcluster, - origNode, G, newEdges); - - ListConstIterator it = newEdges.begin(); - while (it.valid()) - { - OrigNodePair np = (*it); - edge nedge = GG.newEdge(np.m_src, np.m_tgt); - //cout<<"Adding edge: "< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "ogdf/basic/geometry.h" -#include "ogdf/basic/GraphAttributes.h" -#include "ogdf/basic/Math.h" -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// IPoint -//--------------------------------------------------------- - -ostream &operator<<(ostream &os, const IPoint &ip) -{ - os << "(" << ip.m_x << "," << ip.m_y << ")"; - return os; -} - - -//--------------------------------------------------------- -// DPoint -//--------------------------------------------------------- - -// gives the euclidean distance between p and *this -double IPoint::distance(const IPoint &p) const -{ - double dx = p.m_x - m_x; - double dy = p.m_y - m_y; - return sqrt( (dx*dx) + (dy*dy) ); -} - - -//--------------------------------------------------------- -// IPolyline -//--------------------------------------------------------- - -// calculates the total length of a polyline -double IPolyline::length() const -{ - OGDF_ASSERT(!empty()); - - double len = 0.0; - ListConstIterator pred, iter; - - pred = iter = begin(); - ++iter; - - while (iter.valid()) { - len += (*iter).distance(*pred); - ++pred; - ++iter; - } - - return len; -} - - -//--------------------------------------------------------- -// DPoint -//--------------------------------------------------------- - -// gives the euclidean distance between p and *this -double DPoint::distance(const DPoint &p) const -{ - double dx = p.m_x - m_x; - double dy = p.m_y - m_y; - return sqrt( (dx*dx) + (dy*dy) ); -} - -// adds p to *this -DPoint DPoint::operator+(const DPoint &p) const -{ - return DPoint(m_x + p.m_x, m_y + p.m_y); -} - -// subtracts p from *this -DPoint DPoint::operator-(const DPoint &p) const -{ - return DPoint(m_x - p.m_x, m_y - p.m_y); -} - -// outputs dp -ostream &operator<<(ostream &os, const DPoint &dp) -{ - os << "(" << dp.m_x << "," << dp.m_y << ")"; - return os; -} - - -//--------------------------------------------------------- -// DVector -//--------------------------------------------------------- -DVector DVector::operator*(const double val) const -{ - DVector ret(m_x*val, m_y*val); - return ret; -} - -DVector DVector::operator/(const double val) const -{ - DVector ret(m_x/val, m_y/val); - return ret; -} - -// length -double DVector::length() const -{ - return sqrt((m_x * m_x) + (m_y * m_y)); -} - -// determinante -double DVector::operator^(const DVector &dv) const -{ - return ((m_x * dv.m_y) - (m_y * dv.m_x)); -} - -// s-product -double DVector::operator*(const DVector &dv) const -{ - return ((m_x * dv.m_x) + (m_y * dv.m_y)); -} - -// ortho left -DVector DVector::operator++() const -{ - DVector ret; - if (m_x != 0.0) { - ret.m_y = 1.0; - ret.m_x = - m_y / m_x; - } - else { - ret.m_x = 1.0; - ret.m_y = 0.0; - - } - return ret; -} - -// ortho right -DVector DVector::operator--() const -{ - return (++(*this)) * (-1.0); -} - - - -//--------------------------------------------------------- -// DPolyline -//--------------------------------------------------------- - -const double DPolyline::s_prec = 10000.0; - -// calculates the total length of a polyline -double DPolyline::length() const -{ - OGDF_ASSERT(!empty()); - - double len = 0.0; - ListConstIterator pred, iter; - - pred = iter = begin(); - ++iter; - - while (iter.valid()) { - len += (*iter).distance(*pred); - ++pred; - ++iter; - } - - return len; -} - - -// gives the point on a polyline, which is fraction*len away from the start -DPoint DPolyline::position(const double fraction, double len) const -{ - OGDF_ASSERT(!empty()); - OGDF_ASSERT(fraction >= 0.0 && fraction <= 1.0); - if (len < 0.0) - len = length(); - OGDF_ASSERT(len >= 0.0); - - DPoint p = (*begin()); - double liter = 0.0; - double pos = len * fraction; - double seglen = 0.0; - ListConstIterator pred, iter; - - pred = iter = begin(); - ++iter; - - // search the segment, which contains the desired point - double DX = 0, DY = 0; // for further use - while (iter.valid()) { - DX = (*iter).m_x - (*pred).m_x; - DY = (*iter).m_y - (*pred).m_y; - seglen = sqrt( (DX*DX) + (DY*DY) ); - liter += seglen; - if (liter >= pos) - break; - ++pred; - ++iter; - } - - if (!iter.valid()) // position not inside the polyline, return last point! - p = (*rbegin()); - else { - if (seglen == 0.0) // *pred == *iter and pos is inbetween - return (*pred); - - double segpos = seglen + pos - liter; - - double dx = DX * segpos / seglen; - double dy = DY * segpos / seglen; - - p = (*pred); - p.m_x += dx; - p.m_y += dy; - } - - return p; -} - - -// -void DPolyline::writeGML(ostream &stream) const -{ - Graph g; - GraphAttributes ag(g); - - node u = NULL; - node v = NULL; - - ListConstIterator iter; - for (iter = begin(); iter.valid(); ++iter) { - v = g.newNode(); - if (u != NULL) - g.newEdge(u, v); - u = v; - - ag.x(v) = (*iter).m_x; - ag.y(v) = (*iter).m_y; - } - ag.writeGML(stream); -} - - -// outputs the GML-file, which illustrates the Polyline as Graph -void DPolyline::writeGML(const char *filename) const -{ - ofstream file(filename); - writeGML(file); -} - - -// delete all consecutive double-points -void DPolyline::unify() -{ - if (empty()) return; - ListIterator iter, next; - for (iter = next = begin(), ++next; next.valid() && (size() > 2); ++next) { - if (*iter == *next) { - del(next); - next = iter; - } else - iter = next; - } -} - - -// deletes all points, which are not facets -void DPolyline::normalize() -{ - unify(); - - ListIterator iter, next, onext; - for (iter = begin(); iter.valid(); ++iter) { - for( ; ; ) { - next = iter; next++; - if (!next.valid()) break; - onext = next, onext++; - if (!onext.valid()) break; - - DSegment s1((*iter), (*next)); - DSegment s2((*next), (*onext)); - DRect r ((*iter), (*onext)); - - // is *next on the way from *iter to *onext? - if (s1.slope() == s2.slope() && r.contains(*next)) - del(next); - else - break; /* while */ - } - } -} - - -void DPolyline::normalize(DPoint src, DPoint tgt) -{ - if (empty()) - return; - - unify(); - ListIterator iter, next, onext; - DPoint pCur = src; - DPoint pNext; - DPoint pNextNext; - for (iter = begin(); iter.valid(); ++iter) { - for( ; ; ) { - - if (!iter.valid()) - break; - - next = iter; - pNext = *next; - next++; - - if (!next.valid()) { - pNextNext = tgt; - } - else - pNextNext = *next; - - - DSegment s1(pCur, pNext); - DSegment s2(pNext, pNextNext); - DRect r (pCur, pNextNext); - - // is *next on the way from *iter to *onext? - if (s1.slope() == s2.slope() && r.contains(pNext)) { - del(iter); - iter = next; - } - else - break; /* while */ - } - if (iter.valid()) - pCur = *iter; - else - break; - } -} - - -// -void DPolyline::convertToInt() -{ - ListIterator iter; - for (iter = begin(); iter.valid(); ++iter) { - DPoint &p = *iter; - p.m_x = DRound(p.m_x * s_prec); - p.m_y = DRound(p.m_y * s_prec); - } -} - -// Removed since I do not see that this makes sense... (CG) -//void DPolyline::reConvertToDouble() -//{ -// ListIterator iter; -// for (iter = begin(); iter.valid(); ++iter) { -// DPoint &p = *iter; -// p.m_x = p.m_x / s_prec; -// p.m_y = p.m_y / s_prec; -// } -//} - -//--------------------------------------------------------- -// DLine -//--------------------------------------------------------- - -// gives the intersection-point between two lines, returns true, if any -// computes the crossing point between the (infinite) lines -// defined by the endpoints of the DLines, then checks if it -// lies within the two rectangles defined by the DLines endpoints -bool DLine::intersection( - const DLine &line, - DPoint &inter, - bool endpoints) const -{ - double ix, iy; - - //do not return true if parallel edges are encountered - if (slope() == line.slope()) return false; - - //two possible checks: - // only check for overlap on endpoints if option parameter set, - // compute crossing otherwise - // or skip computation if endpoints overlap (can't have "real" crossing) - // (currently implemented) - //if (endpoints) { - - if (m_start == line.m_start || m_start == line.m_end) { - inter = m_start; - if (endpoints) return true; - else return false; - } - - if (m_end == line.m_start || m_end == line.m_end) { - inter = m_end; - if (endpoints) return true; - else return false; - } - - //}//if endpoints - - //if the edge is vertical, we cannot compute the slope - if (isVertical()) - ix = m_start.m_x; - else - if (line.isVertical()) - ix = line.m_start.m_x; - else - ix = (line.yAbs() - yAbs())/(slope() - line.slope()); - - //set iy to the value of the infinite line at xvalue ix - //use a non-vertical line (can't be both, otherwise they're parallel) - if (isVertical()) - iy = line.slope() * ix + line.yAbs(); - else - iy = slope() * ix + yAbs(); - - inter = DPoint(ix, iy); //the (infinite) lines cross point - - DRect tRect(line); - DRect mRect(*this); - - return (tRect.contains(inter) && mRect.contains(inter)); -} - - -// returns true, if line contains p -bool DLine::contains(const DPoint &p) const -{ - if (p == start() || p == end()) - return true; - - // check, if outside rect - DRect r(start(), end()); - if (!r.contains(p)) - return false; - - if (dx() == 0.0) { // first check, if line is vertical - if (DIsEqual (p.m_x, start().m_x) && - DIsLessEqual (p.m_y, (max(start().m_y, end().m_y))) && - DIsGreaterEqual(p.m_y, (min(start().m_y, end().m_y)))) - return true; - return false; - } - - double dx2p = p.m_x - start().m_x; - double dy2p = p.m_y - start().m_y; - - if (dx2p == 0.0) // dx() != 0.0, already checked - return false; - - if (DIsEqual(slope(), (dy2p/dx2p))) - return true; - return false; -} - - -// gives the intersection with the horizontal axis 'horAxis', returns the number of intersections -// 0 = no, 1 = one, 2 = infinity or both end-points, e.g. parallel on this axis -int DLine::horIntersection(const double horAxis, double &crossing) const -{ - if (dy() == 0.0) { - crossing = 0.0; - if (m_start.m_y == horAxis) - return 2; - else - return 0; - } - if (min(m_start.m_y, m_end.m_y) <= horAxis && max(m_start.m_y, m_end.m_y) >= horAxis) { - crossing = (m_start.m_x * (m_end.m_y - horAxis) - - m_end.m_x * (m_start.m_y - horAxis) ) / dy(); - return 1; - } - else { - crossing = 0.0; - return 0; - } -} - - -// gives the intersection with the vertical axis 'verAxis', returns the number of intersections -// 0 = no, 1 = one, 2 = infinity or both end-points, e.g. parallel on this axis -int DLine::verIntersection(const double verAxis, double &crossing) const -{ - if (dx() == 0.0) { - crossing = 0.0; - if (m_start.m_x == verAxis) - return 2; - else - return 0; - } - if (min(m_start.m_x, m_end.m_x) <= verAxis && max(m_start.m_x, m_end.m_x) >= verAxis) { - crossing = (m_start.m_y * (m_end.m_x - verAxis) - - m_end.m_y * (m_start.m_x - verAxis) ) / dx(); - return 1; - } - else { - crossing = 0.0; - return 0; - } -} - -// output the line -ostream &operator<<(ostream &os, const DLine &dl) -{ - os << "Line-Start: " << dl.start() << ", Line-End: " << dl.end(); - return os; -} - - -//--------------------------------------------------------- -// DRect -//--------------------------------------------------------- - -// output the rect -ostream &operator<<(ostream &os, const DRect &dr) -{ - os << "Rect-LowerLeftPoint: " << dr.p1() << ", Rect-UpperRightPoint: " << dr.p2(); - return os; -} - - -//--------------------------------------------------------- -// DScaler -//--------------------------------------------------------- - -// output the two rects in the scaler -ostream &operator<<(ostream &os, const DScaler &ds) -{ - os << "Scale from " << ds.from() << " to " << ds.to(); - return os; -} - - - -//---------------------------------------------------------------- -// DPolygon -//---------------------------------------------------------------- - -// gives the segment starting at point 'it' -DSegment DPolygon::segment(ListConstIterator it) const -{ - OGDF_ASSERT(!empty() && size() != 1); - return DSegment(*it, *cyclicSucc(it)); -} - - - -// Assignment operator (for assigning from a rectangle). -DPolygon &DPolygon::operator=(const DRect &rect) -{ - clear(); - DRect r1(rect); - DRect r2(rect); - if (m_counterclock) - r2.xInvert(); - else - r2.yInvert(); - - pushBack(r1.p1()); - pushBack(r2.p1()); - pushBack(r1.p2()); - pushBack(r2.p2()); - - unify(); - return *this; -} - - -// inserts the point p, which must ly on the boarder of the polygon, between the two points p1 and p2 -// returns the index to that point, which is inserted only once -ListIterator DPolygon::insertPoint( - const DPoint &p, - ListIterator p1, - ListIterator p2) -{ - ListIterator i = p1; - - do { - DSegment seg = segment(i); - if (seg.contains(p)) { - if (seg.start() == p) - return i; - else if (seg.end() == p) { - i = cyclicSucc(i); - return i; - } - else - return insertAfter(p, i); - } - - i = cyclicSucc(i); - } while (i != p2); - - OGDF_ASSERT(false); // Point not in polygon, should not be reached! - return i; -} - - -// inserts 'p' on every segment (a,b) with p in the open range ]a, b[ -void DPolygon::insertCrossPoint(const DPoint &p) -{ - ListIterator i = begin(); - - do { - DSegment seg = segment(i); - if (seg.contains(p)) - if (seg.start() != p && seg.end() != p) - i = insertAfter(p, i); - - i = cyclicSucc(i); - } while (i != begin()); -} - - -// -int DPolygon::getCrossPoints(const DPolygon &p, List &crossPoints) const -{ - crossPoints.clear(); - - ListConstIterator i, j; - for (i = begin(); i.valid(); ++i) { - DSegment s1 = segment(i); - for (j = p.begin(); j.valid(); ++j) { - DSegment s2 = p.segment(j); - - DPoint intersec; - - if (s1.intersection(s2, intersec)) - crossPoints.pushBack(intersec); - } - } - // unify the list - ListIterator k, l; - for (k = crossPoints.begin(); k.valid(); ++k) - for (l = k, ++l; l.valid(); ++l) - if (*k == *l) { - --l; - crossPoints.del(crossPoints.cyclicSucc(l)); - } - - return crossPoints.size(); -} - - - -// delete all consecutive double-points -void DPolygon::unify() -{ - ListIterator iter, next; - for (iter = begin(); iter.valid(); ++iter) { - next = cyclicSucc(iter); - while (*iter == *next) { - del(next); - next = cyclicSucc(iter); - if (iter == next) - break; - } - } -} - - -// deletes all points, which are not facets -void DPolygon::normalize() -{ - unify(); - - ListIterator iter, next; - for (iter = begin(); iter.valid(); ++iter) { - for( ; ; ) { - next = cyclicSucc(iter); - DSegment s1 = segment(iter); - DSegment s2 = segment(next); - DRect r (*iter, *cyclicSucc(next)); - if (s1.slope() == s2.slope() && r.contains(*next)) - del(next); - else - break; // while - } - } -} - - -// -void DPolygon::writeGML(ostream &stream) const -{ - Graph g; - GraphAttributes ag(g); - - node u = NULL; - node v = NULL; - node first = 0; - - ListConstIterator iter; - for (iter = begin(); iter.valid(); ++iter) { - v = g.newNode(); - if (u != NULL) - g.newEdge(u, v); - else - first = v; - u = v; - - ag.x(v) = (*iter).m_x; - ag.y(v) = (*iter).m_y; - } - g.newEdge(v, first); - - ag.writeGML(stream); -} - - -// outputs the GML-file, which illustrates the Polygon as Graph -void DPolygon::writeGML(const char *filename) const -{ - ofstream file(filename); - writeGML(file); -} - - -// Checks wether a Point /a p is inside the Poylgon or not. -bool DPolygon::containsPoint(DPoint &p) const -{ - if (size() < 3) { - return false; - } - - double angle = 0.0; - DPolygon::const_iterator i = cyclicPred(begin()); - double lastangle = atan2((*i).m_y - p.m_y, (*i).m_x - p.m_x); - double tempangle = 0.0; - for (i = begin(); i != end(); i++) - { - tempangle = atan2((*i).m_y - p.m_y, (*i).m_x - p.m_x); - double step = lastangle - tempangle; - while (step > Math::pi) step -= 2.0*Math::pi; - while (step < -Math::pi) step += 2.0*Math::pi; - angle += step; - lastangle = tempangle; - } - - double d = angle / (2.0 * Math::pi); - int rounds = static_cast(d<0?d-.5:d+.5); - - return ((rounds % 2) != 0); -} - - -// outputs the polygon -ostream &operator<<(ostream &os, const DPolygon &dop) -{ - print(os, dop, ' '); - return os; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/graph_generators.cpp b/ext/OGDF/src/basic/graph_generators.cpp deleted file mode 100644 index 63c56115e..000000000 --- a/ext/OGDF/src/basic/graph_generators.cpp +++ /dev/null @@ -1,1205 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of some graph generators - * - * \author Carsten Gutwenger, Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -inline int __IDX(int a, int b, int n, int max) { - int t = n - a - 1; - int s = t * (t+1) / 2; - int w = max - s; - int o = b - a - 1; - return w + o; -} - -void randomGraph(Graph &G, int n, int m) -{ - G.clear(); - - Array v(n); - - int i; - for(i = 0; i < n; i++) - v[i] = G.newNode(); - - for(i = 0; i < m; i++) { - int v1 = randomNumber(0,n-1); - int v2 = randomNumber(0,n-1); - - G.newEdge(v[v1],v[v2]); - } -} - -bool randomSimpleGraph(Graph &G, int n, int m) -{ - G.clear(); - - if(n < 1) - return false; - - int max = n * (n-1) / 2; - if(m > max || m < n) - return false; - - Array v(n); - - int i; - for(i = 0; i < n; i++) - v[i] = G.newNode(); - - bool remove; - if(m > max /2) { - m = max - m; - remove = true; - } else { - remove = false; - } - - Array used(max); - for(i = max; i-->0;) - used[i] = remove; - - int a,b; - while(m > 0) { - a = randomNumber(0,n-1); - b = randomNumber(0,n-2); - if(b >= a) b++; - else { - int c = a; - a = b; - b = c; - } - if(used[i = __IDX(a,b,n,max)] == remove) { - used[i] = !remove; - m--; - } - } - - for(a = 0; a < n; a++) - for(b = a+1; b < n; b++) - if(used[__IDX(a,b,n,max)]) - G.newEdge(v[a],v[b]); - - return true; -} - - -void randomTree(Graph &G, int n, int maxDeg, int maxWidth) -{ - G.clear(); - - if (n <= 0) return; - if (maxDeg <= 0) maxDeg = n; - if (maxWidth <= 0) maxWidth = n; - - int max = 0; - Array possible(n); - Array width(0,n,0); - NodeArray level(G,0); - - level[possible[0] = G.newNode()] = 0; - --n; - - while(n > 0) { - int i = randomNumber(0,max); - node v = possible[i]; - - if (width[level[v]+1] == maxWidth) { - possible[i] = possible[max--]; - continue; - } - - if (v->outdeg()+1 == maxDeg) - possible[i] = possible[max--]; - - node w = G.newNode(); - possible[++max] = w; - G.newEdge(v,w); - width[level[w] = level[v]+1]++; - - --n; - } -} - - -void randomBiconnectedGraph(Graph &G, int n, int m) -{ - if (n < 3) n = 3; - if (m < n) m = n; - - int kse = n-3; // number of split edge operations - int kae = m-n; // number of add edge operations - - G.clear(); - - Array edges(m); - Array nodes(n); - - // we start with a triangle - nodes[0] = G.newNode(); - nodes[1] = G.newNode(); - nodes[2] = G.newNode(); - edges[0] = G.newEdge(nodes[0],nodes[1]); - edges[1] = G.newEdge(nodes[1],nodes[2]); - edges[2] = G.newEdge(nodes[2],nodes[0]); - - int nNodes = 3, nEdges = 3; - - while(kse+kae > 0) - { - int p = randomNumber(1,kse+kae); - - if (p <= kse) { - // split edge operation - edge e = edges[randomNumber(0,nEdges-1)]; - edge e1 = G.split(e); - - edges[nEdges++] = e1; - nodes[nNodes++] = e1->source(); - - --kse; - - } else { - // add edge operation - int i = randomNumber(0,nNodes-1); - int j = (i + randomNumber(1,nNodes-1)) % nNodes; - - edges[nEdges++] = G.newEdge(nodes[i], nodes[j]); - - --kae; - } - } -} - - -void randomTriconnectedGraph(Graph &G, int n, double p1, double p2) -{ - if(n < 4) n = 4; - - // start with K_4 - completeGraph(G,4); - - // nodes[0],...,nodes[i-1] is array of all nodes - Array nodes(n); - - node v; - int i = 0; - forall_nodes(v,G) - nodes[i++] = v; - - // Will be used below as array of neighbors of v - Array neighbors(n); - - // used to mark neighbors - // 0 = not marked - // 1 = marked left - // 2 = marked right - // 3 = marked both - Array mark(0,n-1,0); - - for(; i < n; ++i) - { - // pick a random node - v = nodes[randomNumber(0,i-1)]; - - // create a new node w such that v is split into v and w - node w = nodes[i] = G.newNode(); - - // build array of all neighbors - int d = v->degree(); - - int j = 0; - adjEntry adj; - forall_adj(adj,v) - neighbors[j++] = adj->theEdge(); - - // mark two distinct neighbors for left - for(j = 2; j > 0; ) { - int r = randomNumber(0,d-1); - if((mark[r] & 1) == 0) { - mark[r] |= 1; --j; - } - } - - // mark two distinct neighbors for right - for(j = 2; j > 0; ) { - int r = randomNumber(0,d-1); - if((mark[r] & 2) == 0) { - mark[r] |= 2; --j; - } - } - - for(j = 0; j < d; ++j) { - int m = mark[j]; - mark[j] = 0; - - // decide to with which node each neighbor is connected - // (possible: v, w, or both) - double x = randomDouble(0.0,1.0); - switch(m) - { - case 0: - if(x < p1) - m = 1; - else if(x < p1+p2) - m = 2; - else - m = 3; - break; - case 1: - case 2: - if(x >= p1+p2) m = 3; - break; - } - - // move edge or create new one if necessary - edge e = neighbors[j]; - switch(m) - { - case 2: - if(v == e->source()) - G.moveSource(e,w); - else - G.moveTarget(e,w); - break; - case 3: - G.newEdge(w,e->opposite(v)); - break; - } - } - - G.newEdge(v,w); - } -} - - -void planarTriconnectedGraph(Graph &G, int n, double p1, double p2) -{ - if (n < 4) n = 4; - - // start with K_4 - completeGraph(G,4); - - planarEmbedPlanarGraph(G); - - // nodes[0],...,nodes[i-1] is array of all nodes - Array nodes(n); - - node v; - int i = 0; - forall_nodes(v,G) - nodes[i++] = v; - - for(; i < n; ++i) - { - // pick a random node - v = nodes[randomNumber(0,i-1)]; - - int m = v->degree(); - int a1 = randomNumber(0,m-1); - int a2 = randomNumber(0,m-2); - - int j; - adjEntry adj1, adj2; - for(adj1 = v->firstAdj(), j = 0; j < a1; adj1 = adj1->succ(), ++j) ; - for(adj2 = adj1->cyclicSucc(), j = 0; j < a2; adj2 = adj2->cyclicSucc(), ++j) ; - - adjEntry adj_b1 = adj2->cyclicPred(); - adjEntry adj_b2 = adj1->cyclicPred(); - - nodes[i] = G.splitNode(adj1, adj2); - - if(adj1 == adj_b1) - G.newEdge(adj_b1, adj2->twin()); - else if(adj2 == adj_b2) - G.newEdge(adj2, adj_b1->twin(), ogdf::before); - else { - double r = randomDouble(0.0,1.0); - if(r <= p1) { - int s = randomNumber(0,1); - if(s == 0) - G.newEdge(adj_b1, adj2->twin()); - else - G.newEdge(adj2, adj_b1->twin(), ogdf::before); - } - } - - double r = randomDouble(0.0,1.0); - if(r <= p2) { - int s = randomNumber(0,1); - if(s == 0) - G.newEdge(adj1, adj_b2->twin(), ogdf::before); - else - G.newEdge(adj_b2, adj1->twin()); - } - } -} - - -void planarTriconnectedGraph(Graph &G, int n, int m) -{ - if (n < 4) n = 4; - if(n % 2) ++n; // need an even number - - // start with K_4 - completeGraph(G,4); - - planarEmbedPlanarGraph(G); - - // nodes[0],...,nodes[i-1] is array of all nodes - Array nodes(n); - - node v; - int i = 0; - forall_nodes(v,G) - nodes[i++] = v; - - // create planar triconnected 3-graph - for(; i < n; ) - { - // pick a random node - v = nodes[randomNumber(0,i-1)]; - - adjEntry adj2 = v->firstAdj(); - int r = randomNumber(0,2); - switch(r) { - case 2: adj2 = adj2->succ(); // fall through to next case - case 1: adj2 = adj2->succ(); - } - adjEntry adj1 = adj2->cyclicSucc(); - - nodes[i++] = G.splitNode(adj1,adj2); - - r = randomNumber(0,1); - if(r == 0) { - adjEntry adj = adj1->twin(); - G.newEdge(adj2,adj); - nodes[i++] = G.splitNode(adj,adj->cyclicSucc()->cyclicSucc()); - - } else { - adjEntry adj = adj1->cyclicSucc()->twin(); - G.newEdge(adj2,adj,ogdf::before); - nodes[i++] = G.splitNode(adj->cyclicPred(),adj->cyclicSucc()); - } - } - - nodes.init(); - Array edges(m); - - CombinatorialEmbedding E(G); - Array faces(2*n); - - i = 0; - face f; - forall_faces(f,E) { - if(f->size() >= 4) - faces[i++] = f; - } - - while(G.numberOfEdges() < m && i > 0) - { - int r = randomNumber(0,i-1); - f = faces[r]; - faces[r] = faces[--i]; - - int p = randomNumber(0,f->size()-1); - int j = 0; - adjEntry adj, adj2; - for(adj = f->firstAdj(); j < p; adj = adj->faceCycleSucc(), ++j) ; - - p = randomNumber(2, f->size()-2); - for(j = 0, adj2 = adj; j < p; adj2 = adj2->faceCycleSucc(), ++j) ; - - edge e = E.splitFace(adj,adj2); - - f = E.rightFace(e->adjSource()); - if(f->size() >= 4) faces[i++] = f; - - f = E.rightFace(e->adjTarget()); - if(f->size() >= 4) faces[i++] = f; - } -} - -void planarConnectedGraph(Graph &G, int n, int m) -{ - if (n < 1) n = 1; - if (m < n-1) m = n-1; - if (m > 3*n-6) m = 3*n-6; - - G.clear(); - Array nodes(n); - - // we start with a triangle - nodes[0] = G.newNode(); - - //build tree - int i; - for(i=1; idegree(); - if(on->degree() > 1) { - adjEntry adj = on->firstAdj(); - for(int fwd = randomNumber(0,on->degree()-1); fwd>0; --fwd) - adj = adj->succ(); - G.newEdge(nn, adj); - } else { - G.newEdge(nn, on); - } - } - - List bigFaces; // not a triangle - - CombinatorialEmbedding E(G); - bigFaces.pushBack(E.firstFace()); - for(i = m-n+1; i-->0;) { - ListIterator fi = bigFaces.chooseIterator(); - face f = *fi; - bigFaces.del(fi); - - List fnodes; - adjEntry adj; - forall_face_adj(adj, f) { - fnodes.pushBack(adj); - } - fnodes.permute(); - adjEntry adj1,adj2; - bool okay = false; - do { - adj1 = fnodes.popFrontRet(); - node n1 = adj1->theNode(); - forall_listiterators(adjEntry, it, fnodes) { - adj2 = *it; - node n2 = adj2->theNode(); - - if(n1==n2 || adj1->faceCyclePred() == adj2 || adj2->faceCyclePred() == adj1) { - continue; - } - edge e; - okay = true; - forall_adj_edges(e,n1) { - if(e->opposite(n1) == n2) { - okay = false; - break; - } - } - if(okay) break; - } - } while(!okay); - - edge ne = E.splitFace(adj1,adj2); - - face f1 = E.rightFace(ne->adjSource()); - face f2 = E.rightFace(ne->adjTarget()); - - if (f1->size() > 3) bigFaces.pushBack(f1); - if (f2->size() > 3) bigFaces.pushBack(f2); - } -} - - -void planarBiconnectedGraph(Graph &G, int n, int m, bool multiEdges) -{ - if (n < 3) n = 3; - if (m < n) m = n; - if (m > 3*n-6) m = 3*n-6; - - int ke = n-3, kf = m-n; - - G.clear(); - - Array edges(m); - Array bigFaces(m); - //random_source S; - - // we start with a triangle - node v1 = G.newNode(), v2 = G.newNode(), v3 = G.newNode(); - edges[0] = G.newEdge(v1,v2); - edges[1] = G.newEdge(v2,v3); - edges[2] = G.newEdge(v3,v1); - - CombinatorialEmbedding E(G); - FaceArray posBigFaces(E); - int nBigFaces = 0, nEdges = 3; - - while(ke+kf > 0) { - int p = randomNumber(1,ke+kf); - - if (nBigFaces == 0 || p <= ke) { - edge e = edges[randomNumber(0,nEdges-1)]; - face f = E.rightFace(e->adjSource()); - face fr = E.rightFace(e->adjTarget()); - - edges[nEdges++] = E.split(e); - - if (f->size() == 4) { - posBigFaces[f] = nBigFaces; - bigFaces[nBigFaces++] = f; - } - if (fr->size() == 4) { - posBigFaces[fr] = nBigFaces; - bigFaces[nBigFaces++] = fr; - } - - ke--; - - } else { - int pos = randomNumber(0,nBigFaces-1); - face f = bigFaces[pos]; - int df = f->size(); - int i = randomNumber(0,df-1), j = randomNumber(2,df-2); - - adjEntry adj1; - for (adj1 = f->firstAdj(); i > 0; adj1 = adj1->faceCycleSucc()) - i--; - - adjEntry adj2; - for (adj2 = adj1; j > 0; adj2 = adj2->faceCycleSucc()) - j--; - - edge e = E.splitFace(adj1,adj2); - edges[nEdges++] = e; - - face f1 = E.rightFace(e->adjSource()); - face f2 = E.rightFace(e->adjTarget()); - - bigFaces[pos] = f1; - posBigFaces[f1] = pos; - if (f2->size() >= 4) { - posBigFaces[f2] = nBigFaces; - bigFaces[nBigFaces++] = f2; - } - if (f1->size() == 3) { - bigFaces[pos] = bigFaces[--nBigFaces]; - } - - kf--; - } - } - - if (multiEdges == false) { - SListPure allEdges; - EdgeArray minIndex(G), maxIndex(G); - - parallelFreeSortUndirected(G,allEdges,minIndex,maxIndex); - - SListConstIterator it = allEdges.begin(); - edge ePrev = *it, e; - for(it = ++it; it.valid(); ++it, ePrev = e) { - e = *it; - if (minIndex[ePrev] == minIndex[e] && - maxIndex[ePrev] == maxIndex[e]) - { - G.move(e, - e->adjTarget()->faceCycleSucc()->twin(), ogdf::before, - e->adjSource()->faceCycleSucc()->twin(), ogdf::before); - } - } - - } -} - -void planarCNBGraph(Graph &G, int n, int m, int b) -{ - G.clear(); - if (b <= 0) b = 1; - if (n <= 0) n = 1; - if ((m <= 0) || (m > 3*n-6)) m = 3*n-6; - - node cutv; - G.newNode(); - - for (int nB=1; nB<=b; nB++){ - cutv = G.chooseNode(); - // set number of nodes for the current created block - int actN = randomNumber(1, n); - - node v1 = G.newNode(); - - if (actN <= 1){ - G.newEdge(v1, cutv); - } - else - if (actN == 2){ - node v2 = G.newNode(); - G.newEdge(v1, v2); - - int rnd = randomNumber(1, 2); - edge newE; - int rnd2 = randomNumber(1, 2); - if (rnd == 1){ - newE = G.newEdge(v1, cutv); - } - else{ - newE = G.newEdge(v2, cutv); - } - if (rnd2 == 1){ - G.contract(newE); - } - } - else{ - // set number of edges for the current created block - int actM; - if (m > 3*actN-6) - actM = randomNumber(1, 3*actN-6); - else - actM = randomNumber(1, m); - if (actM < actN) - actM = actN; - - int ke = actN-3, kf = actM-actN; - - Array nodes(actN); - Array edges(actM); - Array bigFaces(actM); - - // we start with a triangle - node v2 = G.newNode(), v3 = G.newNode(); - nodes[0] = v1; - nodes[1] = v2; - nodes[2] = v3; - edges[0] = G.newEdge(v1,v2); - edges[1] = G.newEdge(v2,v3); - edges[2] = G.newEdge(v3,v1); - - int actInsertedNodes = 3; - - CombinatorialEmbedding E(G); - FaceArray posBigFaces(E); - int nBigFaces = 0, nEdges = 3; - - while(ke+kf > 0) { - int p = randomNumber(1,ke+kf); - - if (nBigFaces == 0 || p <= ke) { - int eNr = randomNumber(0,nEdges-1); - edge e = edges[eNr]; - face f = E.rightFace(e->adjSource()); - face fr = E.rightFace(e->adjTarget()); - - node u = e->source(); - node v = e->target(); - - edges[nEdges++] = E.split(e); - - if (e->source() != v && e->source() != u) - nodes[actInsertedNodes++] = e->source(); - else - nodes[actInsertedNodes++] = e->target(); - - if (f->size() == 4) { - posBigFaces[f] = nBigFaces; - bigFaces[nBigFaces++] = f; - } - if (fr->size() == 4) { - posBigFaces[fr] = nBigFaces; - bigFaces[nBigFaces++] = fr; - } - - ke--; - } - else { - int pos = randomNumber(0,nBigFaces-1); - face f = bigFaces[pos]; - int df = f->size(); - int i = randomNumber(0,df-1), j = randomNumber(2,df-2); - - adjEntry adj1; - for (adj1 = f->firstAdj(); i > 0; adj1 = adj1->faceCycleSucc()) - i--; - - adjEntry adj2; - for (adj2 = adj1; j > 0; adj2 = adj2->faceCycleSucc()) - j--; - - edge e = E.splitFace(adj1,adj2); - edges[nEdges++] = e; - - face f1 = E.rightFace(e->adjSource()); - face f2 = E.rightFace(e->adjTarget()); - - bigFaces[pos] = f1; - posBigFaces[f1] = pos; - if (f2->size() >= 4) { - posBigFaces[f2] = nBigFaces; - bigFaces[nBigFaces++] = f2; - } - if (f1->size() == 3) { - bigFaces[pos] = bigFaces[--nBigFaces]; - } - - kf--; - } - } - - // delete multi edges - SListPure allEdges; - EdgeArray minIndex(G), maxIndex(G); - - parallelFreeSortUndirected(G,allEdges,minIndex,maxIndex); - - SListConstIterator it = allEdges.begin(); - edge ePrev = *it, e; - for(it = ++it; it.valid(); ++it, ePrev = e) { - e = *it; - if (minIndex[ePrev] == minIndex[e] && - maxIndex[ePrev] == maxIndex[e]) - { - G.move(e, - e->adjTarget()->faceCycleSucc()->twin(), ogdf::before, - e->adjSource()->faceCycleSucc()->twin(), ogdf::before); - } - } - - node cutv2 = nodes[randomNumber(0,actN-1)]; - - int rnd = randomNumber(1,2); - edge newE = G.newEdge(cutv2, cutv); - if (rnd == 1){ - G.contract(newE); - } - } - } -} - - -void constructCConnectedCluster(node v,ClusterGraph &C); -void constructCluster(node v,ClusterGraph &C); -void bfs(node v,SList &newCluster,NodeArray &visited,ClusterGraph &C); - -void randomClusterGraph(ClusterGraph &C,Graph &G,int cNum) -{ - int n = G.numberOfNodes(); - //int m = G.numberOfEdges(); - - node v; - int count = 0; - NodeArray num(G); - Array numNode(0,n-1,0); - forall_nodes(v,G) - { - num[v] = count; - numNode[count] = v; - count++; - } - - for (int i = 0; i < cNum; i++) - { - int rand = randomNumber(0,n-1); - - node start = numNode[rand]; - - constructCluster(start,C); - } - - OGDF_ASSERT(C.consistencyCheck()); - -}//randomClusterGraph - -void randomClusterPlanarGraph(ClusterGraph &C,Graph &G,int cNum) -{ - int n = G.numberOfNodes(); - //int m = G.numberOfEdges(); - - node v; - int count = 0; - NodeArray num(G); - Array numNode(0,n-1,0); - forall_nodes(v,G) - { - num[v] = count; - numNode[count] = v; - count++; - } - - for (int i = 0; i < cNum; i++) - { - int rand = randomNumber(0,n-1); - - node start = numNode[rand]; - - constructCConnectedCluster(start,C); - } - - // By construction, clusters might have just one child. - // remove these clusters - SListPure store; - cluster c; - forall_clusters(c,C) - { - if ((c->cCount() + c->nCount()) == 1 ) - store.pushBack(c); - } - while (!store.empty()) - { - c = store.popFrontRet(); - if (c != C.rootCluster()) - C.delCluster(c); - } - if ((C.rootCluster()->cCount() == 1) && (C.rootCluster()->nCount() == 0)) - { - cluster cl = (*C.rootCluster()->cBegin()); - C.delCluster(cl); - } - - - OGDF_ASSERT(C.consistencyCheck()); - -} - -void constructCConnectedCluster(node v,ClusterGraph &C) -{ - SList newCluster; - newCluster.pushBack(v); - NodeArray visited(C.getGraph(),false); - visited[v] = true; - bfs(v,newCluster,visited,C); - if (newCluster.size() > 1) - { - cluster cl = C.newCluster(C.clusterOf(v)); -// cout << " Cluster " << cl->index() << endl; - while (!newCluster.empty()) - { - node w = newCluster.popFrontRet(); -// cout << " Node in cluster " << w << endl; - C.reassignNode(w,cl); - } - } -} - -//construct new (child) cluster by randomly choosing nodes in v's cluster -void constructCluster(node v,ClusterGraph &C) -{ - if (C.clusterOf(v)->nCount() < 2) return; - - SList newCluster; - newCluster.pushBack(v); - - //store the cluster nodes for random selection - //we could just randomly select by running up the list - //HashArray clusterNodes; - //int i = 0; - ListConstIterator it = C.clusterOf(v)->nBegin(); - while (it.valid()) - { - if (!((*it) == v)) - { - if (randomNumber(0,99) > 65) - newCluster.pushBack((*it)); - } - it++; - }//while - - cluster cl = C.newCluster(C.clusterOf(v)); - while (!newCluster.empty()) - { - node w = newCluster.popFrontRet(); - C.reassignNode(w,cl); - } - -}//constructcluster - -//insert nodes in v's cluster to new cluster with a certain probability -void bfs(node v,SList &newCluster,NodeArray &visited,ClusterGraph &C) -{ - - edge e; - SListPure bfsL; - forall_adj_edges (e,v) - { - node w = e->opposite(v); - int probability = randomNumber(0,99); - if (probability < 70 && !visited[w]) - { - visited[w] = true; - if (C.clusterOf(v) == C.clusterOf(w)) - { - newCluster.pushBack(w); - bfsL.pushBack(w); - } - } - else - visited[w] = true; - } - while(!bfsL.empty()) - bfs(bfsL.popFrontRet(),newCluster,visited,C); -} - - -void randomTree(Graph& G, int n) { - G.clear(); - G.newNode(); - for(int i=1; i& internal, List& leaves) { - cluster currC = predC ? C.createEmptyCluster(predC) : C.rootCluster(); - if(curr->degree()==1 && pred!=0) { - leaves.pushBack(currC); - } else { - edge e; - forall_adj_edges(e,curr) { - node next = e->opposite(curr); - if(next == pred) continue; - createClustersHelper(C, next,curr,currC, internal,leaves); - } - internal.pushBack(currC); - } -} - -void randomClusterGraph(ClusterGraph& C, const Graph& G, const node root, int moreInLeaves) { - C.init(G); - - // Build cluster structure (and store which clusters are internal and which are leaves) - List internal; - List leaves; - createClustersHelper(C, root,0,0, internal,leaves); - - // Assign nodes to clusters - List nodes; - G.allNodes >(nodes); - - // Step 1: Ensure two node per leaf-cluster - nodes.permute(); - forall_listiterators(cluster, it, leaves) { - C.reassignNode(nodes.popFrontRet(),*it); - C.reassignNode(nodes.popFrontRet(),*it); - } - - // Step 2: Distribute the other nodes - int n = G.numberOfNodes(); - int numI = internal.size(); - int numL = leaves.size(); - double chanceForInternal = ( numI*n/double(numL*moreInLeaves+numI) ) / double(n-2*numL); - // a leaf-cluster should have (on average) moreInLeaves-times as many vertices as in internal-cluster. - // #verticesInInternalCluster = n / (numL*moreInLeaves + numI) - // #nodesToDistribute = n - 2*numL - // => chance that a node goes into an internal cluster = numI * #verticesInInternalCluster / (n-2*numL) - while(!nodes.empty()) { - cluster cl; - if(randomDouble(0,1) < chanceForInternal) { - cl = * internal.get(randomNumber(0,internal.size()-1)); - } else { - cl = * leaves.get(randomNumber(0,leaves.size()-1)); - } - C.reassignNode(nodes.popFrontRet(),cl); - } -} - -void completeGraph(Graph &G, int n) -{ - G.clear(); - - Array v(n); - - int i,j; - for(i = n; i-->0;) - v[i] = G.newNode(); - - for(i = n; i-->0;) - for(j = i; j-->0;) - G.newEdge(v[i],v[j]); -} - -void completeBipartiteGraph(Graph &G, int n, int m) -{ - G.clear(); - - Array a(n); - Array b(m); - - int i,j; - for(i = n; i-->0;) - a[i] = G.newNode(); - for(j = m; j-->0;) - b[j] = G.newNode(); - - for(i = n; i-->0;) - for(j = m; j-->0;) - G.newEdge(a[i],b[j]); -} - -void wheelGraph(Graph &G, int n) -{ - G.clear(); - if(n <= 2) return; - - node center = G.newNode(); - - node n0,n1=0,n2; - for(; n-->0;) { - G.newEdge(center, n2 = G.newNode()); - if(n1) G.newEdge(n1,n2); - else n0 = n2; - n1 = n2; - } - G.newEdge(n1,n0); -} - -void suspension(Graph &G, int n) -{ - if(n == 0) return; - OGDF_ASSERT( n>0 ); - - List nds; - G.allNodes(nds); - for(; n-->0;) { - node n0 = G.newNode(); - forall_listiterators(node, it, nds) - G.newEdge(n0,*it); - } -} - -void cubeGraph(Graph &G, int n) -{ - OGDF_ASSERT( n>=0 && n < 8*(int)sizeof(int)-1 ); // one sign bit, one less to be safe - G.clear(); - - int c = 1 << n; - Array lu(c); - for(int i=0; i front(0,n-1,0); - Array fringe(0,n-1,0); - node first = 0; - node last = 0; - node cur; - for(int j=m; j-->0;) { - for(int i=n; i-->0;) { - cur = G.newNode(); - if(!last) first=cur; - else G.newEdge(last,cur); - if(fringe[i]) G.newEdge(fringe[i],cur); - else front[i] = cur; - fringe[i] = cur; - last = cur; - } - if(loopN) - G.newEdge(last, first); - last = 0; - } - if(loopM) { - for(int i=n; i-->0;) { - G.newEdge(fringe[i],front[i]); - } - } -} - -void petersenGraph(Graph &G, int n, int m) { - G.clear(); - Array inner(0, n-1, 0); - node first = 0; - node last = 0; - for(int i=n; i-->0;) { - node outn = G.newNode(); - node inn = G.newNode(); - G.newEdge(outn,inn); - inner[i]=inn; - if(!last) first=outn; - else G.newEdge(last,outn); - last = outn; - } - G.newEdge(last, first); - for(int i=n; i-->0;) { - G.newEdge(inner[i],inner[(i+m)%n]); - } -} - -void randomDiGraph(Graph &G, int n, double p) { - - OGDF_ASSERT(n>=0 && p<=1 && p>=0); - - for(int i=0; i nodeList; - G.allNodes(nodeList); - nodeList.permute(); - forall_listiterators(node, it, nodeList) { - node v = *it; - node w; - forall_nodes(w, G) { - if (v==w) - continue; - if (randomDouble(0,1) - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - -void AcyclicSubgraphModule::callAndReverse(Graph &G, List &reversed) -{ - call(G,reversed); - - ListConstIterator it; - for(it = reversed.begin(); it.valid(); ++it) - G.reverseEdge(*it); -} - - -void AcyclicSubgraphModule::callAndReverse(Graph &G) -{ - List reversed; - callAndReverse(G,reversed); -} - - -void AcyclicSubgraphModule::callAndDelete(Graph &G) -{ - List arcSet; - call(G,arcSet); - - ListConstIterator it; - for(it = arcSet.begin(); it.valid(); ++it) - G.delEdge(*it); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/random_hierarchy.cpp b/ext/OGDF/src/basic/random_hierarchy.cpp deleted file mode 100644 index a7daa76e9..000000000 --- a/ext/OGDF/src/basic/random_hierarchy.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements graph generator for hierarchical graphs. - * - * \author Carsten Gutwenger, Christoph Buchheim - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -class BEdge { -public: - int head, tail, id, pos; - BEdge *next; - BEdge(int t,int h,int c) : head(h), tail(t), id(c), pos(-1), next(0) { } - OGDF_NEW_DELETE -}; - -typedef BEdge *bEdge; - - -int cmpId(const bEdge &a, const bEdge &b) { - return (a->id < b->id ? -1 : (a->id > b->id ? 1 : 0)); -} - - -class CmpTail { -public: - static int compare(const bEdge &a, const bEdge &b) { - return (a->tail < b->tail ? -1 : (a->tail > b->tail ? 1 : cmpId(a,b))); - } - OGDF_AUGMENT_STATICCOMPARER(bEdge) -}; - - -class CmpHead { -public: - static int compare(const bEdge &a, const bEdge &b) { - return (a->head < b->head ? -1 : (a->head > b->head ? 1 : cmpId(a,b))); - } - OGDF_AUGMENT_STATICCOMPARER(bEdge) -}; - -void randomHierarchy(Graph &G, - int numberOfNodes,int numberOfEdges, - bool planar,bool singleSource,bool longEdges) -{ - G.clear(); - - node *nnr = new node[3*numberOfNodes]; - int *vrt = new int[3*numberOfNodes]; - int *fst = new int[numberOfNodes+1]; - List startEdges; - bEdge actEdge, nextEdge, toDelete; - node v; - int act, next, n1, n2, idc=0; - double x1, x2, r; - bool connected; - - /** Place nodes **/ - - for(int i = 0; i < numberOfNodes; i++) - G.newNode(); - - int numberOfLayers=0, totNumber=0, realCount=0; - fst[0] = 0; - forall_nodes(v,G) { - if(longEdges&&numberOfLayers) vrt[totNumber++] = 1; - - nnr[totNumber] = v; - vrt[totNumber++] = 0; - realCount++; - r = double(randomNumber(0,1000)) / 1000.0; - if((totNumber == 1 && singleSource) || realCount == numberOfNodes || r*r*numberOfNodes < 1) - { - if(longEdges && numberOfLayers) - vrt[totNumber++] = 1; - fst[++numberOfLayers] = totNumber; - } - } - - /** Determine allowed neighbours **/ - - int *leftN = new int[totNumber]; - int *rightN = new int[totNumber]; - for(int l = 1; l < numberOfLayers; l++) - { - if(planar) { - n1 = fst[l-1]; - n2 = fst[l]; - leftN[n2] = n1; - while(n1 < fst[l] && n2 < fst[l+1]) { - r = double(randomNumber(0,1000)) / 1000.0; - if(n1 != fst[l]-1 && - (n2 == fst[l+1]-1 || - r < (double)(fst[l]-fst[l-1])/(double)(fst[l+1]-fst[l-1]))) - n1++; - else { - rightN[n2] = n1; - if(++n2 < fst[l+1]) - leftN[n2] = n1; - } - } - } - else - for(n2 = fst[l]; n2 < fst[l+1]; n2++) { - leftN [n2] = fst[l-1]; - rightN[n2] = fst[l]-1; - } - } - - /** Insert edges **/ - - SList *edgeIn = new SList[totNumber]; - SList *edgeOut = new SList[totNumber]; - if(numberOfLayers) { - x1 = numberOfEdges; - x2 = 0; - for(n2 = fst[1]; n2 < totNumber; n2++) - if(!vrt[n2]) - x2 += rightN[n2] - leftN[n2]+1; - - for(n2 = fst[1]; n2 < totNumber; n2++) - if(!vrt[n2]) { - connected = !singleSource; - for(n1 = leftN[n2]; n1 <= rightN[n2] || !connected; n1++) { - r = double(randomNumber(0,1000)) / 1000.0; - if(r < x1/x2 || n1 > rightN[n2]) { - next = (n1 <= rightN[n2] ? n1 : randomNumber(leftN[n2],rightN[n2])); - act = n2; - nextEdge = OGDF_NEW BEdge(next,act,idc++); - while(vrt[next]) { - act = next; - next = randomNumber(leftN[act],rightN[act]); - edgeOut[act].pushBack(nextEdge); - nextEdge = OGDF_NEW BEdge(next,act,idc++); - edgeIn[act].pushBack(nextEdge); - } - startEdges.pushBack(nextEdge); - connected = 1; - x1 -= 1; - } - if(n1<=rightN[n2]) - x2-=1; - } - } - } - - delete[] leftN; - delete[] rightN; - - if(planar) - for(act = 0; act < totNumber; act++) { - CmpTail cmpTail; - edgeIn[act].quicksort(cmpTail); - CmpHead cmpHead; - edgeOut[act].quicksort(cmpHead); - } - - for(act = 0; act < totNumber; act++) { - SListIterator it; - for(it = edgeIn[act].begin(); it.valid(); ++it) { - nextEdge = *it; - nextEdge->next = edgeOut[act].popFrontRet(); - } - } - - delete[] edgeOut; - - ListIterator it; - for(it = startEdges.begin(); it.valid(); ++it) { - actEdge = *it; - nextEdge = actEdge; - while(vrt[nextEdge->head]) - nextEdge = nextEdge->next; - G.newEdge(nnr[actEdge->tail], nnr[nextEdge->head]); - } - - /** Clean up **/ - for(it = startEdges.begin(); it.valid(); ++it) { - nextEdge = *it; - toDelete = nextEdge; - while(vrt[nextEdge->head]) { - nextEdge = nextEdge->next; - delete toDelete; - toDelete = nextEdge; - } - delete toDelete; - } - - delete[] edgeIn; - delete[] fst; - delete[] vrt; - delete[] nnr; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/simple_graph_alg.cpp b/ext/OGDF/src/basic/simple_graph_alg.cpp deleted file mode 100644 index e7d9e600c..000000000 --- a/ext/OGDF/src/basic/simple_graph_alg.cpp +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * $Revision: 2594 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 15:35:29 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of simple graph algorithms - * - * \author Carsten Gutwenger, Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// isLoopFree(), makeLoopFree() -// testing for self-loops, removing self-loops -//--------------------------------------------------------- -bool isLoopFree(const Graph &G) -{ - edge e; - forall_edges(e,G) - if(e->isSelfLoop()) return false; - - return true; -} - - -void makeLoopFree(Graph &G) -{ - edge e, eNext; - for (e = G.firstEdge(); e; e = eNext) { - eNext = e->succ(); - if (e->isSelfLoop()) G.delEdge(e); - } -} - - -//--------------------------------------------------------- -// isParallelFree(), makeParallelFree() -// testing for multi-edges, removing multi-edges -//--------------------------------------------------------- - -void parallelFreeSort(const Graph &G, SListPure &edges) -{ - G.allEdges(edges); - - BucketSourceIndex bucketSrc; - edges.bucketSort(0,G.maxNodeIndex(),bucketSrc); - - BucketTargetIndex bucketTgt; - edges.bucketSort(0,G.maxNodeIndex(),bucketTgt); -} - - -bool isParallelFree(const Graph &G) -{ - if (G.numberOfEdges() <= 1) return true; - - SListPure edges; - parallelFreeSort(G,edges); - - SListConstIterator it = edges.begin(); - edge ePrev = *it, e; - for(it = ++it; it.valid(); ++it, ePrev = e) { - e = *it; - if (ePrev->source() == e->source() && ePrev->target() == e->target()) - return false; - } - - return true; -} - - -int numParallelEdges(const Graph &G) -{ - if (G.numberOfEdges() <= 1) return 0; - - SListPure edges; - parallelFreeSort(G,edges); - - int num = 0; - SListConstIterator it = edges.begin(); - edge ePrev = *it, e; - for(it = ++it; it.valid(); ++it, ePrev = e) { - e = *it; - if (ePrev->source() == e->source() && ePrev->target() == e->target()) - ++num; - } - - return num; -} - - - -//--------------------------------------------------------- -// isParallelFreeUndirected(), makeParallelFreeUndirected() -// testing for (undirected) multi-edges, removing (undirected) multi-edges -//--------------------------------------------------------- - -void parallelFreeSortUndirected(const Graph &G, - SListPure &edges, - EdgeArray &minIndex, - EdgeArray &maxIndex) -{ - G.allEdges(edges); - - edge e; - forall_edges(e,G) { - int srcIndex = e->source()->index(), tgtIndex = e->target()->index(); - if (srcIndex <= tgtIndex) { - minIndex[e] = srcIndex; maxIndex[e] = tgtIndex; - } else { - minIndex[e] = tgtIndex; maxIndex[e] = srcIndex; - } - } - - BucketEdgeArray bucketMin(minIndex), bucketMax(maxIndex); - edges.bucketSort(0,G.maxNodeIndex(),bucketMin); - edges.bucketSort(0,G.maxNodeIndex(),bucketMax); -} - - -bool isParallelFreeUndirected(const Graph &G) -{ - if (G.numberOfEdges() <= 1) return true; - - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G,edges,minIndex,maxIndex); - - SListConstIterator it = edges.begin(); - edge ePrev = *it, e; - for(it = ++it; it.valid(); ++it, ePrev = e) { - e = *it; - if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) - return false; - } - - return true; -} - - -int numParallelEdgesUndirected(const Graph &G) -{ - if (G.numberOfEdges() <= 1) return 0; - - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G,edges,minIndex,maxIndex); - - int num = 0; - SListConstIterator it = edges.begin(); - edge ePrev = *it, e; - for(it = ++it; it.valid(); ++it, ePrev = e) { - e = *it; - if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) - ++num; - } - - return num; -} - - - -//--------------------------------------------------------- -// isConnected(), makeConnected() -// testing connectivity, establishing connectivity -//--------------------------------------------------------- - -bool isConnected(const Graph &G) -{ - node v = G.firstNode(); - if (v == 0) return true; - - int count = 0; - NodeArray visited(G,false); - BoundedStack S(G.numberOfNodes()); - - S.push(v); - visited[v] = true; - while(!S.empty()) { - v = S.pop(); - ++count; - - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(!visited[w]) { - visited[w] = true; - S.push(w); - } - } - } - - return (count == G.numberOfNodes()); -} - - -void makeConnected(Graph &G, List &added) -{ - added.clear(); - if (G.numberOfNodes() == 0) return; - NodeArray visited(G,false); - BoundedStack S(G.numberOfNodes()); - - node pred = 0, u; - forall_nodes(u,G) - { - if (visited[u]) continue; - - node vMinDeg = u; - int minDeg = u->degree(); - - S.push(u); - visited[u] = true; - - while(!S.empty()) - { - node v = S.pop(); - - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(!visited[w]) { - visited[w] = true; - S.push(w); - - int wDeg = w->degree(); - if (wDeg < minDeg) { - vMinDeg = w; - minDeg = wDeg; - } - } - } - } - - if (pred) - added.pushBack(G.newEdge(pred,vMinDeg)); - pred = vMinDeg; - } -} - - -int connectedComponents(const Graph &G, NodeArray &component) -{ - int nComponent = 0; - component.fill(-1); - - StackPure S; - - node v; - forall_nodes(v,G) { - if (component[v] != -1) continue; - - S.push(v); - component[v] = nComponent; - - while(!S.empty()) { - node w = S.pop(); - edge e; - forall_adj_edges(e,w) { - node x = e->opposite(w); - if (component[x] == -1) { - component[x] = nComponent; - S.push(x); - } - } - } - - ++nComponent; - } - - return nComponent; -} - -//return the isolated nodes too, is used in incremental layout -int connectedIsolatedComponents(const Graph &G, List &isolated, - NodeArray &component) -{ - int nComponent = 0; - component.fill(-1); - - StackPure S; - - node v; - forall_nodes(v,G) { - if (component[v] != -1) continue; - - S.push(v); - component[v] = nComponent; - - while(!S.empty()) { - node w = S.pop(); - if (w->degree() == 0) isolated.pushBack(w); - edge e; - forall_adj_edges(e,w) { - node x = e->opposite(w); - if (component[x] == -1) { - component[x] = nComponent; - S.push(x); - } - } - } - - ++nComponent; - } - - return nComponent; -}//connectedIsolated - - -//--------------------------------------------------------- -// isBiconnected(), makeBiconnected() -// testing biconnectivity, establishing biconnectivity -//--------------------------------------------------------- -static node dfsIsBicon (const Graph &G, node v, node father, - NodeArray &number, NodeArray &lowpt, int &numCount) -{ - node first_son = 0; - - lowpt[v] = number[v] = ++numCount; - - edge e; - forall_adj_edges(e,v) { - node w = e->opposite(v); - if (v == w) continue; // ignore self-loops - - if (number[w] == 0) { - if (first_son == 0) first_son = w; - - node cutVertex = dfsIsBicon(G,w,v,number,lowpt,numCount); - if (cutVertex) return cutVertex; - - // is v cut vertex ? - if (lowpt[w] >= number[v] && (w != first_son || father != 0)) - return v; - - if (lowpt[w] < lowpt[v]) lowpt[v] = lowpt[w]; - - } else { - - if (number[w] < lowpt[v]) lowpt[v] = number[w]; - } - } - - return 0; -} - - -bool isBiconnected(const Graph &G, node &cutVertex) -{ - if (G.empty()) return true; - - NodeArray number(G,0); - NodeArray lowpt(G); - int numCount = 0; - - cutVertex = dfsIsBicon(G,G.firstNode(),0,number,lowpt,numCount); - - return (numCount == G.numberOfNodes() && cutVertex == 0); -} - - -static void dfsMakeBicon (Graph &G, - node v, node father, - NodeArray &number, - NodeArray &lowpt, - int &numCount, - List &added) -{ - node predSon = 0; - - lowpt[v] = number[v] = ++numCount; - - edge e; - forall_adj_edges(e,v) { - node w = e->opposite(v); - if (v == w) continue; // ignore self-loops - - if (number[w] == 0) { - - dfsMakeBicon(G,w,v,number,lowpt,numCount,added); - - // is v cut vertex ? - if (lowpt[w] >= number[v]) { - if (predSon == 0 && father != 0) - added .pushBack(G.newEdge(w,father)); - - else if (predSon != 0) - added.pushBack(G.newEdge(w,predSon)); - } - - if (lowpt[w] < lowpt[v]) lowpt[v] = lowpt[w]; - predSon = w; - - } else { - - if (number[w] < lowpt[v]) lowpt[v] = number[w]; - } - } -} - - -void makeBiconnected(Graph &G, List &added) -{ - if (G.empty()) return; - - makeConnected(G,added); - - NodeArray number(G,0); - NodeArray lowpt(G); - int numCount = 0; - - dfsMakeBicon(G,G.firstNode(),0,number,lowpt,numCount,added); -} - - -//--------------------------------------------------------- -// biconnectedComponents() -// computing biconnected components -//--------------------------------------------------------- -static void dfsBiconComp (const Graph &G, - node v, - node father, - NodeArray &number, - NodeArray &lowpt, - StackPure &called, - EdgeArray &component, - int &nNumber, - int &nComponent) -{ - lowpt[v] = number[v] = ++nNumber; - called.push(v); - - edge e; - forall_adj_edges(e,v) { - node w = e->opposite(v); - if (v == w) continue; // ignore self-loops - - if (number[w] == 0) { - - dfsBiconComp(G,w,v,number,lowpt,called,component, - nNumber,nComponent); - - if (lowpt[w] < lowpt[v]) lowpt[v] = lowpt[w]; - - } else { - - if (number[w] < lowpt[v]) lowpt[v] = number[w]; - } - } - - if (father && (lowpt[v] == number[father])) { - node w; - do { - w = called.top(); called.pop(); - - forall_adj_edges(e,w) { - if (number[w] > number[e->opposite(w)]) - component[e] = nComponent; - } - } while (w != v); - - ++nComponent; - } -} - - -int biconnectedComponents(const Graph &G, EdgeArray &component) -{ - if (G.empty()) return 0; - - StackPure called; - NodeArray number(G,0); - NodeArray lowpt(G); - int nNumber = 0, nComponent = 0, nIsolated = 0; - - node v; - forall_nodes(v,G) { - if (number[v] == 0) { - bool isolated = true; - edge e; - forall_adj_edges(e,v) - if (!e->isSelfLoop()) { - isolated = false; break; - } - - if (isolated) - ++nIsolated; - else - dfsBiconComp(G,v,0,number,lowpt,called,component, - nNumber,nComponent); - } - } - - return nComponent + nIsolated; -} - - -//--------------------------------------------------------- -// isTriconnected() -// testing triconnectivity -//--------------------------------------------------------- -bool isTriconnectedPrimitive(const Graph &G, node &s1, node &s2) -{ - s1 = s2 = 0; - - if (isConnected(G) == false) - return false; - - if (isBiconnected(G,s1) == false) - return false; - - if (G.numberOfNodes() <= 3) - return true; - - // make a copy of G - GraphCopySimple GC(G); - - // for each node v in G, we test if G \ v is biconnected - node v; - forall_nodes(v,G) - { - node vC = GC.copy(v), wC; - - // store adjacent nodes - SListPure adjacentNodes; - edge eC; - forall_adj_edges(eC,vC) { - wC = eC->opposite(vC); - // forget self-loops (vC would no longer be in GC!) - if (wC != vC) - adjacentNodes.pushBack(wC); - } - - GC.delNode(vC); - - // test for biconnectivity - if(isBiconnected(GC,wC) == false) { - s1 = v; s2 = GC.original(wC); - return false; - } - - // restore deleted node with adjacent edges - vC = GC.newNode(v); - SListConstIterator it; - for(it = adjacentNodes.begin(); it.valid(); ++it) - GC.newEdge(vC,*it); - } - - return true; -} - - -//-------------------------------------------------------------------------- -// triangulate() -//-------------------------------------------------------------------------- -void triangulate(Graph &G) -{ - OGDF_ASSERT(isSimple(G)); - - CombinatorialEmbedding E(G); - - OGDF_ASSERT(E.consistencyCheck()); - - node v; - edge e; - adjEntry adj, succ, succ2, succ3; - NodeArray marked(E.getGraph(), 0); - - forall_nodes(v,E.getGraph()) { - marked.init(E.getGraph(), 0); - - forall_adj(adj,v) { - marked[adj->twinNode()] = 1; - } - - // forall faces adj to v - forall_adj(adj,v) { - succ = adj->faceCycleSucc(); - succ2 = succ->faceCycleSucc(); - - if (succ->twinNode() != v && adj->twinNode() != v) { - while (succ2->twinNode() != v) { - if (marked[succ2->theNode()] == 1) { - // edge e=(x2,x4) - succ3 = succ2->faceCycleSucc(); - E.splitFace(succ, succ3); - } - else { - // edge e=(v=x1,x3) - e = E.splitFace(adj, succ2); - marked[succ2->theNode()] = 1; - - // old adj is in wrong face - adj = e->adjSource(); - } - succ = adj->faceCycleSucc(); - succ2 = succ->faceCycleSucc(); - } - } - } - } -} - - -//-------------------------------------------------------------------------- -// isAcyclic(), isAcyclicUndirected(), makeAcyclic(), makeAcyclicByReverse() -// testing acyclicity, establishing acyclicity -//-------------------------------------------------------------------------- -void dfsIsAcyclic(const Graph &G, - node v, - NodeArray &number, - NodeArray &completion, - int &nNumber, - int &nCompletion) -{ - number[v] = ++nNumber; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - - if (number[w] == 0) - dfsIsAcyclic(G,w,number,completion,nNumber,nCompletion); - } - - completion[v] = ++nCompletion; -} - - -void dfsIsAcyclicUndirected(const Graph &G, - node v, - NodeArray &number, - int &nNumber, - List &backedges) -{ - number[v] = ++nNumber; - - adjEntry adj; - node w; - forall_adj(adj,v) { - w = adj->twinNode(); - if (number[w] == 0) { - dfsIsAcyclicUndirected(G,w,number,nNumber,backedges); - } else { - if (number[w] > number[v]) { - backedges.pushBack(adj->theEdge()); - } - } - } -} - - -bool isAcyclic(const Graph &G, List &backedges) -{ - backedges.clear(); - - NodeArray number(G,0), completion(G); - int nNumber = 0, nCompletion = 0; - - node v; - forall_nodes(v,G) - if (number[v] == 0) - dfsIsAcyclic(G,v,number,completion,nNumber,nCompletion); - - edge e; - forall_edges(e,G) { - node src = e->source(), tgt = e->target(); - - if (number[src] >= number[tgt] && completion[src] <= completion[tgt]) - backedges.pushBack(e); - } - - return backedges.empty(); -} - - -bool isAcyclicUndirected(const Graph &G, List &backedges) -{ - backedges.clear(); - int nNumber = 0; - NodeArray number(G,0); - - node v; - forall_nodes(v,G) { - if (number[v] == 0) { - dfsIsAcyclicUndirected(G,v,number,nNumber,backedges); - } - } - return backedges.empty(); -} - - -void makeAcyclic(Graph &G) -{ - List backedges; - isAcyclic(G,backedges); - - ListIterator it; - for(it = backedges.begin(); it.valid(); ++it) - G.delEdge(*it); -} - - -void makeAcyclicByReverse(Graph &G) -{ - List backedges; - isAcyclic(G,backedges); - - ListIterator it; - for(it = backedges.begin(); it.valid(); ++it) - if (!(*it)->isSelfLoop()) G.reverseEdge(*it); -} - - -//--------------------------------------------------------- -// hasSingleSource(), hasSingleSink() -// testing for single source/sink -//--------------------------------------------------------- -bool hasSingleSource(const Graph& G, node &s) -{ - node v; - s = 0; - - forall_nodes(v,G) { - if (v->indeg() == 0) { - if (s != 0) { - s = 0; - return false; - } else s = v; - } - } - return (G.empty() || s != 0); -} - - -bool hasSingleSink(const Graph& G, node &t) -{ - node v; - t = 0; - - forall_nodes(v,G) { - if (v->outdeg() == 0) { - if (t != 0) { - t = 0; - return false; - } else t = v; - } - } - return (G.empty() || t != 0); -} - - -//--------------------------------------------------------- -// isStGraph() -// true <=> G is st-graph, i.e., is acyclic, contains exactly one source s -// and one sink t, and the edge (s,t); returns single source s and single -// sink t if contained (otherwise they are set to 0), and edge st if -// contained (otherwise 0) -//--------------------------------------------------------- -bool isStGraph(const Graph &G, node &s, node &t, edge &st) -{ - st = 0; - - hasSingleSource(G,s); - hasSingleSink (G,t); - - if (s == 0 || t == 0 || isAcyclic(G) == false) { - s = t = 0; - return false; - } - - edge e; - forall_adj_edges(e,s) { - if (e->target() == t) { - st = e; - break; - } - } - - return (st != 0); -} - - -//--------------------------------------------------------- -// topologicalNumbering() -// computes a topological numbering of an acyclic graph -//--------------------------------------------------------- - -void topologicalNumbering(const Graph &G, NodeArray &num) -{ - BoundedStack S(G.numberOfNodes()); - NodeArray indeg(G); - - node v; - forall_nodes(v,G) - if((indeg[v] = v->indeg()) == 0) - S.push(v); - - int count = 0; - while(!S.empty()) { - node v = S.pop(); - num[v] = count++; - - edge e; - forall_adj_edges(e,v) { - node u = e->target(); - if(u != v) { - if(--indeg[u] == 0) - S.push(u); - } - } - } -} - - -//--------------------------------------------------------- -// strongComponents() -// computes the strongly connected components -//--------------------------------------------------------- - -//! Computes the strongly connected components with the algorithm of Tarjan. -/** - * @param G is the input graph. - * @param w is the current node. - * @param S is the stack containing all vertices of the current - * component during the algorithm - * @param pre is the preorder number. - * @param low is the lowest reachable preorder number (lowpoint). - * @param cnt is the counter for the dfs-number. - * @param scnt is the counter for the components. - * @param component is assigned a mapping from nodes to component numbers. - */ -void dfsStrongComponents( - const Graph& G, - node w, - BoundedStack& S, - NodeArray& pre, - NodeArray& low, - int& cnt, - int& scnt, - NodeArray& component) -{ - S.push(w); - int min = cnt; - low[w] = cnt; - pre[w] = cnt; - cnt++; - node t; - edge e; - forall_adj_edges(e, w) { - if (e->source() == w) { - t = e->target(); - if(pre[t] == -1) { - dfsStrongComponents(G, t, S, pre, low, cnt, scnt, component); - } - if (low[t] < low[w]) - min = low[t]; - } - } - if (min < low[w]) { - low[w] = min; - return; - } - do { - t = S.pop(); - component[t] = scnt; - low[t] = G.numberOfNodes(); - } while (t != w); - scnt++; -} - -int strongComponents(const Graph& G, NodeArray& component) -{ - if (G.numberOfNodes() == 0) - return 0; - if (G.numberOfNodes() == 1){ - component[G.firstNode()] = 0; - return 1; - } - NodeArray pre(G, -1); - NodeArray low(G, G.numberOfNodes()); - BoundedStack S(G.numberOfNodes()); - int cnt = 0; - int scnt = 0; - node v; - forall_nodes(v, G){ - if (pre[v] == -1){ - dfsStrongComponents(G, v, S, pre, low, cnt, scnt, component); - } - } - return scnt; -} - - -//--------------------------------------------------------- -// isFreeForest() -// testing if graph represents a free forest -//--------------------------------------------------------- - -bool isFreeForest(const Graph &G) -{ - NodeArray visited(G,false); - - node vFirst; - forall_nodes(vFirst,G) - { - if(visited[vFirst]) continue; - - StackPure > S; - S.push(Tuple2(vFirst,0)); - - while(!S.empty()) - { - Tuple2 t = S.pop(); - node v = t.x1(); - node parent = t.x2(); - - visited[v] = true; - - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - // skip edge to parent, but only once! - if(w == parent) { - parent = 0; - continue; - } - - if(visited[w] == true) - return false; - - S.push(Tuple2(w,v)); - } - } - } - - return true; -} - - -//--------------------------------------------------------- -// isForest(), isTree() -// testing if graph represents a forest/tree -//--------------------------------------------------------- -static bool dfsIsForest (node v, - NodeArray &visited, - NodeArray &mark) -{ - SListPure sons; - - visited[v] = true; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if (w != v && !mark[w]) { - mark[w] = true; - sons.pushBack(w); - } - } - - SListIterator it; - for(it = sons.begin(); it.valid(); ++it) - mark[*it] = false; - - while(!sons.empty()) { - node w = sons.front(); - sons.popFront(); - - if (visited [w] || dfsIsForest(w,visited,mark) == false) - return false; - } - - return true; -} - -bool isForest(const Graph& G, List &roots) -{ - roots.clear(); - if (G.empty()) return true; - - NodeArray visited(G,false), mark(G,false); - - node v; - forall_nodes(v,G) - if (v->indeg() == 0) { - roots.pushBack(v); - if (dfsIsForest(v,visited,mark) == false) - return false; - } - - forall_nodes(v,G) - if (!visited[v]) return false; - - return true; -} - - -bool isTree (const Graph& G, node &root) -{ - List roots; - - if (isForest(G,roots) && roots.size() == 1) { - root = roots.front(); return true; - } - return false; -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/basic/stNumber.cpp b/ext/OGDF/src/basic/stNumber.cpp deleted file mode 100644 index 38475201b..000000000 --- a/ext/OGDF/src/basic/stNumber.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of st-numbering algorithm - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - -namespace ogdf { - -// Needed by the function stNumber -void stSearch( - const Graph &C, - node sink, - int &count, - NodeArray &low, - NodeArray &dfn, - NodeArray &dfsInEdge, - NodeArray &followLowPath); - -// Needed by the function stNumber -bool stPath( - StackPure &path, - node v, - adjEntry &adj, - NodeArray &markedNode, - EdgeArray &markedEdge, - NodeArray &dfn, - NodeArray &dfsInEdge, - NodeArray &followLowPath); - -// Computes an st-Numbering. -// Precondition: G must be biconnected and simple. -// Exception: the Graph is allowed to have isolated nodes. -// The st-numbers are stored in NodeArray. Return value is -// the number t. It is 0, if the computation was unsuccessful. -// The nodes s and t may be specified. In this case -// s and t have to be adjacent. -// If s and t are set 0 and parameter randomized is set to true, -// the st edge is chosen to be a random edge in G. - -int stNumber(const Graph &G, - NodeArray &numbering, - node s, - node t, - bool randomized) -{ - - int count = 1; - - // Stores for every vertex its LOW number - NodeArray low(G,0); - // Stores for every vertex ist DFN number - NodeArray dfn(G,0); - - // Stores for every vertex if it has been visited dsuring the st-numbering - NodeArray markedNode(G,false); - // Stores for every edge if it has been visited dsuring the st-numbering - EdgeArray markedEdge(G,false); - - // Stores for every node its ingoing edge of the dfs tree. - NodeArray dfsInEdge(G,0); - - // Stores a path of vertices that have not been visited. - StackPure path; - - //Stores for every node the outgoing, first edge on the - // path that defines the low number of the node. - NodeArray followLowPath(G,0); - - edge st; - node v; - - if (s && t) - { - bool found = false; - forall_adj_edges(st,s) - if (st->opposite(s) == t) - { - found = true; - break; - } - if (!found) - return 0; - } - else if (s) - { - st = s->firstAdj()->theEdge(); - t = st->opposite(s); - } - else if (t) - { - st = t->firstAdj()->theEdge(); - s = st->opposite(t); - } - else - { - if(randomized) { - // chose a random edge in G - st = G.chooseEdge(); - if(!st) // graph is empty? - return 0; - s = st->source(); - t = st->target(); - - } else { - forall_nodes(s,G) - { - if (s->degree() > 0) - { - st = s->firstAdj()->theEdge(); - t = st->opposite(s); - break; - } - } - } - } - if (!s || !t) - return 0; - - // Compute the DFN and LOW numbers - // of the block. - dfn[t] = count++; - low[t] = dfn[t]; - stSearch(G,s,count,low,dfn,dfsInEdge,followLowPath); - if (low[t] > low[s]) - low[t] = low[s]; - - markedNode[s] = true; - markedNode[t] = true; - markedEdge[st] = true; - - StackPure nodeStack; // nodeStack stores the vertices during the - // computation of the st-numbering. - nodeStack.push(t); - nodeStack.push(s); - count = 1; - v = nodeStack.pop(); - adjEntry adj = 0; - while (v != t) - { - if (!stPath(path,v,adj,markedNode,markedEdge,dfn,dfsInEdge,followLowPath)) - { - numbering[v] = count; - count++; - adj = 0; - } - else - { - while (!path.empty()) - nodeStack.push(path.pop()); - } - v = nodeStack.pop(); - } - numbering[t] = count; - return count; -} - - -// Computes the DFN and LOW numbers of a biconnected component -// Uses DFS strategy -void stSearch( - const Graph &G, - node v, - int &count, - NodeArray &low, - NodeArray &dfn, - NodeArray &dfsInEdge, - NodeArray &followLowPath) -{ - dfn[v] = count; - count++; - low[v] = dfn[v]; - - node adj = 0; - edge e; - forall_adj_edges(e,v) - { - adj = e->opposite(v); - - if(!dfn[adj]) // node not visited yet - { - dfsInEdge[adj] = e; - stSearch(G,adj,count,low,dfn,dfsInEdge,followLowPath); - if (low[v] > low[adj]) - { - low[v] = low[adj]; - followLowPath[v] = e; - } - } - else if (low[v] > dfn[adj]) - { - low[v] = dfn[adj]; - followLowPath[v] = e; - } - } -} - - -bool stPath(StackPure &path, - node v, - adjEntry &adj, - NodeArray &markedNode, - EdgeArray &markedEdge, - NodeArray &dfn, - NodeArray &dfsInEdge, - NodeArray &followLowPath) -{ - edge e; - node w; - path.clear(); - - if (!adj) - adj = v->firstAdj(); // no edge has been visited yet - do { - e = adj->theEdge(); - adj = adj->succ(); - if (markedEdge[e]) - continue; - markedEdge[e] = true; - - w = e->opposite(v); - - if (dfsInEdge[w] == e) - { - path.push(v); - while (!markedNode[w]) - { - e = followLowPath[w]; - path.push(w); - markedNode[w] = true; - markedEdge[e] = true; - w = e->opposite(w); - } - return true; - } - else if (dfn[v] < dfn[w]) - { - path.push(v); - while (!markedNode[w]) - { - e = dfsInEdge[w]; - path.push(w); - markedNode[w] = true; - markedEdge[e] = true; - w = e->opposite(w); - } - return true; - } - - }while (adj != 0); - - return false; -} - - -bool testSTnumber(const Graph &G, NodeArray &st_no,int max) -{ - bool foundLow = false; - bool foundHigh = false; - bool it_is = true; - node v; - - forall_nodes(v,G) - { - if (v->degree() == 0) - continue; - - foundHigh = foundLow = 0; - if (st_no[v] == 1) - { - adjEntry adj; - forall_adj(adj,v) - { - if (st_no[adj->theEdge()->opposite(v)] == max) - foundLow = foundHigh = 1; - } - } - - else if (st_no[v] == max) - { - adjEntry adj; - forall_adj(adj,v) - { - if (st_no[adj->theEdge()->opposite(v)] == 1) - foundLow = foundHigh = 1; - } - } - - else - { - adjEntry adj; - forall_adj(adj,v) - { - if (st_no[adj->theEdge()->opposite(v)] < st_no[v]) - foundLow = 1; - else if (st_no[adj->theEdge()->opposite(v)] > st_no[v]) - foundHigh = 1; - } - } - if (!foundLow || !foundHigh) - it_is = 0; - } - return it_is; -} - - -} diff --git a/ext/OGDF/src/cluster/CPlanarEdgeInserter.cpp b/ext/OGDF/src/cluster/CPlanarEdgeInserter.cpp deleted file mode 100644 index f411f1fa5..000000000 --- a/ext/OGDF/src/cluster/CPlanarEdgeInserter.cpp +++ /dev/null @@ -1,853 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Reinsertion of deleted edges in embedded subgraph with - * modeled cluster boundaries. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -namespace ogdf { - - -//Note that edge insertions in cluster (sub)graphs are always performed -//on already embedded graphs with modeled cluster boundaries -void CPlanarEdgeInserter::call( - ClusterPlanRep& CPR, - CombinatorialEmbedding& E, - Graph& G, - const List& origEdges, - List& newEdges) -{ - OGDF_ASSERT(&E.getGraph() == &CPR) - - m_originalGraph = &G; - FaceArray nodeOfFace(E, 0); - //NodeArray&, faceOfNode(m_dualGraph, 0); - EdgeArray arcRightToLeft(CPR, 0);//arc from srcadj face to tgtadj face - EdgeArray arcLeftToRight(CPR, 0);//vice versa - EdgeArray arcTwin(m_dualGraph, 0); - m_arcOrig.init(m_dualGraph, 0); - - constructDualGraph(CPR, E, arcRightToLeft, arcLeftToRight, nodeOfFace, arcTwin); - //the dual graph has a node for each face of E - //and two arcs for every edge of CPR - - m_eStatus.init(m_dualGraph, 0); //1 = usable - - const ClusterGraph& CG = CPR.getClusterGraph(); - - //every face is completely inside a cluster (at least root) - //facenodes are associated with clusters - NodeArray clusterOfFaceNode(m_dualGraph, 0); - deriveFaceCluster(CPR, E, CG, nodeOfFace, clusterOfFaceNode); - - //nodes representing the edge endpoints - node uDummy = m_dualGraph.newNode(); - node vDummy = m_dualGraph.newNode(); - - //for each edge (u,v) to be inserted, we need the path in the - //cluster hierarchy to orient the dual arcs (set the status) - ListConstIterator itE = origEdges.begin(); - while (itE.valid()) - { - //m_eStatus.fill(0); do this manually - //first, we temporarily insert connections from node dummies - //to the faces adjacent to start- and endpoint of the edge - node oSource = (*itE).m_src; - node oTarget = (*itE).m_tgt; - node u = CPR.copy(oSource); - node v = CPR.copy(oTarget); - - List cList; - - //we compute the cluster tree path between oS and oT - CG.commonClusterPath(oSource, oTarget, cList); - - //----------------------------------------------- - //orient the edges according to cluster structure - //save which clusters are on path from u to v - //(do this by setting their edge status) - Array onPath(0,CG.clusterIdCount(), false); - edge eArc; - EdgeArray done(m_dualGraph, false); - forall_edges(eArc, m_dualGraph) - { - if (done[eArc]) continue; //twin already processed - if (arcTwin[eArc] == 0) {done[eArc] = true; continue;} //dummies - - cluster c1 = clusterOfFaceNode[eArc->source()]; - cluster c2 = clusterOfFaceNode[eArc->target()]; - - ListIterator itC = cList.begin(); - - OGDF_ASSERT(itC.valid()) - //run over path and search for c1, c2 - int ind = 1, ind1 = 0, ind2 = 0; - while (itC.valid()) - { - cluster cCheck = (*itC); - - if (cCheck == c1) - { - ind1 = ind; - }//if - if (cCheck == c2) - { - ind2 = ind; - }//if - - itC++; - ind++; - - //stop search, both clusters found - if ((ind1 > 0) && (ind2 > 0)) - itC = cList.rbegin().succ(); - }//while - //set status - if ((ind1 > 0 ) && (ind2 > 0)) - { - if (ind1 == ind2) //bidirectional - { - m_eStatus[eArc] = 1; - m_eStatus[arcTwin[eArc]] = 1; - }//if both - else - if (ind1 < ind2) - { - m_eStatus[eArc] = 1; - m_eStatus[arcTwin[eArc]] = 0; - } - else - { - m_eStatus[eArc] = 0; - m_eStatus[arcTwin[eArc]] = 1; - } - - } - else - { - //remove edge - m_eStatus[eArc] = 0; - m_eStatus[arcTwin[eArc]] = 0; - } - - done[arcTwin[eArc]] = true; - done[eArc] = true; - }//foralledges - - //---------------------------- - //we compute the shortest path - SList crossed; - findShortestPath(E, u, v, uDummy, vDummy, crossed, nodeOfFace); - - //------------------ - //we insert the edge - edge newOR = insertEdge(CPR, E, *itE, nodeOfFace, arcRightToLeft, arcLeftToRight, - arcTwin, clusterOfFaceNode, crossed); - newEdges.pushBack(newOR); - - //--------------------------------------------------------------- - //we updated the dual graph and are ready to insert the next edge - - itE++; - - }//while edges to be inserted - - //delete artificial endpoint representations - m_dualGraph.delNode(vDummy); - m_dualGraph.delNode(uDummy); - -}//call - - -//***************************************************************************** -// protected member functions - -void CPlanarEdgeInserter::constructDualGraph(ClusterPlanRep& CPR, - CombinatorialEmbedding& E, - EdgeArray& arcRightToLeft, - EdgeArray& arcLeftToRight, - FaceArray& nodeOfFace, - //NodeArray&, faceOfNode, - EdgeArray& arcTwin) -{ - //dual graph gets two arcs for each edge (in both directions) - //these arcs get their status (usable for path) depending on - //the edge to be reinserted - - m_dualGraph.clear(); - //faceOfNode.init(m_dualGraph, 0); - - //********************************* - //construct nodes - //corresponding to the graphs faces - face f; - for (f = E.firstFace(); f; f = f->succ()) - { - node v = m_dualGraph.newNode(); - nodeOfFace[f] = v; - //faceOfNode[v] = f; - } - - //********************************* - // - edge e; - forall_edges(e, CPR) - { - edge arc1 = m_dualGraph.newEdge( nodeOfFace[E.rightFace(e->adjTarget())], - nodeOfFace[E.rightFace(e->adjSource())] ); - arcLeftToRight[e] = arc1; - edge arc2 = m_dualGraph.newEdge( nodeOfFace[E.rightFace(e->adjSource())], - nodeOfFace[E.rightFace(e->adjTarget())] ); - arcRightToLeft[e] = arc2; - arcTwin[arc1] = arc2; - arcTwin[arc2] = arc1; - m_arcOrig[arc1] = e->adjSource();//e->adjTarget(); - m_arcOrig[arc2] = e->adjTarget();//e->adjSource(); - } - -}//constructDualGraph - - -//***************************************************************************** -//private functions -void CPlanarEdgeInserter::deriveFaceCluster(ClusterPlanRep& CPR, - CombinatorialEmbedding& E, - const ClusterGraph& CG, - FaceArray& nodeOfFace, - NodeArray& clusterOfFaceNode) -{ - //we need to map indices to clusters - cluster ci; - //cluster numbers don't need to be consecutive - HashArray ClusterOfIndex; - forall_clusters(ci, CG) - { - ClusterOfIndex[ci->index()] = ci; //numbers are unique - }//forallclusters - - face f; - for (f = E.firstFace(); f; f = f->succ()) - { - //we examine all face nodes - //nodes v with original define the cluster in which the face lies - //- it's cluster(original(v)) - //dummy nodes can sit on unbounded many different cluster boundaries - //either one is the parent of another (=> is the searched face) - //or all lie in the same parent face - cluster c1 = 0; - cluster cResult = 0; - adjEntry adjE; - forall_face_adj(adjE, f) - { - node v = adjE->theNode(); - if (CPR.original(v)) - { - cResult = CG.clusterOf(CPR.original(v)); - break; - }//if original - else - { - //a dummy node on a cluster boundary - cluster c = ClusterOfIndex[CPR.ClusterID(v)]; - if (!c1) c1 = c; - else - { - if (c != c1) - { - //either they lie in the same parent or one is the parent - //of the other one - OGDF_ASSERT( (c->parent() == c1->parent()) || (c1 == c->parent()) || (c == c1->parent()) ); - if (c1 == c->parent()) - { - cResult = c1; - break; - }//if - if (c == c1->parent()) - { - cResult = c; - break; - }//if - if (c->parent() == c1->parent()) - { - cResult = c->parent(); - break; - }//if - - }//if - }//else c1 - }//else - }//forall face adjacencies - - OGDF_ASSERT(cResult); - clusterOfFaceNode[nodeOfFace[f]] = cResult; - }//for all faces -}//deriveFaceCluster - - -//--------------------------------------------------------- -// finds a shortest path in the dual graph augmented by s and t (represented -// by sDummy and tDummy); returns list of crossed adjacency entries (corresponding -// to used edges in the dual) in crossed. -// -void CPlanarEdgeInserter::findShortestPath( - const CombinatorialEmbedding &E, - node s, //edge startpoint - node t, //edge endpoint - node sDummy, //representing s in network - node tDummy, //representing t in network - //Graph::EdgeType eType, - SList &crossed, - FaceArray& nodeOfFace) -{ - OGDF_ASSERT(s != t) - - OGDF_ASSERT(sDummy->graphOf() == tDummy->graphOf()) - - OGDF_ASSERT(s->graphOf() == t->graphOf()) - - NodeArray spPred(m_dualGraph,0); - QueuePure queue; - int oldIdCount = m_dualGraph.maxEdgeIndex(); - - //list of current best path - SList bestCrossed; - SList currentCrossed; - //int bestCost = 4*m_dualGraph.numberOfEdges(); //just an upper bound - - adjEntry adjE; - //insert connections to adjacent faces - //be careful with selfloops and bridges (later) - forall_adj(adjE, s) - { - edge eNew = m_dualGraph.newEdge(sDummy, nodeOfFace[E.rightFace(adjE)]); - m_arcOrig[eNew] = adjE; - m_eStatus[eNew] = 1; - }//foralladj - forall_adj(adjE, t) - { - edge eNew = m_dualGraph.newEdge(nodeOfFace[E.rightFace(adjE)], tDummy); - m_arcOrig[eNew] = adjE; - m_eStatus[eNew] = 1; - }//foralladj - - // Start with outgoing edges - adjEntry adj; - forall_adj(adj, sDummy) { - // starting edges of bfs-search are all edges leaving s - //edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]); - //m_primalAdj[eDual] = adj; - queue.append(adj->theEdge()); - } - OGDF_ASSERT(!queue.empty()) - // actual search (using bfs on directed dual) - for( ; ; ) - { - // next candidate edge - edge eCand = queue.pop(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == tDummy) - { - // ... then search is done. - // We should not stop here but calculate the cost and save - // the path if it is an improvement - - // constructed list of used edges (translated to crossed - // adjacency entries in PG) from t back to s (including first - // and last!) - - do { - edge eDual = spPred[v]; - if (m_arcOrig[eDual] != 0) - currentCrossed.pushFront(m_arcOrig[eDual]); - v = eDual->source(); - } while(v != sDummy); - - //break; - //now check if the current solution is cheaper than bestCrossed - //min cross is 1 at this point - bool betterSol = false; - if (bestCrossed.empty()) betterSol = true; - if (!betterSol) - { - //derive actual cost - SListIterator cit = currentCrossed.begin(); - while (cit.valid()) - { - //here we can check different edge costs - - //only temporary: just fill in - bestCrossed.pushBack((*cit)); - cit++; - }//while - }//if not bestcrossed empty: compare - //cop current into best - if (betterSol) - { - SListIterator cit = currentCrossed.begin(); - while (cit.valid()) - { - bestCrossed.pushBack((*cit)); - cit++; - } - } - - break;//only temporary, rebuild path later - }//if target found - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if ((v == e->source()) && - (m_eStatus[e] == 1) ) - { - queue.append(e); - } - } - } - } - - //set result in list parameter - SListIterator cit = bestCrossed.begin(); - while (cit.valid()) - { - crossed.pushBack((*cit)); - cit++; - } - - bestCrossed.clear(); - currentCrossed.clear(); - - //-------------- - //delete dummies - //connections and update graph - List delMe; - forall_adj(adjE,sDummy) - { - delMe.pushBack(adjE->theEdge()); - } - while (!delMe.empty()) - m_dualGraph.delEdge(delMe.popFrontRet()); - - forall_adj(adjE,tDummy) - { - delMe.pushBack(adjE->theEdge()); - } - while (!delMe.empty()) - m_dualGraph.delEdge(delMe.popFrontRet()); -/* - // remove augmented edges again - while ((adj = sDummy->firstAdj()) != 0) - m_dualGraph.delEdge(adj->theEdge()); - - while ((adj = tDummy->firstAdj()) != 0) - m_dualGraph.delEdge(adj->theEdge()); - - - */ - m_dualGraph.resetEdgeIdCount(oldIdCount); -}//shortestPath - -//--------------------------------------------------------- -// inserts edge e according to insertion path crossed. -// updates embeding and dual graph -// -edge CPlanarEdgeInserter::insertEdge( - ClusterPlanRep &CPR, - CombinatorialEmbedding &E, - const NodePair& np, - FaceArray& nodeOfFace, - EdgeArray& arcRightToLeft, - EdgeArray& arcLeftToRight, - EdgeArray& arcTwin, - NodeArray& clusterOfFaceNode, - const SList &crossed) -{ - // remove dual nodes on insertion path - - List faceCluster; //clusters of deleted faces - - //first node double, what about last? - SListConstIterator it; - Stack delS; - it = crossed.begin(); - while(it.valid()) - //for(it = crossed.begin(); it != crossed.rbegin(); ++it) - { - //m_dualGraph.delNode(nodeOfFace[E.rightFace(*it)]); - if (!delS.empty()) - { - if (!(delS.top() == nodeOfFace[E.rightFace(*it)])) - { - delS.push(nodeOfFace[E.rightFace(*it)]); - faceCluster.pushBack(clusterOfFaceNode[nodeOfFace[E.rightFace(*it)]]); - } - } - else - { - delS.push(nodeOfFace[E.rightFace(*it)]); - faceCluster.pushBack(clusterOfFaceNode[nodeOfFace[E.rightFace(*it)]]); - } - it++; - }//while/for - - while (!delS.empty()) - { - m_dualGraph.delNode(delS.pop()); - } - /* - for(it = crossed.begin(); it.valid(); it++) - { - //it != crossed.rbegin(); ++it) { - //only dummy edge - if (!( (CPR.copy(np.m_src) == (*it)->theNode()) - || (CPR.copy(np.m_tgt) == (*it)->theNode()))) - m_dualGraph.delNode(nodeOfFace[E.rightFace(*it)]); - }*/ - - //--------------------- - //update original Graph - - adjEntry orE; - it = crossed.begin(); - edge e = CPR.original((*it)->theEdge()); - OGDF_ASSERT(e) - OGDF_ASSERT((np.m_src == e->source()) || (np.m_src == e->target())) - if (np.m_src == e->source()) orE = e->adjSource(); - else orE = e->adjTarget(); - adjEntry orF; - it = crossed.rbegin(); - e = CPR.original((*it)->theEdge()); - OGDF_ASSERT(e) - OGDF_ASSERT((np.m_tgt == e->source()) || (np.m_tgt == e->target())) - if (np.m_tgt == e->source()) orF = e->adjSource(); - else orF = e->adjTarget(); - //***************** - edge orEdge = m_originalGraph->newEdge(orE, orF);//(np.m_src, np.m_tgt); - //************** - // update primal - CPR.insertEdgePathEmbedded(orEdge,E,crossed); - - - // insert new face nodes into dual - const List &path = CPR.chain(orEdge); - ListConstIterator itEdge; - - OGDF_ASSERT(faceCluster.size() == path.size()) - ListConstIterator itC = faceCluster.begin(); - - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adj = (*itEdge)->adjSource(); - nodeOfFace[E.leftFace (adj)] = m_dualGraph.newNode(); - nodeOfFace[E.rightFace(adj)] = m_dualGraph.newNode(); - clusterOfFaceNode[nodeOfFace[E.leftFace (adj)]] = (*itC); - clusterOfFaceNode[nodeOfFace[E.rightFace (adj)]] = (*itC); - itC++; - - } - - //***************************** - //update network for both faces - - // insert new edges into dual - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adjSrc = (*itEdge)->adjSource(); - face f = E.rightFace(adjSrc); // face to the right of adj in loop - node vRight = nodeOfFace[f]; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - node vLeft = nodeOfFace[E.leftFace(adj)]; - - edge eLR = m_dualGraph.newEdge(vLeft,vRight); - m_arcOrig[eLR] = adj; - - edge eRL = m_dualGraph.newEdge(vRight,vLeft); - m_arcOrig[eRL] = adj->twin(); - - arcTwin[eLR] = eRL; - arcTwin[eRL] = eLR; - - //now check if edge can be used - setArcStatus(eLR, np.m_src, np.m_tgt, CPR.getClusterGraph(), - clusterOfFaceNode, arcTwin); - - if (adj == adj->theEdge()->adjSource()) - { - arcLeftToRight[adj->theEdge()] = eLR; - arcRightToLeft[adj->theEdge()] = eRL; - //m_arcOrig[eLR] = e->adjTarget(); - //m_arcOrig[eRL] = e->adjSource(); - } - else - { - arcLeftToRight[adj->theEdge()] = eRL; - arcRightToLeft[adj->theEdge()] = eLR; - //m_arcOrig[eRL] = e->adjTarget(); - //m_arcOrig[eLR] = e->adjSource(); - } - - } - while((adj = adj->faceCycleSucc()) != adj1); - - // the other face adjacent to *itEdge ... - f = E.rightFace(adjSrc->twin()); - vRight = nodeOfFace[f]; - - adj1 = f->firstAdj(); - adj = adj1; - do { - node vLeft = nodeOfFace[E.leftFace(adj)]; - - edge eLR = m_dualGraph.newEdge(vLeft,vRight); - m_arcOrig[eLR] = adj; - - edge eRL = m_dualGraph.newEdge(vRight,vLeft); - m_arcOrig[eRL] = adj->twin(); - - arcTwin[eLR] = eRL; - arcTwin[eRL] = eLR; - - if (adj == adj->theEdge()->adjSource()) - { - arcLeftToRight[adj->theEdge()] = eLR; - arcRightToLeft[adj->theEdge()] = eRL; - //m_arcOrig[eLR] = e->adjTarget(); - //m_arcOrig[eRL] = e->adjSource(); - } - else - { - arcLeftToRight[adj->theEdge()] = eRL; - arcRightToLeft[adj->theEdge()] = eLR; - //m_arcOrig[eRL] = e->adjTarget(); - //m_arcOrig[eLR] = e->adjSource(); - } - - } - while((adj = adj->faceCycleSucc()) != adj1); - } - return orEdge; -}//insertEdge - - -//sets status for new arc and twin -//uses dual arc, original nodes of edge to be inserted, ClusterGraph -void CPlanarEdgeInserter::setArcStatus( - edge eArc, - node oSrc, - node oTgt, - const ClusterGraph& CG, - NodeArray& clusterOfFaceNode, - EdgeArray& arcTwin) -{ - cluster c1 = clusterOfFaceNode[eArc->source()]; - cluster c2 = clusterOfFaceNode[eArc->target()]; - //cout<< "Searching for clusters " << c1 << " and " << c2 << "\n"; - List cList; - - //we compute the cluster tree path between oS and oT - CG.commonClusterPath(oSrc, oTgt, cList); - ListIterator itC = cList.begin(); - OGDF_ASSERT(itC.valid()) - //run over path and search for c1, c2 - int ind = 0, ind1 = 0, ind2 = 0; - while (itC.valid()) - { - cluster cCheck = (*itC); - //cout << "Checking " << cCheck << "\n" << flush; - - if (cCheck == c1) - { - ind1 = ind; - //cout << "Found c1 " << cCheck << " at number "<< ind << "\n" << flush; - }//if - if (cCheck == c2) - { - ind2 = ind; - //cout << "Found c2 " << cCheck << " at number "<< ind << "\n" << flush; - }//if - - itC++; - ind++; - - //stop search, both clusters found - if ((ind1 > 0) && (ind2 > 0)) - itC = cList.rbegin().succ(); - }//while - - //********** - //set status - OGDF_ASSERT(arcTwin[eArc]) - if ((ind1 > 0 ) && (ind2 > 0)) - { - if (ind1 == ind2) //bidirectional - { - m_eStatus[eArc] = 1; - m_eStatus[arcTwin[eArc]] = 1; - }//if both - else - if (ind1 < ind2) - { - m_eStatus[eArc] = 1; - m_eStatus[arcTwin[eArc]] = 0; - } - else - { - m_eStatus[eArc] = 0; - m_eStatus[arcTwin[eArc]] = 1; - } - - }//if - else - { - //remove edge - m_eStatus[eArc] = 0; - m_eStatus[arcTwin[eArc]] = 0; - }//else -}//setArcStatus - - -//************************************ -//improve the insertion result by heuristics -//TODO -void CPlanarEdgeInserter::postProcess() -{ - switch (m_ppType) - { - case ppRemoveReinsert: - - break; - default: - break; - }//switch -}//postprocess - -//***************************************************************************** -//file output - -void CPlanarEdgeInserter::writeDual(const char *fileName) -{ - Layout drawing(m_dualGraph); - ofstream os(fileName); - writeGML(os,drawing); -} - - -void CPlanarEdgeInserter::writeGML(ostream &os, const Layout &drawing) -{ - const Graph &G = m_dualGraph; - - NodeArray id(m_dualGraph); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::CPlanarEdgeInserter::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - os << " label \"" << v->index() << "\"\n"; - - os << " graphics [\n"; - os << " x " << drawing.x(v) << "\n"; - os << " y " << drawing.y(v) << "\n"; - os << " w " << 10.0 << "\n"; - os << " h " << 10.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - edge e; - forall_edges(e,G) - { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - os << " arrow \"last\"\n"; - - if (m_eStatus[e] > 0) - os << " fill \"#FF0000\"\n"; - else - os << " fill \"#0000FF\"\n"; - os << " width 3.0\n"; - - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/cluster/CPlanarSubCLusteredST.cpp b/ext/OGDF/src/cluster/CPlanarSubCLusteredST.cpp deleted file mode 100644 index c314ef38c..000000000 --- a/ext/OGDF/src/cluster/CPlanarSubCLusteredST.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class CPlanarSubClusteredST. - * Computes a (c-connected) spanning tree of a c-connected graph. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - #include - -#include -#include - -//debug -#include - -namespace ogdf { - -void CPlanarSubClusteredST::initialize(const ClusterGraph& CG) -{ - //initialize "call-global" info arrays - m_allocCluster.init(CG.getGraph(), 0); - //edge status - //m_edgeStatus.init(CG.getGraph(), 0); - //edge to rep edge - m_repEdge.init(CG.getGraph(), 0); - //nodes and clusters to rep nodes - m_cRepNode.init(CG, 0); - m_vRepNode.init(CG.getGraph(), 0); -} - -void CPlanarSubClusteredST::call(const ClusterGraph &CG, EdgeArray& inST) -{ - initialize(CG); - inST.fill(false); - - //representationsgraphs for every cluster, on clustergraph - ClusterArray l_clusterRepGraph(CG, 0); - computeRepresentationGraphs(CG, l_clusterRepGraph); - - //now we compute the spanning trees on the representation graphs - //we should save the selection info on the original edge - //are statically on the repgraphedges (we only have edge -> repedge - //information) but - ClusterArray< EdgeArray > l_inTree(CG); - - cluster c; - forall_clusters(c, CG) - { - l_inTree[c].init(*l_clusterRepGraph[c], false); - //compute STs - NodeArray visited(*l_clusterRepGraph[c], false); - dfsBuildSpanningTree(l_clusterRepGraph[c]->firstNode(), - l_inTree[c], - visited); - }//forallclusters - - OGDF_ASSERT(isConnected(CG.getGraph())); - - //compute the subclustered graph by constructing a spanning tree - //using only the representation edges used in STs on the repgraphs - NodeArray visited(CG.getGraph(), false); - - dfsBuildOriginalST(CG.getGraph().firstNode(), - l_inTree, - inST, - visited); - - //unregister the edgearrays to avoid destructor failure after - //representation graph deletion - forall_clusters(c, CG) - { - l_inTree[c].init(); - } - - deleteRepresentationGraphs(CG, l_clusterRepGraph); -}//call - -void CPlanarSubClusteredST::call(const ClusterGraph& CG, - EdgeArray& inST, - EdgeArray& weight) -{ - initialize(CG); - - //representationsgraphs for every cluster, on clustergraph - ClusterArray l_clusterRepGraph(CG, 0); - computeRepresentationGraphs(CG, l_clusterRepGraph); - - //Now we compute the spanning trees on the representation graphs - //are statically on the repgraphedges (we only have edge -> repedge - //information) - ClusterArray< EdgeArray > l_inTree(CG); - //Weight of the representation edges - ClusterArray< EdgeArray > l_repWeight(CG); - //Copy the weight - cluster c; - edge e; - forall_clusters(c, CG) - { - l_repWeight[c].init(*l_clusterRepGraph[c], 0.0); - } - forall_edges(e, CG.getGraph()) - { - l_repWeight[m_allocCluster[e]][m_repEdge[e]] = weight[e]; - } - - forall_clusters(c, CG) - { - l_inTree[c].init(*l_clusterRepGraph[c], false); - //compute STs - computeMinST(*l_clusterRepGraph[c], l_repWeight[c], - l_inTree[c]); - }//forallclusters - - OGDF_ASSERT(isConnected(CG.getGraph())); - - //Compute the subclustered graph - forall_edges(e, CG.getGraph()) - { - if (l_inTree[m_allocCluster[e]][m_repEdge[e]]) - inST[e] = true; - else inST[e] = false; - } -#ifdef OGDF_DEBUG - GraphCopy cg(CG.getGraph()); - forall_edges(e, CG.getGraph()) - { - if (!inST[e]) - cg.delCopy(cg.copy(e)); - } - OGDF_ASSERT(isConnected(cg)); - OGDF_ASSERT(cg.numberOfEdges() == cg.numberOfNodes()-1) - -#endif - //unregister the edgearrays to avoid destructor failure after - //representation graph deletion - forall_clusters(c, CG) - { - l_inTree[c].init(); - l_repWeight[c].init(); - } - - deleteRepresentationGraphs(CG, l_clusterRepGraph); -}//call - -//spanning tree on input graph setting edge status and using -//repgraph spanning tree information -void CPlanarSubClusteredST::dfsBuildOriginalST(node v, - ClusterArray< EdgeArray > &treeEdges, //edges in repgraph - EdgeArray& inST, //original edges - NodeArray &visited) -{ - - visited[v] = true; - - edge e; - forall_adj_edges(e,v) - { - //no selfloops - node w = e->opposite(v); - if (w == v) continue; - //only repgraph ST edges are allowed - //we should save the common cluster at the first computation above, - //otherwise running time m*m*c - //cluster c1, c2; - cluster allocCluster = m_allocCluster[e]; - - OGDF_ASSERT(allocCluster != 0); - - if (! treeEdges[allocCluster][m_repEdge[e]]) continue; - - //(this part is always connected in original!) - - if(!visited[w]) { - //treeEdges[e] = true; - //m_edgeStatus[e] |= 1; //e is in ST - inST[e] = true; - dfsBuildOriginalST(w, treeEdges, inST, visited); - } - } -} - -//we should later provide a minimum st to allow weights on edges -void CPlanarSubClusteredST::dfsBuildSpanningTree( - node v, - EdgeArray &treeEdges, - NodeArray &visited) -{ - OGDF_ASSERT(isConnected(*(v->graphOf()))); - visited[v] = true; - - edge e; - forall_adj_edges(e,v) - { - node w = e->opposite(v); - if(w == v) continue; - - if(!visited[w]) { - treeEdges[e] = true; - // m_genDebug++; //debugonly - dfsBuildSpanningTree(w,treeEdges,visited); - } - } -} - - -}//end namespace ogdf diff --git a/ext/OGDF/src/cluster/CPlanarSubClusteredGraph.cpp b/ext/OGDF/src/cluster/CPlanarSubClusteredGraph.cpp deleted file mode 100644 index 18aa83fd3..000000000 --- a/ext/OGDF/src/cluster/CPlanarSubClusteredGraph.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class CPlanarSubClusteredGraph. - * Constructs a c-planar subclustered graph of the input on - * base of a spanning tree. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - - -namespace ogdf { - -//precondition: graph is c-connected -void CPlanarSubClusteredGraph::call(const ClusterGraph &CG, - EdgeArray& inSub) //original edges in subgraph? - -{ - List leftOver;//original edges not in subgraph - call(CG, inSub, leftOver); - -}//call -//precondition: graph is c-connected -void CPlanarSubClusteredGraph::call(const ClusterGraph &CGO, - EdgeArray& inSub, //original edges in subgraph? - List& leftOver)//original edges not in subgraph -{ - EdgeArray weightDummy; - call(CGO, inSub, leftOver, weightDummy); -} - -void CPlanarSubClusteredGraph::call(const ClusterGraph &CGO, - EdgeArray& inSub, //original edges in subgraph? - List& leftOver, //original edges not in subgraph - EdgeArray& edgeWeight) //prefer lightweight edges -{ - leftOver.clear(); - - //we compute a c-planar subclustered graph by calling - //CPlanarSubClusteredST and then perform reinsertion on - //a copy of the computed subclustered graph - //initialize "call-global" info arrays - //edge status - const Graph& origG = CGO.getGraph(); - m_edgeStatus.init(origG, 0); - - CPlanarSubClusteredST CPST; - if (edgeWeight.valid()) - CPST.call(CGO, inSub, edgeWeight); - else - CPST.call(CGO, inSub); - - //now construct the copy - //we should create a clusterGraph copy function that - //builds a clustergraph upon a subgraph of the - //original graph, preliminarily use fullcopy and delete edges - - ClusterArray clusterCopy(CGO); - NodeArray nodeCopy(origG); - EdgeArray edgeCopy(origG); - Graph testG; - ClusterGraph CG(CGO, testG, clusterCopy, nodeCopy, edgeCopy); - - CconnectClusterPlanar CCCP; - - //------------------------------------- - //perform reinsertion of leftover edges - //fill list of uninserted edges - - EdgeArray visited(origG,false); - - //delete the non-ST edges - edge e; - forall_edges(e, origG) - { - if (!inSub[e]) - { - leftOver.pushBack(e); //original edges - testG.delEdge(edgeCopy[e]); - }//if - }//foralledges - - //todo: cope with preferred edges - //simple reinsertion strategy: just iterate over list and test - ListIterator itE = leftOver.begin(); - while (itE.valid()) - { - //testG=CG.getGraph() - edge newCopy = testG.newEdge(nodeCopy[(*itE)->source()], - nodeCopy[(*itE)->target()]); - edgeCopy[*itE] = newCopy; - - bool cplanar = CCCP.call(CG); - - - if (!cplanar) - { - testG.delEdge(newCopy); - itE++; - }//if - else - { - ListIterator itDel = itE; - itE++; - leftOver.del(itDel); - } - }//while - - /* - ListConstIterator it; - for(it = preferedEdges.begin(); it.valid(); ++it) - { - edge eG = *it; - visited[eG] = true; - - edge eH = testG.newEdge(toTestG[eG->source()],toTestG[eG->target()]); - - if (preferedImplyPlanar == false && isPlanar(H) == false) { - testG.delEdge(eH); - delEdges.pushBack(eG); - } - } - */ - - -}//call - -}//end namespace ogdf diff --git a/ext/OGDF/src/cluster/CconnectClusterPlanar.cpp b/ext/OGDF/src/cluster/CconnectClusterPlanar.cpp deleted file mode 100644 index e812571d8..000000000 --- a/ext/OGDF/src/cluster/CconnectClusterPlanar.cpp +++ /dev/null @@ -1,737 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of cluster planarity tests and cluster - * planar embedding for c-connected clustered graphs. Based on - * the algorithm by Cohen, Feng and Eades which uses PQ-trees. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - -namespace ogdf { - -// Constructor -CconnectClusterPlanar::CconnectClusterPlanar() -{ - ogdf::strcpy(errorCode,124,"\0"); - m_errorCode = none; -} - -// Destructor -CconnectClusterPlanar::~CconnectClusterPlanar() -{ -} - -// Tests if a ClusterGraph is C-planar -// Specifies reason for non planarity -bool CconnectClusterPlanar::call(ClusterGraph &C, char (&code)[124]) -{ - bool cPlanar = call(C); - strcpy(code,124,errorCode); - return cPlanar; -} - -// Tests if a ClusterGraph is C-planar -bool CconnectClusterPlanar::call(ClusterGraph &C) -{ - Graph G; - ClusterGraph Cp(C,G); - OGDF_ASSERT(Cp.consistencyCheck()); - - - m_clusterPQTree.init(Cp,0); - - bool cPlanar = preProcess(Cp,G); - - m_parallelEdges.init(); - m_isParallel.init(); - m_clusterPQTree.init(); - - return cPlanar; -} - - - -// Tests if a ClusterGraph is C-planar -bool CconnectClusterPlanar::call(const ClusterGraph &C) -{ - Graph G; - ClusterGraph Cp(C,G); - OGDF_ASSERT(Cp.consistencyCheck()); - OGDF_ASSERT(&G == &(Graph&) Cp); - - m_clusterPQTree.init(Cp,0); - - - bool cPlanar = preProcess(Cp,G); - - m_parallelEdges.init(); - m_isParallel.init(); - m_clusterPQTree.init(); - - return cPlanar; -} - - - -// -// CallTree: -// -// call(ClusterGraph &C) -// -// preProcess(ClusterGraph &C,Graph &G) -// -// planarityTest(ClusterGraph &C,cluster &act,Graph &G) -// -// foreach ChildCluster -// planarityTest(ClusterGraph &C,cluster &act,Graph &G) -// -// preparation(Graph &G,cluster &cl) -// -// foreach biconnected Component -// doTest(Graph &G,NodeArray &numbering,cluster &cl) -// - - - - - - -bool CconnectClusterPlanar::preProcess(ClusterGraph &C,Graph &G) -{ - if (!isCConnected(C)) - { - ogdf::sprintf(errorCode,124,"Graph is not C-connected \n"); - m_errorCode = nonCConnected; - return false; - } - - if (!isPlanar(C)) - { - ogdf::sprintf(errorCode,124,"Graph is not planar\n"); - m_errorCode = nonPlanar; - return false; - } - - cluster c; - - SListPure selfLoops; - makeLoopFree(G,selfLoops); - - c = C.rootCluster(); - - bool cPlanar = planarityTest(C,c,G); - - return cPlanar; -} - - - -// Recursive call for testing c-planarity of the clustered graph -// that is induced by cluster act -bool CconnectClusterPlanar::planarityTest( - ClusterGraph &C, - cluster &act, - Graph &G) -{ - // Test children first - ListConstIterator it; - for (it = act->cBegin(); it.valid();) - { - ListConstIterator succ = it.succ(); - cluster next = (*it); - if (!planarityTest(C,next,G)) - return false; - it = succ; - } - - // Get induced subgraph of cluster act and test it for planarity - - List subGraphNodes; - ListIterator its; - for (its = act->nBegin(); its.valid(); its++) - subGraphNodes.pushBack(*its); - - Graph subGraph; - NodeArray table; - inducedSubGraph(G,subGraphNodes.begin(),subGraph,table); - - - // Introduce super sink and add edges corresponding - // to outgoing edges of the cluster - - node superSink = subGraph.newNode(); - EdgeArray outgoingTable(subGraph,0); - - - - for (its = act->nBegin(); its.valid(); its++) - { - node w = (*its); - adjEntry adj = w->firstAdj(); - forall_adj(adj,w) - { - edge e = adj->theEdge(); - edge cor = 0; - if (table[e->source()] == 0) // edge is connected to a node outside the cluster - { - cor = subGraph.newEdge(table[e->target()],superSink); - outgoingTable[cor] = e->source(); - } - else if (table[e->target()] == 0) // dito - { - cor = subGraph.newEdge(table[e->source()],superSink); - outgoingTable[cor] = e->target(); - } - - // else edge connects two nodes of the cluster - } - } - if (superSink->degree() == 0) // root cluster is not connected to outside clusters - { - subGraph.delNode(superSink); - superSink = 0; - } - - - bool cPlanar = preparation(subGraph,act,superSink); - - - if (cPlanar && act != C.rootCluster()) - { - // Remove induced subgraph and the cluster act. - // Replace it by a wheel graph - while (!subGraphNodes.empty()) - { - node w = subGraphNodes.popFrontRet(); -// C.unassignNode(w); - G.delNode(w); - } - - cluster parent = act->parent(); - - if (superSink && m_clusterPQTree[act]) - constructWheelGraph(C,G,parent,m_clusterPQTree[act],outgoingTable); - - C.delCluster(act); - if (m_clusterPQTree[act] != 0) // if query necessary for clusters with just one child - { - m_clusterPQTree[act]->emptyAllPertinentNodes(); - delete m_clusterPQTree[act]; - } - - } - else if (!cPlanar) - { - ogdf::sprintf(errorCode,124,"Graph is not planar at cluster %d.\n",act->index()); - m_errorCode = nonCPlanar; - }//if not cplanar - - return cPlanar; - -} - - - - -void CconnectClusterPlanar::constructWheelGraph(ClusterGraph &C, - Graph &G, - cluster &parent, - PlanarPQTree* T, - EdgeArray &outgoingTable) -{ - - const PQNode* root = T->root(); - const PQNode* checkNode = 0; - - Queue*> treeNodes; - treeNodes.append(root); - - node correspond = G.newNode(); // Corresponds to the root node. - // root node is either a leaf or a P-node - C.reassignNode(correspond,parent); - - Queue graphNodes; - graphNodes.append(correspond); - - node hub; - node next = 0; - node pre; - node newNode; // corresponds to anchor of a hub or a cut node - - - - while (!treeNodes.empty()) - { - checkNode = treeNodes.pop(); - correspond = graphNodes.pop(); - - PQNode* firstSon = 0; - PQNode* nextSon = 0; - PQNode* oldSib = 0; - PQNode* holdSib = 0; - - - if (checkNode->type() == PQNodeRoot::PNode) - { - // correspond is a cut node - - OGDF_ASSERT(checkNode->referenceChild()) - firstSon = checkNode->referenceChild(); - - if (firstSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(firstSon); - newNode = G.newNode(); - C.reassignNode(newNode,parent); - graphNodes.append(newNode); - G.newEdge(correspond,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) firstSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - G.newEdge(correspond,outgoingTable[f]); - delete leaf->getKey(); - } - - nextSon = firstSon->getNextSib(oldSib); - oldSib = firstSon; - pre = next; - while (nextSon && nextSon != firstSon) - { - if (nextSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(nextSon); - newNode = G.newNode(); // new node corresponding to anchor - // or cutnode - C.reassignNode(newNode,parent); - graphNodes.append(newNode); - G.newEdge(correspond,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) nextSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - G.newEdge(correspond,outgoingTable[f]); - delete leaf->getKey(); - } - holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - // correspond is the anchor of a hub - OGDF_ASSERT(checkNode->getEndmost(PQNodeRoot::LEFT)) - firstSon = checkNode->getEndmost(PQNodeRoot::LEFT); - - hub = G.newNode(); - C.reassignNode(hub,parent); - G.newEdge(hub,correspond); // link anchor and hub - next = G.newNode(); // for first son - C.reassignNode(next,parent); - G.newEdge(hub,next); - G.newEdge(correspond,next); - - if (firstSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(firstSon); - newNode = G.newNode(); - C.reassignNode(newNode,parent); - graphNodes.append(newNode); - G.newEdge(next,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) firstSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - G.newEdge(next,outgoingTable[f]); - delete leaf->getKey(); - } - - nextSon = firstSon->getNextSib(oldSib); - oldSib = firstSon; - pre = next; - while (nextSon) - { - next = G.newNode(); - C.reassignNode(next,parent); - G.newEdge(hub,next); - G.newEdge(pre,next); - if (nextSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(nextSon); - newNode = G.newNode(); // new node corresponding to anchor - // or cutnode - C.reassignNode(newNode,parent); - graphNodes.append(newNode); - - G.newEdge(next,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) nextSon; - edge f = leaf->getKey()->m_userStructKey; - G.newEdge(next,outgoingTable[f]); - delete leaf->getKey(); - } - holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - pre = next; - - } - G.newEdge(next,correspond); - } - } - - OGDF_ASSERT(C.consistencyCheck()); -} - - - - - -// -// Prepare planarity test for one cluster -// -bool CconnectClusterPlanar::preparation(Graph &G, - cluster &cl, - node superSink) -{ - - node v; - edge e; - int bcIdSuperSink = -1; // ID of biconnected component that contains superSink - // Initialization with -1 necessary for assertion - bool cPlanar = true; - - - NodeArray tableNodes(G,0); - EdgeArray tableEdges(G,0); - NodeArray mark(G,0); - - EdgeArray componentID(G); - - - // Determine Biconnected Components - int bcCount = biconnectedComponents(G,componentID); - - // Determine edges per biconnected component - Array > blockEdges(0,bcCount-1); - forall_edges(e,G) - { - blockEdges[componentID[e]].pushFront(e); - } - - // Determine nodes per biconnected component. - Array > blockNodes(0,bcCount-1); - for (int i = 0; i < bcCount; i++) - { - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - if (!mark[e->source()]) - { - blockNodes[i].pushBack(e->source()); - mark[e->source()] = true; - } - if (!mark[e->target()]) - { - blockNodes[i].pushBack(e->target()); - mark[e->target()] = true; - } - } - if (superSink && mark[superSink]) - { - OGDF_ASSERT(bcIdSuperSink == -1); - bcIdSuperSink = i; - } - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++itn) - { - v = *itn; - if (mark[v]) - mark[v] = false; - else - { - OGDF_ASSERT(mark[v]); // v has been placed two times on the list. - } - } - - } - - - // Perform planarity test for every biconnected component - - if (bcCount == 1) - { - // Compute st-numbering - NodeArray numbering(G,0); - int n; - if (superSink) - n = stNumber(G,numbering,0,superSink); - else - n = stNumber(G,numbering); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(G,numbering,n)) - - - EdgeArray backTableEdges(G,0); - forall_edges(e,G) - backTableEdges[e] = e; - - cPlanar = doTest(G,numbering,cl,superSink,backTableEdges); - } - else - { - for (int i = 0; i < bcCount; i++) - { - #ifdef OGDF_DEBUG - if(int(ogdf::debugLevel)>=int(dlHeavyChecks)){ - cout< itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - { - v = *itn; - node w = C.newNode(); - tableNodes[v] = w; - - #ifdef OGDF_DEBUG - if(int(ogdf::debugLevel)>=int(dlHeavyChecks)){ - cout <<"Original: " << v << " New: " << w<< endl;} - #endif - - } - - NodeArray backTableNodes(C,0); - - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - edge f = C.newEdge(tableNodes[e->source()],tableNodes[e->target()]); - tableEdges[e] = f; - } - - EdgeArray backTableEdges(C,0); - for (it = blockEdges[i].begin(); it.valid(); ++it) - backTableEdges[tableEdges[*it]] = *it; - - // Compute st-numbering - NodeArray numbering(C,0); - int n; - if (bcIdSuperSink == i) - { - n = stNumber(C,numbering,0,tableNodes[superSink]); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(C,numbering,n)) - cPlanar = doTest(C,numbering,cl,tableNodes[superSink],backTableEdges); - } - else - { - n = stNumber(C,numbering); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(C,numbering,n)) - cPlanar = doTest(C,numbering,cl,0,backTableEdges); - } - - if (!cPlanar) - break; - - - - } - - } - - return cPlanar; -} - - -// Performs a planarity test on a biconnected component -// of G. numbering contains an st-numbering of the component. -bool CconnectClusterPlanar::doTest( - Graph &G, - NodeArray &numbering, - cluster &cl, - node superSink, - EdgeArray &edgeTable) -{ - node v; - bool cPlanar = true; - - NodeArray* > > inLeaves(G); - NodeArray* > > outLeaves(G); - Array table(G.numberOfNodes()+1); - - forall_nodes(v,G) - { - edge e; - forall_adj_edges(e,v) - { - if (numbering[e->opposite(v)] > numbering[v]) - //sideeffect: loops are ignored - { - PlanarLeafKey* L = OGDF_NEW PlanarLeafKey(e); - inLeaves[v].pushFront(L); - } - } - table[numbering[v]] = v; - } - - forall_nodes(v,G) - { - SListIterator* > it; - for (it = inLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* L = *it; - outLeaves[L->userStructKey()->opposite(v)].pushFront(L); - } - } - - PlanarPQTree* T = new PlanarPQTree(); - - T->Initialize(inLeaves[table[1]]); - for (int i = 2; i < G.numberOfNodes(); i++) - { - if (T->Reduction(outLeaves[table[i]])) - { - T->ReplaceRoot(inLeaves[table[i]]); - T->emptyAllPertinentNodes(); - - } - else - { - cPlanar = false; - break; - } - } - if (cPlanar && cl && superSink) - { - // Keep the PQTree to construct a wheelgraph - // Replace the edge stored in the keys of T - // by the original edges. - // Necessary, since the edges currently in T - // correspond to a graph that mirrors a biconnected - // component and thus is deallocated - - SListIterator* > it; - int n = G.numberOfNodes(); - - for (it = outLeaves[table[n]].begin(); it.valid(); ++it) - { - PQLeafKey* key = (PQLeafKey*) *it; - key->m_userStructKey = edgeTable[key->m_userStructKey]; - } - - m_clusterPQTree[cl] = T; - - } - else //if (cPlanar) - delete T; - - // Cleanup - forall_nodes(v,G) - { - if (v != superSink || !cPlanar) - { - while (!outLeaves[v].empty()) - { - PlanarLeafKey* L = outLeaves[v].popFrontRet(); - delete L; - } - } - } - - return cPlanar; -} - - - -void CconnectClusterPlanar::prepareParallelEdges(Graph &G) -{ - - edge e; - - // Stores for one reference edge all parallel edges. - m_parallelEdges.init(G); - // Is true for any multiedge, except for the reference edge. - m_isParallel.init(G,false); - getParallelFreeUndirected(G,m_parallelEdges); - m_parallelCount = 0; - forall_edges(e,G) - { - if (!m_parallelEdges[e].empty()) - { - ListIterator it; - for (it = m_parallelEdges[e].begin(); it.valid(); it++) - { - m_isParallel[*it] = true; - m_parallelCount++; - } - } - } -} - - - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/cluster/CconnectClusterPlanarEmbed.cpp b/ext/OGDF/src/cluster/CconnectClusterPlanarEmbed.cpp deleted file mode 100644 index 479a192d7..000000000 --- a/ext/OGDF/src/cluster/CconnectClusterPlanarEmbed.cpp +++ /dev/null @@ -1,2303 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Cluster Planarity tests and Cluster - * Planar embedding for C-connected Cluster Graphs - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -//#include -#include - -#include - -#include -#include -#include - -#include - - -namespace ogdf { - -// Constructor -CconnectClusterPlanarEmbed::CconnectClusterPlanarEmbed() -{ - ogdf::strcpy(errorCode,124,"\0"); - m_errorCode = none; -} - -// Destructor -CconnectClusterPlanarEmbed::~CconnectClusterPlanarEmbed() -{ -} - - -// Tests if a ClusterGraph is c-planar and embedds it. -bool CconnectClusterPlanarEmbed::embed(ClusterGraph &C,Graph &G) -{ - - OGDF_ASSERT(C.consistencyCheck()) - - if (G.numberOfNodes() <= 1) return true; - - // Initialize Node and cluster arrays associated with original graph. - m_instance = &C; - m_nodeTableOrig2Copy.init(G,0); - m_clusterTableOrig2Copy.init(C,0); - m_clusterEmbedding.init(C,0); - m_clusterSubgraph.init(C,0); - m_clusterSubgraphHubs.init(C,0); - m_clusterSubgraphWheelGraph.init(C,0); - m_clusterClusterGraph.init(C,0); - m_clusterNodeTableNew2Orig.init(C,0); - m_clusterOutgoingEdgesAnker.init(C,0); - m_clusterSuperSink.init(C,0); - m_clusterPQContainer.init(C); - m_unsatisfiedCluster.init(C,false); - - // Copy the graph (necessary, since we modify it throughout the planarity test) - Graph Gcopy; - ClusterGraph Ccopy(C,Gcopy,m_clusterTableOrig2Copy,m_nodeTableOrig2Copy); - - // Initialize translation tables for nodes and clusters - m_clusterTableCopy2Orig.init(Ccopy,0); - cluster c; - forall_clusters(c,C) - { - cluster c1 = m_clusterTableOrig2Copy[c]; - m_clusterTableCopy2Orig[c1] = c; - } - m_nodeTableCopy2Orig.init(Gcopy,0); - node v; - forall_nodes(v,G) - { - node w = m_nodeTableOrig2Copy[v]; - m_nodeTableCopy2Orig[w] = v; - } - // Remove empty clusters - SList removeCluster; - forall_clusters(c,Ccopy) - { - if (c->cCount() == 0 && c->nCount() == 0) - removeCluster.pushBack(c); - } - while (!removeCluster.empty()) - { - c = removeCluster.popFrontRet(); - m_unsatisfiedCluster[m_clusterTableCopy2Orig[c]] = true; - cluster parent = c->parent(); - Ccopy.delCluster(c); - if (parent->cCount() == 0 && parent->nCount() == 0) - removeCluster.pushBack(parent); - } - while (Ccopy.rootCluster()->cCount() == 1 && Ccopy.rootCluster()->nCount() == 0) - { - c = (*(Ccopy.rootCluster()->cBegin())); - m_unsatisfiedCluster[m_clusterTableCopy2Orig[c]] = true; - Ccopy.delCluster(c); - } - - OGDF_ASSERT(Ccopy.consistencyCheck()); - - // Initialize node and cluster arrays associated with copied graph. - m_clusterPQTree.init(Ccopy,0); - m_currentHubs.init(Gcopy,false); - m_wheelGraphNodes.init(Gcopy,0); - m_outgoingEdgesAnker.init(Gcopy,0); - - // Planarity test - bool cPlanar = preProcess(Ccopy,Gcopy); - - if (cPlanar) - { - OGDF_ASSERT(Gcopy.representsCombEmbedding()) - //OGDF_ASSERT(Ccopy.consistencyCheck()); - - recursiveEmbed(Ccopy,Gcopy); - OGDF_ASSERT(Ccopy.consistencyCheck()); - - copyEmbedding(Ccopy,Gcopy,C,G); - - C.adjAvailable(true); - - } - else - nonPlanarCleanup(Ccopy,Gcopy); - - - // Cleanup - forall_clusters(c,C) - { - if (m_clusterSubgraph[c] != 0 && c != C.rootCluster()) - delete m_clusterSubgraph[c]; - } - - - // Deinitialize all node and cluster arrays - m_parallelEdges.init(); - m_isParallel.init(); - m_clusterPQTree.init(); - m_clusterEmbedding.init(); - m_clusterSubgraph.init(); - m_clusterSubgraphHubs.init(); - m_clusterSubgraphWheelGraph.init(); - m_clusterClusterGraph.init(); - m_clusterNodeTableNew2Orig.init(); - m_clusterOutgoingEdgesAnker.init(); - m_clusterSuperSink.init(); - m_clusterPQContainer.init(); - - m_clusterTableOrig2Copy.init(); - m_clusterTableCopy2Orig.init(); - m_nodeTableOrig2Copy.init(); - m_nodeTableCopy2Orig.init(); - m_currentHubs.init(); - m_wheelGraphNodes.init(); - m_outgoingEdgesAnker.init(); - - return cPlanar; -} - - - -// Tests if a ClusterGraph is c-planar and embedds it. -// Specifies reason for non planarity -bool CconnectClusterPlanarEmbed::embed(ClusterGraph &C,Graph &G, char (&code)[124]) -{ - - bool cPlanar = embed(C,G); - ogdf::strcpy(code,124,errorCode); - return cPlanar; -} - - - - - -// -// CallTree: -// -// call(ClusterGraph &C) -// -// preProcess(ClusterGraph &C,Graph &G) -// -// planarityTest(ClusterGraph &C,cluster &act,Graph &G) -// -// foreach ChildCluster -// planarityTest(ClusterGraph &C,cluster &act,Graph &G) -// -// preparation(Graph &G,cluster &origCluster) -// -// foreach biconnected Component -// doTest(Graph &G,NodeArray &numbering,cluster &origCluster) -// - - - -/******************************************************************************* - copyEmbedding -********************************************************************************/ - -// Copies the embedding of Ccopy to C - -void CconnectClusterPlanarEmbed::copyEmbedding( - ClusterGraph &Ccopy, - Graph &Gcopy, - ClusterGraph &C, - Graph &G) -{ - - node vCopy; - node v; - cluster c; - OGDF_ASSERT(Gcopy.representsCombEmbedding()) - - OGDF_ASSERT(Ccopy.representsCombEmbedding()) - - AdjEntryArray adjTableCopy2Orig(Gcopy); - AdjEntryArray adjTableOrig2Copy(G); - AdjEntryArray visited(G,false); // For parallel edges - EdgeArray edgeTableCopy2Orig(Gcopy,0); // Translation table for parallel edges - EdgeArray parallelEdge(Gcopy,false); // Marks parallel edges in copy Graph - AdjEntryArray parallelEntryPoint(G,0); // For storing information on parallel - // edges for cluster adjlistst. - AdjEntryArray parallelToBeIgnored(Gcopy,false);// For storing information on parallel - // edges for cluster adjlistst. - - // prepare parallel Edges - prepareParallelEdges(G); - NodeArray > entireEmbedding(G); - - //process over all copy nodes - forall_nodes(vCopy,Gcopy) - { - //get the original node - node wOrig = m_nodeTableCopy2Orig[vCopy]; - - adjEntry vAdj; - - //process over all adjacent copy edges - SList entries; - Gcopy.adjEntries(vCopy,entries); - SListIterator itv; - for (itv = entries.begin(); itv.valid(); itv++) - { - vAdj = *itv; - node vN = vAdj->twinNode(); - node wN = m_nodeTableCopy2Orig[vN]; - m_nodeTableOrig2Copy[wN] = vN; - - adjEntry wAdj; - forall_adj(wAdj,wOrig) - { - - if (edgeTableCopy2Orig[vAdj->theEdge()] != 0 && - m_isParallel[edgeTableCopy2Orig[vAdj->theEdge()]]) - // Break if parallel edge (not a reference edge) that has already been assigned. - break; - if (wAdj->twinNode() == wN - && !visited[wAdj] && !m_isParallel[wAdj->theEdge()]) -// && !m_isParallel[wAdj->theEdge()]) - // Either a non parallel edge or the reference edge of a set of - // parallel edges. - { - adjTableCopy2Orig[vAdj] = wAdj; - adjTableOrig2Copy[wAdj] = vAdj; -// adjTableCopy2Orig[vAdj->twin()] = wAdj->twin(); -// adjTableOrig2Copy[wAdj->twin()] = vAdj->twin(); - edgeTableCopy2Orig[vAdj->theEdge()] = wAdj->theEdge(); - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << "Orig " << wAdj << " " << wAdj->index() << "\t twin " << wAdj->twin()->index() << endl; - cout << "Copy " << vAdj << " " << vAdj->index() << "\t twin " << vAdj->twin()->index() << endl << endl;} - //qDebug ("Visited: %d->%d %d", wAdj->theNode()->index(), - // wAdj->twinNode()->index(), - // wAdj->index()); - #endif - entireEmbedding[wOrig].pushBack(wAdj); // if no parallel edges exist, - // this will be our embedding. -// entireEmbedding[wN].pushFront(wAdj->twin()); - visited[wAdj] = true; // for multi-edges -// visited[wAdj->twin()] = true; // for multi-edges - break; - } - else if (wAdj->twinNode() == wN && !visited[wAdj]) - // A parallel edge that is not the reference edge. - // We need to set the translation table - { - adjTableCopy2Orig[vAdj] = wAdj; - adjTableOrig2Copy[wAdj] = vAdj; - adjTableCopy2Orig[vAdj->twin()] = wAdj->twin(); - adjTableOrig2Copy[wAdj->twin()] = vAdj->twin(); - edgeTableCopy2Orig[vAdj->theEdge()] = wAdj->theEdge(); - visited[wAdj] = true; // So we do not consider parallel edges twice. - visited[wAdj->twin()] = true; // So we do not consider parallel edges twice. - } - - } - } - } - - // Locate all parallel edges - // Sort them within the adjacency lists, - // such that they appear consecutively. - NodeArray > newEntireEmbedding(G); - NodeArray > newEntireEmbeddingCopy(Gcopy); - - if (m_parallelCount > 0) - { - forall_nodes(v,G) - { - SListIterator it; - for(it = entireEmbedding[v].begin();it.valid();it++) - { - edge e = (*it)->theEdge(); - - if (!m_parallelEdges[e].empty()) - { - // This edge is the reference edge - // of a bundle of parallel edges - - ListIterator it; - // If v is source of e, insert the parallel edges - // in the order stored in the list. - if (e->adjSource()->theNode() == v) - { - adjEntry adj = e->adjSource(); - - newEntireEmbedding[v].pushBack(adj); - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]].pushBack(adjTableOrig2Copy[adj]); - - parallelEntryPoint[e->adjSource()] = adj; - parallelToBeIgnored[adjTableOrig2Copy[adj]] = true; - - for (it = m_parallelEdges[e].begin(); it.valid(); it++) - { - edge parallel = (*it); - adjEntry adj = parallel->adjSource()->theNode() == v ? - parallel->adjSource() : parallel->adjTarget(); - parallelToBeIgnored[adjTableOrig2Copy[adj]] = true; - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << adj << " " << adj->index() << "\t twin " << adj->twin()->index() << endl;} - #endif - newEntireEmbedding[v].pushBack(adj); - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]].pushBack(adjTableOrig2Copy[adj]); - } - } - else - // v is target of e, insert the parallel edges - // in the opposite order stored in the list. - // This keeps the embedding. - { - bool first = true; - for (it = m_parallelEdges[e].rbegin(); it.valid(); it--) - { - edge parallel = (*it); - adjEntry adj = parallel->adjSource()->theNode() == v ? - parallel->adjSource() : parallel->adjTarget(); - parallelToBeIgnored[adjTableOrig2Copy[adj]] = true; - - newEntireEmbedding[v].pushBack(adj); - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]].pushBack(adjTableOrig2Copy[adj]); - if (first) - { -// parallelEntryPoint[adjTableOrig2Copy[adj]] = adj; - parallelEntryPoint[e->adjTarget()] = adj; - first = false; - } - } - adjEntry adj = e->adjTarget(); - - newEntireEmbedding[v].pushBack(adj); - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]];//.pushBack(adjTableOrig2Copy[adj]); - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]].pushBack(adjTableOrig2Copy[adj]); - parallelToBeIgnored[adjTableOrig2Copy[adj]] = true; - } - }//if parallel edges - else if (!m_isParallel[e]) - // normal non-multi-edge - { - adjEntry adj = e->adjSource()->theNode() == v? - e->adjSource() : e->adjTarget(); - - newEntireEmbedding[v].pushBack(adj); - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]];//pushBack(adjTableOrig2Copy[adj]); - adjTableOrig2Copy[adj]; - newEntireEmbeddingCopy[m_nodeTableOrig2Copy[v]].pushBack(adjTableOrig2Copy[adj]); - } - // else e is a multi-edge but not the reference edge - } - } - - forall_nodes(v,G) - G.sort(v,newEntireEmbedding[v]); - forall_nodes(v,Gcopy) - Gcopy.sort(v,newEntireEmbeddingCopy[v]); - - } - else - { - forall_nodes(v,G) - G.sort(v,entireEmbedding[v]); - OGDF_ASSERT(G.representsCombEmbedding()) - } - - adjEntry adj; - - OGDF_ASSERT(G.representsCombEmbedding()) - - forall_clusters(c,Ccopy) - { - SListPure embedding; - - - ListIterator it; - - for(it = c->firstAdj();it.valid(); it++) - { - adj = *it; - edge e = adj->theEdge(); - - if (!m_parallelEdges[edgeTableCopy2Orig[e]].empty()) - { - adjEntry padj = parallelEntryPoint[adjTableCopy2Orig[adj]]; - - bool lastMultiEdgeFound = false; - node target = padj->twinNode(); - - while (!lastMultiEdgeFound) // Scan the parallel edges of e - // in the original graph along the embedded - // adjacency list of its target - { - if (padj->twinNode() == target) // is a multi edge - { - embedding.pushBack(padj); - padj = padj->succ(); - if (!padj) break; //only multi edges - } - else // Not a multi Edge - break; - } - } - else if (!parallelToBeIgnored[adj]) - { - embedding.pushBack(adjTableCopy2Orig[adj]); - } - } - - C.makeAdjEntries(m_clusterTableCopy2Orig[c],embedding.begin()); - } - -} - -/******************************************************************************* - nonPlanarCleanup -********************************************************************************/ - - -// Deallocates all memory, if the cluster graph is not cluster planar - -void CconnectClusterPlanarEmbed::nonPlanarCleanup(ClusterGraph &Ccopy,Graph &Gcopy) -{ - - while (!m_callStack.empty()) - { - cluster act = m_callStack.pop(); - - Graph *subGraph = m_clusterSubgraph[act]; - - node superSink = m_clusterPQContainer[act].m_superSink; - if (superSink) - { - edge e; - forall_edges(e,*subGraph) - { - if (e->source() != superSink && e->target() != superSink) - if ((*m_clusterOutgoingEdgesAnker[act])[e]) - delete (*m_clusterOutgoingEdgesAnker[act])[e]; - } - } - - if (m_clusterEmbedding[act] != 0) - delete m_clusterEmbedding[act]; - delete m_clusterSubgraphHubs[act]; - delete m_clusterSubgraphWheelGraph[act]; - delete m_clusterNodeTableNew2Orig[act]; - delete m_clusterOutgoingEdgesAnker[act]; - - m_clusterPQContainer[act].Cleanup(); - } - - - edge e; - forall_edges(e,Gcopy) - { - if (m_outgoingEdgesAnker[e]) - delete m_outgoingEdgesAnker[e]; - } -} - - - -/******************************************************************************* - hubControl -********************************************************************************/ - - -// This function is called by recursiveEmbed only. It fixes -// the adjacency lists of the hubs in Gcopy after a cluster has been -// reembedded. - -void CconnectClusterPlanarEmbed::hubControl(Graph &G,NodeArray &hubs) -{ - node hub; - forall_nodes(hub,G) - { - if (hubs[hub]) // hub is a hub - { - node firstNode; - node secNode; - - adjEntry startAdj = hub->firstAdj(); - adjEntry firstAdj = 0; - adjEntry secAdj = 0; - while (firstAdj != startAdj) - { - if (firstAdj == 0) - firstAdj = startAdj; - secAdj = firstAdj->cyclicSucc(); - firstNode = firstAdj->twinNode(); - secNode = secAdj->twinNode(); - - adjEntry cyclicPredOfFirst = firstAdj->twin()->cyclicPred(); - while(cyclicPredOfFirst->twinNode() - != secNode) - { - cyclicPredOfFirst = cyclicPredOfFirst->cyclicPred(); - } - G.moveAdjBefore(cyclicPredOfFirst,firstAdj->twin()); - - - adjEntry cyclicSuccOfSec= secAdj->twin()->cyclicSucc(); - while(cyclicSuccOfSec->twinNode() - != firstNode) - { - cyclicSuccOfSec = cyclicSuccOfSec->cyclicSucc(); - } - G.moveAdjAfter(cyclicSuccOfSec,secAdj->twin()); - - firstAdj = secAdj; - - } - - } - } -} - - - - - - -/******************************************************************************* - recursiveEmbed -********************************************************************************/ - - -// Function computes the cluster planar embedding of a cluster graph -// by recursively reinserting the clusters back into Gcopy and embedding -// their corresponding subgraphs within the planar embedding of Gcopy. - - -void CconnectClusterPlanarEmbed::recursiveEmbed(ClusterGraph &Ccopy,Graph &Gcopy) -{ - - node v; - // Remove root cluster from stack. - // Induced subgraph of root cluster corresponds to Gcopy - cluster root = m_callStack.pop(); - - OGDF_ASSERT(Gcopy.representsCombEmbedding()) - - hubControl(Gcopy,m_currentHubs); - - while (!m_callStack.empty()) - { - - // Cluster act is reinserted into Gcopy. - cluster act = m_callStack.pop(); - if (m_unsatisfiedCluster[act] == true) - continue; - - // subgraph is the graph that replaces the wheelGraph of act in Gcopy - Graph *subGraph = m_clusterSubgraph[act]; - // embedding contains the (partial) embedding of all biconnected components - // that do not have outgoing edges of the cluster act. - NodeArray > *embedding = m_clusterEmbedding[act]; - // For every node of subGraph hubs is true if the node is a hub in subGraph - NodeArray *hubs = m_clusterSubgraphHubs[act]; - // For every node in subGraph wheelGraphNodes stores the corresponding - // cluster, if the node is a node of a wheel graph - NodeArray *wheelGraphNodes= m_clusterSubgraphWheelGraph[act]; - EmbedPQTree *T = m_clusterPQContainer[act].m_T; - EdgeArray*> *outgoingAnker = m_clusterOutgoingEdgesAnker[act]; - - // What else do we have: - // - // 1. In m_wheelGraphNodes we have for every node of Gcopy that - // is a wheel graph node its corresponding cluster. - // Must UPDATE this information after we have replaced the current - // wheel graph by subGraph. - - // Make sure that: - // - // 1. When inserting new Nodes to Gcopy, that correspond to nodes of subGraph - // copy the information on the wheel graphs (stored in wheelGraphNodes) - // 2. When inserting new Nodes to Gcopy, that correspond to nodes of subGraph - // copy the information if it is a hub (stored in hubs) - - - //----------------------------------------// - // Translation tables between the subgraph and - // its corresponding subgraph in Gcopy - AdjEntryArray tableAdjEntrySubGraph2Gcopy(*subGraph); - NodeArray nodeTableGcopy2SubGraph(Gcopy,0); - NodeArray nodeTableSubGraph2Gcopy(*subGraph,0); - - - //----------------------------------------// - // Identify all wheelgraph nodes in Gcopy that correspond to act. - // These nodes have to be removed and replaced by subGraph. - - SList replaceNodes; - forall_nodes(v,Gcopy) - if (m_wheelGraphNodes[v] == act) - replaceNodes.pushBack(v); - - - //----------------------------------------// - // Introduce a new cluster in Gcopy - cluster newCluster = 0; - if (m_unsatisfiedCluster[act->parent()] == true) - newCluster = Ccopy.newCluster(Ccopy.rootCluster()); - else - newCluster = Ccopy.newCluster(m_clusterTableOrig2Copy[act->parent()]); - m_clusterTableOrig2Copy[act] = newCluster; - m_clusterTableCopy2Orig[newCluster] = act; - - - //----------------------------------------// - // Insert for every node of subGraph - // a new node in Gcopy. - forall_nodes(v,*subGraph) - { - if (v != m_clusterSuperSink[act]) - { - node newNode = Gcopy.newNode(); - Ccopy.reassignNode(newNode,newCluster); - nodeTableGcopy2SubGraph[newNode] = v; - nodeTableSubGraph2Gcopy[v] = newNode; - - // Copy information from subGraph nodes to new Gcopy nodes. - if ((*wheelGraphNodes)[v]) - m_wheelGraphNodes[newNode] = (*wheelGraphNodes)[v]; - if ((*hubs)[v]) - m_currentHubs[newNode] = (*hubs)[v]; - m_nodeTableCopy2Orig[newNode] = (*m_clusterNodeTableNew2Orig[act])[v]; - } - } - - - //----------------------------------------// - // Insert the edges between the new nodes - EdgeArray visited((*subGraph),false); - forall_nodes(v,*subGraph) - { - node newV = nodeTableSubGraph2Gcopy[v]; - edge e; - - if (v != m_clusterSuperSink[act]) - { - forall_adj_edges (e,v) - { - node w = e->opposite(v); - - if (w != m_clusterSuperSink[act] && !visited[e]) - { - node newW = nodeTableSubGraph2Gcopy[w]; - edge eNew = Gcopy.newEdge(newV,newW); - if ((e->adjSource()->theNode() == v && - eNew->adjSource()->theNode() == nodeTableSubGraph2Gcopy[v]) || - (e->adjTarget()->theNode() == v && - eNew->adjTarget()->theNode() == nodeTableSubGraph2Gcopy[v])) - { - tableAdjEntrySubGraph2Gcopy[e->adjSource()] = eNew->adjSource(); - tableAdjEntrySubGraph2Gcopy[e->adjTarget()] = eNew->adjTarget(); - } - else - { - tableAdjEntrySubGraph2Gcopy[e->adjTarget()] = eNew->adjSource(); - tableAdjEntrySubGraph2Gcopy[e->adjSource()] = eNew->adjTarget(); - } - - // Copy the information of outgoing edges - // to the new edge. - m_outgoingEdgesAnker[eNew] = (*outgoingAnker)[e]; - visited[e] = true; - } - } - } - }//forallnodes - //edge borderEdge = m_clusterPQContainer[act].m_stEdgeLeaf->userStructKey(); - - - - //----------------------------------------// - - edge startEdge = 0; // first outgoing edge of cluster - // start embedding here - SListIterator its; - for (its = replaceNodes.begin(); its.valid(); its++) - { - v = (*its); - // Assert that v is a node of the wheelgraph belonging - // to cluster child. - OGDF_ASSERT(m_wheelGraphNodes[v] == act) - - // Traverse all edges adajcent to v to locate an outgoing edge. - edge e; - forall_adj_edges(e,v) - { - node w = e->opposite(v); - if (act != m_wheelGraphNodes[w]) - { - // Outgoing Edge of wheelgraph detected. - startEdge = e; - its = replaceNodes.rbegin(); // break outer for loop - break; - } - } - } - - - // Stack outgoing edges according to embedding - - // Assert that there is an outgoing edge of the cluster - OGDF_ASSERT(startEdge); - List outgoingEdges; - outgoingEdges.pushBack(startEdge); - - adjEntry adj = startEdge->adjSource()->theNode() == v ? - startEdge->adjSource() : startEdge->adjTarget(); - edge currentEdge = 0; - while (currentEdge != startEdge) - { - adjEntry newAdj = adj->cyclicSucc(); - newAdj = newAdj->twin(); - currentEdge = newAdj->theEdge(); - if (act != m_wheelGraphNodes[newAdj->theNode()]) - { - // Outgoing Edge of wheelgraph detected. - if (currentEdge != startEdge) - outgoingEdges.pushBack(currentEdge); - adj = adj->cyclicSucc(); - } - else - adj = newAdj; - - } - - //----------------------------------------// - // Insert the edges between the new nodes and - // the existing nodes of Gcopy. - - PlanarLeafKey* leftKey = 0; - PlanarLeafKey* rightKey = 0; - edge firstEdge = 0; - node t = m_clusterPQContainer[act].m_superSink; - SListPure*> allOutgoing; - - #ifdef OGDF_DEBUG - EdgeArray debugTableOutgoingSubGraph2Gcopy(*subGraph,0); - #endif - - ListIterator ite; - for (ite = outgoingEdges.begin(); ite.valid();) - { - edge e = (*ite); - ListIterator succ = ite.succ(); - - - // Assert that stack for anker nodes is not empty - OGDF_ASSERT(!m_outgoingEdgesAnker[e]->empty()) - - node nonWheelNode; // The node of Gcopy that does not - // correspond to cluster act - if (act != m_wheelGraphNodes[e->source()]) - nonWheelNode = e->source(); - else { - OGDF_ASSERT(act != m_wheelGraphNodes[e->target()]) - nonWheelNode = e->target(); - } - - edge subGraphEdge = m_outgoingEdgesAnker[e]->pop(); - node subGraphNode = subGraphEdge->opposite(t); - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - debugTableOutgoingSubGraph2Gcopy[subGraphEdge] = e;} - #endif - - rightKey = (*m_clusterPQContainer[act].m_edge2Key)[subGraphEdge]; - allOutgoing.pushBack(rightKey); - if (leftKey) - { - SListPure*> pair; - pair.pushBack(leftKey); - pair.pushBack(rightKey); -#ifdef OGDF_DEBUG - bool planar = -#endif - T->Reduction(pair); - // Assert that the Reduction did not fail - OGDF_ASSERT(planar) - T->PQTree::emptyAllPertinentNodes(); - } - else - firstEdge = subGraphEdge; - - leftKey = rightKey; - - // Assert that the anker node is a node - // of the subgraph. - OGDF_ASSERT(subGraphNode->graphOf() == subGraph) - - // Redirect the edge to the new node. - // This keeps the embedding of Gcopy. - if (nonWheelNode == e->source()) - { - Gcopy.moveTarget(e, nodeTableSubGraph2Gcopy[subGraphNode]); - - if (subGraphEdge->source() == subGraphNode) - { - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjSource()] = e->adjTarget(); - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjTarget()] = e->adjSource(); - } - else - { - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjSource()] = e->adjSource(); - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjTarget()] = e->adjTarget(); - } - } - else - { - Gcopy.moveSource(e,nodeTableSubGraph2Gcopy[subGraphNode]); - - if (subGraphEdge->target() == subGraphNode) - { - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjSource()] = e->adjTarget(); - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjTarget()] = e->adjSource(); - } - else - { - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjSource()] = e->adjSource(); - tableAdjEntrySubGraph2Gcopy[subGraphEdge->adjTarget()] = e->adjTarget(); - } - } - - ite = succ; - } - - - //----------------------------------------// - // Compute an embedding of the subgraph - - // Mark all leaves as relevant -#ifdef OGDF_DEBUG - bool planar = -#endif - T->Reduction(allOutgoing); - // Assert that the Reduction did not fail - OGDF_ASSERT(planar) - - // Stores for every node v the keys corresponding to the incoming edges of v - NodeArray* > >* inLeaves - = m_clusterPQContainer[act].m_inLeaves; - - // Stores for every node v the keys corresponding to the outgoing edges of v - /*NodeArray* > >* outLeaves - = m_clusterPQContainer[act].m_outLeaves;*/ - - // Stores for every node v the sequence of incoming edges of v according - // to the embedding - NodeArray >* frontier - = m_clusterPQContainer[act].m_frontier; - - // Stores for every node v the nodes corresponding to the - // opposed sink indicators found in the frontier of v. - NodeArray >* opposed - = m_clusterPQContainer[act].m_opposed; - - // Stores for every node v the nodes corresponding to the - // opposed sink indicators found in the frontier of v. - NodeArray >* nonOpposed - = m_clusterPQContainer[act].m_nonOpposed; - - // Stores for every node the st-number - NodeArray* numbering = m_clusterPQContainer[act].m_numbering; - - // Stores for every st-Number the corresponding node - Array* tableNumber2Node = m_clusterPQContainer[act].m_tableNumber2Node; - - Array toReverse(1,(*numbering)[t],false); - - // Get necessary embedding information - T->ReplaceRoot((*inLeaves)[t], (*frontier)[t], (*opposed)[t], (*nonOpposed)[t],t); - - - //---------------------------------------------------------// - // Compute a regular embedding of the biconnected component. - - // Reverse adjacency lists if necessary - edge check = (*frontier)[t].front(); - - // Check if the order of edges around t has to be reversed. - if (firstEdge == check) - toReverse[(*numbering)[t]] = true; - - int i; - for (i = (*numbering)[t]; i >= 2; i--) - { - if (toReverse[i]) - { - while (!(*nonOpposed)[(*tableNumber2Node)[i]].empty()) - { - v = (*nonOpposed)[(*tableNumber2Node)[i]].popFrontRet(); - OGDF_ASSERT(!toReverse[(*numbering)[v]]) - toReverse[(*numbering)[v]] = true; - } - (*frontier)[(*tableNumber2Node)[i]].reverse(); - } - else - { - while (!(*opposed)[(*tableNumber2Node)[i]].empty()) - { - v = (*opposed)[(*tableNumber2Node)[i]].popFrontRet(); - OGDF_ASSERT(!toReverse[(*numbering)[v]]) - toReverse[(*numbering)[v]] = true; - } - } - (*nonOpposed)[(*tableNumber2Node)[i]].clear(); - (*opposed)[(*tableNumber2Node)[i]].clear(); - } - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << endl << "New Lists after Reversing " << endl; - for (i = 1; i <= (*numbering)[t]; i++){v = (*tableNumber2Node)[i]; - cout<<"v = "< it; - for(it=(*frontier)[v].begin();it.valid();it++)cout<<*it<<" "; - cout << endl;}} - #endif - - // Compute the upward embedding - - NodeArray > biCompEmbedding(*subGraph); - for (i = 1; i <= (*numbering)[t]; i++) - { - v = (*tableNumber2Node)[i]; - while (!(*frontier)[v].empty()) - { - edge e = (*frontier)[v].popFrontRet(); - biCompEmbedding[v].pushBack( - (e->adjSource()->theNode() == v)? e->adjSource() : e->adjTarget()); - } - } - - //---------------------------------------------// - // Compute the entire embedding of the subGraph - - NodeArray mark(*subGraph,false); - NodeArray > adjMarker(*subGraph,0); - for (i = 1; i <= (*numbering)[t]; i++) - { - v = (*tableNumber2Node)[i]; - adjMarker[v] = biCompEmbedding[v].begin(); - } - v = (*tableNumber2Node)[(*numbering)[t]]; - entireEmbed(*subGraph,biCompEmbedding,adjMarker,mark,v); - - - //--------------------------------------------------// - // Sort the adjacency list of the new nodes in Gcopy - // using the entire embedding of subGraph - - NodeArray > embeddingGcopy(Gcopy); - - // Copy Embedding of biconnected Componts with no outging edges first - - forall_nodes(v,(*subGraph)) - { - SListIterator it; - for (it = (*embedding)[v].begin(); it.valid(); it++) - embeddingGcopy[nodeTableSubGraph2Gcopy[v]].pushBack( - tableAdjEntrySubGraph2Gcopy[*it]); - } - - - // Copy Embedding of the biconnected componts - // with outging edges. Don't add the outgoing edges - - for (i = 1; i < (*numbering)[t]; i++) - { - v = (*tableNumber2Node)[i]; - SListIterator it; - while (!biCompEmbedding[v].empty()) - { - adjEntry adj = biCompEmbedding[v].popFrontRet(); - (*embedding)[v].pushBack(adj); - embeddingGcopy[nodeTableSubGraph2Gcopy[v]].pushBack( - tableAdjEntrySubGraph2Gcopy[adj]); - } - } - - - forall_nodes(v,*subGraph) - if (v != t) - Gcopy.sort(nodeTableSubGraph2Gcopy[v], embeddingGcopy[nodeTableSubGraph2Gcopy[v]]); - - - //----------------------------------------// - // Sort the adjacency list of the new cluster nodes in Gcopy - // using the adjacency list of t - - SListPure embeddingClusterList; - while (!biCompEmbedding[t].empty()) - { - adjEntry adj = biCompEmbedding[t].popFrontRet(); - (*embedding)[t].pushBack(adj); - // Choose the twin of adj, since adj is associated with t - // which is the outside of the cluster. - embeddingClusterList.pushFront(tableAdjEntrySubGraph2Gcopy[adj->twin()]); - } - - Ccopy.makeAdjEntries(newCluster,embeddingClusterList.begin()); - - - - - //----------------------------------------// - // Delete the wheelGraph nodes from Gcopy - while (!replaceNodes.empty()) - { - v = replaceNodes.popFrontRet(); -// Ccopy.unassignNode(v); - Gcopy.delNode(v); - } - - OGDF_ASSERT(Gcopy.representsCombEmbedding()) - - - if (m_clusterEmbedding[act] != 0) - delete m_clusterEmbedding[act]; - delete m_clusterSubgraphHubs[act]; - delete m_clusterSubgraphWheelGraph[act]; - delete m_clusterNodeTableNew2Orig[act]; - delete m_clusterOutgoingEdgesAnker[act]; - - m_clusterPQContainer[act].Cleanup(); - - hubControl(Gcopy,m_currentHubs); - - } - - edge e; - forall_edges(e,Gcopy) - { - if (m_outgoingEdgesAnker[e]) - delete m_outgoingEdgesAnker[e]; - } - - delete m_clusterSubgraphHubs[root]; - delete m_clusterSubgraphWheelGraph[root]; - delete m_clusterOutgoingEdgesAnker[root]; - - - Ccopy.adjAvailable(true); -} - - - - - -/******************************************************************************* - preProcess -********************************************************************************/ - -//Checks if the algorithm is applicable (input is c-connected and planar) and -//then calls the planarity test method - -bool CconnectClusterPlanarEmbed::preProcess(ClusterGraph &Ccopy,Graph &Gcopy) -{ - m_errorCode = none; - if (!isCConnected(Ccopy)) - { - ogdf::sprintf(errorCode,124,"Graph is not Ccopy-connected \n"); - m_errorCode = nonCConnected; - return false; - } - - if (!isPlanar(Ccopy)) - { - ogdf::sprintf(errorCode,124,"Graph is not planar\n"); - m_errorCode = nonPlanar; - return false; - } - - cluster c; - - SListPure selfLoops; - makeLoopFree(Gcopy,selfLoops); - - c = Ccopy.rootCluster(); - - bool cPlanar = planarityTest(Ccopy,c,Gcopy); - - - return cPlanar; -} - - - -/******************************************************************************* - planarityTest -********************************************************************************/ - - -// Recursive call for testing Planarity of a Cluster - -bool CconnectClusterPlanarEmbed::planarityTest( - ClusterGraph &Ccopy, - cluster &act, - Graph &Gcopy) -{ - cluster origOfAct = m_clusterTableCopy2Orig[act]; - - - // Test children first - ListConstIterator it; - for (it = act->cBegin(); it.valid();) - { - ListConstIterator succ = it.succ(); - cluster next = (*it); - if (!planarityTest(Ccopy,next,Gcopy)) - return false; - it = succ; - } - - - m_callStack.push(origOfAct); - - // Get induced subgraph of cluster act and test it for planarity - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << endl << endl << "Testing cluster " << origOfAct->index()< subGraphNodes; - ListIterator its; - for (its = act->nBegin(); its.valid(); its++) - subGraphNodes.pushBack(*its); - - Graph *subGraph = OGDF_NEW Graph(); - NodeArray nodeTableOrig2New; - EdgeArray edgeTableOrig2New; - inducedSubGraph(Gcopy, subGraphNodes.begin(), (*subGraph), nodeTableOrig2New, edgeTableOrig2New); - NodeArray nodeTableNew2Orig((*subGraph),0); - - // Necessary only for root cluster. - EdgeArray edgeTableNew2Orig(*subGraph,0); - - if (act != Ccopy.rootCluster()) - { - m_clusterSubgraph[origOfAct] = subGraph; - m_clusterNodeTableNew2Orig[origOfAct] = new NodeArray((*subGraph),0); - m_clusterSubgraphHubs[origOfAct] = OGDF_NEW NodeArray((*subGraph),0); - m_clusterSubgraphWheelGraph[origOfAct] = OGDF_NEW NodeArray((*subGraph),0); - m_clusterOutgoingEdgesAnker[origOfAct] = OGDF_NEW EdgeArray*>((*subGraph),0); - for (its = act->nBegin(); its.valid(); its++) - { - node w = (*its); - (*m_clusterNodeTableNew2Orig[origOfAct])[nodeTableOrig2New[w]] - = m_nodeTableCopy2Orig[w]; - } - edge e; - forall_edges(e,Gcopy) - { - if (edgeTableOrig2New[e] && m_outgoingEdgesAnker[e]) - (*m_clusterOutgoingEdgesAnker[origOfAct])[edgeTableOrig2New[e]] - = m_outgoingEdgesAnker[e]; - } - } - else - { - m_clusterSubgraph[origOfAct] = &Gcopy; - m_clusterSubgraphHubs[origOfAct] = OGDF_NEW NodeArray(Gcopy,0); - m_clusterSubgraphWheelGraph[origOfAct] = OGDF_NEW NodeArray(Gcopy,0); - m_clusterOutgoingEdgesAnker[origOfAct] = OGDF_NEW EdgeArray*>(Gcopy,0); - for (its = act->nBegin(); its.valid(); its++) - { - node w = (*its); - node ttt = nodeTableOrig2New[w]; - nodeTableNew2Orig[ttt] = w; - } - edge e; - forall_edges(e,Gcopy) - { - edgeTableNew2Orig[edgeTableOrig2New[e]] = e; - if (m_outgoingEdgesAnker[e]) - (*m_clusterOutgoingEdgesAnker[origOfAct])[e] - = m_outgoingEdgesAnker[e]; - } - } - - - - // Introduce super sink and add edges corresponding - // to outgoing edges of the cluster - - node superSink = subGraph->newNode(); - EdgeArray outgoingTable((*subGraph),0); - - for (its = act->nBegin(); its.valid(); its++) - { - node w = (*its); - adjEntry adj = w->firstAdj(); - forall_adj(adj,w) - { - edge e = adj->theEdge(); - edge cor = 0; - if (nodeTableOrig2New[e->source()] == 0) - // edge is connected to a node outside the cluster - { - cor = subGraph->newEdge(nodeTableOrig2New[e->target()],superSink); - outgoingTable[cor] = e->source(); - if (m_outgoingEdgesAnker[e]) - (*m_clusterOutgoingEdgesAnker[origOfAct])[cor] - = m_outgoingEdgesAnker[e]; - } - else if (nodeTableOrig2New[e->target()] == 0) // dito - { - cor = subGraph->newEdge(nodeTableOrig2New[e->source()],superSink); - outgoingTable[cor] = e->target(); - if (m_outgoingEdgesAnker[e]) - (*m_clusterOutgoingEdgesAnker[origOfAct])[cor] - = m_outgoingEdgesAnker[e]; } - - // else edge connects two nodes of the cluster - } - } - if (superSink->degree() == 0) // root cluster is not connected to outside clusters - { - subGraph->delNode(superSink); - superSink = 0; - } - else - m_clusterSuperSink[origOfAct] = superSink; - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - char filename[124]; - ogdf::sprintf(filename,124,"Ccopy%d.gml",origOfAct->index()); - subGraph->writeGML(filename); - } - #endif - - - bool cPlanar = preparation((*subGraph),origOfAct,superSink); - - - if (cPlanar && act != Ccopy.rootCluster()) - { - // Remove induced subgraph and the cluster act. - // Replace it by a wheel graph - while (!subGraphNodes.empty()) - { - node w = subGraphNodes.popFrontRet(); - if (m_currentHubs[w]) - (*m_clusterSubgraphHubs[origOfAct])[nodeTableOrig2New[w]] - = true; - if (m_wheelGraphNodes[w]) - (*m_clusterSubgraphWheelGraph[origOfAct])[nodeTableOrig2New[w]] - = m_wheelGraphNodes[w]; - -// Ccopy.unassignNode(w); - Gcopy.delNode(w); - } - - cluster parent = act->parent(); - - if (superSink && m_clusterPQContainer[origOfAct].m_T) - constructWheelGraph(Ccopy,Gcopy,parent,origOfAct, - m_clusterPQContainer[origOfAct].m_T, - outgoingTable,superSink); - - - m_clusterTableOrig2Copy[origOfAct] = 0; - Ccopy.delCluster(act); - } - - else if (cPlanar && act == Ccopy.rootCluster()) - { - - node w ; - forall_nodes(w,Gcopy) - { - if (m_currentHubs[w]) - (*m_clusterSubgraphHubs[origOfAct])[w] = true; - if (m_wheelGraphNodes[w]) - (*m_clusterSubgraphWheelGraph[origOfAct])[w] = m_wheelGraphNodes[w]; - } - - forall_nodes(w,*subGraph) - subGraph->sort(w,(*m_clusterEmbedding[origOfAct])[w]); - - forall_nodes(w,(*subGraph)) - { - node originalOfw = nodeTableNew2Orig[w]; - - SListPure adjList; - - adjEntry a; - forall_adj(a,w) - { - edge e = edgeTableNew2Orig[a->theEdge()]; - adjEntry adj = (e->adjSource()->theNode() == originalOfw)? - e->adjSource() : e->adjTarget(); - adjList.pushBack(adj); - } - - Gcopy.sort(originalOfw,adjList); - } - - // Test if embedding was determined correctly. - OGDF_ASSERT(subGraph->representsCombEmbedding()) - - edgeTableNew2Orig.init(); - outgoingTable.init(); - nodeTableNew2Orig.init(); - delete m_clusterEmbedding[origOfAct]; - m_clusterEmbedding[origOfAct] = 0; - delete subGraph; - - } - - else if (!cPlanar && act == Ccopy.rootCluster()) - { - edgeTableNew2Orig.init(); - outgoingTable.init(); - nodeTableNew2Orig.init(); - delete m_clusterEmbedding[origOfAct]; - m_clusterEmbedding[origOfAct] = 0; - delete subGraph; - } - - if (!cPlanar) - { - ogdf::sprintf(errorCode,124,"Graph is not planar at cluster %d.\n",act->index()); - m_errorCode = nonCPlanar; - }//if - - - return cPlanar; - -} - - - - -/******************************************************************************* - preparation -********************************************************************************/ - - -// -// Prepare planarity test for one cluster -// -bool CconnectClusterPlanarEmbed::preparation(Graph &subGraph, - cluster &origCluster, - node superSink) -{ - - node v; - edge e; - int bcIdSuperSink = -1; // ID of biconnected component that contains superSink - // Initialization with -1 necessary for assertion - bool cPlanar = true; - - - NodeArray tableNodesSubGraph2BiComp(subGraph,0); - EdgeArray tableEdgesSubGraph2BiComp(subGraph,0); - NodeArray mark(subGraph,0); - - EdgeArray componentID(subGraph); - - // Generate datastructure for embedding, even if it is left empty. - // Embedding either contains - // Embedding of the root cluster - // or - // Partial Embedding of the biconnected components not having - // outgoing edges. - - NodeArray > - *entireEmbedding = OGDF_NEW NodeArray >(subGraph); - m_clusterEmbedding[origCluster] = entireEmbedding; - - // Determine Biconnected Components - int bcCount = biconnectedComponents(subGraph,componentID); - - // Determine edges per biconnected component - Array > blockEdges(0,bcCount-1); - forall_edges(e,subGraph) - { - blockEdges[componentID[e]].pushFront(e); - } - - // Determine nodes per biconnected component. - Array > blockNodes(0,bcCount-1); - for (int i = 0; i < bcCount; i++) - { - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - if (!mark[e->source()]) - { - blockNodes[i].pushBack(e->source()); - mark[e->source()] = true; - } - if (!mark[e->target()]) - { - blockNodes[i].pushBack(e->target()); - mark[e->target()] = true; - } - } - if (superSink && mark[superSink]) - { - OGDF_ASSERT(bcIdSuperSink == -1); - bcIdSuperSink = i; - } - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++itn) - { - v = *itn; - if (mark[v]) - mark[v] = false; - else - { - OGDF_ASSERT(mark[v]); // v has been placed two times on the list. - } - } - - } - - - - // Perform Planarity Test for every biconnected component - - if (bcCount == 1) - { - // Compute st-numbering - NodeArray numbering(subGraph,0); - int n; - if (superSink) - n = stNumber(subGraph,numbering,0,superSink); - else - n = stNumber(subGraph,numbering); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(subGraph,numbering,n)) - - EdgeArray tableEdgesBiComp2SubGraph(subGraph,0); - NodeArray tableNodesBiComp2SubGraph(subGraph,0); - forall_edges(e,subGraph) - tableEdgesBiComp2SubGraph[e] = e; - forall_nodes(v,subGraph) - tableNodesBiComp2SubGraph[v] = v; - - // Initialize the container class for storing all information - // if it does not belong to the root cluster. - if (bcIdSuperSink == 0) - m_clusterPQContainer[origCluster].init(&subGraph); - - cPlanar = doEmbed( - &subGraph, - numbering, - origCluster, - superSink, - subGraph, - tableEdgesBiComp2SubGraph, - tableEdgesBiComp2SubGraph, - tableNodesBiComp2SubGraph); - - // Do not save the embedding of the subgraph. It is not complete. - if (bcIdSuperSink == -1) - { - // The root cluster is embedded. - // Gather the embeddding of the biconnected graph, if it belongs to - // the root cluster. - // The embedding of the subgraph is saved, as it is the root cluster graph. - forall_nodes(v,subGraph) - { - adjEntry a; - forall_adj(a,v) - (*entireEmbedding)[v].pushBack(a); - } - } - - } - else - { - for (int i = 0; i < bcCount; i++) - { - Graph *biCompOfSubGraph = OGDF_NEW Graph(); - - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - { - v = *itn; - node w = biCompOfSubGraph->newNode(); - tableNodesSubGraph2BiComp[v] = w; - } - - NodeArray tableNodesBiComp2SubGraph(*biCompOfSubGraph,0); - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - tableNodesBiComp2SubGraph[tableNodesSubGraph2BiComp[*itn]] = *itn; - - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - edge f = biCompOfSubGraph->newEdge( - tableNodesSubGraph2BiComp[e->source()], tableNodesSubGraph2BiComp[e->target()]); - tableEdgesSubGraph2BiComp[e] = f; - } - - EdgeArray tableEdgesBiComp2SubGraph(*biCompOfSubGraph,0); - for (it = blockEdges[i].begin(); it.valid(); ++it) - tableEdgesBiComp2SubGraph[tableEdgesSubGraph2BiComp[*it]] = *it; - - NodeArray numbering(*biCompOfSubGraph,0); - int n; - if (bcIdSuperSink == i) - { - n = stNumber(*biCompOfSubGraph,numbering,0,tableNodesSubGraph2BiComp[superSink]); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(*biCompOfSubGraph,numbering,n)) - - // Initialize the container class for storing all information - m_clusterPQContainer[origCluster].init(&subGraph); - - cPlanar = doEmbed( - biCompOfSubGraph, - numbering, - origCluster, - tableNodesSubGraph2BiComp[superSink], - subGraph, - tableEdgesBiComp2SubGraph, - tableEdgesSubGraph2BiComp, - tableNodesBiComp2SubGraph); - } - else - { - n = stNumber(*biCompOfSubGraph,numbering); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(*biCompOfSubGraph,numbering,n)); - cPlanar = doEmbed( - biCompOfSubGraph, - numbering, - origCluster, - 0, - subGraph, - tableEdgesBiComp2SubGraph, - tableEdgesSubGraph2BiComp, - tableNodesBiComp2SubGraph); - } - - if (!cPlanar) - { - numbering.init(); - tableEdgesBiComp2SubGraph.init(); - tableNodesBiComp2SubGraph.init(); - delete biCompOfSubGraph; - break; - } - - if (bcIdSuperSink == -1) - { - // The root cluster is embedded. - // Gather the embedding of the biconnected graph, if it belongs to - // the root cluster. - // The embedding of the subgraph is saved, as it is the root cluster graph. - forall_nodes(v,*biCompOfSubGraph) - { - node w = tableNodesBiComp2SubGraph[v]; - adjEntry a; - forall_adj(a,v) - { - edge e = tableEdgesBiComp2SubGraph[a->theEdge()]; - adjEntry adj = (e->adjSource()->theNode() == w)? - e->adjSource() : e->adjTarget(); - (*entireEmbedding)[w].pushBack(adj); - } - } - } - else if (bcIdSuperSink != i) - { - // A non root cluster is embedded. - // Gather the embeddings of the biconnected components - // that do not have outgoing edges of the cluster. - forall_nodes(v,*biCompOfSubGraph) - { - node w = tableNodesBiComp2SubGraph[v]; - adjEntry a; - forall_adj(a,v) - { - edge e = tableEdgesBiComp2SubGraph[a->theEdge()]; - adjEntry adj = (e->adjSource()->theNode() == w)? - e->adjSource() : e->adjTarget(); - (*entireEmbedding)[w].pushBack(adj); - } - } - - } - numbering.init(); - tableEdgesBiComp2SubGraph.init(); - tableNodesBiComp2SubGraph.init(); - delete biCompOfSubGraph; - - - }//for bccount - - // m_clusterEmbedding[origCluster] now contains the (partial) embedding - // of all biconnected components that do not have outgoing edges - // of the cluster origCluster. - } - - return cPlanar; - -}// preparation - - - - -/******************************************************************************* - doEmbed -********************************************************************************/ - - -// Performs a planarity test on a biconnected component -// of subGraph and embedds it planar. -// numbering contains an st-numbering of the component. -bool CconnectClusterPlanarEmbed::doEmbed(Graph *biconComp, - NodeArray &numbering, - cluster &origCluster, - node superSink, - Graph &subGraph, - EdgeArray &tableEdgesBiComp2SubGraph, - EdgeArray &tableEdgesSubGraph2BiComp, - NodeArray &tableNodesBiComp2SubGraph) -{ - node v; - bool cPlanar = true; - - // Definition - // incoming edge of v: an edge e = (v,w) with number(v) < number(w) - - - // Stores for every node v the keys corresponding to the incoming edges of v - NodeArray* > > inLeaves(*biconComp); - - // Stores for every node v the keys corresponding to the outgoing edges of v - NodeArray* > > outLeaves(*biconComp); - - // Stores for every node v the sequence of incoming edges of v according - // to the embedding - NodeArray > frontier(*biconComp); - - // Stores for every node v the nodes corresponding to the - // opposed sink indicators found in the frontier of v. - NodeArray > opposed(*biconComp); - - // Stores for every node v the nodes corresponding to the - // non opposed sink indicators found in the frontier of v. - NodeArray > nonOpposed(*biconComp); - - // Stores for every st-Number the corresponding node - Array tableNumber2Node(biconComp->numberOfNodes()+1); - - Array toReverse(1,biconComp->numberOfNodes()+1,false); - - PlanarLeafKey* stEdgeLeaf; - - forall_nodes(v,*biconComp) - { - edge e; - - forall_adj_edges(e,v) - { - if (numbering[e->opposite(v)] > numbering[v]) - { - PlanarLeafKey* L = OGDF_NEW PlanarLeafKey(e); - inLeaves[v].pushFront(L); - if (numbering[v] == 1 && numbering[e->opposite(v)]) - stEdgeLeaf = L; - } - } - tableNumber2Node[numbering[v]] = v; - } - - forall_nodes(v,*biconComp) - { - SListIterator* > it; - for (it = inLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* L = *it; - outLeaves[L->userStructKey()->opposite(v)].pushFront(L); - } - } - - EmbedPQTree* T = new EmbedPQTree(); - - T->Initialize(inLeaves[tableNumber2Node[1]]); - int i; - for (i = 2; i < biconComp->numberOfNodes(); i++) - { - if (T->Reduction(outLeaves[tableNumber2Node[i]])) - { - T->ReplaceRoot( - inLeaves[tableNumber2Node[i]], - frontier[tableNumber2Node[i]], - opposed[tableNumber2Node[i]], - nonOpposed[tableNumber2Node[i]], - tableNumber2Node[i]); - T->emptyAllPertinentNodes(); - } - else - { - cPlanar = false; - break; - } - } - - if (cPlanar && superSink) - { - // The tested component contains the outgoing edges - // of the cluster. - - // Keep the PQTree to construct a Wheelgraph - // Replace the edge stored in the keys of T - // by the original edges. - // Necessary, since the edges currently in T - // correspond to a graph that mirrors a biconnected - // component and thus is deallocated - - // For embedding the graph, we need to keep the - // PQTree as well. - - SListIterator* > it; - //int n = biconComp->numberOfNodes(); - - // Replace the edge stored in the keys of T - // by the original edges. - - - //--------------------------------------// - // All information that we keep is dependend on subGraph. - // Translate the information back from biconComp to subGraph. - - - m_clusterPQContainer[origCluster].m_superSink - = tableNodesBiComp2SubGraph[superSink]; - - forall_nodes(v,*biconComp) - { - // Replace the edge stored in the every key used for constructing T - // by the original edges. - // This implicity replaces the keys at the leaves and at inLeaves. - - - node orig = tableNodesBiComp2SubGraph[v]; - - // Assert that m_outLeaves is empty - OGDF_ASSERT((*m_clusterPQContainer[origCluster].m_outLeaves)[orig].empty()) - for (it = outLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* key = *it; - key->m_userStructKey = tableEdgesBiComp2SubGraph[key->m_userStructKey]; - (*m_clusterPQContainer[origCluster].m_edge2Key)[key->m_userStructKey] = key; - (*m_clusterPQContainer[origCluster].m_outLeaves)[orig].pushBack(key); - } - - // Assert that m_inLeaves is empty - OGDF_ASSERT((*m_clusterPQContainer[origCluster].m_inLeaves)[orig].empty()) - for (it = inLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* key = *it; - (*m_clusterPQContainer[origCluster].m_inLeaves)[orig].pushBack(key); - } - - // Replace the nodes stored in the lists opposed and nonOpposed - // by the original nodes - - // Assert that m_opposed and m_nonOpposed are empty - OGDF_ASSERT((*m_clusterPQContainer[origCluster].m_opposed)[orig].empty()) - OGDF_ASSERT((*m_clusterPQContainer[origCluster].m_nonOpposed)[orig].empty()) - SListIterator itn; - for (itn = nonOpposed[v].begin(); itn.valid(); itn++) - { - node w = tableNodesBiComp2SubGraph[(*itn)]; - (*m_clusterPQContainer[origCluster].m_nonOpposed)[orig].pushBack(w); - } - for (itn = opposed[v].begin(); itn.valid(); itn++) - { - node w = tableNodesBiComp2SubGraph[(*itn)]; - (*m_clusterPQContainer[origCluster].m_opposed)[orig].pushBack(w); - } - - (*m_clusterPQContainer[origCluster].m_numbering)[orig] = numbering[v]; - (*m_clusterPQContainer[origCluster].m_tableNumber2Node)[numbering[v]] = orig; - - - // Replace the edges stored in frontier - // by the original edges of subgraph. - - OGDF_ASSERT((*m_clusterPQContainer[origCluster].m_frontier)[orig].empty()) - SListIterator ite; - for (ite = frontier[v].begin(); ite.valid(); ite++) - { - edge e = tableEdgesBiComp2SubGraph[(*ite)]; - (*m_clusterPQContainer[origCluster].m_frontier)[orig].pushBack(e); - } - - - } - m_clusterPQContainer[origCluster].m_T = T; - m_clusterPQContainer[origCluster].m_stEdgeLeaf = stEdgeLeaf; - SListPure*> leafKeys; - T->getFront(T->root(),leafKeys); - SListIterator* > itk; - for (itk = leafKeys.begin(); itk.valid(); itk++) - { - if ((*itk)->nodePointer()->status() == PQNodeRoot::INDICATOR) - { - node ofInd = (*itk)->nodePointer()->getNodeInfo()->userStructInfo()->getAssociatedNode(); - (*itk)->nodePointer()->getNodeInfo()->userStructInfo()->resetAssociatedNode(tableNodesBiComp2SubGraph[ofInd]); - } - } - } - else if (cPlanar) - { - // The tested component does not contain outgoing edges - // of the cluster. - // Compute a regular embedding of the biconnected component. - int i = biconComp->numberOfNodes(); - if (T->Reduction(outLeaves[tableNumber2Node[i]])) - { - T->ReplaceRoot( - inLeaves[tableNumber2Node[i]], - frontier[tableNumber2Node[i]], - opposed[tableNumber2Node[i]], - nonOpposed[tableNumber2Node[i]], - tableNumber2Node[i]); - } - delete T; - } - - // Cleanup - if (!origCluster || !superSink || !cPlanar) - // Do not cleanup information of component - // with outgoing edges. - { - forall_nodes(v,*biconComp) - { - if (v != superSink || !cPlanar) - { - while (!outLeaves[v].empty()) - { - PlanarLeafKey* L = outLeaves[v].popFrontRet(); - delete L; - } - } - } - } - if (!cPlanar) - delete T; - - - if (cPlanar && (!origCluster || !superSink)) - { - // The tested component does not contain outgoing edges - // of the cluster. - // Compute a regular embedding of the biconnected component. - - // Reverse adjacency lists if necessary - // This gives an upward embedding - for (i = biconComp->numberOfNodes(); i >= 2; i--) - { - if (toReverse[i]) - { - while (!nonOpposed[tableNumber2Node[i]].empty()) - { - v = nonOpposed[tableNumber2Node[i]].popFrontRet(); - OGDF_ASSERT(!toReverse[numbering[v]]) - toReverse[numbering[v]] = true; - } - frontier[tableNumber2Node[i]].reverse(); - } - else - { - while (!opposed[tableNumber2Node[i]].empty()) - { - v = opposed[tableNumber2Node[i]].popFrontRet(); - OGDF_ASSERT(!toReverse[numbering[v]]) - toReverse[numbering[v]] = true; - } - } - nonOpposed[tableNumber2Node[i]].clear(); - opposed[tableNumber2Node[i]].clear(); - } - - // Compute the entire embedding - NodeArray > entireEmbedding(*biconComp); - forall_nodes(v,*biconComp) - { - while (!frontier[v].empty()) - { - edge e = frontier[v].popFrontRet(); - entireEmbedding[v].pushBack( - (e->adjSource()->theNode() == v)? e->adjSource() : e->adjTarget()); - } - } - - - NodeArray mark(*biconComp,false); - NodeArray > adjMarker(*biconComp,0); - forall_nodes(v,*biconComp) - adjMarker[v] = entireEmbedding[v].begin(); - v = tableNumber2Node[biconComp->numberOfNodes()]; - entireEmbed(*biconComp,entireEmbedding,adjMarker,mark,v); - - - forall_nodes(v,*biconComp) - biconComp->sort(v,entireEmbedding[v]); - - // Test if embedding was determined correctly. - OGDF_ASSERT(biconComp->representsCombEmbedding()) - - } - - return cPlanar; - - -}// doEmbed - - - - - -/******************************************************************************* - entireEmbed -********************************************************************************/ - - -// Used by doEmbed. Computes an entire embedding from an -// upward embedding. -void CconnectClusterPlanarEmbed::entireEmbed( - Graph &biconComp, - NodeArray > &entireEmbedding, - NodeArray > &adjMarker, - NodeArray &mark, - node v) -{ - mark[v] = true; - SListIterator it; - for (it = adjMarker[v]; it.valid(); ++it) - { - adjEntry a = *it; - edge e = a->theEdge(); - adjEntry adj = (e->adjSource()->theNode() == v)? - e->adjTarget() : e->adjSource(); - node w = adj->theNode(); - entireEmbedding[w].pushFront(adj); - if (!mark[w]) - entireEmbed(biconComp,entireEmbedding,adjMarker,mark,w); - } -} - - - - - - -/******************************************************************************* - prepareParallelEdges -********************************************************************************/ - - -void CconnectClusterPlanarEmbed::prepareParallelEdges(Graph &G) -{ - - edge e; - - // Stores for one reference edge all parallel edges. - m_parallelEdges.init(G); - // Is true for any multiedge, except for the reference edge. - m_isParallel.init(G,false); - getParallelFreeUndirected(G,m_parallelEdges); - m_parallelCount = 0; - forall_edges(e,G) - { - if (!m_parallelEdges[e].empty()) - { - ListIterator it; - for (it = m_parallelEdges[e].begin(); it.valid(); it++) - { - m_isParallel[*it] = true; - m_parallelCount++; - } - } - } -} - - - - -/******************************************************************************* - constructWheelGraph -********************************************************************************/ - - -void CconnectClusterPlanarEmbed::constructWheelGraph(ClusterGraph &Ccopy, - Graph &Gcopy, - cluster &parent, - cluster &origOfAct, - EmbedPQTree* T, - EdgeArray &outgoingTable, - node superSink) -{ - - OGDF_ASSERT(Ccopy.consistencyCheck()); - PQNode* root = T->root(); - PQNode* checkNode = 0; - - Queue*> treeNodes; - treeNodes.append(root); - - node correspond = Gcopy.newNode(); // Corresponds to the root node. - // root node is either a leaf or a P-node - m_nodeTableCopy2Orig[correspond] = 0; // Node does not correspond to a node - // in the original graph - m_wheelGraphNodes[correspond] = origOfAct; - Ccopy.reassignNode(correspond,parent); - - Queue graphNodes; - graphNodes.append(correspond); - - node hub; - node next = 0; - node pre; - node newNode; // corresponds to anchor of a hub or a cut node - - - - while (!treeNodes.empty()) - { - checkNode = treeNodes.pop(); - correspond = graphNodes.pop(); - - PQNode* firstSon = 0; - PQNode* nextSon = 0; - PQNode* oldSib = 0; - PQNode* holdSib = 0; - - - if (checkNode->type() == PQNodeRoot::PNode) - { - // correspond is a cut node - - OGDF_ASSERT(checkNode->referenceChild()) - firstSon = checkNode->referenceChild(); - - if (firstSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(firstSon); - newNode = Gcopy.newNode(); - m_nodeTableCopy2Orig[newNode] = 0; - m_wheelGraphNodes[newNode] = origOfAct; - Ccopy.reassignNode(newNode,parent); - graphNodes.append(newNode); - Gcopy.newEdge(correspond,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) firstSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - edge newEdge = Gcopy.newEdge(correspond,outgoingTable[f]); - - - if ((*m_clusterOutgoingEdgesAnker[origOfAct])[f]) - { - m_outgoingEdgesAnker[newEdge] - = (*m_clusterOutgoingEdgesAnker[origOfAct])[f]; - } - else - m_outgoingEdgesAnker[newEdge] = OGDF_NEW Stack; - m_outgoingEdgesAnker[newEdge]->push(f); - } - - nextSon = firstSon->getNextSib(oldSib); - oldSib = firstSon; - pre = next; - while (nextSon && nextSon != firstSon) - { - if (nextSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(nextSon); - newNode = Gcopy.newNode(); // new node corresponding to anchor - // or cutnode - m_nodeTableCopy2Orig[newNode] = 0; - m_wheelGraphNodes[newNode] = origOfAct; - Ccopy.reassignNode(newNode,parent); - graphNodes.append(newNode); - Gcopy.newEdge(correspond,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) nextSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - edge newEdge = Gcopy.newEdge(correspond,outgoingTable[f]); - - if ((*m_clusterOutgoingEdgesAnker[origOfAct])[f]) - { - m_outgoingEdgesAnker[newEdge] - = (*m_clusterOutgoingEdgesAnker[origOfAct])[f]; - } - else - m_outgoingEdgesAnker[newEdge] = OGDF_NEW Stack; - m_outgoingEdgesAnker[newEdge]->push(f); - } - holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - - // correspond is the achor of a hub - OGDF_ASSERT(T->scanLeftEndmost(checkNode)) - firstSon = T->scanLeftEndmost(checkNode); - - hub = Gcopy.newNode(); - m_nodeTableCopy2Orig[hub] = 0; - m_currentHubs[hub] = true; - m_wheelGraphNodes[hub] = origOfAct; - Ccopy.reassignNode(hub,parent); - - Gcopy.newEdge(hub,correspond); // link achor and hub - next = Gcopy.newNode(); // for first son - m_nodeTableCopy2Orig[next] = 0; - m_wheelGraphNodes[next] = origOfAct; - Ccopy.reassignNode(next,parent); - Gcopy.newEdge(hub,next); - Gcopy.newEdge(correspond,next); - - if (firstSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(firstSon); - newNode = Gcopy.newNode(); - m_nodeTableCopy2Orig[newNode] = 0; - m_wheelGraphNodes[newNode] = origOfAct; - Ccopy.reassignNode(newNode,parent); - graphNodes.append(newNode); - Gcopy.newEdge(next,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) firstSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - edge newEdge = Gcopy.newEdge(next,outgoingTable[f]); - - if ((*m_clusterOutgoingEdgesAnker[origOfAct])[f]) - { - m_outgoingEdgesAnker[newEdge] - = (*m_clusterOutgoingEdgesAnker[origOfAct])[f]; - } - else - m_outgoingEdgesAnker[newEdge] = OGDF_NEW Stack; - m_outgoingEdgesAnker[newEdge]->push(f); - } - - nextSon = T->scanNextSib(firstSon,oldSib); - oldSib = firstSon; - pre = next; - while (nextSon) - { - next = Gcopy.newNode(); - m_nodeTableCopy2Orig[next] = 0; - m_wheelGraphNodes[next] = origOfAct; - Ccopy.reassignNode(next,parent); - Gcopy.newEdge(hub,next); - Gcopy.newEdge(pre,next); - if (nextSon->type() != PQNodeRoot::leaf) - { - treeNodes.append(nextSon); - newNode = Gcopy.newNode(); // new node corresponding to anchor - // or cutnode - m_nodeTableCopy2Orig[newNode] = 0; - m_wheelGraphNodes[newNode] = origOfAct; - Ccopy.reassignNode(newNode,parent); - graphNodes.append(newNode); - - Gcopy.newEdge(next,newNode); - } - else - { - // insert Edge to the outside - PQLeaf* leaf = - (PQLeaf*) nextSon; - edge f = leaf->getKey()->m_userStructKey; - //node x = outgoingTable[f]; - edge newEdge = Gcopy.newEdge(next,outgoingTable[f]); - - if ((*m_clusterOutgoingEdgesAnker[origOfAct])[f]) - { - m_outgoingEdgesAnker[newEdge] - = (*m_clusterOutgoingEdgesAnker[origOfAct])[f]; - } - else - m_outgoingEdgesAnker[newEdge] = OGDF_NEW Stack; - m_outgoingEdgesAnker[newEdge]->push(f); - } - holdSib = T->scanNextSib(nextSon,oldSib); - oldSib = nextSon; - nextSon = holdSib; - pre = next; - - } - Gcopy.newEdge(next,correspond); - } - } - - OGDF_ASSERT(Ccopy.consistencyCheck()); -}// constructWheelGraph - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/cluster/ClusterGraph.cpp b/ext/OGDF/src/cluster/ClusterGraph.cpp deleted file mode 100644 index 3312fec63..000000000 --- a/ext/OGDF/src/cluster/ClusterGraph.cpp +++ /dev/null @@ -1,1775 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements the class ClusterGraph, providing - * extra functionality for clustered graphs. - * A clustered graph C=(G,T) consists of an undirected graph G - * and a rooted tree T in which the leaves of T correspond - * to the vertices of G=(V,E). - * - * \author Sebastian Leipert, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - - -namespace ogdf { - -#define MIN_CLUSTER_TABLE_SIZE (1 << 4) - -//--------------------------------------------------------- -//node search in cluster hierarchy -//--------------------------------------------------------- -void ClusterElement::getClusterInducedNodes(List &clusterNodes) { - - ListConstIterator nit; - for (nit=m_entries.begin(); nit.valid(); ++nit) { - clusterNodes.pushBack(*nit); - } - ListConstIterator cit; - for (cit=m_children.begin(); cit.valid(); ++cit) { - (*cit)->getClusterInducedNodes(clusterNodes); - } -} - -void ClusterElement::getClusterNodes(List &clusterNodes) { - - clusterNodes.clear(); - getClusterInducedNodes(clusterNodes); -} - -void ClusterElement::getClusterInducedNodes(NodeArray &clusterNode, int& num) { - - ListConstIterator nit; - for (nit=m_entries.begin(); nit.valid(); ++nit) { - clusterNode[*nit] = true; - num++; - } - ListConstIterator cit; - for (cit=m_children.begin(); cit.valid(); ++cit) { - (*cit)->getClusterInducedNodes(clusterNode, num); - } -} - -int ClusterElement::getClusterNodes(NodeArray &clusterNode) -{ - int num = 0; - getClusterInducedNodes(clusterNode, num); - - return num; -} - - -//--------------------------------------------------------- -// Construction -//--------------------------------------------------------- - -ClusterGraph::ClusterGraph() -{ - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_rootCluster = 0; - - m_allowEmptyClusters = true; - m_updateDepth = false; - m_depthUpToDate = false; - - m_nClusters = 0; - m_lcaNumber = 0; - m_clusterArrayTableSize = MIN_CLUSTER_TABLE_SIZE; - m_adjAvailable = false; - m_lcaNumber = 0; - m_lcaSearch = 0; - m_vAncestor = 0; - m_wAncestor = 0; - //m_clusterDepth.init(*this, 0); -} - - - -// Construction of a new cluster graph. All nodes -// are children of the root cluster -ClusterGraph::ClusterGraph(const Graph &G) : GraphObserver(&G), m_pGraph(&G) -{ - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_rootCluster = 0; - - m_allowEmptyClusters = true; - m_updateDepth = false; - m_depthUpToDate = false; - - m_nClusters = 0; - m_lcaNumber = 0; - m_clusterArrayTableSize = G.nextPower2(MIN_CLUSTER_TABLE_SIZE, G.nodeArrayTableSize()); - //m_clusterDepth.init(*this, 0); - initGraph(G); -} - - -ClusterGraph::ClusterGraph(const ClusterGraph &C) : - GraphObserver(&(C.getGraph())), - m_lcaSearch(0), - m_vAncestor(0), - m_wAncestor(0) -{ - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_rootCluster = 0; - - m_allowEmptyClusters = true; - m_updateDepth = false; - m_depthUpToDate = false; - - m_nClusters = 0; - m_lcaNumber = 0; - - m_clusterArrayTableSize = C.m_clusterArrayTableSize; - shallowCopy(C); -} - - -ClusterGraph::ClusterGraph( - const ClusterGraph &C, - Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable) -: - GraphObserver(&G), - m_lcaSearch(0), - m_vAncestor(0), - m_wAncestor(0) -{ - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_rootCluster = 0; - - m_allowEmptyClusters = true; - m_updateDepth = false; - m_depthUpToDate = false; - - m_nClusters = 0; - m_lcaNumber = 0; - - m_clusterArrayTableSize = C.m_clusterArrayTableSize; - deepCopy(C,G,originalClusterTable,originalNodeTable); -} - - -ClusterGraph::ClusterGraph( - const ClusterGraph &C, - Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable, - EdgeArray &edgeCopy) -: - GraphObserver(&G), - m_lcaSearch(0), - m_vAncestor(0), - m_wAncestor(0) -{ - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_rootCluster = 0; - - m_allowEmptyClusters = true; - m_updateDepth = false; - m_depthUpToDate = false; - - m_nClusters = 0; - m_lcaNumber = 0; - - m_clusterArrayTableSize = C.m_clusterArrayTableSize; - deepCopy(C, G, originalClusterTable, originalNodeTable, edgeCopy); -} - - -ClusterGraph::ClusterGraph(const ClusterGraph &C,Graph &G) : - GraphObserver(&G), - m_lcaSearch(0), - m_vAncestor(0), - m_wAncestor(0) -{ - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_rootCluster = 0; - - m_allowEmptyClusters = true; - m_updateDepth = false; - m_depthUpToDate = false; - - m_nClusters = 0; - m_lcaNumber = 0; - - m_clusterArrayTableSize = C.m_clusterArrayTableSize; - deepCopy(C,G); -} - - -ClusterGraph::~ClusterGraph() -{ - for(ListIterator it = m_regClusterArrays.begin(); - it.valid(); ++it) - { - (*it)->disconnect(); - } - - clear(); -} - - -// Construction of a new cluster graph. All nodes -// are children of the root cluster -void ClusterGraph::init(const Graph &G) -{ - clear(); - m_clusterIdCount = 0; - m_postOrderStart = 0; - m_pGraph = &G; - - m_nClusters = 0; - m_lcaNumber = 0; - m_clusterArrayTableSize = G.nextPower2(MIN_CLUSTER_TABLE_SIZE, G.nodeArrayTableSize()); - //m_clusterDepth.init(*this, 0); - initGraph(G); -} - - - -//--------------------------------------------------------- -// = -//--------------------------------------------------------- - -ClusterGraph &ClusterGraph::operator=(const ClusterGraph &C) -{ - clear(); shallowCopy(C); - m_clusterArrayTableSize = C.m_clusterArrayTableSize; - reinitArrays(); - - OGDF_ASSERT_IF(dlConsistencyChecks, consistencyCheck()); - return *this; -} - - -//--------------------------------------------------------- -// copy,initGraph -//--------------------------------------------------------- - -// Copy Function -void ClusterGraph::shallowCopy(const ClusterGraph &C) -{ - const Graph &G = C; - m_pGraph = &G; - - m_nClusters = 0; - - //m_clusterDepth.init(*this, 0); - - initGraph(G); - - m_updateDepth = C.m_updateDepth; - m_depthUpToDate = C.m_depthUpToDate; - - // Construct cluster tree - ClusterArray originalClusterTable(C); - cluster c = 0; - forall_clusters(c,C) - { - if (c == C.m_rootCluster) - { - originalClusterTable[c] = m_rootCluster; - //does not really need to be assigned HERE in for - m_rootCluster->depth() = 1; - OGDF_ASSERT(C.rootCluster()->depth() == 1) - continue; - } - originalClusterTable[c] = newCluster(); - originalClusterTable[c]->depth() = c->depth(); - } - forall_clusters(c,C) - { - - if (c == C.m_rootCluster) - continue; - originalClusterTable[c]->m_parent = originalClusterTable[c->m_parent]; - originalClusterTable[c->m_parent]->m_children.pushBack(originalClusterTable[c]); - originalClusterTable[c]->m_it = originalClusterTable[c->m_parent]->m_children.rbegin(); - } - - node v; - forall_nodes(v,G) - reassignNode(v,originalClusterTable[C.clusterOf(v)]); - - copyLCA(C); -} - - - -// Initialize the graph -void ClusterGraph::initGraph(const Graph &G) -{ - - reregister(&G); //will in some constructors cause double registration - - m_lcaNumber = 0; - m_lcaSearch = 0; - m_vAncestor = 0; - m_wAncestor = 0; - - //if (G.empty()) - // return; - - m_adjAvailable = false; - - //assign already existing nodes, new nodes are assigned - //over nodeadded - List allNodes; - G.allNodes(allNodes); - - //clusterIdcount may be zero in case of constructor call, - //but can be != zero if readgraphwin is used - //root cluster should always get id 0 - #ifdef OGDF_DEBUG - m_rootCluster = OGDF_NEW ClusterElement(this, 0);//m_clusterIdCount++); - #else - m_rootCluster = OGDF_NEW ClusterElement(0);//m_clusterIdCount++); - #endif - - OGDF_ASSERT(m_nClusters == 0) - - m_clusterIdCount++; - m_rootCluster->depth() = 1; - m_rootCluster->init(allNodes); - m_nodeMap.init(G,m_rootCluster); - m_itMap.init(G,0); - ListIterator it; - for (it = m_rootCluster->m_entries.begin(); it.valid(); it++) - m_itMap[*it] = it; - - m_nClusters++; - m_clusters.pushBack(m_rootCluster); -} - - -void ClusterGraph::reinitGraph(const Graph &G) - { - m_pGraph = &G; - - OGDF_ASSERT_IF(dlConsistencyChecks, G.consistencyCheck()); - - m_clusterArrayTableSize = G.nextPower2(MIN_CLUSTER_TABLE_SIZE, G.nodeArrayTableSize()); - - if (numberOfClusters() != 0) - { - clear(); - }//if - initGraph(G); //already constructs root cluster, reassign - } - - -void ClusterGraph::reinitArrays() -{ - ListIterator itCluster = m_regClusterArrays.begin(); - for(; itCluster.valid(); ++itCluster) - (*itCluster)->reinit(m_clusterArrayTableSize); -} - - - -// Copy Function -void ClusterGraph::deepCopy(const ClusterGraph &C,Graph &G) -{ - - const Graph &cG = C; // original graph - - ClusterArray originalClusterTable(C); - NodeArray originalNodeTable(cG); - EdgeArray edgeCopy(cG); - - deepCopy(C,G,originalClusterTable, originalNodeTable, edgeCopy); -} - -void ClusterGraph::deepCopy(const ClusterGraph &C,Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable) -{ - - const Graph &cG = C; // original graph - - EdgeArray edgeCopy(cG); - - deepCopy(C,G,originalClusterTable, originalNodeTable, edgeCopy); -} - -void ClusterGraph::deepCopy(const ClusterGraph &C,Graph &G, - ClusterArray &originalClusterTable, - NodeArray &originalNodeTable, - EdgeArray &edgeCopy) -{ - G.clear(); - - const Graph &cG = C; // original graph - - m_pGraph = &G; - - m_nClusters = 0; - - initGraph(G); //arrays have already to be initialized for newnode - - m_updateDepth = C.m_updateDepth; - m_depthUpToDate = C.m_depthUpToDate; - - NodeArray orig(G); - node v; - edge e; - - forall_nodes(v,cG) - { - node w = G.newNode(); - orig[w] = v; - originalNodeTable[v] = w; - } - forall_edges(e,cG) - { - edge eNew = G.newEdge(originalNodeTable[e->adjSource()->theNode()], - originalNodeTable[e->adjTarget()->theNode()]); - edgeCopy[e] = eNew; - }//foralledges - - //m_clusterDepth.init(*this, 0); - - - // Construct cluster tree - cluster c = 0; - forall_clusters(c,C) - { - if (c == C.m_rootCluster) - { - originalClusterTable[c] = m_rootCluster; - //does not really need to be assigned HERE in for - m_rootCluster->depth() = 1; - OGDF_ASSERT(c->depth() == 1) - continue; - } - originalClusterTable[c] = newCluster(); - originalClusterTable[c]->depth() = c->depth(); - } - forall_clusters(c,C) - { - - if (c == C.m_rootCluster) - continue; - originalClusterTable[c]->m_parent = originalClusterTable[c->m_parent]; - originalClusterTable[c->m_parent]->m_children.pushBack(originalClusterTable[c]); - originalClusterTable[c]->m_it = originalClusterTable[c->m_parent]->m_children.rbegin(); - } - - forall_nodes(v,G) - reassignNode(v,originalClusterTable[C.clusterOf(orig[v])]); - - //ClusterArray* ca = ; - copyLCA(C, &originalClusterTable); -} - -//********************************************************* -//cluster search - -//We search for the lowest common cluster of a set of nodes. -//We first compute the common path of two nodes, then update path if root -//path from other nodes hits it . -//We always stop if we encounter root cluster. -cluster ClusterGraph::commonCluster(SList& nodes) -{ - //worst case running time #nodes x clustertreeheight-1 - //always <= complete tree run - //we could even use pathcompression... - //at any time, we stop if root is encountered as lowest - //common cluster of a node subset - - - if (nodes.empty()) return 0; - - //For simplicity, we use cluster arrays - ClusterArray commonPathHit(*this, 0); //count for clusters path hits - int runs = 0; //number of nodes already considered - cluster pathCluster; - SListIterator sIt = nodes.begin(); - node v1 = (*sIt); - if (nodes.size() == 1) return clusterOf(v1); - sIt++; - node v2 = (*sIt); - - cluster lowestCommon = commonCluster(v1, v2); - commonPathHit[lowestCommon] = 2; - pathCluster = lowestCommon; - while (pathCluster->parent()) - { - pathCluster = pathCluster->parent(); - commonPathHit[pathCluster] = 2; - } - runs = 2; - //we save direct lca access, it also lies on a runs hit path from root - while ((runs < nodes.size()) && (lowestCommon != m_rootCluster)) - { - sIt++; - node v = (*sIt); - pathCluster = clusterOf(v); - while (commonPathHit[pathCluster] == 0) - { - if (pathCluster->parent()) pathCluster = pathCluster->parent(); - else return m_rootCluster; //can never happen - }//while - //assign new (maybe same) lowest common - if (commonPathHit[pathCluster] == runs) lowestCommon = pathCluster; - commonPathHit[pathCluster] = commonPathHit[pathCluster]+1; - if (pathCluster == m_rootCluster) return m_rootCluster; - //update hits in path to root - while (pathCluster->parent()) - { - pathCluster = pathCluster->parent(); - commonPathHit[pathCluster] = commonPathHit[pathCluster]+1; - } - - runs++; - } - return lowestCommon; - - -}//commoncluster - -//lowest common cluster of v,w -cluster ClusterGraph::commonCluster(node v, node w) const -{ - cluster c1, c2; - return commonClusterLastAncestors(v, w, c1, c2); -}//commonCluster - -//lowest common cluster of v,w and its ancestors -cluster ClusterGraph::commonClusterLastAncestors(node v, - node w, - cluster& c1, - cluster& c2) const -{ - List e; - return commonClusterAncestorsPath(v, w, c1, c2, e); -}//commonClusterLastAncestors -//lowest common cluster and path between v and w containing it -//note that eL is directed from v to w -cluster ClusterGraph::commonClusterPath(node v, - node w, - List& eL) const -{ - cluster c1, c2; - return commonClusterAncestorsPath(v, w, c1, c2, eL); -}//commonClusterLastAncestors - -//note that eL is directed from v to w -cluster ClusterGraph::commonClusterAncestorsPath(node v, - node w, - cluster& c1, - cluster& c2, - List& eL) const -{ - OGDF_ASSERT(v->graphOf() == m_pGraph) - OGDF_ASSERT(w->graphOf() == m_pGraph) - - cluster cv = clusterOf(v); - cluster cw = clusterOf(w); - - - //clusters from v and w to common - List vList; - List wList; - - //CASE1 no search necessary - //if both nodes are in the same cluster, we return this cluster - //and have to check if c1 == c2 to have a (v,w) representation edge - if (cv == cw) - { - c1 = c2 = cv; - eL.pushBack(c1); - return cv; - } - - if (m_lcaNumber == INT_MAX - 1) m_lcaNumber = 0; - else m_lcaNumber++; - if (!m_lcaSearch) - { - m_lcaSearch = OGDF_NEW ClusterArray(*this, -1); - m_vAncestor = OGDF_NEW ClusterArray(*this, 0); - m_wAncestor = OGDF_NEW ClusterArray(*this, 0); - } - - //CASE2: one of the nodes hangs at root: save root as ancestor - //any other case: save cluster of node as ancestor, too, to check this - //case:: common = xCluster != yCluster - //(*m_vAncestor)[rootCluster()] = rootCluster(); - //(*m_wAncestor)[rootCluster()] = rootCluster(); - (*m_vAncestor)[cv] = 0; - (*m_wAncestor)[cw] = 0; - - //we rely on the fact all nodes are in the rootcluster or - //that parent is initialized to zero to terminate - - //we start with different clusters due to CASE1 - //save the ancestor information - (*m_lcaSearch)[cw] = m_lcaNumber; //not really necessary, we won't return - (*m_lcaSearch)[cv] = m_lcaNumber; - vList.pushBack(cv); - wList.pushBack(cw); - - //we break and return if we find a common node - //before we reach the rootcluster - do - { - if (cv->parent()) //root reached? - { - (*m_vAncestor)[cv->parent()] = cv; - cv = cv->parent(); - //was cv visited on path from w - if ((*m_lcaSearch)[cv] == m_lcaNumber) - { - c1 = (*m_vAncestor)[cv]; - c2 = (*m_wAncestor)[cv]; - //setup list - ListIterator itC = vList.begin(); - - while (itC.valid()) - { - eL.pushBack(*itC); - itC++; - } - itC = wList.rbegin(); - while (itC.valid() && ((*itC) != cv)) - itC--; - while (itC.valid()) - { - eL.pushBack(*itC); - itC--; - } - - return cv; - } - vList.pushBack(cv); - (*m_lcaSearch)[cv] = m_lcaNumber; - }//if not root reached on cvpath - - if (cw->parent()) - { - (*m_wAncestor)[cw->parent()] = cw; - cw = cw->parent(); - //was cw visited on path from v - if ((*m_lcaSearch)[cw] == m_lcaNumber) - { - c1 = (*m_vAncestor)[cw]; - c2 = (*m_wAncestor)[cw]; - //setup list - ListIterator itC = vList.begin(); - while (itC.valid() && ((*itC) != cw)) - { - eL.pushBack(*itC); - itC++; - } - - eL.pushBack(cw); - - itC = wList.rbegin(); - while (itC.valid()) - { - eL.pushBack(*itC); - itC--; - } - - return cw; - } - wList.pushBack(cw); - (*m_lcaSearch)[cw] = m_lcaNumber; - - }//if not root reached on cwpath - } while ( cv->parent() || cw->parent() ); - - //v,w should be at least together in the rootcluster - c1 = (*m_vAncestor)[rootCluster()]; - c2 = (*m_wAncestor)[rootCluster()]; - return rootCluster(); - -}//commonclusterlastAncestors - -void ClusterGraph::copyLCA( - const ClusterGraph &C, - ClusterArray* clusterCopy) -{ - if (m_lcaSearch) - { - delete m_lcaSearch; - delete m_vAncestor; - delete m_wAncestor; - }//if - if (C.m_lcaSearch) - { - //otherwise, initialization won't work - m_clusterArrayTableSize = C.m_clusterArrayTableSize; - - m_lcaSearch = OGDF_NEW ClusterArray(*this, -1);//(*C.m_lcaSearch); - - m_vAncestor = OGDF_NEW ClusterArray(*this, 0); //*C.m_vAncestor); - //m_vAncestor->init(*this, 0), - m_wAncestor = OGDF_NEW ClusterArray(*this, 0);//*C.m_wAncestor); - //setting of clusters is not necessary! - //(*m_v/wAncestor)[(*clusterCopy)[c]]= (*(C.m_v/wAncestor))[c]; - }//if -}//copylca - -//--------------------------------------------------------- -// check the graph for empty clusters -//--------------------------------------------------------- -//we never set rootcluster to be one of the empty clusters!! -void ClusterGraph::emptyClusters(SList& emptyCluster, - SList* checkCluster) -{ - emptyCluster.clear(); - cluster cc; - //for all nodes = #nodes - if (checkCluster) - { - SListIterator it = checkCluster->begin(); - - while (it.valid()) - { - if ((*it)->cCount() + (*it)->nCount() == 0) - if ((*it) != rootCluster()) //we dont add rootcluster - emptyCluster.pushBack((*it)); - it++; - }//while - }//if checkcluster given - else - { - forall_clusters(cc, *this) - { - if (cc->cCount() + cc->nCount() == 0) - if (cc != rootCluster()) //we dont add rootcluster - emptyCluster.pushBack(cc); - }//forallclusters - }//else checkcluster - //other clusters can get empty, too, if we delete these - ClusterArray delCount(*this, 0); - SList emptyParent; - SListIterator itC = emptyCluster.begin(); - while (itC.valid()) - { - //count deleted children - cluster runc = (*itC)->parent(); - if (runc) //is always the case as long as root was not inserted to list - { - delCount[runc]++; - while ((runc->nCount() == 0) && (runc->cCount() == delCount[runc])) - { - if (runc == rootCluster()) break; - emptyParent.pushBack(runc); - runc = runc->parent(); - delCount[runc]++; - }//while parent emptied - }//if not runc = root->parent - - itC++; - }//while empty leaves - - emptyCluster.conc(emptyParent); - //for reinsertion, start at emptycluster's back - -}//emptyClusters - -//--------------------------------------------------------- -// newCluster, delCluster, createCluster -//--------------------------------------------------------- - -// Inserts a new cluster prescribing its parent -cluster ClusterGraph::newCluster(cluster parent, int id) -{ - OGDF_ASSERT(parent); - cluster c; - if (id > 0) - c = newCluster(id); - else - c = newCluster(); - parent->m_children.pushBack(c); - c->m_it = parent->m_children.rbegin(); - c->m_parent = parent; - c->depth() = parent->depth() + 1; - - return c; -} - -//Insert a new cluster with given ID, precondition: id not used -//has to be updated in the same way as newcluster() -cluster ClusterGraph::newCluster(int id) -{ - m_nClusters++; - m_adjAvailable = false; - m_postOrderStart = 0; - if (id >= m_clusterIdCount) m_clusterIdCount = id+1; - if (m_clusterIdCount >= m_clusterArrayTableSize) - { - m_clusterArrayTableSize = - m_pGraph->nextPower2(m_clusterArrayTableSize, id); - for(ListIterator it = m_regClusterArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_clusterArrayTableSize); - } - } - #ifdef OGDF_DEBUG - cluster c = OGDF_NEW ClusterElement(this,id); - #else - cluster c = OGDF_NEW ClusterElement(id); - #endif - m_clusters.pushBack(c); - // notify observers - for(ListIterator it = m_regObservers.begin(); - it.valid(); ++it) (*it)->clusterAdded(c); - return c; -} - -// Inserts a new cluster -//has to be updated in the same way as newcluster(id) -cluster ClusterGraph::newCluster() -{ - m_nClusters++; - m_adjAvailable = false; - m_postOrderStart = 0; - if (m_clusterIdCount == m_clusterArrayTableSize) - { - m_clusterArrayTableSize <<= 1; - for(ListIterator it = m_regClusterArrays.begin(); - it.valid(); ++it) - { - (*it)->enlargeTable(m_clusterArrayTableSize); - } - } - #ifdef OGDF_DEBUG - cluster c = OGDF_NEW ClusterElement(this,m_clusterIdCount++); - #else - cluster c = OGDF_NEW ClusterElement(m_clusterIdCount++); - #endif - m_clusters.pushBack(c); - // notify observers - for(ListIterator it = m_regObservers.begin(); - it.valid(); ++it) (*it)->clusterAdded(c); - return c; -} - -cluster ClusterGraph::createEmptyCluster(const cluster parent, int clusterId) -{ - //if no id given, use next free id - if (clusterId < 0) clusterId = m_clusterIdCount; - //create the new cluster - cluster cnew; - if (parent) - cnew = newCluster(parent, clusterId); - else - cnew = newCluster(m_rootCluster, clusterId); - return cnew; -}//createemptycluster - -cluster ClusterGraph::createCluster(SList& nodes, const cluster parent) -{ - cluster c; - if (m_allowEmptyClusters) - { - c = doCreateCluster(nodes, parent); - return c; - } - else - { - SList emptyCluster; - - c = doCreateCluster(nodes, emptyCluster, parent); - - SListIterator sIt = emptyCluster.begin(); - while (sIt.valid()) - { - delCluster((*sIt)); - - //root cluster can never be empty, as we deleted a node - sIt++; - }//While - } - return c; -} - -cluster ClusterGraph::doCreateCluster(SList& nodes, - const cluster parent, - int clusterId) -{ - - if (nodes.empty()) return 0; - - //if no id given, use next free id - if (clusterId < 0) clusterId = m_clusterIdCount; - //create the new cluster - cluster cnew; - if (parent) - cnew = newCluster(parent, clusterId); - else - cnew = newCluster(m_rootCluster, clusterId); - - //insert nodes in new cluster - SListIterator it = nodes.begin(); - while (it.valid()) - { - reassignNode((*it), cnew); - it++; - }//while - - return cnew; -}//createcluster - -cluster ClusterGraph::doCreateCluster(SList& nodes, - SList& emptyCluster, - const cluster parent, - int clusterId) -{ - // Even if m_allowEmptyClusters is set we check if a cluster - // looses all of its nodes and has - // no more entries and childs. This can be used for special cluster - // object handling or for deletion if m_allowEmptyClusters is not set - // if it is not the new parent, it can be deleted - // running time max(#cluster, length(nodelist)) - // TODO: Parameter, der dies auslaesst, da hohe Laufzeit - // hier macht das nur Sinn, wenn es schneller ist als forallclusters, - // sonst koennte man es ja auch aussen testen, aber bisher ist es nicht - // schneller implementiert - // Vorgehen: hash auf cluster index, falls nicht gesetzt, in liste einfuegen - // und als checkcluster an emptycluster uebergeben - - if (nodes.empty()) return 0; - - //if no id given, use next free id - if (clusterId < 0) clusterId = m_clusterIdCount; - //create the new cluster - cluster cnew; - if (parent) - cnew = newCluster(parent, clusterId); - else - cnew = newCluster(m_rootCluster, clusterId); - - //insert nodes in new cluster - SListIterator it = nodes.begin(); - while (it.valid()) - { - reassignNode((*it), cnew); - it++; - }//while - - //should be: only for changed clusters (see comment above) - //it is important to save the cluster in an order - //that allows deletion as well as reinsertion - emptyClusters(emptyCluster); - //for reinsertion, start at emptycluster's back - - return cnew; -}//createcluster - -// Deletes cluster c -// All subclusters become children of parent cluster -// Precondition: c is not the root cluster -// updating of cluster depth information pumps running time -// up to worst case O(#C) -void ClusterGraph::delCluster(cluster c) -{ - OGDF_ASSERT(c != 0 && c->graphOf() == this && c != m_rootCluster) - - // notify observers - for(ListIterator it = m_regObservers.begin(); - it.valid(); ++it) (*it)->clusterDeleted(c); - - --m_nClusters; - m_adjAvailable = false; - - c->m_parent->m_children.del(c->m_it); - c->m_it = 0; - - while (!c->m_children.empty()) - { - cluster trace = c->m_children.popFrontRet(); - trace->m_parent = c->m_parent; - trace->m_parent->m_children.pushBack(trace); - trace->m_it = trace->m_parent->m_children.rbegin(); - - //only recompute depth if option set and it makes sense - if (m_updateDepth && m_depthUpToDate) - { - //update depth for all children in subtree - OGDF_ASSERT(trace->depth() == trace->parent()->depth()+2) - pullUpSubTree(trace); - //could just set depth-1 here - //trace->depth() = trace->parent()->depth()+1; - - }///if depth update - else m_depthUpToDate = false; - } - while (!c->m_entries.empty()) - { - node v = c->m_entries.popFrontRet(); - m_nodeMap[v] = 0; - reassignNode(v,c->m_parent); - } - - m_clusters.del(c); -} - -//pulls up depth of subtree located at c by one -//precondition: depth is consistent -//we dont ask for depthuptodate since the caller needs -//to know for himself if he wants the tree to be pulled -//for any special purpose -void ClusterGraph::pullUpSubTree(cluster c) -{ - c->depth() = c->depth() - 1; - ListConstIterator it = c->getChildren().begin(); - while (it.valid()) - { - pullUpSubTree(*it); - it++; - } - -} - -//--------------------------------------------------------- -// clear, clearClusterTree -//--------------------------------------------------------- - -void ClusterGraph::clear() -{ - //split condition - if (m_lcaSearch) - { - delete m_lcaSearch; - delete m_vAncestor; - delete m_wAncestor; - } - if (m_nClusters != 0) - { - clearClusterTree(m_rootCluster); - m_clusters.del(m_rootCluster); - } - //no clusters, so we can restart at 0 - m_clusterIdCount = 0; - m_nClusters = 0; -} - - -// Removes the Clustering of a Tree and frees the allocated memory -void ClusterGraph::clearClusterTree(cluster c) -{ - cluster trace = 0; - cluster parent = c->parent(); - m_postOrderStart = 0; - m_adjAvailable = false; - - List children = c->getChildren(); - List attached; - - while (!children.empty()) - { - trace = children.popFrontRet(); - clearClusterTree(trace,attached); - } - - if (parent != 0) - { - ListIterator it; - for (it = attached.begin();it.valid();it++) - { - m_nodeMap[(*it)] = parent; - parent->m_entries.pushBack((*it)); - m_itMap[(*it)] = parent->m_entries.rbegin(); - } - m_clusters.del(c); - } - else if (c == m_rootCluster) - { - ListIterator it; - for (it = attached.begin();it.valid();it++) - { - m_nodeMap[(*it)] = m_rootCluster; - m_rootCluster->m_entries.pushBack((*it)); - m_itMap[(*it)] = m_rootCluster->m_entries.rbegin(); - } - m_rootCluster->m_children.clear(); - } -} - -void ClusterGraph::clearClusterTree(cluster c,List &attached) -{ - cluster trace; - List children = c->getChildren(); - attached.conc(c->m_entries); - m_adjAvailable = false; - - while (!children.empty()) - { - trace = children.popFrontRet(); - clearClusterTree(trace,attached); - } - m_clusters.del(c); -} - -//don't delete root cluster -void ClusterGraph::semiClear() -{ - //split condition - if (m_lcaSearch) - { - delete m_lcaSearch; - delete m_vAncestor; - delete m_wAncestor; - } - if (m_nClusters != 0) - { - //clear the cluster structure under root cluster - clearClusterTree(m_rootCluster); - //now delete all rootcluster entries - while (!m_rootCluster->m_entries.empty()) - { - node v = m_rootCluster->m_entries.popFrontRet(); - m_nodeMap[v] = 0; - } - } - //no child clusters, so we can restart at 1 - m_clusterIdCount = 1; - m_nClusters = 1; -} - -//reassign cluster depth for clusters in subtree rooted at c -void ClusterGraph::computeSubTreeDepth(cluster c) const -{ - if (c == rootCluster()) m_depthUpToDate = true; - if (!(c->parent())) c->depth() = 1; - else c->depth() = c->parent()->depth() + 1; - ListConstIterator it = c->getChildren().begin(); - while (it.valid()) - { - computeSubTreeDepth(*it); - it++; - } - -} - -//move cluster from old parent to an other -void ClusterGraph::moveCluster(cluster c, cluster newParent) -{ - if (c == rootCluster()) return; - if ((c == 0) || (newParent == 0)) return; //no cheap tricks - if (c->parent() == newParent) return; //no work to do - - cluster oldParent = c->parent(); - //we dont move root - OGDF_ASSERT(oldParent) - - //check if we move to a descendant - cluster crun = newParent->parent(); - bool descendant = false; - while (crun) - { - if (crun == c) - { - descendant = true; - break; - } - crun = crun->parent(); - }//while running upwards - - //do not allow to move empty clusters to descendants - if (descendant && (c->nCount() == 0)) - return; - - // save postorder for old parent - bool newOrder = false; - if (!m_postOrderStart) - { - newOrder = true; - } - - //temporarily only recompute postorder for all clusters - - oldParent->m_children.del(c->m_it); - newParent->m_children.pushBack(c); - c->m_it = newParent->m_children.rbegin(); - c->m_parent = newParent; - - //update the cluster depth information in the subtree - //If moved to descendant, recompute - //depth for parent (including all brother trees) - if (descendant) - { - //how do we move: - //only entries with c? => may be empty - //we currently dont allow this, because it makes - //no sense, you could just delete the cluster or move - //the children - //move all children to oldparent - - while (!c->m_children.empty()) - { - cluster child = c->m_children.popFrontRet(); - child->m_parent = oldParent; - child->m_parent->m_children.pushBack(child); - child->m_it = child->m_parent->m_children.rbegin(); - //child++; - } - - //recompute depth only if option set AND it makes sense at that point - if (m_updateDepth && m_depthUpToDate) - computeSubTreeDepth(oldParent); - else m_depthUpToDate = false; - }//moved to descendant - else - { - if (m_updateDepth && m_depthUpToDate) - computeSubTreeDepth(c); - else m_depthUpToDate = false; - } - - // update postorder for new parent - // we only recompute postorder for all clusters - // because of special cases like move to descendant... - if (newOrder) postOrder(); - else postOrder(); - - m_adjAvailable = false; - - //checkPostOrder(); -}//move cluster - - -//***************** -//postorder updates - -//leftmostcluster in subtree rooted at c, has postorderpred for subtree -cluster ClusterGraph::leftMostCluster(cluster c) const -{ - cluster result = c; - if (!c) return 0; - while (!result->m_children.empty()) - { - result = result->m_children.front(); - } - return result; -}//leftMostCluster - -//searches for predecessor of SUBTREE at c -cluster ClusterGraph::postOrderPredecessor(cluster c) const -{ - //all clusters on a path from root to leftmost cluster in tree - //have no predecessor for their subtree - cluster run = c; - ListConstIterator it; - do - { - //predecessor of clustertree is 0 - if (run == m_rootCluster) return 0; - it = run->m_it; - //a child to the left is the immediate predecessor, - //otherwise we go one level up - if (it == (run->m_parent)->m_children.begin()) - run = run->parent(); - else return (*(it.pred())); - - } while (run); - - return 0; -}//postorderpredecessor - -//*************** -//node assignment -//Assigns a node to a new cluster -void ClusterGraph::assignNode(node v, cluster c) -{ - m_adjAvailable = false; - m_postOrderStart = 0; - m_nodeMap[v] = c; - c->m_entries.pushBack(v); - m_itMap[v] = c->m_entries.rbegin(); -} - - -//Reassigns a node to a new cluster -void ClusterGraph::reassignNode(node v, cluster c) -{ - OGDF_ASSERT(v->graphOf() == m_pGraph); - OGDF_ASSERT(c->graphOf() == this); - - unassignNode(v); - m_nodeMap[v] = c; - c->m_entries.pushBack(v); - m_itMap[v] = c->m_entries.rbegin(); -} - - -//Unassigns a node of cluster -//Note: Nodes can already be unassigned by the nodeDeleted function. -void ClusterGraph::unassignNode(node v) -{ - m_adjAvailable = false; - m_postOrderStart = 0; - - removeNodeAssignment(v); -} - - -//--------------------------------------------------------- -// Sort clusters in post order -//--------------------------------------------------------- - -// Start function for post order -void ClusterGraph::postOrder() const -{ - SListPure L; - postOrder(m_rootCluster,L); - cluster c = 0; - cluster prev = L.popFrontRet(); - prev->m_pPrev = 0; - m_postOrderStart = prev; - while (!L.empty()) - { - c = L.popFrontRet(); - prev->m_pNext = c; - c->m_pPrev = prev; - prev = c; - } - if (c != 0) - c->m_pNext = 0; - else - m_postOrderStart->m_pNext = 0; -#ifdef OGDF_DEBUG - forall_clusters(c, *this) - { - cluster cp = leftMostCluster(c); - OGDF_ASSERT(cp->pPred() == postOrderPredecessor(c)) - } -#endif -} - -void ClusterGraph::checkPostOrder() const -{ - SListPure L; - postOrder(m_rootCluster,L); - cluster c = 0; - cluster prev = L.popFrontRet(); - OGDF_ASSERT(prev->m_pPrev == 0); - - while (!L.empty()) - { - c = L.popFrontRet(); - OGDF_ASSERT(prev->m_pNext == c) - OGDF_ASSERT(c->m_pPrev == prev) - prev = c; - } - if (c != 0) - { - OGDF_ASSERT(c->m_pNext == 0) - } - else - { - OGDF_ASSERT(m_postOrderStart->m_pNext == 0); - } -} -// Recursive function for post order -void ClusterGraph::postOrder(cluster c,SListPure &L) const -{ - ListIterator it; - for (it = c->m_children.begin(); it.valid(); it++) - postOrder((*it),L); - L.pushBack(c); -} - - - - -//--------------------------------------------------------- -// Methods for debugging -//--------------------------------------------------------- - - -// checks the consistency of the data structure -// (for debugging only) -bool ClusterGraph::consistencyCheck() -{ - - ClusterArray visitedClusters((*this),false); - NodeArray visitedNodes((*m_pGraph),false); - - - cluster c = 0; - forall_postOrderClusters(c,(*this)) - { - visitedClusters[c] = true; - ListIterator itn; - for (itn = c->m_entries.begin(); itn.valid(); itn++) - { - node v = *itn; - if (m_nodeMap[v] != c) - return false; - visitedNodes[v] = true; - } - } - forall_clusters(c,(*this)) - if (!visitedClusters[c]) - return false; - node v; - forall_nodes(v,(*m_pGraph)) - if (!visitedNodes[v]) - return false; - return true; -} - - - -bool ClusterGraph::representsCombEmbedding() -{ - - if (!m_adjAvailable) - return false; - - if (!consistencyCheck()) - return false; - - - cluster c = 0; - forall_postOrderClusters(c,(*this)) - { - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << "__________________________________________________________________" - << endl << endl - << "Testing cluster " << c << endl - << "Check on AdjList of c" << endl; - adjEntry adjDD; - forall_cluster_adj(adjDD,c) - cout << adjDD << "; "; - cout << endl; - } - #endif - - if (c != m_rootCluster) - { - - ListIterator it; - it = c->firstAdj(); - adjEntry start = *it; - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << "firstAdj " << start << endl; } - #endif - - while (it.valid()) - { - AdjEntryArray visitedAdjEntries((*m_pGraph),false); - - ListIterator succ = it.succ(); - adjEntry adj = *it; - adjEntry succAdj; - - if (succ.valid()) - succAdj = *succ; - else - succAdj = start; // reached the last outgoing edge - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << "Check next " << endl; - cout << "current in adj list of" << adj << endl; - cout << "succ in adj list of c " << succAdj << endl; - cout << "cyclic succ in outer face " << adj->cyclicSucc() << endl; - } - #endif - - - - if (adj->cyclicSucc() != succAdj) - // run along the outer face of the cluster - // until you find the next outgoing edge - { - adjEntry next = adj->cyclicSucc(); - adjEntry twin = next->twin(); - - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << "Running along the outer face ... " << endl; - cout << "next adj " << next << endl; - cout << "twin adj " << twin << endl; - } - #endif - - if (visitedAdjEntries[twin]) - return false; - visitedAdjEntries[twin] = true; - while ( next != succAdj) - { - next = twin->cyclicSucc(); - twin = next->twin(); - #ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)){ - cout << "Running along the outer face ... " << endl; - cout << "next adj " << next << endl; - cout << "twin adj " << twin << endl; - } - #endif - if (visitedAdjEntries[twin]) - return false; - visitedAdjEntries[twin] = true; - } - - } - // else - // next edge is also outgoing - - it = succ; - } - } - } - - - return true; - -} - - - - -// registers a cluster array -ListIterator ClusterGraph::registerArray( - ClusterArrayBase *pClusterArray) const -{ - return m_regClusterArrays.pushBack(pClusterArray); -} - -// unregisters a cluster array -void ClusterGraph::unregisterArray(ListIterator it) const -{ - m_regClusterArrays.del(it); -} - -//! Registers a ClusterGraphObserver. -ListIterator ClusterGraph::registerObserver(ClusterGraphObserver *pObserver) const -{ - return m_regObservers.pushBack(pObserver); -} - -//! Unregisters a ClusterGraphObserver. -void ClusterGraph::unregisterObserver(ListIterator it) const -{ - m_regObservers.del(it); -} -//--------------------------------------------------------- -// Methods for printing -//--------------------------------------------------------- - - -// writes graph in GML format to file fileName -void ClusterGraph::writeGML(const char *fileName) -{ - ofstream os(fileName); - writeGML(os); -} - -// writes graph in GML format to output stream os -void ClusterGraph::writeGML(ostream &os) -{ - NodeArray nId(*m_pGraph); - ClusterArray cId(*this); - int nextId = 0; - - os << "Creator \"ogdf::ClusterGraph::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,*m_pGraph) { - os << " node [\n"; - os << " id " << (nId[v] = nextId++) << "\n"; - os << " ]\n"; // node - } - - edge e; - forall_edges(e,*m_pGraph) { - os << " edge [\n"; - os << " source " << nId[e->source()] << "\n"; - os << " target " << nId[e->target()] << "\n"; - os << " ]\n"; // edge - } - - String scip = " "; - nextId = 0; - writeCluster(os,nId,cId,nextId,m_rootCluster,scip); - - os << "]\n"; // graph -} - - -// recursively write the cluster structure in GML -void ClusterGraph::writeCluster(ostream &os, - NodeArray &nId, - ClusterArray & cId, - int &nextId, - cluster c, - String scip) -{ - String newScip = scip; - newScip+=" "; - os << scip << "cluster [\n"; - os << scip << " id " << (cId[c] = nextId++) << "\n"; - ListIterator it; - for (it = c->m_children.begin(); it.valid(); it++) - writeCluster(os,nId,cId,nextId,*it,newScip); - ListIterator itn; - for (itn = c->m_entries.begin(); itn.valid(); itn++) - os << scip << " node " << nId[*itn] << "\n"; - os << scip << "]\n"; // cluster -} - - -// recursively write the cluster structure in GraphWin GML -void ClusterGraph::writeGraphWinCluster(ostream &os, - NodeArray &nId, - NodeArray &nStr, - ClusterArray & cId, - ClusterArray & cStr, - int &nextId, - cluster c, - String scip) -{ - String newScip = scip; - newScip+=" "; - if (c == m_rootCluster) - os << scip << "rootcluster [\n"; - else - { - os << scip << "cluster [\n"; -// os << scip << " id " << (cId[c] = nextId++) << "\n"; - os << scip << " id " << c->index() << "\n"; - char newLabel[124]; -// sprintf(newLabel,"C%d",cId[c]); - ogdf::sprintf(newLabel,124,"C%d",c->index()); - cStr[c] = newLabel; - os << scip << " label \"" << cStr[c] << "\"\n"; - - } - ListIterator it; - for (it = c->m_children.begin(); it.valid(); it++) - writeGraphWinCluster(os,nId,nStr,cId,cStr,nextId,*it,newScip); - ListIterator itn; - for (itn = c->m_entries.begin(); itn.valid(); itn++) - os << scip << " vertex \"v" << nId[*itn] << "\"\n"; - os << scip << "]\n"; // cluster -} - - -//++++++++++++++++++++++++++++++++++++++++++++ -//reading graph, cluster structure -bool ClusterGraph::readClusterGML(const char* fileName, - Graph& G) -{ - ifstream is(fileName); - if (!is) - return false; // couldn't open file - - return readClusterGML(is, G); -} - -bool ClusterGraph::readClusterGML(istream& is, - Graph& G) -{ - bool result; - GmlParser gml(is); - if (gml.error()) - return false; - - result = gml.read(G); - - if (!result) return false; - - return gml.readCluster(G, *this); -} - - -// read Cluster Graph from OGML file -//bool ClusterGraph::readClusterGraphOGML(const char* fileName, -// ClusterGraph& CG, -// Graph& G) -//{ -// ifstream is(fileName); -// // not able to open file -// if (!is) return false; -// -// OgmlParser *op = new OgmlParser(); -// // build graph -// // method read contains the validation -// if (!op->read(fileName, G, CG, *this)){ -// delete(op); -// cerr << "ERROR occured while reading. Aborting." << endl << flush; -// return false; -// } -// -// delete(op); -// return true; -//}; - - -} // end namespace ogdf - -//**************************************************************** -ostream &operator<<(ostream &os, ogdf::cluster c) -{ - if (c) os << c->index(); else os << "nil"; - return os; -} diff --git a/ext/OGDF/src/cluster/ClusterGraphAttributes.cpp b/ext/OGDF/src/cluster/ClusterGraphAttributes.cpp deleted file mode 100644 index cc842f208..000000000 --- a/ext/OGDF/src/cluster/ClusterGraphAttributes.cpp +++ /dev/null @@ -1,740 +0,0 @@ -/* - * $Revision: 2616 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 15:34:43 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implement class ClusterGraphAttributes - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -ClusterGraphAttributes::ClusterGraphAttributes( - ClusterGraph& cg, - long initAttributes) -: GraphAttributes(cg.getGraph(), initAttributes | edgeType | nodeType | - nodeGraphics | edgeGraphics), m_clusterTemplate(cg), m_pClusterGraph(&cg) -//we should initialize m__clusterinfo here -{ - //should we always fill the cluster infos here? -}//constructor - - -//reinitialize graph -void ClusterGraphAttributes::init(ClusterGraph &cg, long initAttributes) -{ - m_pClusterGraph = &cg; - m_clusterInfo.clear(); - - //need to initialize GraphAttributes with getGraph() - //we only use parameter initAttributes here in constrast - //to the initialization in the constructor - GraphAttributes::init(cg.getGraph(), initAttributes ); -} - - -// -// calculates the bounding box of the graph including clusters -const DRect ClusterGraphAttributes::boundingBox() const -{ - DRect bb = GraphAttributes::boundingBox(); - double minx = bb.p1().m_x; - double miny = bb.p1().m_y; - double maxx = bb.p2().m_x; - double maxy = bb.p2().m_y; - - cluster c; - forall_clusters(c,*m_pClusterGraph) - { - if(c == m_pClusterGraph->rootCluster()) - continue; - - double x1 = clusterXPos(c); - double y1 = clusterYPos(c); - double x2 = x1 + clusterWidth(c); - double y2 = y1 + clusterHeight(c); - - if (x1 < minx) minx = x1; - if (x2 > maxx) maxx = x2; - if (y1 < miny) miny = y1; - if (y2 > maxy) maxy = y2; - } - - return DRect(minx, miny, maxx, maxy); -} - - -void ClusterGraphAttributes::updateClusterPositions(double boundaryDist) -{ - cluster c; - //run through children and nodes and update size accordingly - //we use width, height temporarily to store max values - forall_postOrderClusters(c,*m_pClusterGraph) - { - ListIterator nit = c->nBegin(); - ListConstIterator cit = c->cBegin(); - //Initialize with first element - if (nit.valid()) - { - clusterXPos(c->index()) = m_x[*nit] - m_width[*nit]/2; - clusterYPos(c->index()) = m_y[*nit] - m_height[*nit]/2; - clusterWidth(c->index()) = m_x[*nit] + m_width[*nit]/2; - clusterHeight(c->index()) = m_y[*nit] + m_height[*nit]/2; - nit++; - } - else - { - if (cit.valid()) - { - clusterXPos(c->index()) = clusterXPos(*cit); - clusterYPos(c->index()) = clusterYPos(*cit); - clusterWidth(c->index()) = clusterXPos(*cit) + clusterWidth(*cit); - clusterHeight(c->index()) = clusterYPos(*cit) + clusterHeight(*cit); - cit++; - } - else - { - clusterXPos(c->index()) = 0.0; - clusterYPos(c->index()) = 0.0; - clusterWidth(c->index()) = 1.0; - clusterHeight(c->index()) = 1.0; - } - } - //run through elements and update - while (nit.valid()) - { - if (clusterXPos(c->index()) > m_x[*nit] - m_width[*nit]/2) - clusterXPos(c->index()) = m_x[*nit] - m_width[*nit]/2; - if (clusterYPos(c->index()) > m_y[*nit] - m_height[*nit]/2) - clusterYPos(c->index()) = m_y[*nit] - m_height[*nit]/2; - if (clusterWidth(c->index()) < m_x[*nit] + m_width[*nit]/2) - clusterWidth(c->index()) = m_x[*nit] + m_width[*nit]/2; - if (clusterHeight(c->index()) < m_y[*nit] + m_height[*nit]/2) - clusterHeight(c->index()) = m_y[*nit] + m_height[*nit]/2; - nit++; - } - while (cit.valid()) - { - if (clusterXPos(c->index()) > clusterXPos((*cit)->index())) - clusterXPos(c->index()) = clusterXPos((*cit)->index()); - if (clusterYPos(c->index()) > clusterYPos((*cit)->index())) - clusterYPos(c->index()) = clusterYPos((*cit)->index()); - if (clusterWidth(c->index()) < clusterXPos((*cit)->index()) + clusterWidth((*cit)->index())) - clusterWidth(c->index()) = clusterXPos((*cit)->index()) + clusterWidth((*cit)->index()); - if (clusterHeight(c->index()) < clusterYPos((*cit)->index()) + clusterHeight((*cit)->index())) - clusterHeight(c->index()) = clusterYPos((*cit)->index()) + clusterHeight((*cit)->index()); - cit++; - } - clusterXPos(c->index()) -= boundaryDist; - clusterYPos(c->index()) -= boundaryDist; - clusterWidth(c->index()) = clusterWidth(c->index()) - clusterXPos(c->index()) + boundaryDist; - clusterHeight(c->index()) = clusterHeight(c->index()) - clusterYPos(c->index()) + boundaryDist; - } -} - - -void ClusterGraphAttributes::writeGML(const char *fileName) -{ - ofstream os(fileName); - writeGML(os); -} - - -void ClusterGraphAttributes::writeGML(ostream &os) -{ - NodeArray nId(*m_pGraph); - - int nextId = 0; - - os.setf(ios::showpoint); - - GraphAttributes::writeGML(os); - - // set index string for cluster entries - node v; - forall_nodes(v,*m_pGraph) - { - nId[v] = nextId++; - } - - // output the cluster information - String indent = "\0"; - nextId = 1; - writeGraphWinCluster(os, nId, nextId, - m_pClusterGraph->rootCluster(), indent); -} - - -// recursively write the cluster structure in GML -void ClusterGraphAttributes::writeCluster( - ostream &os, - NodeArray &nId, - ClusterArray & cId, - int &nextId, - cluster c, - String indent) -{ - String newindent = indent; - newindent += " "; - os << indent << "cluster [\n"; - os << indent << " id " << (cId[c] = nextId++) << "\n"; - ListConstIterator it; - for (it = c->cBegin(); it.valid(); it++) - writeCluster(os,nId,cId,nextId,*it,newindent); - ListConstIterator itn; - for (itn = c->nBegin(); itn.valid(); itn++) - os << indent << " node " << nId[*itn] << "\n"; - os << indent << "]\n"; // cluster -} - - -// recursively write the cluster structure in GraphWin GML -void ClusterGraphAttributes::writeGraphWinCluster( - ostream &os, - NodeArray &nId, - int &nextId, - cluster c, - String indent - ) -{ - String newindent = indent; - newindent += " "; - - if (c == m_pClusterGraph->rootCluster()) - os << indent << "rootcluster [\n"; - else - { - os << indent << "cluster [\n"; - os << indent << " id " << c->index() << "\n"; - - const String &templStr = m_clusterTemplate[c]; - if(templStr.length() > 0) { - // GDE extension: Write cluster template and custom attribute - os << " template "; - writeLongString(os, templStr); - os << "\n"; - - os << " label "; - writeLongString(os, clusterLabel(c)); - os << "\n"; - - } else { - os << indent << " label \"" << clusterLabel(c) << "\"\n"; - } - - os << indent << " graphics [\n"; - - double shiftPos; - shiftPos = clusterYPos(c->index()); - - os << indent << " x " << clusterXPos(c->index()) << "\n"; - os << indent << " y " << shiftPos/*clusterYPos(c->index())*/ << "\n"; - - os << indent << " width " << clusterWidth(c->index()) << "\n"; - os << indent << " height " << clusterHeight(c->index()) << "\n"; - os << indent << " fill \"" << clusterFillColor(c->index()) << "\"\n"; - os << indent << " pattern " << clusterFillPattern(c->index()) << "\n"; - - //border line styles - os << indent << " color \"" << clusterColor(c) << "\"\n"; - os << indent << " lineWidth " << clusterLineWidth(c) << "\n"; - //save space by defaulting - if (clusterLineStyle(c) != esSolid) - os << indent << " stipple " << clusterLineStyle(c) << "\n"; - - os << indent << " style \"rectangle\"\n"; - - os << indent << " ]\n"; //graphics - } - - // write contained clusters - ListConstIterator it; - for (it = c->cBegin(); it.valid(); it++) - writeGraphWinCluster(os, nId, nextId, *it, newindent); - - // write contained nodes - ListConstIterator itn; - for (itn = c->nBegin(); itn.valid(); itn++) - os << indent << "vertex \"" << nId[*itn] << "\"\n"; - - os << indent << "]\n"; // cluster -} - - -const char NEWLINE('\n'); // newline character -const char INDENTCHAR(' '); // indent character -const int INDENTSIZE(2); // indent size - - -class omani -{ - int m_n; - ostream& (*m_f)(ostream&, int); - -public: - omani(ostream& (*f)(ostream&, int), int n) : m_n(n), m_f(f) { } - - friend ostream& operator<<(ostream& os, omani man) { - return man.m_f(os, man.m_n); - } -}; - -ostream& padN(ostream& os, int depth) -{ - int n = INDENTSIZE * depth; - for( ; n > 0; --n) - os.put(INDENTCHAR); - - return os; -} - -omani ind(int depth) -{ - return omani(&padN, depth); -} - - -ostream &ind(ostream &os, int depth) -{ - int n = INDENTSIZE * depth; - for( ; n > 0; --n) - os.put(INDENTCHAR); - - return os; -} - -void ClusterGraphAttributes::writeOGML(const char *fileName)//, GraphConstraints &GC) -{ - ofstream os(fileName); - writeOGML(os);//, GC); -} - - -void ClusterGraphAttributes::writeOGML(ostream & os) //, GraphConstraints & GC) -{ - int labelId = 0; // new ID of current label - int pointId = 0; // new ID of current point - - int indentDepth = 0; // main indent depth - int indentDepthS = 4; // indent depth for styles block - std::ostringstream osS; // string output stream for buffering the styles of the handled elements - std::ostringstream osC; // string output stream for buffering constraints - - // CONFIGURING OUTPUT STREAMS - os.setf(ios::showpoint); - os.precision(10); - osS.setf(ios::showpoint); - osS.precision(10); - osC.setf(ios::showpoint); - osC.precision(10); - - // XML DECLARATION AND OGML TAG - os << "" << NEWLINE; // Latin-1 - // Simple version - os << "" << NEWLINE; - // Strict version - // os << "" << NEWLINE; - - // WRITING GRAPH BLOCK - os << ind(++indentDepth) << "" << NEWLINE; - - // WRITING STRUCTURE BLOCK - os << ind(++indentDepth) << "" << NEWLINE; - - // recursive handling of clusters - writeClusterOGML(os, osS, labelId, m_pClusterGraph->rootCluster(), ++indentDepth, indentDepthS); - - // handling of edges - edge e; - forall_edges(e, *m_pGraph) - { - // EDGE STRUCTURE - os << ind(indentDepth) << "index() << "\">" << NEWLINE; - ++indentDepth; - - // handling of label (if exists) - if (attributes() & edgeLabel) { - os << ind(indentDepth) << "" << NEWLINE; - } - - os << ind(indentDepth) << "source()->index() << "\"/>" << NEWLINE; - os << ind(indentDepth) << "target()->index() << "\"/>" << NEWLINE; - - /* - * TODO find solution for handling the edge types (app specific data?) - * - * os << "GENERALIZATION=\"" << (m_eType[e]==Graph::generalization?1:0) << "\">" << delimiter; - */ - - os << ind(--indentDepth) << "" << NEWLINE; // edge - - // EDGE LAYOUT - if (attributes() & edgeGraphics || attributes() & edgeColor || attributes() & edgeStyle) - { - osS << ind(indentDepthS) << "index() << "\">" << NEWLINE; - - // handling of style information - if(attributes() & edgeStyle || attributes() & edgeColor) - { - osS << ind(indentDepthS+1) << "" << NEWLINE; - } else { - osS << "/>" << NEWLINE; - } - } - - // TODO review the handling of edge arrows - if(attributes() & edgeArrow) - { - ++indentDepthS; - switch(arrowEdge(e)) { - case GraphAttributes::none: - osS << ind(indentDepthS) << "" << NEWLINE; - osS << ind(indentDepthS) << "" << NEWLINE; - break; - case GraphAttributes::last: - osS << ind(indentDepthS) << "" << NEWLINE; - osS << ind(indentDepthS) << "" << NEWLINE; - break; - case GraphAttributes::first: - osS << ind(indentDepthS) << "" << NEWLINE; - osS << ind(indentDepthS) << "" << NEWLINE; - break; - case GraphAttributes::both: - osS << ind(indentDepthS) << "" << NEWLINE; - osS << ind(indentDepthS) << "" << NEWLINE; - break; - case GraphAttributes::undefined: - // do nothing - break; - default: - // do nothing - break; - } - --indentDepthS; - } - - // handling of points - const DPolyline &dpl = m_bends[e]; - if (!dpl.empty()) { - ++indentDepthS; - // handle source - node v = e->source(); - if(dpl.front().m_x < m_x[v] - m_width[v]/2 || - dpl.front().m_x > m_x[v] + m_width[v]/2 || - dpl.front().m_y < m_y[v] - m_height[v]/2 || - dpl.front().m_y > m_y[v] + m_height[v]/2) { - osS << ind(indentDepthS) << "source()] << "\" y=\"" << m_y[e->source()] << "\"/>" << NEWLINE; - } - // handle points - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) { - osS << ind(indentDepthS) << "" << NEWLINE; - } - // handle target - v = e->target(); - if(dpl.back().m_x < m_x[v] - m_width[v]/2 || - dpl.back().m_x > m_x[v] + m_width[v]/2 || - dpl.back().m_y < m_y[v] - m_height[v]/2 || - dpl.back().m_y > m_y[v] + m_height[v]/2) { - osS << ind(indentDepthS) << "target()] << "\" y=\"" << m_y[e->target()] << "\"/>" << NEWLINE; - } - --indentDepthS; - } - - osS << ind(indentDepthS) << "" << NEWLINE; - } - } - - --indentDepth; - os << ind(indentDepth) << "" << NEWLINE; - - // WRITING LAYOUT BLOCK - os << ind(indentDepth) << "" << NEWLINE; - - // WRITING STYLES - ++indentDepth; - os << ind(indentDepth) << "" << NEWLINE; - os << osS.str(); - os << ind(indentDepth) << "" << NEWLINE; - - // 2.2.2) WRITING CONSTRAINTS - // No constraint handling so far in OGDF - /* - List * csList = GC.getConstraints(); - ListConstIterator it; - int constID = 0; - if (csList->size() > 0) { - os << indent << "" << NEWLINE; - for (it = csList->begin(); it.valid(); ++it) { - (*it)->storeToOgml(constID++, os, indentDepth + indentDepthS + 1); - } - os << indent << "" << NEWLINE; - cout << "Constraints written...\n" << flush; - } - */ - - --indentDepth; - os << ind(indentDepth) << "" << NEWLINE; - - --indentDepth; - os << ind(indentDepth) << "" << NEWLINE; - - os << ""; -} - - -// recursively write the cluster structure in OGML -void ClusterGraphAttributes::writeClusterOGML( - ostream & os, - std::ostringstream & osS, - int & nextLabelId, - cluster clust, - int & indentDepth, - int indentDepthS) -{ - // we handle all cluster except the root cluster - if (clust != m_pClusterGraph->rootCluster()) { - /* cluster structure infos */ - os << ind(indentDepth) << "index() << "\">" << NEWLINE; - - /* - * TODO What are cluster templates and how can/should they be handled? - * - const String &templStr = m_clusterTemplate[cluster]; - if(templStr.length() > 0) { - // GDE extension: Write cluster template and custom attribute - os << "template "; - writeLongString(os, templStr); - os << "\n"; - os << "label "; - writeLongString(os, clusterLabel(cluster)); - os << "\n"; - } else { - */ - - ++indentDepth; - os << ind(indentDepth) << "" << NEWLINE; - } - - // we handle the contained nodes first - ListConstIterator itn; - for (itn = clust->nBegin(); itn.valid(); ++itn) - { - node v = *itn; - - // node structure infos - os << ind(indentDepth) << "index() << "\">" << NEWLINE; - - // handling of label (if exists) - if (attributes() & nodeLabel) { - os << ind(indentDepth+1) << "" << NEWLINE; - } - - os << ind(indentDepth) << "" << NEWLINE; - - // node layout infos - osS << ind(indentDepthS) << "index() << "\">" << NEWLINE; - ++indentDepthS; - osS << ind(indentDepthS) << "" << NEWLINE; - osS << ind(indentDepthS) << "" << NEWLINE; - if(attributes() & nodeColor || attributes() & nodeStyle) { - // fill-tag - osS << ind(indentDepthS) << " 0) { - osS << " color=\"" << m_nodeColor[v] << "\""; - } - } - if (attributes() & nodeStyle) { - // pattern- and patternColor-attribute of fill-tag (closing) - osS << " pattern=\"" << brushPatternToOGML(m_nodePattern[v]) << "\" patternColor=\"#000000\"/>" << NEWLINE; - // line-tag - osS << ind(indentDepthS) << "" << NEWLINE; - } else { - // closing fill-tag - osS << "/>" << NEWLINE; - } - } - - --indentDepthS; - osS << ind(indentDepthS) << "" << NEWLINE; - }//for clusters - - // now we recursively handle the contained clusters - ListConstIterator it; - for (it = clust->cBegin(); it.valid(); ++it) { - writeClusterOGML(os, osS, nextLabelId, *it, indentDepth, indentDepthS); - } - - // we handle all clusters except the root cluster - if (clust != m_pClusterGraph->rootCluster()) { - --indentDepth; - os << ind(indentDepth) << "" << NEWLINE; - - // cluster layout infos - osS << ind(indentDepthS) << "index() << "\">" << NEWLINE; - - ++indentDepthS; - osS << ind(indentDepthS) << "" << NEWLINE; - osS << ind(indentDepthS) << "" << NEWLINE; - if(clusterFillColor(clust).length() > 0) { - osS << ind(indentDepthS) << "" << NEWLINE; - } - osS << ind(indentDepthS) << "" << NEWLINE; - --indentDepthS; - - osS << ind(indentDepthS) << "" << NEWLINE; - } -} - - -//++++++++++++++++++++++++++++++++++++++++++++ -//reading graph, attributes, cluster structure -bool ClusterGraphAttributes::readClusterGML( - const char* fileName, - ClusterGraph& CG, - Graph& G) -{ - - ifstream is(fileName); - if (!is) - return false; // couldn't open file - - return readClusterGML(is, CG, G); -} - - -bool ClusterGraphAttributes::readClusterGML( - istream& is, - ClusterGraph& CG, - Graph& G) -{ - - bool result; - GmlParser gml(is); - if (gml.error()) - return false; - - result = gml.read(G,*this); - - if (!result) return false; - - return readClusterGraphGML(CG, G, gml); -} - - -//read Cluster Graph with Attributes, base graph G, from fileName -bool ClusterGraphAttributes::readClusterGraphGML( - const char* fileName, - ClusterGraph& CG, - Graph& G, - GmlParser& gml) -{ - ifstream is(fileName); - if (!is) - return false; // couldn't open file - - return readClusterGraphGML(CG, G, gml); -} - - -//read from input stream -bool ClusterGraphAttributes::readClusterGraphGML( - ClusterGraph& CG, - Graph& G, - GmlParser& gml) -{ - return gml.readAttributedCluster(G, CG, *this); -} - - -// read Cluster Graph from OGML file -bool ClusterGraphAttributes::readClusterGraphOGML( - const char* fileName, - ClusterGraph& CG, - Graph& G) -{ - ifstream is(fileName); - if (!is) - return false; - - OgmlParser op; - return op.read(fileName, G, CG, *this); -}; - - -ostream &operator<<(ostream &os, ogdf::cluster c) -{ - if (c) os << c->index(); else os << "nil"; - return os; -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/cluster/ClusterPlanarizationLayout.cpp b/ext/OGDF/src/cluster/ClusterPlanarizationLayout.cpp deleted file mode 100644 index cf5e68a36..000000000 --- a/ext/OGDF/src/cluster/ClusterPlanarizationLayout.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of class ClusterPlanarizationLayout - * applies planarization approach for drawing Cluster diagrams - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -ClusterPlanarizationLayout::ClusterPlanarizationLayout() -{ - m_pageRatio = 1.0; - - m_planarLayouter.set(new ClusterOrthoLayout); - m_packer.set(new TileToRowsCCPacker); -} - - -//the call function that lets ClusterPlanarizationLayout compute a layout -//for the input -void ClusterPlanarizationLayout::call( - Graph& G, - ClusterGraphAttributes& acGraph, - ClusterGraph& cGraph, - bool simpleCConnect) //default true -{ - EdgeArray edgeWeight; - call(G, acGraph, cGraph, edgeWeight, simpleCConnect); -} -//the call function that lets ClusterPlanarizationLayout compute a layout -//for the input using \a weight for the computation of the cluster planar subgraph -void ClusterPlanarizationLayout::call( - Graph& G, - ClusterGraphAttributes& acGraph, - ClusterGraph& cGraph, - EdgeArray& edgeWeight, - bool simpleCConnect) //default true -{ - m_nCrossings = 0; - bool subGraph = false; // c-planar subgraph computed? - - //check some simple cases - if (G.numberOfNodes() == 0) return; - -//------------------------------------------------------------- -//we set pointers and arrays to the working graph, which can be -//the original or, in the case of non-c-planar input, a copy - - Graph* workGraph = &G; - ClusterGraph* workCG = &cGraph; - ClusterGraphAttributes* workACG = &acGraph; - - //potential copy of original if non c-planar - Graph GW; - //list of non c-planarity causing edges - List leftEdges; - - //list of nodepairs to be connected (deleted edges) - List leftWNodes; - - //store some information - //original to copy - NodeArray resultNode(G); - EdgeArray resultEdge(G); - ClusterArray resultCluster(cGraph); - //copy to original - NodeArray orNode(G); - EdgeArray orEdge(G); - ClusterArray orCluster(cGraph); - - //cluster IDs may differ after copying - ClusterArray originalClId(cGraph); - //maybe clusterof(ornode(v)) will do - - node workv; - forall_nodes(workv, G) - { - resultNode[workv] = workv; //will be set to copy if non-c-planar - orNode[workv] = workv; - } - edge worke; - forall_edges(worke, G) - { - resultEdge[worke] = worke; //will be set to copy if non-c-planar - orEdge[worke] = worke; - } - cluster workc; - forall_clusters(workc, cGraph) - { - resultCluster[workc] = workc; //will be set to copy if non-c-planar - orCluster[workc] = workc; - originalClId[workc] = workc->index(); - } - - - //----------------------------------------------- - //check if instance is clusterplanar and embed it - CconnectClusterPlanarEmbed CCPE; //cccp - - bool cplanar = CCPE.embed(cGraph, G); - - List connectEdges; - - //if the graph is not c-planar, we have to check the reason and to - //correct the problem by planarising or inserting connection edges - if (!cplanar) - { - bool connect = false; - - if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) || - (CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) ) - { - //we insert edges to make the input c-connected - makeCConnected(cGraph, G, connectEdges, simpleCConnect); - - //save edgearray info for inserted edges - ListConstIterator itE = connectEdges.begin(); - while (itE.valid()) - { - resultEdge[*itE] = (*itE); - orEdge[*itE] = (*itE); - itE++; - }//while - - connect = true; - - CCPE.embed(cGraph, G); - - if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) || - (CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) ) - { - cerr << "no correct connection made\n"< inSubGraph(G, false); - - CPlanarSubClusteredGraph cps; - if (edgeWeight.valid()) - cps.call(cGraph, inSubGraph, leftEdges, edgeWeight); - else - cps.call(cGraph, inSubGraph, leftEdges); -#ifdef OGDF_DEBUG - forall_edges(worke, G) - { -// if (inSubGraph[worke]) -// acGraph.colorEdge(worke) = "#FF0000"; - } -#endif - //--------------------------------------------------------------- - //now we delete the copies of all edges not in subgraph and embed - //the subgraph (use a new copy) - - //construct copy - - //ClusterGraph CGW(cGraph, GW, resultCluster, resultNode, resultEdge); - - workGraph = &GW; - workCG = new ClusterGraph(cGraph, GW, resultCluster, resultNode, resultEdge); - //&CGW; - - //---------------------- - //reinit original arrays - orNode.init(GW,0); - orEdge.init(GW,0); - orCluster.init(*workCG,0); - originalClId.init(*workCG, -1); - - //set array entries to the appropriate values - forall_nodes(workv, G) - { - orNode[resultNode[workv]] = workv; - } - forall_edges(worke, G) - { - orEdge[resultEdge[worke]] = worke; - } - forall_clusters(workc, cGraph) - { - orCluster[resultCluster[workc]] = workc; - originalClId[resultCluster[workc]] = workc->index(); - } - - //---------------------------------------------------- - //create new ACG and copy values (width, height, type) - - workACG = new ClusterGraphAttributes(*workCG, workACG->attributes()); - forall_nodes(workv, GW) - { - //should set same attributes in construction!!! - if (acGraph.attributes() & GraphAttributes::nodeType) - workACG->type(workv) = acGraph.type(orNode[workv]); - workACG->height(workv) = acGraph.height(orNode[workv]); - workACG->width(workv) = acGraph.width(orNode[workv]); - } - if (acGraph.attributes() & GraphAttributes::edgeType) - forall_edges(worke, GW) - { - workACG->type(worke) = acGraph.type(orEdge[worke]); - //all other attributes are not needed or will be set - } - - //delete edges - ListConstIterator itE = leftEdges.begin(); - - while (itE.valid()) - { - edge e = resultEdge[*itE]; - NodePair np; - np.m_src = e->source(); - np.m_tgt = e->target(); - - leftWNodes.pushBack(np); - - GW.delEdge(e); - - itE++; - }//while - - CconnectClusterPlanarEmbed CCP; - -#ifdef OGDF_DEBUG - bool subPlanar = -#endif - CCP.embed(*workCG, GW); - //bool subPlanar = CCP.embed(*workCG, *workGraph); - OGDF_ASSERT(subPlanar); - }//if not planar - else - { - if (!connect) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcClusterPlanar); - } - - }//if - - //if multiple CCs are handled, the connectedges (their copies resp.) - //can be deleted here - - //now CCPE should give us the external face - - ClusterPlanRep CP(*workACG, *workCG); - - OGDF_ASSERT(CP.representsCombEmbedding()); - - const int numCC = CP.numberOfCCs(); //equal to one - //preliminary - OGDF_ASSERT(numCC == 1); - - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - for (int ikl = 0; ikl < numCC; ikl++) - { - - CP.initCC(ikl); - CP.setOriginalEmbedding(); - - OGDF_ASSERT(CP.representsCombEmbedding()) - - Layout drawing(CP); - - //m_planarLayouter.get().setOptions(4);//progressive - - adjEntry ae = 0; - - //internally compute adjEntry for outer face - - //edges that are reinserted in workGraph (in the same - //order as leftWNodes) - List newEdges; - m_planarLayouter.get().call(CP, ae, drawing, leftWNodes, newEdges, *workGraph); - - OGDF_ASSERT(leftWNodes.size()==newEdges.size()) - OGDF_ASSERT(leftEdges.size()==newEdges.size()) - - ListConstIterator itE = newEdges.begin(); - ListConstIterator itEor = leftEdges.begin(); - while (itE.valid()) - { - orEdge[*itE] = *itEor; - itE++; - itEor++; - } - - //hash index over cluster ids - HashArray CA; - - computeClusterPositions(CP, drawing, CA); - - // copy layout into acGraph - // Later, we move nodes and edges in each connected component, such - // that no two overlap. - const List &origInCC = CP.nodesInCC(ikl); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) - { - node vG = *itV; - - acGraph.x(orNode[vG]) = drawing.x(CP.copy(vG)); - acGraph.y(orNode[vG]) = drawing.y(CP.copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) - { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - edge orE = orEdge[eG]; - if (orE) - drawing.computePolylineClear(CP,eG,acGraph.bends(orE)); - }//foralladj - - }//for - - //even assignment for all nodes is not enough, we need all clusters - cluster c; - forall_clusters(c, *workCG) - { - int clNumber = c->index(); - int orNumber = originalClId[c]; - - if (c != workCG->rootCluster()) - { - OGDF_ASSERT(CA.isDefined(clNumber)); - acGraph.clusterHeight(orNumber) = CA[clNumber].m_height; - acGraph.clusterWidth(orNumber) = CA[clNumber].m_width; - acGraph.clusterYPos(orNumber) = CA[clNumber].m_miny; - acGraph.clusterXPos(orNumber) = CA[clNumber].m_minx; - }//if real cluster - }//forallclusters - - // the width/height of the layout has been computed by the planar - // layout algorithm; required as input to packing algorithm - boundingBox[ikl] = m_planarLayouter.get().getBoundingBox(); - - }//for connected components - - //postProcess(acGraph); - // - // arrange layouts of connected components - // - - Array offset(numCC); - - m_packer.get().call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node, edge and cluster by the offset - // of its connected component. - - for(int i = 0; i < numCC; ++i) - { - const List &nodes = CP.nodesInCC(i); - - const double dx = offset[i].m_x; - const double dy = offset[i].m_y; - - HashArray shifted(false); - - // iterate over all nodes in ith CC - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - acGraph.x(orNode[v]) += dx; - acGraph.y(orNode[v]) += dy; - - // update cluster positions accordingly - int clNumber = cGraph.clusterOf(orNode[v])->index(); - - if ((clNumber > 0) && !shifted[clNumber]) - { - acGraph.clusterYPos(clNumber) += dy; - acGraph.clusterXPos(clNumber) += dx; - shifted[clNumber] = true; - }//if real cluster - - adjEntry adj; - forall_adj(adj,v) { - if ((adj->index() & 1) == 0) continue; - edge e = adj->theEdge(); - - //edge eOr = orEdge[e]; - if (orEdge[e]) - { - DPolyline &dpl = acGraph.bends(orEdge[e]); - ListIterator it; - for(it = dpl.begin(); it.valid(); ++it) { - (*it).m_x += dx; - (*it).m_y += dy; - }//for - }//if - }//foralladj - }//for nodes - }//for numcc - - - while (!connectEdges.empty()) - { - G.delEdge(connectEdges.popFrontRet()); - } - - if (subGraph) - { - originalClId.init(); - orCluster.init(); - orNode.init(); - orEdge.init(); - delete workCG; - delete workACG; - }//if subgraph created - - acGraph.removeUnnecessaryBendsHV(); - -}//call - - -void ClusterPlanarizationLayout::computeClusterPositions( - ClusterPlanRep& CP, - Layout drawing, - HashArray& CA) -{ - edge e; - forall_edges(e, CP) - { - if (CP.isClusterBoundary(e)) - { - ClusterPosition cpos; - //minimum vertex position values - double minx, maxx, miny, maxy; - minx = min(drawing.x(e->source()), drawing.x(e->target())); - maxx = max(drawing.x(e->source()), drawing.x(e->target())); - miny = min(drawing.y(e->source()), drawing.y(e->target())); - maxy = max(drawing.y(e->source()), drawing.y(e->target())); - - //check if x,y of lower left corner have to be updated - if (CA.isDefined(CP.ClusterID(e))) - { - cpos = CA[CP.ClusterID(e)]; - - double preValmaxx = cpos.m_maxx; - double preValmaxy = cpos.m_maxy; - - if (cpos.m_minx > minx) cpos.m_minx = minx; - if (cpos.m_miny > miny) cpos.m_miny = miny; - if (preValmaxx < maxx) cpos.m_maxx = maxx; - if (preValmaxy < maxy) cpos.m_maxy = maxy; - - }//if - else - { - cpos.m_minx = minx; - cpos.m_maxx = maxx; - cpos.m_miny = miny; - cpos.m_maxy = maxy; - }//else - - //not necessary for all boundary edges, but we only have the ids - //to adress, they may have holes - cpos.m_width = cpos.m_maxx - cpos.m_minx; - cpos.m_height = cpos.m_maxy - cpos.m_miny; - - //write values back - CA[CP.ClusterID(e)] = cpos; - - }//if is Boundary - }//foralledges -}//computeClusterPositions - -} // end namespace ogdf diff --git a/ext/OGDF/src/cluster/Cluster_ChunkConnection.cpp b/ext/OGDF/src/cluster/Cluster_ChunkConnection.cpp deleted file mode 100644 index 4ee9ecd45..000000000 --- a/ext/OGDF/src/cluster/Cluster_ChunkConnection.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of initial cut-constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * A feasible ILP solution has to imply a completely connected, planar Sub-Clustergraph. - * For each cluster that is not connected, additional connection edges have to be inserted - * between the chunks of the cluster, to obtain c-connectivity. - * Thus, initial constraints are added that guarantee this behaviour, if the number of chunks - * is at most 3. If some cluster consists of more than 3 chunks, additional constraints - * have to be separated during the algorithm. - * - * \author Mathias Jansen - * - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include - -using namespace ogdf; - -ChunkConnection::ChunkConnection(ABA_MASTER *master, const ArrayBuffer& chunk, const ArrayBuffer& cochunk) : - BaseConstraint(master, 0, ABA_CSENSE::Greater, 1.0, false, false, true) -{ - chunk.compactMemcpy(m_chunk); - cochunk.compactMemcpy(m_cochunk); -} - - -ChunkConnection::~ChunkConnection() {} - - -int ChunkConnection::coeff(node n1, node n2) { - //TODO: speedup - int i,j; - forall_arrayindices(i,m_chunk) { - if(m_chunk[i] == n1) { - forall_arrayindices(j,m_cochunk) { - if(m_cochunk[j] == n2) { - return 1; - } - } - return 0; - } else if(m_chunk[i] == n2) { - forall_arrayindices(j,m_cochunk) { - if(m_cochunk[j] == n1) { - return 1; - } - } - return 0; - } - } - return 0; -} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/Cluster_CutConstraint.cpp b/ext/OGDF/src/cluster/Cluster_CutConstraint.cpp deleted file mode 100644 index 853c47652..000000000 --- a/ext/OGDF/src/cluster/Cluster_CutConstraint.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * This class represents the cut-constraints belonging to the ILP formulation. - * Cut-constraints are dynamically separated be means of cutting plane methods. - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include - -using namespace ogdf; - -CutConstraint::CutConstraint(ABA_MASTER *master, ABA_SUB *sub, List &edges) : - BaseConstraint(master, sub, ABA_CSENSE::Greater, 1.0, true, true, true) -{ - ListConstIterator it; - for (it = edges.begin(); it.valid(); ++it) { - m_cutEdges.pushBack(*it); - } -} - - -CutConstraint::~CutConstraint() {} - - -int CutConstraint::coeff(node n1, node n2) { - ListConstIterator it; - for (it = m_cutEdges.begin(); it.valid(); ++it) { - if ( ((*it).v1 == n1 && (*it).v2 == n2) || - ((*it).v2 == n1 && (*it).v1 == n2) ) - {return 1;} - } - return 0; -} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/Cluster_EdgeVar.cpp b/ext/OGDF/src/cluster/Cluster_EdgeVar.cpp deleted file mode 100644 index 352529a13..000000000 --- a/ext/OGDF/src/cluster/Cluster_EdgeVar.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2549 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the variable class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include -#include - -using namespace ogdf; - -EdgeVar::EdgeVar(ABA_MASTER *master, double obj, edgeType eType, node source, node target) : - ABA_VARIABLE (master, 0, false, false, obj, eType==CONNECT ? 0.0 : (((Master*)master)->getCheckCPlanar() ? 1.0 : 0.0), 1.0, eType==CONNECT ? ABA_VARTYPE::Binary : (((Master*)master)->getCheckCPlanar() ? ABA_VARTYPE::Continuous : ABA_VARTYPE::Binary)) // TODO-TESTING -{ - m_eType = eType; - m_source = source; - m_target = target; -// m_objCoeff = obj; // not necc. -//TODO no searchedge! - if (eType == ORIGINAL) m_edge = ((Master*)master)->getGraph()->searchEdge(source,target); - else m_edge = NULL; -} - -EdgeVar::EdgeVar(ABA_MASTER *master, double obj, node source, node target) : - ABA_VARIABLE (master, 0, false, false, obj, 0.0, 1.0, ABA_VARTYPE::Binary) -{ - m_eType = CONNECT; - m_source = source; - m_target = target; - m_edge = NULL; -} - -EdgeVar::EdgeVar(ABA_MASTER *master, double obj, double lbound, node source, node target) : - ABA_VARIABLE (master, 0, false, false, obj, lbound, 1.0, ABA_VARTYPE::Binary) -{ - m_eType = CONNECT; - m_source = source; - m_target = target; - m_edge = NULL; -} - -EdgeVar::~EdgeVar() {} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/Cluster_MaxPlanarEdges.cpp b/ext/OGDF/src/cluster/Cluster_MaxPlanarEdges.cpp deleted file mode 100644 index 1bcc8e5e0..000000000 --- a/ext/OGDF/src/cluster/Cluster_MaxPlanarEdges.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * These constraints represent the planarity-constraints belonging to the - * ILP formulation. These constraints are dynamically separated. - * For the separation the planarity test algorithm by Boyer and Myrvold is used. - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include - -using namespace ogdf; - - -MaxPlanarEdgesConstraint::MaxPlanarEdgesConstraint(ABA_MASTER *master, int edgeBound, List &edges) : - ABA_CONSTRAINT(master, 0, ABA_CSENSE::Less, edgeBound, false, false, true) -{ - m_graphCons = false; - ListConstIterator it; - for (it=edges.begin(); it.valid(); ++it) { - m_edges.pushBack(*it); - } -} - -MaxPlanarEdgesConstraint::MaxPlanarEdgesConstraint(ABA_MASTER *master, int edgeBound) : - ABA_CONSTRAINT(master, 0, ABA_CSENSE::Less, edgeBound, false, false, true) -{ - m_graphCons = true; -} - - -MaxPlanarEdgesConstraint::~MaxPlanarEdgesConstraint() {} - - -double MaxPlanarEdgesConstraint::coeff(ABA_VARIABLE *v) { - //TODO: speedup, we know between which nodepairs edges exist... - if (m_graphCons) return 1.0; - - EdgeVar *e = (EdgeVar*)v; - ListConstIterator it; - for (it=m_edges.begin(); it.valid(); ++it) { - if ( ((*it).v1 == e->sourceNode() && (*it).v2 == e->targetNode()) || - ((*it).v1 == e->targetNode() && (*it).v2 == e->sourceNode()) ) - {return 1.0;} - } - return 0.0; -} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/Clusterer.cpp b/ext/OGDF/src/cluster/Clusterer.cpp deleted file mode 100644 index 8c34f264c..000000000 --- a/ext/OGDF/src/cluster/Clusterer.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of a clustering algorithm (by Auber, Chiricota, - * Melancon). - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - -namespace ogdf { - -Clusterer::Clusterer(const Graph &G) : - ClustererModule(G), - m_recursive(true), - m_autoThreshNum(0) -{ - //use automatic thresholds - //m_thresholds.pushFront(3.0); - //m_thresholds.pushFront(1.4); - m_defaultThresholds.pushFront(1.6); - m_defaultThresholds.pushBack(3.2); - m_defaultThresholds.pushBack(4.5); - m_stopIndex = 0.7; -} - - -//computes a list of SimpleCluster pointers, where each SimpleCluster -//models a cluster and has a parent (0 if root) -//list of cluster structures will be parameter -void Clusterer::computeClustering(SList &clustering) -{ - //save to which cluster the vertices belong - //0 is root cluster - SimpleCluster *root = new SimpleCluster(); - root->m_size = m_pGraph->numberOfNodes(); - - //we push root to the front afterwards - //clustering.pushFront(root); - NodeArray vCluster(*m_pGraph, root); - - //we delete edges and therefore work on a copy - GraphCopy GC(*m_pGraph); - //multiedges are not used for the computation - makeSimple(GC); - //based on strengths, we compute a clustering - //Case 1:with depth one (or #thresholds) - //Case 2: Recursively - - edge e; - ListIterator it; - - if (m_thresholds.size() > 0) - it = m_thresholds.begin(); - else - { - OGDF_ASSERT(m_defaultThresholds.size() > 0); - it = m_defaultThresholds.begin(); - } - - //are there more cases than (not) rec.? - int fall = (m_recursive ? 2 : 1); - //int fall = 2; - if (fall == 2) - { - //we just use the first value of auto/default/threshs - //assert(m_thresholds.size() == 1); - //Case2: - //we compute the edge strengths on the components recursively - //we therefore only need a single threshold - - //we compute the edge strengths - EdgeArray strengths(GC,0.0); - - //we need a criterion to stop the process - //we stop if there are no edges deleted or - //the average node clustering index in our copy rises - //above m_stopIndex - bool edgesDeleted = true; - - while (edgesDeleted && (averageCIndex(GC) 0) - { - OGDF_ASSERT(m_autoThresholds.size() > 0); - it = m_autoThresholds.begin(); - } - if (it.valid()) - { - //collect edges that will be deleted - List le; - forall_edges(e, GC) - { - if (strengths[e] < *it) - { - le.pushFront(e); - } - } - //stop criterion - if (le.size() == 0) - { - edgesDeleted = false; - continue; - } - //delete edges - ListIterator itle = le.begin(); - while (itle.valid()) - { - GC.delEdge(*itle); - itle++; - } - //gather cluster information - node v; - //vertices within a connected component are always part - //of the same cluster which then will be parent of the new clusters - - StackPure S; - NodeArray done(GC, false); - forall_nodes(v,GC) - { - if (done[v]) continue; - done[v] = true; - S.push(v); - SimpleCluster* parent = vCluster[GC.original(v)]; - SList theCluster; - - List compNodes; //nodes in a component - - while(!S.empty()) - { - node w = S.pop(); - compNodes.pushFront(w); - edge e; - forall_adj_edges(e,w) - { - node x = e->opposite(w); - if (!(done[x])) - { - done[x] = true; - S.push(x); - } - } - }//While - //run over nodes and set cluster info - //do not construct trivial clusters - if ( (parent->m_size > compNodes.size()) && - (compNodes.size()>2)) - { - SimpleCluster* s = new SimpleCluster(); - s->setParent(parent); - - parent->pushBackChild(s); - clustering.pushFront(s); - ListIterator it = compNodes.begin(); - while (it.valid()) - { - vCluster[GC.original(*it)] = s; - //vertex leaves parent to s - parent->m_size--; - s->m_size++; - it++; - }//While - } - }//forallnodes - }//if thresholds - }//stop criterion - } - else //fall 2 - { - //we compute the edge strengths - EdgeArray strengths(*m_pGraph,0.0); - computeEdgeStrengths(strengths); - if (m_autoThreshNum > 0) - { - OGDF_ASSERT(m_autoThresholds.size() > 0); - it = m_autoThresholds.begin(); - } - //Case1: - - while (it.valid()) - { - //collect edges that will be deleted - List le; - forall_edges(e, GC) - { - if (strengths[e] < *it) - { - le.pushFront(e); - } - } - //delete edges - ListIterator itle = le.begin(); - while (itle.valid()) - { - GC.delCopy(*itle); - itle++; - } - //gather cluster information - node v; - //vertices within a connected component are always part - //of the same cluster which then will be parent of the new clusters - - StackPure S; - NodeArray done(GC, false); - forall_nodes(v,GC) - { - if (done[v]) continue; - done[v] = true; - S.push(v); - SimpleCluster* parent = vCluster[GC.original(v)]; - SList theCluster; - - List compNodes; //nodes in a component - - //do not immediately construct a cluster, first gather and store - //vertices, then test if the cluster fits some constraints, e.g. size - while(!S.empty()) - { - node w = S.pop(); - compNodes.pushFront(w); - edge e; - forall_adj_edges(e,w) - { - node x = e->opposite(w); - if (!(done[x])) - { - done[x] = true; - S.push(x); - } - } - }//While - - //run over nodes and set cluster info - //do not construct trivial clusters - if ( (parent->m_size > compNodes.size()) && - (compNodes.size()>2)) - { - SimpleCluster* s = new SimpleCluster; - s->setParent(parent); - //s->m_index = -1; - parent->pushBackChild(s); - clustering.pushFront(s); - ListIterator it = compNodes.begin(); - while (it.valid()) - { - vCluster[GC.original(*it)] = s; - //vertex leaves parent to s - parent->m_size--; - s->m_size++; - it++; - }//while - } - }//while thresholds - - it++; - }//while - }//case 2 - - clustering.pushFront(root); - //we now have the clustering and know for each vertex, to which cluster - //it was assigned in the last iteration (vCluster) - //we update the lists of children - node v; - forall_nodes(v, *m_pGraph) - { - vCluster[v]->pushBackVertex(v); - } -}//computeClustering - -void Clusterer::computeEdgeStrengths(EdgeArray &strength) -{ - const Graph &G = *m_pGraph; - computeEdgeStrengths(G, strength); -} - -void Clusterer::computeEdgeStrengths(const Graph &G, EdgeArray &strength) -{ - edge e; - strength.init(G, 0.0); - double minStrength = 5.0, maxStrength = 0.0; //used to derive automatic thresholds - //5 is the maximum possible value (sum of five values 0-1) - - //A Kompromiss: Entweder immer Nachbarn der Nachbarn oder einmal berechnen und speichern (gut - //wenn haeufig benoetigt (hoher Grad), braucht aber viel Platz - //B Was ist schneller: Listen nachher nochmal durchlaufen und loeschen, wenn Doppelnachbar oder - //gleich beim Auftreten loeschen ueber Iterator - - //First, compute the sets Mw, Mv, Wwv. Then check their connectivity. - //Use a list for the vertices that are solely connected to w - forall_edges(e, G) - { - List vNb; - List wNb; - List bNb; //neighbour to both vertices - EdgeArray processed(G, false); //edge was processed - NodeArray nba(G, 0); //neighbours of v and w: 1v, 2both, 3w - - node v = e->source(); - node w = e->target(); - - adjEntry adjE; - //neighbourhood sizes - int sizeMv = 0; - int sizeMw = 0; - int sizeWvw = 0; - //neighbourhood links - //int rMv = 0; //within MV - //int rMw = 0; - int rWvw = 0; - - int rMvMw = 0; //from Mv to Mw - int rMvWvw = 0; - int rMwWvw = 0; - - //----------------------------------------- - //Compute neighbourhood - //Muss man selfloops gesondert beruecksichtigen - forall_adj(adjE, v) - { - node u = adjE->twinNode(); - if (u == v) continue; - if ( u != w ) - { - nba[u] = 1; - } - } - forall_adj(adjE, w) - { - node u = adjE->twinNode(); - if (u == w) continue; - if ( u != v ) - { - if (nba[u] == 1) - { - nba[u] = 2; - } - else - { - if (nba[u] != 2) nba[u] = 3; - - sizeMw++; - wNb.pushFront(u); - } - } - }// foralladjw - - //Problem in der Laufzeit ist die paarweise Bewertung der Nachbarschaft - //ohne Nutzung vorheriger Informationen - - //We know the neighbourhood of v and w and have to compute the connectivity - forall_adj(adjE, v) - { - node u = adjE->twinNode(); - - if ( u != w ) - { - adjEntry adjE2; - //check if u is in Mv - if (nba[u] == 1) - { - //vertex in Mv - sizeMv++; - //check links within Mv, to Mw and Wvw - forall_adj(adjE2, u) - { - processed[adjE2->theEdge()] = true; - node t = adjE2->twinNode(); - //test links to other sets - switch (nba[t]) { - //case 1: rMv++; break; - case 2: rMvWvw++; break; - case 3: rMvMw++; break; - }//switch - - } - - } - else - { - //vertex in Wvw, nba == 2 - assert(nba[u] == 2); - sizeWvw++; - forall_adj(adjE2, u) - { - node t = adjE2->twinNode(); - //processed testen? - //test links to other sets - switch (nba[t]) { - //case 1: rMv++; break; - case 2: rWvw++; break; - case 3: rMwWvw++; break; - }//switch - - } - - }//else - }//if not w - }//foralladj - - //Now compute the ratio of existing edges to maximal number - //(complete graph) - - double sMvWvw = 0.0; - double sMwWvw = 0.0; - double sWvw = 0.0; - double sMvMw = 0.0; - //we have to cope with special cases - int smult = sizeMv*sizeWvw; - if (smult != 0) sMvWvw = (double)rMvWvw/smult; - smult = sizeMw*sizeWvw; - if (smult != 0) sMwWvw = (double)rMwWvw/smult; - smult = (sizeMv*sizeMw); - if (smult != 0) sMvMw = (double)rMvMw/smult; - - - if (sizeWvw > 1) - sWvw = 2.0*rWvw/(sizeWvw*(sizeWvw-1)); - else if (sizeWvw == 1) sWvw = 1.0; - //Ratio of cycles of size 3 and 4 - double cycleProportion = ((double)sizeWvw/(sizeWvw+sizeMv+sizeMw)); - double edgeStrength = sMvWvw+sMwWvw+sWvw+sMvMw+cycleProportion; - - if (m_autoThreshNum > 0) - { - if (minStrength > edgeStrength) minStrength = edgeStrength; - if (maxStrength < edgeStrength) maxStrength = edgeStrength; - } - - //cout<<"sWerte: "< 0) - { - if (m_autoThresholds.size()>0) m_autoThresholds.clear(); - if (maxStrength > minStrength) - { - //cout << "Max: "< strengths(*m_pGraph,0.0); - computeEdgeStrengths(strengths); - - //based on strengths, we compute a clustering - //Case 1:with depth one (or #thresholds) - //Case 2: Recursively - - //Case1: - GraphCopy GC(*m_pGraph); - edge e; - ListIterator it = m_thresholds.begin(); - - while (it.valid()) - { - //collect edges that will be deleted - List le; - forall_edges(e, GC) - { - if (strengths[e] < *it) - { - le.pushFront(e); - } - } - //delete edges - ListIterator itle = le.begin(); - while (itle.valid()) - { - GC.delCopy(*itle); - itle++; - } - //gather cluster information - node v; - //vertices within a connected component are always part - //of the same cluster which then will be parent of the new clusters - - StackPure S; - NodeArray done(GC, false); - forall_nodes(v,GC) - { - if (done[v]) continue; - done[v] = true; - S.push(v); - cluster parent = C.clusterOf(GC.original(v)); - SList theCluster; - - while(!S.empty()) - { - node w = S.pop(); - theCluster.pushFront(GC.original(w)); - edge e; - forall_adj_edges(e,w) - { - node x = e->opposite(w); - if (!(done[x])) - { - done[x] = true; - S.push(x); - } - } - }//While - //create the cluster - C.createCluster(theCluster, parent); - - } - - it++; - }//while - - -} - -void Clusterer::setClusteringThresholds(const List &threshs) -{ - //we copy the values, should be a low number - m_thresholds.clear(); - ListConstIterator it = threshs.begin(); - while (it.valid()) - { - m_thresholds.pushFront((*it)); - it++; - } -} - -}//namespace ogdf diff --git a/ext/OGDF/src/cluster/KuratowskiConstraint.cpp b/ext/OGDF/src/cluster/KuratowskiConstraint.cpp deleted file mode 100644 index 6720354ed..000000000 --- a/ext/OGDF/src/cluster/KuratowskiConstraint.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * $Revision: 2615 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 14:23:36 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of a constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * These constraints represent the planarity-constraints belonging to the - * ILP formulation. These constraints are dynamically separated. - * For the separation the planarity test algorithm by Boyer and Myrvold is used. - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include - -using namespace ogdf; - -KuratowskiConstraint::KuratowskiConstraint(ABA_MASTER *master, int nEdges, SListPure &ks) : - ABA_CONSTRAINT(master, 0, ABA_CSENSE::Less, nEdges-1, true, false, true) -{ - SListConstIterator it; - for (it = ks.begin(); it.valid(); ++it) { - m_subdivision.pushBack(*it); - } -} - - -KuratowskiConstraint::~KuratowskiConstraint() {} - - -double KuratowskiConstraint::coeff(ABA_VARIABLE *v) { - EdgeVar *e = (EdgeVar*)v; - for (ListConstIterator it = m_subdivision.begin(); it.valid(); ++it) { - if( ((*it).v1 == e->sourceNode() && (*it).v2 == e->targetNode()) || - ((*it).v1 == e->targetNode() && (*it).v2 == e->sourceNode()) ) - {return 1.0;} - } - return 0.0; -} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/MaxCPlanar_Master.cpp b/ext/OGDF/src/cluster/MaxCPlanar_Master.cpp deleted file mode 100644 index cd1d63b10..000000000 --- a/ext/OGDF/src/cluster/MaxCPlanar_Master.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * $Revision: 2610 $ - * - * last checkin: - * $Author: klein $ - * $Date: 2012-07-16 10:04:15 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the master class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem - * - * This class is managing the optimization. - * Variables and initial constraints are generated and pools are initialized. - * Since variables correspond to the edges of a complete graph, node pairs - * are used mostly instead of edges. - * - * \author Markus Chimani, Mathias Jansen, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include -#include -#include -//#include // not used -#include -#include -#include -#include -#include -//heuristics in case only max planar subgraph is computed -#include -#include -#include - -using namespace ogdf; - - -#ifdef OGDF_DEBUG -void Master::printGraph(const Graph &G) { - edge e; - int i=0; - Logger::slout() << "The Given Graph" << endl; - forall_edges(e,G) { - Logger::slout() << "Edge " << i++ << ": (" << e->source()->index() << "," << e->target()->index() << ") " << endl; - } -} -#endif - -//std::ostream &operator<<(std::ostream &os, const nodePair& v) { -// os << "(" <numberOfNodes()*(m_G->numberOfNodes()-1)) / 2; - m_nMaxVars = nComplete; - //to use less variables in case we have only the root cluster, - //we temporarily set m_nMaxVars to the number of edges - if ( (m_C->numberOfClusters() == 1) && (isConnected(*m_G)) ) - m_nMaxVars = m_G->numberOfEdges(); - - // Computing the main objective function coefficient for the connection edges. - //int nConnectionEdges = nComplete - m_G->numberOfEdges(); - m_epsilon = (double)(0.2/(2*(m_G->numberOfNodes()))); - - // Setting parameters - m_out = ol; - m_nKuratowskiIterations = kuratowskiIterations; - m_nSubdivisions = subdivisions; - m_nKuratowskiSupportGraphs = kSupportGraphs; - m_heuristicLevel = heuristicLevel; - m_nHeuristicRuns = heuristicRuns; - m_usePerturbation = perturbation; - m_kuratowskiBoundHigh = kHigh; - m_kuratowskiBoundLow = kLow; - m_branchingGap = branchingGap; - m_maxCpuTime = new ABA_STRING(this,time); - m_heuristicFractionalBound = heuristicOEdgeBound; - m_nHeuristicPermutationLists = heuristicNPermLists; - m_mpHeuristic = true; - - // Further settings - m_nCConsAdded = 0; - m_nKConsAdded = 0; - m_solvesLP = 0; - m_varsInit = 0; - m_varsAdded = 0; - m_varsPotential = 0; - m_varsMax = 0; - m_varsCut = 0; - m_varsKura = 0; - m_varsPrice = 0; - m_varsBranch = 0; - m_activeRepairs = 0; - m_repairStat.init(100); - - outLevel(ol); -} - - -Master::~Master() { - delete m_maxCpuTime; - delete m_solutionGraph; -} - - -ABA_SUB *Master::firstSub() { - return new Sub(this); -} - - -// Replaces current m_solutionGraph by new GraphCopy based on \a connection list -void Master::updateBestSubGraph(List &original, List &connection, List &deleted) { - - // Creates a new GraphCopy \a m_solutionGraph and deletes all edges - // TODO: Extend GraphCopySimple to be usable here: Allow - // edge deletion and add pure node initialization - // Is the solutiongraph used during computation anyhow? - // Otherwise only store the lists - delete m_solutionGraph; - m_solutionGraph = new GraphCopy(*m_G); - edge e = m_solutionGraph->firstEdge(); - edge succ; - while (e!=0) { - succ = e->succ(); - m_solutionGraph->delEdge(e); - e = succ; - } - - // Delete all edges that have been stored previously in edge lists - m_allOneEdges.clear(); - m_originalOneEdges.clear(); - m_connectionOneEdges.clear(); - m_deletedOriginalEdges.clear(); - - // Update the edge lists according to new solution - ListConstIterator oit = original.begin(); - node cv,cw; - while (oit.valid()) { - - // Add all original edges to \a m_solutionGraph - cv = m_solutionGraph->copy((*oit).v1); - cw = m_solutionGraph->copy((*oit).v2); - m_solutionGraph->newEdge(cv,cw); - - m_allOneEdges.pushBack(*oit); - m_originalOneEdges.pushBack(*oit); - - oit++; - } - - ListConstIterator cit = connection.begin(); - while (cit.valid()) { - - // Add all new connection edges to \a m_solutionGraph - cv = m_solutionGraph->copy((*cit).v1); - cw = m_solutionGraph->copy((*cit).v2); - m_solutionGraph->newEdge(cv,cw); - - m_allOneEdges.pushBack(*cit); - m_connectionOneEdges.pushBack(*cit); - - cit++; - } - - ListConstIterator dit = deleted.begin(); - while (dit.valid()) { - - m_deletedOriginalEdges.pushBack(*dit); - - dit++; - } -#ifdef OGDF_DEBUG - m_solutionGraph->writeGML("UpdateSolutionGraph.gml"); -//Just for special debugging purposes: - if (true) {//note that we output the original graph plus added edges, but don't remove deleted ones - ClusterArray ca(*m_C); - Graph GG; - NodeArray na(*m_G); - ClusterGraph CG(*m_C,GG, ca, na); - - cit = connection.begin(); - - List le; - - while (cit.valid()) { - - // Add all new connection edges to \a m_solutionGraph - cv = na[(*cit).v1]; - cw = na[(*cit).v2]; - edge e = GG.newEdge(cv,cw); - le.pushBack(e); - - cit++; - } - - ClusterGraphAttributes CGA(CG, GraphAttributes::edgeType | GraphAttributes::nodeType | - GraphAttributes::nodeGraphics | GraphAttributes::edgeGraphics | GraphAttributes::edgeColor); - ListConstIterator it = le.begin(); - while (it.valid()) - { - cout << (*it)->graphOf() << "\n"; - cout << &GG << "\n"; - CGA.colorEdge(*it) = "#FF0000"; - it++; - } - CGA.writeGML("PlanarExtensionMCPSP.gml"); - } -#endif -} - - -void Master::getAllOptimalSolutionEdges(List &edges) const { - edges.clear(); - ListConstIterator it; - for (it=m_allOneEdges.begin(); it.valid(); ++it) { - edges.pushBack(*it); - } -} - - -void Master::getOriginalOptimalSolutionEdges(List &edges) const { - edges.clear(); - ListConstIterator it; - for (it=m_originalOneEdges.begin(); it.valid(); ++it) { - edges.pushBack(*it); - } -} - - -void Master::getConnectionOptimalSolutionEdges(List &edges) const { - edges.clear(); - ListConstIterator it; - for (it=m_connectionOneEdges.begin(); it.valid(); ++it) { - edges.pushBack(*it); - } -} - - -void Master::getDeletedEdges(List &edges) const { - edges.clear(); - ListConstIterator it; - for (it=m_deletedOriginalEdges.begin(); it.valid(); ++it) { - edges.pushBack(*it); - } -} - -//todo: is called only once, but could be sped up the same way as the co-conn check -void Master::clusterConnection(cluster c, GraphCopy &gc, double &upperBoundC) { - // For better performance, a node array is used to indicate which nodes are contained - // in the currently considered cluster. - NodeArray vInC(gc,false); - // First check, if the current cluster \a c is a leaf cluster. - // If so, compute the number of edges that have at least to be added - // to make the cluster induced graph connected. - if (c->cCount()==0) { //cluster \a c is a leaf cluster - GraphCopy *inducedC = new GraphCopy((const Graph&)gc); - node v,w; - List clusterNodes; - c->getClusterNodes(clusterNodes); // \a clusterNodes now contains all (original) nodes of cluster \a c. - ListConstIterator it; - for (it=clusterNodes.begin(); it.valid(); ++it) { - vInC[gc.copy(*it)] = true; - } - - // Delete all nodes from \a inducedC that do not belong to the cluster, - // in order to obtain the cluster induced graph. - v = inducedC->firstNode(); - while (v!=0) { - w = v->succ(); - if (!vInC[inducedC->original(v)]) inducedC->delNode(v); - v = w; - } - - // Determine number of connected components of cluster induced graph. - //Todo: check could be skipped - if (!isConnected(*inducedC)) { - - NodeArray conC(*inducedC); - int nCC = connectedComponents(*inducedC,conC); - //at least #connected components - 1 edges have to be added. - upperBoundC -= (nCC-1)*m_largestConnectionCoeff; - } - delete inducedC; - // Cluster \a c is an "inner" cluster. Process all child clusters first. - } else { //c->cCount is != 0, process all child clusters first - - ListConstIterator cit; - for (cit=c->cBegin(); cit.valid(); ++cit) { - clusterConnection(*cit,gc,upperBoundC); - } - - // Create cluster induced graph. - GraphCopy *inducedC = new GraphCopy((const Graph&)gc); - node v,w; - List clusterNodes; - c->getClusterNodes(clusterNodes); //\a clusterNodes now contains all (original) nodes of cluster \a c. - ListConstIterator it; - for (it=clusterNodes.begin(); it.valid(); ++it) { - vInC[gc.copy(*it)] = true; - } - v = inducedC->firstNode(); - while (v!=0) { - w = v->succ(); - if (!vInC[inducedC->original(v)]) inducedC->delNode(v); - v = w; - } - - // Now collapse each child cluster to one node and determine #connected components of \a inducedC. - List oChildClusterNodes; - List cChildClusterNodes; - for (cit=c->cBegin(); cit.valid(); ++cit) { - (*cit)->getClusterNodes(oChildClusterNodes); - ListConstIterator it; - node copy; - // Compute corresponding nodes of graph \a inducedC. - for (it=oChildClusterNodes.begin(); it.valid(); ++it) { - copy = inducedC->copy(gc.copy(*it)); - cChildClusterNodes.pushBack(copy); - } - inducedC->collaps(cChildClusterNodes); - oChildClusterNodes.clear(); - cChildClusterNodes.clear(); - } - // Now, check \a inducedC for connectivity. - if (!isConnected(*inducedC)) { - - NodeArray conC(*inducedC); - int nCC = connectedComponents(*inducedC,conC); - //at least #connected components - 1 edges have to added. - upperBoundC -= (nCC-1)*m_largestConnectionCoeff; - } - delete inducedC; - } -}//clusterConnection - -double Master::heuristicInitialLowerBound() -{ - double lbound = 0.0; - //In case we only have a single (root) cluster, we can - //use the result of a fast Max Planar Subgraph heuristic - //to initialize the lower bound - if ( (m_C->numberOfClusters() == 1) && (m_mpHeuristic) ) - { - //we run both heuristics that currently exist in OGDF - //MaxSimple - MaximalPlanarSubgraphSimple simpleHeur; - List delEdgesList; - simpleHeur.call(*m_G, delEdgesList); - FastPlanarSubgraph fastHeur; - fastHeur.runs(m_fastHeuristicRuns); - List delEdgesListFast; - fastHeur.call(*m_G, delEdgesListFast); - lbound = m_G->numberOfEdges()-min(delEdgesList.size(), delEdgesListFast.size()); - - if (!isConnected(*m_G)) lbound = lbound-1.0; //#edges*epsilon - }//if heuristics used - return lbound; -}//heuristicInitialLowerBound - -double Master::heuristicInitialUpperBound() { - - double upperBoundO = m_G->numberOfEdges(); - double upperBoundC = 0.0; - - // Checking graph for planarity - // If \a m_G is planar \a upperBound is simply set to the number of edges of \a m_G. - GraphCopy gc(*m_G); - BoyerMyrvold bm; - if (bm.isPlanarDestructive(gc)) upperBoundO = m_G->numberOfEdges(); - else { - - // Extract all possible Kuratowski subdivisions. - // Compare extracted subdivisions and try to obtain the - // maximum number of independent subdivisions, i.e. a maximum - // independent set in the overlap graph. - // Due to the complexity of this task, we only check if - // a subdivision (sd) does overlap with a subdivision for which - // we already decreased the upper bound. In this case, - // upperBound stays the same. - - upperBoundO = m_G->numberOfEdges(); - - GraphCopy *gCopy = new GraphCopy(*m_G); - SList subDivs; - - bm.planarEmbedDestructive(*gCopy,subDivs,-1); - //we store a representative and its status for each edge - //note that there might be an overlap, in that case - //we keep a representative with status false if existing - //to check if we can safely reduce the upper bound (ub) - EdgeArray subRep(*gCopy, NULL); //store representing edge for sd - EdgeArray coverStatus(*gCopy, false); //false means not covered by ub decrease yet - - //runtime for the check: we run over all edges in all subdivisions - if (subDivs.size() > 0) { // At least one edge has to be deleted to obtain planarity. - - // We run over all subdivisions and check for overlaps - SListConstIterator sit = subDivs.begin(); - SListConstIterator eit; - while( sit.valid() ) - { - bool covered = false; //may the sd already be covered by a decrease in ub - //for each edge we set the representative to be the first edge of sd - edge sdRep = *((*sit).edgeList.begin());//sd is always non-empty - //we check if any of the edges in sd were already visited and if - //the representative has status false, in this case, we are not - //allowed to decrease the ub - for (eit=(*sit).edgeList.begin(); eit.valid(); ++eit) - { - //we already encountered this edge - if (subRep[*eit] != NULL) - { - //and decreased ub for an enclosing sd - //(could we just break in the if case?) - if (coverStatus[subRep[*eit]]) covered = true; - else subRep[*eit] = sdRep; //might need an update - } - else subRep[*eit] = sdRep; - } - if (!covered) - { - coverStatus[sdRep] = true; - upperBoundO--; - }//not yet covered, independent - sit++; - }//while - } - delete gCopy; - } - - /* - * Heuristic can be improved by checking, how many additional C-edges have to be added at least. - * A first simple approach is the following: - * Since the Graph has to be completely connected in the end, all chunks have to be connected. - * Thus the numbers of chunks minus 1 summed up over all clusters is a trivial lower bound. - - * We perform a bottom-up search through the cluster-tree, each time checking the cluster - * induced Graph for connectivity. If the Graph is not connected, the number of chunks -1 is added to - * a counter. For "inner" clusters we have to collapse all child clusters to one node, - * in order to obtain a correct result. - */ - - GraphCopy gcc(*m_G); - cluster c = m_C->rootCluster(); - clusterConnection(c, gcc, upperBoundC); - - // Return-value results from the max. number of O-edges that might be contained - // in an optimal solution minus \a epsilon times the number of C-edges that have - // to be added at least in any optimal solution. (\a upperBoundC is non-positive) - return (upperBoundO + upperBoundC); -} - -void Master::nodeDistances(node u, NodeArray > &dist) { - - // Computing the graphtheoretical distances of node u - NodeArray visited(*m_G); - List queue; - visited.fill(false); - visited[u] = true; - int nodesVisited = 1; - adjEntry adj; - node v; - forall_adj(adj,u) { - visited[adj->twinNode()] = true; - nodesVisited++; - dist[u][adj->twinNode()] += 1; - queue.pushBack(adj->twinNode()); - } - while (!queue.empty() || nodesVisited!=m_G->numberOfNodes()) { - v = queue.front(); - queue.popFront(); - forall_adj(adj,v) { - if (!visited[adj->twinNode()]) { - visited[adj->twinNode()] = true; - nodesVisited++; - dist[u][adj->twinNode()] += (dist[u][v]+1); - queue.pushBack(adj->twinNode()); - } - } - } -} - -bool Master::goodVar(node a, node b) { - return true; //add all variables even if they are bad (paper submission) - Logger::slout() << "Good Var? " << a << "->" << b << ": "; - GraphCopy GC(*m_G); - edge e = GC.newEdge(GC.copy(a),GC.copy(b)); - BoyerMyrvold bm; - int ret = bm.isPlanarDestructive(GC); - Logger::slout() << ret << "\n"; - return ret; -} - -void Master::initializeOptimization() { - - //we don't try heuristic improvement (edge addition) in MaxCPlanarSub - //when only checking c-planarity - if (m_checkCPlanar) { - heuristicLevel(0); - //TODO Shortcut: lowerbound number original edges (-1) if not pricing - //enumerationStrategy(BreadthFirst); - } - - if (pricing()) - varElimMode(NoVarElim); - else - varElimMode(ReducedCost); - conElimMode(Basic); - if(pricing()) - pricingFreq(1); - - //----------------------------Creation of Variables--------------------------------// - - // Lists for original and connection edges - List origVars; // MCh: ArrayBuffer would speed this up - List connectVars; // MCh: ArrayBuffer would speed this up - - //cluster connectivity only necessary if there are clusters (not for max planar subgraph) - bool toBeConnected = (!( (m_C->numberOfClusters() == 1) && (isConnected(*m_G)) ) ); - - int nComplete = (m_G->numberOfNodes()*(m_G->numberOfNodes()-1))/2; - int nConnectionEdges = nComplete - m_G->numberOfEdges(); - - double perturbMe = (m_usePerturbation)? 0.2*m_epsilon : 0; - m_deltaCount = nConnectionEdges; - m_delta = (m_deltaCount > 0) ? perturbMe/m_deltaCount : 0; - double coeff; - - // In order not to place the initial upper bound too low, - // we use the largest connection edge coefficient for each C-edge - // to lower the upper bound (since these coeffs are negative, - // this corresponds to the coeff that is closest to 0). - m_largestConnectionCoeff = 0.8*m_epsilon; - m_varsMax = 0; - node u,v; - forall_nodes(u,*m_G) { - v = u->succ(); - while (v!=NULL) {//todo could skip searchedge if toBeConnected - if(m_G->searchEdge(u,v)) - origVars.pushBack(new EdgeVar(this,1.0+rand()*perturbMe,EdgeVar::ORIGINAL,u,v)); - else if (toBeConnected) { - if( (!m_checkCPlanar) || goodVar(u,v)) { - if(pricing()) - m_inactiveVariables.pushBack(nodePair(u,v)); - else - connectVars.pushBack( new EdgeVar(this, nextConnectCoeff(), EdgeVar::CONNECT, u,v) ); - } - ++m_varsMax; - } - v = v->succ(); - } - } - m_varsPotential = m_inactiveVariables.size(); - - //-------------------Creation of ChunkConnection-Constraints------------------------// - - int nChunks = 0; - - List constraintsCC; - - // The Graph, in which each cluster-induced Graph is temporarily stored - Graph subGraph; - - // Since the function inducedSubGraph(..) creates a new Graph \a subGraph, the original - // nodes have to be mapped to the copies. This mapping is stored in \a orig2new. - NodeArray orig2new; - - // Iterate over all clusters of the Graph - ListConstIterator it; - cluster c; - forall_clusters(c,*m_C) { - - List clusterNodes; - c->getClusterNodes(clusterNodes); - - // Compute the cluster-induced Subgraph - it = clusterNodes.begin(); - inducedSubGraph(*m_G, it, subGraph, orig2new); - - // Compute the number of connected components - NodeArray components(subGraph); - int nCC = connectedComponents(subGraph,components); - nChunks+=nCC; - // If the cluster consists of more than one connected component, - // ChunkConnection constraints can be created. - if (nCC > 1) { - - // Determine each connected component (chunk) of the current cluster-induced Graph - for (int i=0; i cC(subGraph.numberOfNodes()); - ArrayBuffer cCComplement(subGraph.numberOfNodes()); - node v; - forall_nodes(v,*m_G/*subGraph*/) { - node n = orig2new[v]; - if(n) { - if (components[n] == i) cC.push(v); - else cCComplement.push(v); - } - } - // Creating corresponding constraint - constraintsCC.pushBack(new ChunkConnection(this, cC, cCComplement)); - // Avoiding duplicates if cluster consists of 2 chunks - if (nCC == 2) break; - - }//connected component has been processed - }//end if(nCC > 1) - }//end forall_clusters - if(pricing()) - generateVariablesForFeasibility(constraintsCC, connectVars); - - //------------Creation of MinimalClusterConnection-Constraints---------------// - /* - List constraintsMCC; - cluster succ; - ClusterArray connected(*m_C); - // For each cluster run through all cluster vertices and check if - // they have an outgoing edge to a different cluster. - // In this case, mark that cluster in connected as true. - forall_clusters(c,*m_C) { - - succ = c->succ(); - connected.fill(false); - List clusterNodes; - c->getClusterNodes(clusterNodes); - ListConstIterator it; - for (it=clusterNodes.begin(); it.valid(); ++it) { - adjEntry adj; - forall_adj(adj,*it) { - if(m_C->clusterOf(adj->twinNode()) != c) { - connected[m_C->clusterOf(adj->twinNode())] = true; - } - } - } - - //checking if there is an entry in \a connected of value false - //if so, cluster \a c is not connected to this one and a constraint is created - List mcc_edges; - while(succ!=0) { - if (!connected[succ]) { - ListConstIterator it; - //determine all nodePairs between \a c and \a succ and add them to list \a mcc_edges - for (it=clusterNodes.begin(); it.valid(); ++it) { - adjEntry adj; - nodePair np; - forall_adj(adj,*it) { - if (m_C->clusterOf(adj->twinNode()) == succ) { - np.v1 = (*it); - np.v2 = adj->twinNode(); - mcc_edges.pushBack(np); - } - } - } - Logger::slout() << "mcc_edges: " << mcc_edges.size() << endl; - //create new constraint and put it into list \a constraintsMCC - constraintsMCC.pushBack(new MinimalClusterConnection(this,mcc_edges)); - mcc_edges.clear(); - } - succ = succ->succ(); - } - } - */ - - //------------Creation of MaxPlanarEdges-Constraints---------------// - - List constraintsMPE; - - int nMaxPlanarEdges = 3*m_G->numberOfNodes() - 6; - constraintsMPE.pushBack(new MaxPlanarEdgesConstraint(this,nMaxPlanarEdges)); - - List clusterNodes; - List clusterEdges; - forall_clusters(c,*m_C) { - - if (c == m_C->rootCluster()) continue; - clusterNodes.clear(); clusterEdges.clear(); - c->getClusterNodes(clusterNodes); - if (clusterNodes.size() >= 4) { - nodePair np; - ListConstIterator it; - ListConstIterator it_succ; - for (it=clusterNodes.begin(); it.valid(); ++it) { - it_succ = it.succ(); - while (it_succ.valid()) { - np.v1 = (*it); np.v2 = (*it_succ); - clusterEdges.pushBack(np); - it_succ++; - } - } - int maxPlanarEdges = 3*clusterNodes.size() - 6; - constraintsMPE.pushBack(new MaxPlanarEdgesConstraint(this,maxPlanarEdges,clusterEdges)); - } - } - - - //------------------------Adding Constraints to the Pool---------------------// - - // Adding constraints to the standardpool - ABA_BUFFER initConstraints(this,constraintsCC.size()/*+constraintsMCC.size()*/+constraintsMPE.size()); - - ListConstIterator ccIt; - updateAddedCCons(constraintsCC.size()); - for (ccIt = constraintsCC.begin(); ccIt.valid(); ++ccIt) { - initConstraints.push(*ccIt); - } -// ListConstIterator mccIt; -// for (mccIt = constraintsMCC.begin(); mccIt.valid(); ++mccIt) { -// initConstraints.push(*mccIt); -// } - ListConstIterator mpeIt; - for (mpeIt = constraintsMPE.begin(); mpeIt.valid(); ++mpeIt) { - initConstraints.push(*mpeIt); - } - //output these constraints in a file that can be read by the module - if (m_porta) - { - - ofstream ofs(getStdConstraintsFileName()); - if (!ofs) cerr << "Could not open output stream for PORTA constraints file\n"; - else - { - ofs << "# Chunkconnection constraints\n"; - //holds the coefficients in a single constraint for all vars defined - //so far - List theCoeffs; - ListIterator csIt; - for (csIt = constraintsCC.begin(); ccIt.valid(); ++ccIt) { - getCoefficients((*csIt), origVars, connectVars, theCoeffs); - ListConstIterator dIt = theCoeffs.begin(); - while (dIt.valid()) - { - ofs << (*dIt) << " "; - dIt++; - }//while - //check csense here - ofs << ">= " << (*csIt)->rhs(); - ofs << "\n"; - } -// ofs << "# MinimalClusterconnection constraints\n"; -// ListConstIterator mccIt; -// for (mccIt = constraintsMCC.begin(); mccIt.valid(); ++mccIt) { -// getCoefficients((*mccIt), origVars, connectVars, theCoeffs); -// ListConstIterator dIt = theCoeffs.begin(); -// while (dIt.valid()) -// { -// ofs << (*dIt) << " "; -// dIt++; -// }//while -// ofs << "<= " << (*mccIt)->rhs(); -// ofs << "\n"; -// } - ofs << "# MaxPlanarEdges constraints\n"; - ListConstIterator mpeIt; - for (mpeIt = constraintsMPE.begin(); mpeIt.valid(); ++mpeIt) { - getCoefficients((*mpeIt), origVars, connectVars, theCoeffs); - ListConstIterator dIt = theCoeffs.begin(); - while (dIt.valid()) - { - ofs << (*dIt) << " "; - dIt++; - }//while - ofs << "<= " << (*mpeIt)->rhs(); - ofs << "\n"; - } - ofs.close(); - } - } - - //---------------------Adding Variables to the Pool---------------------// - - // Adding variables to the standardpool - ABA_BUFFER edgeVariables(this,origVars.size()+connectVars.size()); - ListConstIterator eIt; - for (eIt = origVars.begin(); eIt.valid(); ++eIt) { - edgeVariables.push(*eIt); - } - for (eIt = connectVars.begin(); eIt.valid(); ++eIt) { - edgeVariables.push(*eIt); - } - - - //---------------------Initializing the Pools---------------------------// - - int poolsize = (getGraph()->numberOfNodes() * getGraph()->numberOfNodes()); - if (m_useDefaultCutPool) - initializePools(initConstraints, edgeVariables, m_nMaxVars, poolsize, true); - else - { - initializePools(initConstraints, edgeVariables, m_nMaxVars, 0, false); - //TODO: How many of them? - m_cutConnPool = new ABA_STANDARDPOOL(this, poolsize, true); - m_cutKuraPool = new ABA_STANDARDPOOL(this, poolsize, true); - } - - - //---------------------Initialize Upper Bound---------------------------// - - //if we check only for c-planarity, we cannot set bounds - if (!m_checkCPlanar) - { - double upperBound = heuristicInitialUpperBound(); // TODO-TESTING - dualBound(upperBound); // TODO-TESTING - - //---------------------Initialize Lower Bound---------------------------// - - primalBound(heuristicInitialLowerBound()); // TODO-TESTING - } else { - //primalBound(-m_G->numberOfNodes()*3); - } - - //----------------------Setting Parameters------------------------------// - -// conElimMode(ABA_MASTER::NonBinding); - outLevel(m_out); - maxCpuTime(*m_maxCpuTime); - - Logger::ssout() << "#Nodes: " << m_G->numberOfNodes() << "\n"; - Logger::ssout() << "#Edges: " << m_G->numberOfEdges() << "\n"; - Logger::ssout() << "#Clusters: " << m_C->numberOfClusters() << "\n"; - Logger::ssout() << "#Chunks: " << nChunks << "\n"; - - -} - -// returns coefficients of all variables in orig and connect in constraint con -// as list coeffs -void Master::getCoefficients(ABA_CONSTRAINT* con, const List & orig, - const List & connect, List & coeffs) -{ - coeffs.clear(); - ListConstIterator cIt = orig.begin(); - while (cIt.valid()) - { - coeffs.pushBack(con->coeff(*cIt)); - cIt++; - }//while - cIt = connect.begin(); - while (cIt.valid()) - { - coeffs.pushBack(con->coeff(*cIt)); - cIt++; - }//while - -} - - -//output statistics -//and change the list of deleted edges in case only c-planarity is tested -//(to guarantee that the list is non-empty if input is not c-planar) -void Master::terminateOptimization() { - Logger::slout() << "=================================================\n"; - Logger::slout() << "Terminate Optimization:\n"; - Logger::slout() << "(primal Bound: " << primalBound() << ")\n"; - Logger::slout() << "(dual Bound: " << dualBound() << ")\n"; - Logger::slout() << "*** " << (m_deletedOriginalEdges.size() == 0 ? "" : "NON ") << "C-PLANAR ***\n"; - Logger::slout() << "*** " << (feasibleFound() ? "" : "NO ") << "feasible solution found ***\n"; - Logger::slout() << "=================================================\n"; - - Logger::ssout() << "\n"; - - Logger::ssout() << "C-Planar: " << (feasibleFound() && (m_deletedOriginalEdges.size() == 0)) << "\n"; - Logger::ssout() << "FeasibleFound: " << feasibleFound() << "\n"; - Logger::ssout() << "Time: "<< getDoubleTime(totalTime()) << "\n"; - Logger::ssout() << "LP-Time: " << getDoubleTime(lpSolverTime()) << "\n"; - Logger::ssout() << "\n"; - Logger::ssout() << "#BB-nodes: " << nSub() << "\n"; - Logger::ssout() << "#LP-relax: " << m_solvesLP << "\n"; - Logger::ssout() << "Added Edges: " <\n"; - - node n,m; - edge e; - forall_nodes(n, *m_G) { - forall_nodes(m, *m_G) { - if(m->index()<=n->index()) continue; - forall_adj_edges(e, n) { - if(e->opposite(n)==m) { - Logger::slout() << "ORIG: " << n << "-" << m << "\n"; - continue; - } - } - } - } - forall_nodes(n, *m_G) { - forall_nodes(m, *m_G) { - if(m->index()<=n->index()) continue; - forall_adj_edges(e, n) { - if(e->opposite(n)==m) { - goto wup; - } - } - forall_listiterators(nodePair, it, m_inactiveVariables) { - if( ((*it).v1==n && (*it).v2==m) || ((*it).v2==n && (*it).v1==m)) { - goto wup; - } - } - Logger::slout() << "CONN: " << n << "-" << m << "\n"; - wup:; - } - } - - globalPrimalBound = primalBound(); - globalDualBound = dualBound(); -} - -void Master::generateVariablesForFeasibility(const List& ccons, List& connectVars) { - List cpy(ccons); -// forall_listiterators(ChunkConnection*, ccit, cpy) { -// (*ccit)->printMe(); -// } - - ArrayBuffer > creationBuffer(ccons.size()); - forall_nonconst_listiterators(nodePair, npit, m_inactiveVariables) { - bool select = false; -// (*npit).printMe(); - ListIterator ccit = cpy.begin(); - while(ccit.valid()) { - if((*ccit)->coeff(*npit)) { - ListIterator delme = ccit; - ++ccit; - cpy.del(delme); - select = true; - } else - ++ccit; - } - if(select) { -// Logger::slout() << "<--CREATE"; - creationBuffer.push(npit); - } - if(cpy.size()==0) break; - } -// forall_listiterators(ChunkConnection*, ccit, cpy) { -// (*ccit)->printMe(); -// } - OGDF_ASSERT(cpy.size()==0); - Logger::slout() << "Creating " << creationBuffer.size() << " Connect-Variables for feasibility\n"; - m_varsInit = creationBuffer.size(); - // realize creationList - for(int i = creationBuffer.size(); i-->0;) { - connectVars.pushBack( createVariable( creationBuffer[i] ) ); - } -} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/MaxCPlanar_MinimalClusterConnection.cpp b/ext/OGDF/src/cluster/MaxCPlanar_MinimalClusterConnection.cpp deleted file mode 100644 index 61fe1a9f2..000000000 --- a/ext/OGDF/src/cluster/MaxCPlanar_MinimalClusterConnection.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of constraint class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem. - * - * If some cluster has no connection to some other cluster, - * the optimal solution might insert a new connection-edge between theese two clusters, - * to obtain connectivity. Since the objective function minimizes the number - * of new connection-edges, at most one new egde will be inserted between - * two clusters that are not connected. - * This behaviour of the LP-solution is guaranteed from the beginning, by creating - * an initial constraint for each pair of non-connected clusters, - * which is implemented by this constraint class. - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include - -using namespace ogdf; - - -MinimalClusterConnection::MinimalClusterConnection(ABA_MASTER *master, List &edges) : - ABA_CONSTRAINT(master, 0, ABA_CSENSE::Less, 1.0, false, false, true) -{ - ListConstIterator it; - for (it = edges.begin(); it.valid(); ++it) { - m_edges.pushBack(*it); - } -} - - -MinimalClusterConnection::~MinimalClusterConnection() {} - - -double MinimalClusterConnection::coeff(ABA_VARIABLE *v) { - //TODO: speedup, we know between which nodepairs edges exist... - EdgeVar *e = (EdgeVar *)v; - ListConstIterator it; - for (it = m_edges.begin(); it.valid(); ++it) { - if ( ((*it).v1 == e->sourceNode() && (*it).v2 == e->targetNode()) || - ((*it).v2 == e->sourceNode() && (*it).v1 == e->targetNode()) ) - {return 1.0;} - } - return 0.0; -} - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/MaxCPlanar_Sub.cpp b/ext/OGDF/src/cluster/MaxCPlanar_Sub.cpp deleted file mode 100644 index f08a187c5..000000000 --- a/ext/OGDF/src/cluster/MaxCPlanar_Sub.cpp +++ /dev/null @@ -1,2573 +0,0 @@ -/* - * $Revision: 2611 $ - * - * last checkin: - * $Author: klein $ - * $Date: 2012-07-16 10:50:21 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the subproblem class for the Branch&Cut algorithm - * for the Maximum C-Planar SubGraph problem - * Contains separation algorithms as well as primal heuristics. - * - * \authors Markus Chimani, Mathias Jansen, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -//output intermediate results when new sons are generated -//#define IM_OUTPUT -#ifdef IM_OUTPUT -#include -#include -#include -#endif - -using namespace ogdf; - - -Sub::Sub(ABA_MASTER *master) : ABA_SUB(master,500,((Master*)master)->m_inactiveVariables.size(),2000,false),bufferedForCreation(10),detectedInfeasibility(false),inOrigSolveLp(false) { - m_constraintsFound = false; - m_sepFirst = false; -// for(int k=0; k(variable(k)); -// if(ev->theEdgeType()==EdgeVar::ORIGINAL) -// fsVarStat(k)->status()->status(ABA_FSVARSTAT::SetToUpperBound); -// } - - // only output below... -#ifdef OGDF_DEBUG - Logger::slout() << "Construct 1st Sub\n"; - Logger::slout() << nVar() << " " << nCon() << "\n"; - int i; - for(i=0; i(variable(i)))->printMe(Logger::slout()); Logger::slout() << "\n"; - } - for(i=0; i(c); - MaxPlanarEdgesConstraint* cmax = dynamic_cast(c); - if(ccon) { - Logger::slout() << "ChunkConstraint: Chunk="; - int j; - forall_arrayindices(j,ccon->m_chunk) { - Logger::slout() << ccon->m_chunk[j] << ","; - } - Logger::slout() << " Co-Chunk="; - forall_arrayindices(j,ccon->m_cochunk) { - Logger::slout() << ccon->m_cochunk[j] << ","; - } - Logger::slout() << "\n"; - } else if(cmax) { - Logger::slout() << "MaxPlanarEdgesConstraint: rhs=" << cmax->rhs() << ", graphCons=" << cmax->m_graphCons << ", nodePairs="; - forall_listiterators(nodePair, it, cmax->m_edges) { - Logger::slout() << "("<<(*it).v1<<","<<(*it).v2<<")"; - } - Logger::slout() << "\n"; - } else { - Logger::slout() << "** Unexpected Constraint\n"; - } - } -#endif //OGDF_DEBUG -} - - -Sub::Sub(ABA_MASTER *master,ABA_SUB *father,ABA_BRANCHRULE *rule,List& criticalConstraints): -ABA_SUB(master,father,rule), bufferedForCreation(10),detectedInfeasibility(false),inOrigSolveLp(false) { - m_constraintsFound = false; - m_sepFirst = false; - criticalSinceBranching.exchange(criticalConstraints); // fast load - Logger::slout() << "Construct Child Sub " << id() << "\n"; -} - - -Sub::~Sub() {} - - -ABA_SUB *Sub::generateSon(ABA_BRANCHRULE *rule) { - //dualBound_ = realDualBound; - - const double minViolation = 0.001; // value fixed from abacus... - #ifdef IM_OUTPUT - if (father() == 0) - { - ofstream output("Intermediate.txt",ios::app); - if (!output) cerr<<"Could not open file for intermediate results!\n"; - - output << "Intermediate Results at branching in Root Node\n"; - output << "Number of graph nodes: " << ((Master*)master_)->getGraph()->numberOfNodes() <<"\n"; - output << "Number of graph edges: " << ((Master*)master_)->getGraph()->numberOfEdges() <<"\n"; - - output << "Current number of active variables: " << nVar() << "\n"; - output << "Current number of active constraints: " << nCon() << "\n"; - - output << "Current lower bound: " << lowerBound()<<"\n"; - output << "Current upper bound: " << upperBound()<<"\n"; - - output << "Global primal bound: " << ((Master*)master_)->getPrimalBound()<<"\n"; - output << "Global dual bound: " << ((Master*)master_)->getDualBound()<<"\n"; - - output << "Added K cons: " << ((Master*)master_)->addedKConstraints()<<"\n"; - output << "Added C cons: " << ((Master*)master_)->addedCConstraints()<<"\n"; - output.close(); - - GraphAttributes GA(*(((Master*)master_)->getGraph()), GraphAttributes::edgeStyle | - GraphAttributes::edgeDoubleWeight | GraphAttributes::edgeColor | - GraphAttributes::edgeGraphics); - - edge e; - for (int i=0; i<((Master*)master_)->nVar(); ++i) - //forall_edges(e, *(((Master*)master_)->getGraph()) - { - EdgeVar *e = (EdgeVar*)variable(i); - if (e->theEdgeType() == EdgeVar::ORIGINAL) - { - GA.doubleWeight(e->theEdge()) = xVal(i); - GA.edgeWidth(e->theEdge()) = 10.0*xVal(i); - if (xVal(i) == 1.0) GA.colorEdge(e->theEdge()) = "#FF0000"; - }//if real edge - }//forall variables - GA.writeGML("WeightedIntermediateGraph.gml"); - } - #endif - - List< ABA_CONSTRAINT* > criticalConstraints; - if (master()->pricing()) - { - //ABA_SETBRANCHRULE* srule = (ABA_SETBRANCHRULE*)(rule); - ABA_SETBRANCHRULE* srule; - srule = dynamic_cast(rule); - OGDF_ASSERT( srule ); // hopefully no other branching stuff... - //Branching by setting a variable to 0 may - //result in infeasibility of the current system - //because connectivity constraints may not be feasible - //with the current set of variables - if(!srule->setToUpperBound()) { // 0-branching - int varidx = srule->variable(); - EdgeVar* var = (EdgeVar*)variable(varidx); - - Logger::slout() << "FIXING VAR: "; - var->printMe(Logger::slout()); - Logger::slout() << "\n"; - - for(int i = nCon(); i-->0;) { - ABA_CONSTRAINT* con = constraint(i); - double coeff = con->coeff(var); - if(con->sense()->sense()==ABA_CSENSE::Greater && coeff>0.99) { - // check: yVal gives the slack and is always negative or 0 - double slk; - //slk = yVal(i); - slk = con->slack(actVar(),xVal_); - //quick hack using ABACUS value, needs to be corrected - if (slk > 0.0 && slk < minViolation) - { - slk = 0.0; -#ifdef OGDF_DEBUG - cout << "Set slack to 0.0\n"; -#endif - } - if(slk > 0.0) { - Logger::slout() << "ohoh..." << slk << " "; var->printMe(Logger::slout()); Logger::slout()< 0.0001) { // setting might introduce infeasibility - // TODO: is the code below valid (in terms of theory) ??? - // "es reicht wenn noch irgendeine nicht-auf-0-fixierte variable im constraint existiert, die das rettet - // mögliches problem: was wenn alle kanten bis auf die aktive kante in einem kuratowski constraint - // auf 1 fixiert sind (zB grosse teile wegen planaritätstest-modus, und ein paar andere wg. branching). - // - // bool good = false; // does there exist another good variable? - // for(int j = nVar(); j-->0;) { - // if(con->coeff(variable[j])>0.99 && VARIABLE[j]-NOT-FIXED-TO-0) { - // good = true; - // break; - // } - // } - // if(!good) - criticalConstraints.pushBack(con); - } - } - } - } - }//pricing - - return new Sub(master_, this, rule, criticalConstraints); -} - - -int Sub::selectBranchingVariable(int &variable) { - //dualBound_ = realDualBound; - - return ABA_SUB::selectBranchingVariable(variable); - - /// the stuff below does NOTHING! - - int variableABA; - int found = ABA_SUB::selectBranchingVariable(variableABA); - if (found == 0) { - //Edge *e = (Edge*)(this->variable(variableABA)); - //cout << "Branching variable is: " << (e->theEdgeType()==ORIGINAL ? "Original" : "Connect") << " Edge ("; - //cout << e->sourceNode()->index() << "," << e->targetNode()->index() << ") having value: "; - //cout << xVal(variableABA) << " and coefficient " << ((Edge*)this->variable(variableABA))->objCoeff() << endl; - variable = variableABA; - return 0; - } - return 1; -} - - -int Sub::selectBranchingVariableCandidates(ABA_BUFFER &candidates) { -// if(master()->m_checkCPlanar) -// return ABA_SUB::selectBranchingVariableCandidates(candidates); - - ABA_BUFFER candidatesABA(master_,1); - int found = ABA_SUB::selectBranchingVariableCandidates(candidatesABA); - - if (found == 1) return 1; - else { - int i = candidatesABA.pop(); - EdgeVar *e = (EdgeVar*)variable(i); - if (e->theEdgeType() == EdgeVar::ORIGINAL) { - OGDF_ASSERT( !master()->m_checkCPlanar ) - candidates.push(i); - return 0; - } else { - - // Checking if a more appropriate o-edge can be found according to the global parameter - //\a branchingOEdgeSelectGap. Candidates are stored in list \a oEdgeCandits. - List oEdgeCandits; - for (int j=0; jtheEdgeType() == EdgeVar::ORIGINAL) { - if ( (xVal(j) >= (0.5-((Master*)master_)->branchingOEdgeSelectGap())) && - (xVal(j) <= (0.5+((Master*)master_)->branchingOEdgeSelectGap())) ) { - oEdgeCandits.pushBack(j); - } - } - } - if (oEdgeCandits.empty()) { - candidates.push(i); - return 0; - } else { - - // Choose one of those edges randomly. - int random = randomNumber(0,oEdgeCandits.size()-1); - int index = random; - ListConstIterator it = oEdgeCandits.get(index); - candidates.push(*it); - return 0; - } - } - } -} - - -void Sub::updateSolution() { - - List originalOneEdges; - List connectionOneEdges; - List deletedEdges; - nodePair np; -// for (int i=0; i<((Master*)master_)->nVars(); ++i) { - for (int i=0; i= 1.0-(master_->eps())) { - - EdgeVar *e = (EdgeVar*)variable(i); - np.v1 = e->sourceNode(); - np.v2 = e->targetNode(); - if (e->theEdgeType() == EdgeVar::ORIGINAL) originalOneEdges.pushBack(np); - else connectionOneEdges.pushBack(np); - } - else { - - EdgeVar *e = (EdgeVar*)variable(i); - if (e->theEdgeType() == EdgeVar::ORIGINAL) { - deletedEdges.pushBack(e->theEdge()); - } - } - } -#ifdef OGDF_DEBUG - ((Master*)master_)->m_solByHeuristic = false; -#endif - ((Master*)master_)->updateBestSubGraph(originalOneEdges,connectionOneEdges,deletedEdges); -} - - -double Sub::subdivisionLefthandSide(SListConstIterator kw, GraphCopy *gc) { - - double lefthandSide = 0.0; - node v,w; -// for (int i=0; i<((Master*)master_)->nVars(); ++i) { - for (int i=0; isourceNode(); - w = e->targetNode(); - SListConstIterator it; - for (it=(*kw).edgeList.begin(); it.valid(); ++it) { - if ( ((*it)->source() == gc->copy(v) && (*it)->target() == gc->copy(w) ) || - ((*it)->source() == gc->copy(w) && (*it)->target() == gc->copy(v) ) ) { - lefthandSide += xVal(i); - } - } - } - return lefthandSide; -} - - -/////////////////////////////////////////////////// -// HEURISTIC -/////////////////////////////////////////////////// - - -int Sub::getArrayIndex(double lpValue) { - int index = 0; - double x = 1.0; - double listRange = (1.0/((Master*)master_)->numberOfHeuristicPermutationLists()); - while (x >= lpValue) { - x -= listRange; - if (lpValue >= x) return index; - index++; - } - return index; -} - - -void Sub::childClusterSpanningTree( - GraphCopy &GC, - List &clusterEdges, - List &MSTEdges) -{ - // Testing and adding of edges in \a clusterEdges is performed randomized. - // Dividing edges into original and connection 1-edges and fractional edges. - // Tree is built using edges in this order. - List oneOEdges; - List oneToFracBoundOEdges; - List leftoverEdges; - ListConstIterator it = clusterEdges.begin(); - while(it.valid()) { - - if ((*it).lpValue >= (1.0-master_->eps())) { - if ((*it).original) oneOEdges.pushBack(*it); - else leftoverEdges.pushBack(*it); - } else if ((*it).lpValue >= ((Master*)master_)->getHeuristicFractionalBound()) { - if ((*it).original) oneToFracBoundOEdges.pushBack(*it); - else leftoverEdges.pushBack(*it); - } - else leftoverEdges.pushBack(*it); - it++; - } - - // Try to create spanning tree with original 1-edges. - if(oneOEdges.size() > 1) oneOEdges.permute(); - edge newEdge; - node v,w; - nodePair np; - for (it=oneOEdges.begin(); it.valid(); ++it) { - v = (*it).src; - w = (*it).trg; - newEdge = GC.newEdge(GC.copy(v),GC.copy(w)); - //Union-Find could make this faster... - if (!isAcyclicUndirected(GC)) GC.delEdge(newEdge); - else { - np.v1 = v; np.v2 = w; - MSTEdges.pushBack(np); - } - if (GC.numberOfEdges() == GC.numberOfNodes()-1) return; - } - //is there a case this if would return without having returned above? - if (isConnected(GC)) return; - - // Create two Arrays of lists containing nodePairs that have "similar" fractional value. - // "Similar" is defined by the parameter \a Master->nPermutationLists. - double listRange = (1.0/((Master*)master_)->numberOfHeuristicPermutationLists()); - double range = 0.0; - int indexCount = 0; - while ( (1.0-((Master*)master_)->getHeuristicFractionalBound()) > range ) { - indexCount++; - range += listRange; - } - Array > oEdgePermLists(0,indexCount); - Array > leftoverPermLists(0,((Master*)master_)->numberOfHeuristicPermutationLists()); - - // Distributing edges in \a oneToFracBoundOEdges and \a leftoverEdges among the permutation lists. - int index; - for (it=oneToFracBoundOEdges.begin(); it.valid(); ++it) { - index = getArrayIndex((*it).lpValue); - oEdgePermLists[index].pushBack(*it); - } - for (it=leftoverEdges.begin(); it.valid(); ++it) { - index = getArrayIndex((*it).lpValue); - leftoverPermLists[index].pushBack(*it); - } - - - for (int i=0; i 1) oEdgePermLists[i].permute(); - - for (it=oEdgePermLists[i].begin(); it.valid(); ++it) { - v = (*it).src; - w = (*it).trg; - newEdge = GC.newEdge(GC.copy(v),GC.copy(w)); - if (!isAcyclicUndirected(GC)) { - GC.delCopy(newEdge); - } - else { - np.v1 = v; np.v2 = w; - MSTEdges.pushBack(np); - } - if (GC.numberOfEdges() == GC.numberOfNodes()-1) return; - } - - if (isConnected(GC)) return; - } - - for (int i=0; i 1) leftoverPermLists[i].permute(); - - for (it=leftoverPermLists[i].begin(); it.valid(); ++it) { - v = (*it).src; - w = (*it).trg; - newEdge = GC.newEdge(GC.copy(v),GC.copy(w)); - if (!isAcyclicUndirected(GC)) { - GC.delCopy(newEdge); - } - else { - np.v1 = v; np.v2 = w; - MSTEdges.pushBack(np); - } - if (GC.numberOfEdges() == GC.numberOfNodes()-1) return; - } - - if (isConnected(GC)) return; - } - - //Todo: What is happening here? Do we have to abort? - if (!isConnected(GC)) cerr << "Error. For some reason no spanning tree could be computed" << endl << flush; - return; -} - - -void Sub::clusterSpanningTree( - ClusterGraph &C, - cluster c, - ClusterArray > &treeEdges, - ClusterArray > &clusterEdges) -{ - //looks like a minspantree problem with some weights based - //on edge status and LP-value, right? - GraphCopy *GC; - if (c->cCount() == 0) { // Cluster is a leaf, so MST can be computed. - - // Create a cluster induced GraphCopy of \a G and delete all edges. - GC = new GraphCopy(C.getGraph()); - node v = GC->firstNode(); - node v_succ; - while (v!=0) { - v_succ = v->succ(); - if (C.clusterOf(GC->original(v)) != c) { - GC->delNode(v); - } - v = v_succ; - } - edge e = GC->firstEdge(); - edge e_succ; - while (e!=0) { - e_succ = e->succ(); - GC->delCopy(e); - e = e_succ; - } - childClusterSpanningTree(*GC,clusterEdges[c],treeEdges[c]); - delete GC; - return; - } - - // If cluster \a c has further children, they have to be processed first. - ListConstIterator cit; - for (cit=c->cBegin(); cit.valid(); ++cit) { - - clusterSpanningTree(C,(*cit),treeEdges,clusterEdges); - - // Computed treeEdges for the child clusters have to be added to \a treeEdges for current cluster. - ListConstIterator it; - for (it=treeEdges[(*cit)].begin(); it.valid(); ++it) { - treeEdges[c].pushBack(*it); - } - } - - // A spanning tree has been computed for all children of cluster \a c. - // Thus, a spanning tree for \a c can now be computed. - // \a treeEdges[c] now contains all edges that have been previously added - // during the computation of the trees for its child clusters. - - // Create GraphCopy induced by nodes in \a nodes. - GC = new GraphCopy(C.getGraph()); - NodeArray isInCluster(*GC,false); - List clusterNodes; - c->getClusterNodes(clusterNodes); - ListConstIterator it; - for (it=clusterNodes.begin(); it.valid(); ++it) { - isInCluster[GC->copy(*it)] = true; - } - node v = GC->firstNode(); - node v_succ; - while (v!=0) { - v_succ = v->succ(); - if (!isInCluster[v]) { - GC->delNode(v); - } - v = v_succ; - } - edge e = GC->firstEdge(); - edge e_succ; - while (e!=0) { - e_succ = e->succ(); - GC->delCopy(e); - e = e_succ; - } - // Edges that have been added in child clusters by computing a spanning tree - // have to be added to the GraphCopy. - ListConstIterator it2; - node cv,cw; - for (it2=treeEdges[c].begin(); it2.valid(); ++it2) { - cv = GC->copy((*it2).v1); - cw = GC->copy((*it2).v2); - GC->newEdge(cv,cw); - } - - // Compute relevant nodePairs, i.e. all nodePairs induced by cluster c - // leaving out already added ones. - List clusterNodePairs; - ListConstIterator it3; - for (it3=clusterEdges[c].begin(); it3.valid(); ++it3) { - cv = GC->copy((*it3).src); - cw = GC->copy((*it3).trg); - //TODO in liste speichern ob kante vorhanden dann kein searchedge - if (!GC->searchEdge(cv,cw)) clusterNodePairs.pushBack(*it3); - } - - childClusterSpanningTree(*GC,clusterNodePairs,treeEdges[c]); - delete GC; - return; -} - - -double Sub::heuristicImprovePrimalBound( - List &origEdges, - List &conEdges, - List &delEdges) -{ - - origEdges.clear(); conEdges.clear(); delEdges.clear(); - - double oEdgeObjValue = 0.0; - double cEdgeObjValue = 0.0; - int originalEdgeCounter = 0; - - // A copy of the Clustergraph has to be created. - // To be able to have access to the original nodes after the heuristic has been performed, - // we maintain the Arrays \a originalClusterTable and \a originalNodeTable. - Graph G; - ClusterArray originalClusterTable(*(((Master*)master_)->getClusterGraph())); - NodeArray originalNodeTable(*(((Master*)master_)->getGraph())); - ClusterGraph CC( *(((Master*)master_)->getClusterGraph()),G,originalClusterTable,originalNodeTable ); - - //NodeArray \a reverseNodeTable is indexized by \a G and contains the corresponding original nodes - NodeArray reverseNodeTable(G); - node v; - forall_nodes(v,*(((Master*)master_)->getGraph())) { - node w = originalNodeTable[v]; - reverseNodeTable[w] = v; - } - - // First, nodePairs have to be sorted in increasing order of their LP-value. - // Therefore a Binary Heap is built and read once to obtain a sorted list of the nodePairs. - List globalNodePairList; - BinaryHeap2 BH_all(nVar()); - edgeValue ev; - node ov,ow; - double lpValue; - cluster lca; - for (int i=0; isourceNode(); - ow = ((EdgeVar*)variable(i))->targetNode(); - ev.src = originalNodeTable[ov]; //the node copies in G - ev.trg = originalNodeTable[ow]; - ev.e = ((EdgeVar*)variable(i))->theEdge(); //the original edge - lpValue = 1.0-xVal(i); - ev.lpValue = xVal(i); - if ( ((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::ORIGINAL ) ev.original = true; - else ev.original = false; - BH_all.insert(ev,lpValue); - } - - // ClusterArray \a clusterEdges contains for each cluster all corresponding edgeValues - // in increasing order of their LP-values. - ClusterArray > clusterEdges(CC); - for (int i=0; i > spanningTreesNodePairs(CC); - clusterSpanningTree( - CC, - originalClusterTable[(((Master*)master_)->getClusterGraph())->rootCluster()], - spanningTreesNodePairs, - clusterEdges); - // \a spanningTreesNodePairs[CC->rootCluster] now contains the edges of the computed tree. - - // Create the induced ClusterGraph. - edge e = G.firstEdge(); - edge e_succ; - while (e!=0) { - e_succ = e->succ(); - G.delEdge(e); - e = e_succ; - } - ListConstIterator it2; - for (it2=spanningTreesNodePairs[CC.rootCluster()].begin(); it2.valid(); ++it2) { - G.newEdge((*it2).v1,(*it2).v2); - } - - // Creating two lists \a cEdgeNodePairs and \a oEdgeNodePairs in increasing order of LP-values. - int nOEdges = 0; - List oEdgeNodePairs; - BinaryHeap2 BH_oEdges(nVar()); - node cv,cw; - nodePair np; - for (int i=0; isourceNode() ]; - cw = originalNodeTable[ ((EdgeVar*)variable(i))->targetNode() ]; - //todo searchedge? - if (!G.searchEdge(cv,cw)) { - ev.src = cv; ev.trg = cw; - lpValue = 1.0-xVal(i); - ev.lpValue = xVal(i); - if ( ((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::ORIGINAL ) { - ev.e = ((EdgeVar*)variable(i))->theEdge(); //the original edge - BH_oEdges.insert(ev,lpValue); - nOEdges++; - } - } else { // Edge is contained in G. - np.v1 = ((EdgeVar*)variable(i))->sourceNode(); - np.v2 = ((EdgeVar*)variable(i))->targetNode(); - - if ( ((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::ORIGINAL ) { - originalEdgeCounter++; - oEdgeObjValue += 1.0; - // Since edges that have been added are not deleted in further steps, - // list \a origEdges may be updated in this step. - origEdges.pushBack(np); - - } else { - // Since edges that have been added are not deleted in further steps, - // list \a conEdges may be updated in this step. - conEdges.pushBack(np); - } - } - } - - for (int i=1; i<=nOEdges; ++i) { - oEdgeNodePairs.pushBack(BH_oEdges.extractMin()); - } - - //INSERTING LEFTOVER NODEPAIRS IN INCREASING ORDER OF LP_VALUE AND CHECKING FOR C-PLANARITY - - List oneOEdges; - List fracEdges; - ListConstIterator it4 = oEdgeNodePairs.begin(); - while(it4.valid()) { - if ((*it4).lpValue >= (1.0-master_->eps())) { - oneOEdges.pushBack(*it4); - } else { - fracEdges.pushBack(*it4); - } - it4++; - } - - // Randomly permute the edges in \a oneOEdges. - oneOEdges.permute(); - ListConstIterator it3; - edge addEdge; - bool cPlanar; - CconnectClusterPlanar cccp; - for (it3=oneOEdges.begin(); it3.valid(); ++it3) { - - addEdge = G.newEdge((*it3).src,(*it3).trg); - cPlanar = cccp.call(CC); - if (!cPlanar) { - G.delEdge(addEdge); - // Since edges that have been added are not deleted in further steps, - // list \a origEdges may be updated in this step. - np.v1 = reverseNodeTable[(*it3).src]; - np.v2 = reverseNodeTable[(*it3).trg]; - //Hier aus oneOEdges - delEdges.pushBack((*it3).e); - } else { - originalEdgeCounter++; - oEdgeObjValue += 1.0; - // Since edges that have been added are not deleted in further steps, - // list \a origEdges may be updated in this step. - np.v1 = reverseNodeTable[(*it3).src]; - np.v2 = reverseNodeTable[(*it3).trg]; - origEdges.pushBack(np); - } - } - - - Array > leftoverPermLists(0,((Master*)master_)->numberOfHeuristicPermutationLists()); - - // Distributing edges in \a fracEdges among the permutation lists. - int index; - for (it3=fracEdges.begin(); it3.valid(); ++it3) { - index = getArrayIndex((*it3).lpValue); - leftoverPermLists[index].pushBack(*it3); - } - - for (int i=0; igetGraph()->numberOfEdges()) { - -#ifdef OGDF_DEBUG - ((Master*)master_)->m_solByHeuristic = true; -#endif - - ((Master*)master_)->updateBestSubGraph(origEdges,conEdges,delEdges); - - master_->primalBound(oEdgeObjValue+0.79); - } - - return (oEdgeObjValue+0.79); -} - - - -////////////////////////////////////////////// -// OLD HEURISTIC -////////////////////////////////////////////// - -/* -void Sub::minimumSpanningTree( - GraphCopy &GC, - List &clusterEdges, - List &MSTEdges) -{ - - //list \a clusterEdges contains nodePairs of \a G in increasing order of LP-value - //\a GC is a GraphCopy of G and contains previously added edges of the child clusters. - - nodePair np; - node cv,cw; - edge newEdge; - ListConstIterator it; - //function valid() returns true, even if the list clusterEdges is empty. WHY??? - //maybe because the loop doesn't "recognise" that elements are removed from list - //\clusterEdges, but works on the original list the whole time - for (it=clusterEdges.begin(); it.valid(); ++it) { - if (clusterEdges.size() == 0) break; - - np = clusterEdges.front(); - cv = GC.copy(np.v1); - cw = GC.copy(np.v2); - newEdge = GC.newEdge(cv,cw); - - if (!isAcyclicUndirected(GC)) { - GC.delEdge(newEdge); - } else { - MSTEdges.pushBack(np); - } - clusterEdges.popFront(); - - //if the number of edges of \a GC is one less than the number of nodes, - //the search can be stopped, because a tree has been computed and no further edges can be added - if (GC.numberOfEdges() == GC.numberOfNodes()-1) break; - } -} - - -void Sub::recursiveMinimumSpanningTree( - ClusterGraph &C, - cluster c, - ClusterArray > &treeEdges, - List &edgesByIncLPValue, - List &clusterNodes) -{ - - //node forwarding - //nodes corresponding to cluster \a c are added to given list \a clusterNodes - //necessary, to have quick access to the relevant nodes for building up the GraphCopy for the cluster - ListConstIterator it; - for (it=c->nBegin(); it.valid(); ++it) { - clusterNodes.pushBack(*it); - } - - GraphCopy *cG; - if (c->cCount() == 0) { //cluster is a leaf, so MST can be computed - - //Create a cluster induced GraphCopy of \a G and delete all edges - cG = new GraphCopy(C.getGraph()); - node v = cG->firstNode(); - node v_succ; - while (v!=0) { - v_succ = v->succ(); - if (C.clusterOf(cG->original(v)) != c) { - cG->delNode(v); - } - v = v_succ; - } - edge e = cG->firstEdge(); - edge e_succ; - while (e!=0) { - e_succ = e->succ(); - cG->delEdge(e); - e = e_succ; - } - - //Determining the relevant nodePairs of the cluster-induced GraphCopy - //in increasing order of LP-value - //performance should be improved, maybe by using a more sophisticated data structure - List clusterNodePairs; - ListConstIterator it; - for (it=edgesByIncLPValue.begin(); it.valid(); ++it) { - if (C.clusterOf((*it).v1) == c && C.clusterOf((*it).v2) == c) { - clusterNodePairs.pushBack(*it); - } - } - - minimumSpanningTree(*cG,clusterNodePairs,treeEdges[c]); - delete cG; - return; - } - - //If cluster \a c has further children, they have to be processed first - ListConstIterator cit; - List nodes; - for (cit=c->cBegin(); cit.valid(); ++cit) { - - recursiveMinimumSpanningTree(C,(*cit),treeEdges,edgesByIncLPValue,nodes); - - //computed treeEdges for the child clusters have to be added to treeEdges for current cluster - ListConstIterator it; - for (it=treeEdges[(*cit)].begin(); it.valid(); ++it) { - treeEdges[c].pushBack(*it); - } - } - //The MSTs of all children of cluster \a c have been computed - //So MST for \a c can now be computed - - //updating node lists - for (it=nodes.begin(); it.valid(); ++it) { - clusterNodes.pushBack(*it); - } - for (it=c->nBegin(); it.valid(); ++it) { - nodes.pushBack(*it); - } - //now list \a nodes contains all nodes belonging to cluster \a c - - //create GraphCopy induced by nodes in \a nodes - cG = new GraphCopy(C.getGraph()); - NodeArray isInCluster(*cG,false); - for (it=nodes.begin(); it.valid(); ++it) { - isInCluster[cG->copy(*it)] = true; - } - node v = cG->firstNode(); - node v_succ; - while (v!=0) { - v_succ = v->succ(); - if (!isInCluster[v]) { - cG->delNode(v); - } - v = v_succ; - } - edge e = cG->firstEdge(); - edge e_succ; - while (e!=0) { - e_succ = e->succ(); - cG->delEdge(e); - e = e_succ; - } - //edges that have been added in child clusters by computing an MST have to be added to the Graphcopy - ListConstIterator it2; - node cGv,cGw; - for (it2=treeEdges[c].begin(); it2.valid(); ++it2) { - cGv = cG->copy((*it2).v1); - cGw = cG->copy((*it2).v2); - cG->newEdge(cGv,cGw); - } - - //compute relevant nodePairs, i.e. all nodePairs induced by cluster leaving out already added ones - List clusterNodePairs; - ListConstIterator it3; - for (it3=edgesByIncLPValue.begin(); it3.valid(); ++it3) { - cGv = cG->copy((*it3).v1); - cGw = cG->copy((*it3).v2); - //todo remove searchedge - if (isInCluster[cGv] && isInCluster[cGw] && !cG->searchEdge(cGv,cGw)) clusterNodePairs.pushBack(*it3); - } - - minimumSpanningTree(*cG,clusterNodePairs,treeEdges[c]); - delete cG; - return; -} - - -double Sub::heuristicImprovePrimalBoundDet( - List &origEdges, - List &conEdges, - List &delEdges) -{ - - origEdges.clear(); conEdges.clear(); delEdges.clear(); - - //the primal value of the heuristically computed ILP-solution - double oEdgeObjValue = 0.0; - double cEdgeObjValue = 0.0; - int originalEdgeCounter = 0; - - //a copy of the Clustergraph has to be created. - //to be able to have access to the original nodes after the heuristic has been performed, - //we maintain the Arrays \a originalClusterTable and \a originalNodeTable - Graph G; - ClusterArray originalClusterTable(*(((Master*)master_)->getClusterGraph())); - NodeArray originalNodeTable(*(((Master*)master_)->getGraph())); - ClusterGraph CC( *(((Master*)master_)->getClusterGraph()),G,originalClusterTable,originalNodeTable ); - - //NodeArray \a reverseNodeTable is indexized by \a G and contains the corresponding original nodes - NodeArray reverseNodeTable(G); - node v; - forall_nodes(v,*(((Master*)master_)->getGraph())) { - node w = originalNodeTable[v]; - reverseNodeTable[w] = v; - } - - //first, nodePairs have to be sorted in increasing order of their LP-value - //therefore a Binary Heap is build and read once, to obtain a sorted list of the nodePairs - List globalNodePairList; - BinaryHeap2 BH_all(nVar()); - nodePair np; - node ov,ow; - double lpValue; - for (int i=0; isourceNode(); - ow = ((Edge*)variable(i))->targetNode(); - np.v1 = originalNodeTable[ov]; - np.v2 = originalNodeTable[ow]; - lpValue = 1.0-xVal(i); - BH_all.insert(np,lpValue); - } - for (int i=0; i > spanningTreesNodePairs(CC); - List nodes; - recursiveMinimumSpanningTree( - CC, - originalClusterTable[(((Master*)master_)->getClusterGraph())->rootCluster()], - spanningTreesNodePairs, - globalNodePairList, - nodes); - //\a spanningTreesNodePairs[CC->rootCluster] now contains the edges of the computed Tree - - //create the induced ClusterGraph - edge e = G.firstEdge(); - edge e_succ; - while (e!=0) { - e_succ = e->succ(); - G.delEdge(e); - e = e_succ; - } - ListConstIterator it2; - for (it2=spanningTreesNodePairs[CC.rootCluster()].begin(); it2.valid(); ++it2) { - G.newEdge((*it2).v1,(*it2).v2); - } - - //creating two lists \a cEdgeNodePairs and \a oEdgeNodePairs in increasing order of LP-values. - int nOEdges = 0; - int nCEdges = 0; - List cEdgeNodePairs; - List oEdgeNodePairs; - BinaryHeap2 BH_cEdges(nVar()); - BinaryHeap2 BH_oEdges(nVar()); - node cv,cw; - for (int i=0; isourceNode() ]; - cw = originalNodeTable[ ((Edge*)variable(i))->targetNode() ]; - if ((G.searchEdge(cv,cw))==NULL) { - np.v1 = cv; np.v2 = cw; - lpValue = 1.0-xVal(i); - if ( ((Edge*)variable(i))->theEdgeType() == ORIGINAL ) { - BH_oEdges.insert(np,lpValue); - nOEdges++; - } else { - BH_cEdges.insert(np,lpValue); - nCEdges++; - } - } else { //edge is contained in G - np.v1 = ((Edge*)variable(i))->sourceNode(); - np.v2 = ((Edge*)variable(i))->targetNode(); - - if ( ((Edge*)variable(i))->theEdgeType() == ORIGINAL ) { - originalEdgeCounter++; - oEdgeObjValue += 1.0; - //since edges that have been added are not deleted in further steps, - //list \a origEdges may be updated in this step. - origEdges.pushBack(np); - - } else { - //cEdgeObjValue -= ((Master*)master_)->epsilon(); - //since edges that have been added are not deleted in further steps, - //list \a conEdges may be updated in this step. - conEdges.pushBack(np); - } - } - } - - for (int i=1; i<=nCEdges; ++i) { - cEdgeNodePairs.pushBack(BH_cEdges.extractMin()); - } - for (int i=1; i<=nOEdges; ++i) { - oEdgeNodePairs.pushBack(BH_oEdges.extractMin()); - } - - - //INSERTING LEFTOVER NODEPAIRS IN INCREASING ORDER OF LP_VALUE AND CHECKING FOR C-PLANARITY - //first, O-Edges are testet and added. - - ListConstIterator it3; - edge addEdge; - bool cPlanar; - CconnectClusterPlanar cccp; - for (it3=oEdgeNodePairs.begin(); it3.valid(); ++it3) { - - addEdge = G.newEdge((*it3).v1,(*it3).v2); - cPlanar = cccp.call(CC); - if (!cPlanar) { - G.delEdge(addEdge); - //since edges that have been added are not deleted in further steps, - //list \a origEdges may be updated in this step. - np.v1 = reverseNodeTable[(*it3).v1]; - np.v2 = reverseNodeTable[(*it3).v2]; - delEdges.pushBack(np); - } else { - originalEdgeCounter++; - oEdgeObjValue += 1.0; - //since edges that have been added are not deleted in further steps, - //list \a origEdges may be updated in this step. - np.v1 = reverseNodeTable[(*it3).v1]; - np.v2 = reverseNodeTable[(*it3).v2]; - origEdges.pushBack(np); - } - } - - //if the Graph created so far contains all original edges, the Graph is c-planar. - if (originalEdgeCounter == ((Master*)master_)->getGraph()->numberOfEdges()) { - //cout << "Graph is c-planar! Heuristic has computed a solution that contains all original edges" << endl; - ((Master*)master_)->updateBestSubGraph(origEdges,conEdges,delEdges); - //cout << "value of solution is: " << oEdgeObjValue << endl; - master_->primalBound(oEdgeObjValue+0.79); - } - - - cout << "the objective function value of heuristically computed ILP-solution is: " << (oEdgeObjValue + cEdgeObjValue) << endl; - - return (oEdgeObjValue+0.79); -} -*/ - - -int Sub::improve(double &primalValue) { - - if ( ((Master*)master_)->getHeuristicLevel() == 0 ) return 0; - - // If \a heuristicLevel is set to value 1, the heuristic is only run, - // if current solution is fractional and no further constraints have been found. - if ( ((Master*)master_)->getHeuristicLevel() == 1 ) { - if (!integerFeasible() && !m_constraintsFound) { - - List origEdges; - List conEdges; - List delEdges; - - for (int i=((Master*)master_)->getHeuristicRuns(); i>0; i--) { - - origEdges.clear(); conEdges.clear(); delEdges.clear(); - double heuristic = heuristicImprovePrimalBound(origEdges,conEdges,delEdges); - - // \a heuristic contains now the objective function value (primal value) - // of the heuristically computed ILP-solution. - // We have to check if this solution is better than the currently best primal solution. - if(master_->betterPrimal(heuristic)) { -#ifdef OGDF_DEBUG - ((Master*)master_)->m_solByHeuristic = true; -#endif - // Best primal solution has to be updated. - ((Master*)master_)->updateBestSubGraph(origEdges,conEdges,delEdges); - primalValue = heuristic; - return 1; - } - } - return 0; - } - - // If \a heuristicLevel is set to value 2, the heuristic is run after each - // LP-optimization step, i.e. after each iteration. - } else if ( ((Master*)master_)->getHeuristicLevel() == 2 ) { - List origEdges; - List conEdges; - List delEdges; - - double heuristic = heuristicImprovePrimalBound(origEdges,conEdges,delEdges); - - // \a heuristic contains now the objective function value (primal value) - // of the heuristically computed ILP-solution. - // We have to check if this solution is better than the currently best primal solution. - if(master_->betterPrimal(heuristic)) { -#ifdef OGDF_DEBUG - ((Master*)master_)->m_solByHeuristic = true; -#endif - // Best primal solution has to be updated - ((Master*)master_)->updateBestSubGraph(origEdges,conEdges,delEdges); - primalValue = heuristic; - return 1; - } - return 0; - } - - // For any other value of \a m_heuristicLevel the function returns 0. - return 0; -} - -//! Computes the number of bags within the given cluster \a c -//! (non recursive) -//! A bag is a set of chunks within the cluster that are connected -//! via subclusters -int Sub::clusterBags(ClusterGraph &CG, cluster c) -{ - const Graph& G = CG.getGraph(); - if (G.numberOfNodes() == 0) return 0; - int numChunks = 0; //number of chunks (CCs) within cluster c - int numBags; //number of bags (Constructs consisting of CCs connected by subclusters) - - //stores the nodes belonging to c - List nodesInCluster; - //stores the corresponding interator to the list element for each node - NodeArray > listPointer(G); - - NodeArray isVisited(G, false); - NodeArray inCluster(G, false); - NodeArray parent(G); //parent for path to representative in bag gathering - - //saves status of all nodes in hierarchy subtree at c - c->getClusterNodes(nodesInCluster); - int num = nodesInCluster.size(); - if (num == 0) return 0; - -// cout << "#Starting clusterBags with cluster of size " << num << "\n"; - - //now we store the iterators - ListIterator it = nodesInCluster.begin(); - while (it.valid()) - { - listPointer[(*it)] = it; - inCluster[(*it)] = true; - it++; - }//while - - int count = 0; - - //now we make a traversal through the induced subgraph, - //jumping between the chunks - while (count < num) - { - numChunks++; - node start = nodesInCluster.popFrontRet(); - - //do a BFS and del all visited nodes in nodesInCluster using listPointer - Queue activeNodes; //could use arraybuffer - activeNodes.append(start); - isVisited[start] = true; - edge e; - while (!activeNodes.empty()) - { - node v = activeNodes.pop(); //running node - parent[v] = start; //representative points to itself -// cout << "Setting parent of " << v->index() << " to " << start->index() << "\n"; - count++; - - forall_adj_edges(e, v) - { - node w = e->opposite(v); - - if (v == w) continue; // ignore self-loops - - if (inCluster[w] && !isVisited[w]) - { - //use for further traversal - activeNodes.append(w); - isVisited[w] = true; - //remove the node from the candidate list - nodesInCluster.del(listPointer[w]); - } - } - }//while - - }//while - -// cout << "Number of chunks: " << numChunks << "\n"; - //Now all node parents point to the representative of their chunk (start node in search) - numBags = numChunks; //We count backwards if chunks are connected by subcluster - - //Now we use an idea similar to UNION FIND to gather the bags - //out of the chunks. Each node has a parent pointer, leading to - //a representative. Initially, it points to the rep of the chunk, - //but each time we encounter a subcluster connecting multiple - //chunks, we let all of them point to the same representative. - ListConstIterator itC = c->cBegin(); - while (itC.valid()) - { - List nodesInChild; - (*itC)->getClusterNodes(nodesInChild); - cout << nodesInChild.size() << "\n"; - ListConstIterator itN = nodesInChild.begin(); - node bagRep; //stores the representative for the whole bag - if (itN.valid()) bagRep = getRepresentative(*itN, parent); -// cout << " bagRep is " << bagRep->index() << "\n"; - while (itN.valid()) - { - node w = getRepresentative(*itN, parent); -// cout << " Rep is: " << w->index() << "\n"; - if (w != bagRep) - { - numBags--; //found nodes with different representative, merge - parent[w] = bagRep; - parent[*itN] = bagRep; //shorten search path -// cout << " Found new node with different rep, setting numBags to " << numBags << "\n"; - } - itN++; - }//While all nodes in subcluster - - itC++; - }//while all child clusters - - return numBags; -// cout << "#Number of bags: " << numBags << "\n"; -}//clusterBags - - -//! returns connectivity status for complete connectivity -//! returns 1 in this case, 0 otherwise -// New version using arrays to check cluster affiliation during graph traversal, -// old version used graph copies - -// For complete connectivity also the whole graph needs to -// be connected (root cluster). It therefore does not speed up -// the check to test connectivity of the graph in advance. -// Note that then a cluster induced graph always has to be -// connected to the complement, besides one of the two is empty. - -// Uses an array that keeps the information on the cluster -// affiliation and bfs to traverse the graph. -//we rely on the fact that support is a graphcopy of the underlying graph -//with some edges added or removed -bool Sub::checkCConnectivity(const GraphCopy& support) -{ - - const ClusterGraph &CG = *((Master*)master_)->getClusterGraph(); - const Graph& G = CG.getGraph(); - //if there are no nodes, there is nothing to check - if (G.numberOfNodes() < 2) return true; - - cluster c; - - //there is always at least the root cluster - forall_clusters(c, CG) - { - // For each cluster, the induced graph partitions the graph into two sets. - // When the cluster is empty, we still check the complement and vice versa. - bool set1Connected = false; - - //this initialization can be done faster by using the - //knowledge of the cluster hierarchy and only - //constructing the NA once for the graph (bottom up tree traversal) - NodeArray inCluster(G, false); - NodeArray isVisited(G, false); - - //saves status of all nodes in hierarchy subtree at c - int num = c->getClusterNodes(inCluster); - - int count = 0; - //search in graph should reach num and V-num nodes - node complementStart = 0; - - //we start with a non-empty set - node start = G.firstNode(); - bool startState = inCluster[start]; - - Queue activeNodes; //could use arraybuffer - activeNodes.append(start); - isVisited[start] = true; - - //could do a shortcut here for case |c| = 1, but - //this would make the code more complicated without large benefit - edge e; - node u; - while (!activeNodes.empty()) - { - node v = activeNodes.pop(); //running node - count++; - u = support.copy(v); - - forall_adj_edges(e, u) - { - node w = support.original(e->opposite(support.copy(v))); - - if (v == w) continue; // ignore self-loops - - if (inCluster[w] != startState) complementStart = w; - else if (!isVisited[w]) - { - activeNodes.append(w); - isVisited[w] = true; - } - } - }//while - //check if we reached all nodes - //we assume that the graph is connected, otherwise check - //fails for root cluster anyway - //(we could have a connected cluster and a connected complement) - - //condition depends on the checked set, cluster or complement - set1Connected = (startState == true ? (count == num) : (count == G.numberOfNodes() - num)); - //cout << "Set 1 connected: " << set1Connected << " Cluster? " << startState << "\n"; - - if (!set1Connected) return false; - //check if the complement of set1 is also connected - //two cases: complement empty: ok - // complement not empty, - // but no complementStart found: error - //In case of the root cluster, this always triggers, - //therefore we have to continue - if (G.numberOfNodes() == count) - continue; - OGDF_ASSERT(complementStart != 0); - - activeNodes.append(complementStart); - isVisited[complementStart] = true; - startState = ! startState; - int ccount = 0; - while (!activeNodes.empty()) - { - node v = activeNodes.pop(); //running node - ccount++; - u = support.copy(v); - - forall_adj_edges(e, u) - { - node w = support.original(e->opposite(support.copy(v))); - - if (v == w) continue; // ignore self-loops - - if (!isVisited[w]) - { - activeNodes.append(w); - isVisited[w] = true; - } - } - }//while - //Check if we reached all nodes - if (!(ccount + count == G.numberOfNodes())) - return false; - }//forallclusters - return true; -} - -//only left over for experimental evaluation of speedups -bool Sub::checkCConnectivityOld(const GraphCopy& support) -{ - //Todo: It seems to me that this is not always necessary: - //For two clusters, we could stop even if support is not connected - if (isConnected(support)) { - - GraphCopy *cSupport; - cluster c = ((Master*)master_)->getClusterGraph()->firstCluster(); - - while (c != NULL) { - // Determining the nodes of current cluster - List clusterNodes; - c->getClusterNodes(clusterNodes); - - // Step1: checking the restgraph for connectivity - GraphCopy cSupportRest((const Graph&)support); - ListIterator it; - node cv1, cv2; - - for (it=clusterNodes.begin(); it.valid(); ++it) { - - cv1 = support.copy(*it); - cv2 = cSupportRest.copy(cv1); - cSupportRest.delNode(cv2); - } - - // Checking \a cSupportRest for connectivity - if (!isConnected(cSupportRest)) { - return false; - } - - // Step2: checking the cluster induced subgraph for connectivity - cSupport = new GraphCopy((const Graph&)support); - NodeArray inCluster(*((Master*)master_)->getGraph()); - inCluster.fill(false); - - for (it=clusterNodes.begin(); it.valid(); ++it) { - inCluster[*it] = true; - } - node v = ((Master*)master_)->getGraph()->firstNode(); - node succ; - while (v!=0) { - succ = v->succ(); - if (!inCluster[v]) { - cv1 = support.copy(v); - cv2 = cSupport->copy(cv1); - cSupport->delNode(cv2); - } - v = succ; - } - if (!isConnected(*cSupport)) { - return false; - } - delete cSupport; - - // Next cluster - c = c->succ(); - } - - } else { - return false; - } - return true; - -} - -bool Sub::feasible() { -// cout << "Checking feasibility\n"; - - if (!integerFeasible()) { - return false; - } - else { - - //---------------------------------------------------------------- - // Checking if the solution induced graph is completely connected. - GraphCopy support(*((Master*)master_)->getGraph()); - intSolutionInducedGraph(support); - - //introduced merely for debug checks - bool cc = checkCConnectivity(support); - bool ccOld = checkCConnectivityOld(support); - if (cc != ccOld) - { - cout << "CC: "< than - // the current optimal primal solution. - // If so, the solution induced graph is updated. - double primalBoundValue = (double)(floor(lp_->value()) + 0.79); - if (master_->betterPrimal(primalBoundValue)) { - master_->primalBound(primalBoundValue); - updateSolution(); - } - return true; - - } else { - return false; - } - } -}//feasible - -static void dfsIsConnected(node v, NodeArray &visited, int &count) -{ - count++; - visited[v] = true; - - edge e; - forall_adj_edges(e,v) { - node w = e->opposite(v); - if (!visited[w]) dfsIsConnected(w,visited,count); - } -} - -/* -bool Sub::fastfeasible() { - - if (!integerFeasible()) { - return false; - } - else { - - // Checking if the solution induced Graph is completely connected. - GraphCopy support(*((Master*)master_)->getGraph()); - intSolutionInducedGraph(support); - - //Todo: It seems to me that this is not always necessary: - //For two clusters, we could stop even if support is not connected - //we also do not need the root cluster - if (isConnected(support)) { - - GraphCopy *cSupport; - cluster c = ((Master*)master_)->getClusterGraph()->firstCluster(); - - while (c != NULL) - { - if (c == ((Master*)master_)->getClusterGraph().rootCluster()) - { - //attention: does the rest of the code rely on the fact - //that the root is connected - // Next cluster - c = c->succ(); - continue; - }//if root cluster - // Determining the nodes of current cluster - List clusterNodes; - c->getClusterNodes(clusterNodes); - - int count = 0; - NodeArray blocked(support, false); - // Step1: checking the restgraph for connectivity - ListIterator it; - node cv1, cv2; - - for (it=clusterNodes.begin(); it.valid(); ++it) - { - blocked[*it] = true; - - } - - // Checking \a cSupportRest for connectivity - - if (clusterNodes.size() < support.numberOfNodes()) - { - //search for a node outside c - //should be done more efficiently, rewrite this - node runv = support->firstNode(); - while (blocked[runv] == true) {runv = runv->succ();} - - dfsIsConnected(runv,blocked,count); - if (count != support.numberOfNodes()-clusterNodes.size()) - return false; - } - - - // Step2: checking the cluster induced subgraph for connectivity - //NodeArray inCluster(*((Master*)master_)->getGraph()); - //inCluster.fill(false); - blocked.init(support, true); - - for (it=clusterNodes.begin(); it.valid(); ++it) { - blocked[*it] = false; - } - node v = ((Master*)master_)->getGraph()->firstNode(); - node succ; - while (v!=0) { - succ = v->succ(); - if (!inCluster[v]) { - cv1 = support.copy(v); - cv2 = cSupport->copy(cv1); - cSupport->delNode(cv2); - } - v = succ; - } - if (!isConnected(*cSupport)) { - return false; - } - delete cSupport; - - // Next cluster - c = c->succ(); - } - - } else { - return false; - } - - // Checking for planarity - - BoyerMyrvold bm; - bool planar = bm.planarDestructive(support); - if (planar) { - - // Current solution is integer feasible, completely connected and planar. - // Checking, if the objective function value of this subproblem is > than - // the current optimal primal solution. - // If so, the solution induced graph is updated. - double primalBoundValue = (double)(floor(lp_->value()) + 0.79); - if (master_->betterPrimal(primalBoundValue)) { - master_->primalBound(primalBoundValue); - updateSolution(); - } - return true; - - } else { - return false; - } - } -}//fastfeasible - -*/ -void Sub::intSolutionInducedGraph(GraphCopy &support) { - - edge e, ce; - node v, w, cv, cw; - for (int i=0; i= 1.0-(master_->eps()) ) { - - if (((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::CONNECT) { - - // If Connection-variables have value == 1.0 they have to be ADDED to the support graph. - v = ((EdgeVar*)variable(i))->sourceNode(); - w = ((EdgeVar*)variable(i))->targetNode(); - cv = support.copy(v); - cw = support.copy(w); - support.newEdge(cv,cw); - } - } else { - - // If Original-variables have value == 0.0 they have to be DELETED from the support graph. - if (((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::ORIGINAL) { - e = ((EdgeVar*)variable(i))->theEdge(); - ce = support.copy(e); - support.delEdge(ce); - } - } - } -} - - -void Sub::kuratowskiSupportGraph(GraphCopy &support, double low, double high) { - - edge e, ce; - node v, w, cv, cw; - for (int i=0; i= high) { - - // If variables have value >= \a high and are of type CONNECT - // they are ADDED to the support graph. - if (((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::CONNECT) { - - v = ((EdgeVar*)variable(i))->sourceNode(); - w = ((EdgeVar*)variable(i))->targetNode(); - cv = support.copy(v); - cw = support.copy(w); - support.newEdge(cv,cw); - } else continue; - } else if (xVal(i) <= low) { - - // If variables have value <= \a low and are of type ORIGINAL - // they are DELETED from the support graph. - if (((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::ORIGINAL) { - - e = ((EdgeVar*)variable(i))->theEdge(); - ce = support.copy(e); - //delCopy! - support.delEdge(ce); - } else continue; - } - - else { // Value of current variable lies between \a low and \a high. - - // Variable is added/deleted randomized according to its current value. - - // Variable of type ORIGINAL is deleted with probability 1-xVal(i). - if (((EdgeVar*)variable(i))->theEdgeType() == EdgeVar::ORIGINAL) { - - double ranVal = randomDouble(0.0,1.0); - if (ranVal > xVal(i)) { - e = ((EdgeVar*)variable(i))->theEdge(); - ce = support.copy(e); - support.delEdge(ce); - } - - } else { - // Variable of type CONNECT is added with probability of xVal(i). - - double ranVal = randomDouble(0.0,1.0); - if (ranVal < xVal(i)) { - v = ((EdgeVar*)variable(i))->sourceNode(); - w = ((EdgeVar*)variable(i))->targetNode(); - cv = support.copy(v); - cw = support.copy(w); - // searchEdge ist hier wohl �berfl�ssig... (assertion) - if (!support.searchEdge(cv,cw)) support.newEdge(cv,cw); - } - } - } - - } // end for(int i=0; i &weight) { - - // Step 1+2: Create the support graph & Determine edge weights and fill the EdgeArray \a weight. - // MCh: warning: modified by unifying both steps. performance was otherwise weak. - edge e, ce; - node v, w, cv, cw; - //initializes weight array to original graph (values undefined) - weight.init(support); - for (int i=0; i master()->eps()) { - // Connection edges have to be added. - if (var->theEdgeType() == EdgeVar::CONNECT) { - v = var->sourceNode(); - w = var->targetNode(); - cv = support.copy(v); - cw = support.copy(w); - weight[ support.newEdge(cv,cw) ] = val; - } else - weight[ support.chain(var->theEdge()).front() ] = val; - } else { - // Original edges have to be deleted if their current value equals 0.0. - //if (val <= master()->eps()) { - if (var->theEdgeType() == EdgeVar::ORIGINAL) { - ce = support.copy( var->theEdge() ); - support.delCopy(ce); //MCh: was: delEdge - } - } - } - //TODO: KK: Removed this (think it is safe), test! - // Step 2: - /* - for (int i=0; isourceNode(); - w = ((EdgeVar*)variable(i))->targetNode(); - //TODO: Inefficient! Speed search up - e = support.searchEdge(support.copy(v),support.copy(w)); - if (e) weight[e] = xVal(i); - } - */ -} - -//----------------------------Computation of Cutting Planes-------------------------// -// // -//Implementation and usage of separation algorithmns // -//for the Kuratowski- and the Connectivity- constraints // -// // -//----------------------------------------------------------------------------------// - -int Sub::separateReal(double minViolate) { - - // The number of generated and added constraints. - // Each time a constraint is created and added to the buffer, the variable \a count is incremented. - // When adding the created constraints \a nGenerated and \a count are checked for equality. - int nGenerated = 0; - int count = 0; - m_constraintsFound = false; - - if(master()->m_useDefaultCutPool) - nGenerated = constraintPoolSeparation(0,0,minViolate); - if(nGenerated>0) return nGenerated; - - //-------------------------------CUT-SEPARATION--------------------------------------// - - // We first try to regenerate cuts from our cutpools - nGenerated = separateConnPool(minViolate); - if (nGenerated > 0) - { -#ifdef OGDF_DEBUG - Logger::slout()<<"con-regeneration."; -#endif - return nGenerated; - //TODO: Check if/how we can proceed here, i.e. should we have this else? - } - else - { -#ifdef OGDF_DEBUG -// cout<<"Connectivity Regeneration did not work\n"; -#endif - GraphCopy support (*((Master*)master())->getGraph()); - EdgeArray w; - connectivitySupportGraph(support,w); - - // Buffer for the constraints - int nClusters = (((Master*)master_)->getClusterGraph())->numberOfClusters(); - //ABA_BUFFER cConstraints(master_,2*nClusters); - - GraphCopy *c_support; - EdgeArray c_w; - cluster c; - - // INTER-CLUSTER CONNECTIVITY - - forall_clusters(c,*((Master*)master_)->getClusterGraph()) { - - c_support = new GraphCopy((const Graph&)support); - c_w.init(*c_support); - - // Copying edge weights to \a c_w. - List weights; - edge e,c_e; - forall_edges(e,support) { - weights.pushBack(w[e]); - } - ListConstIterator wIt = weights.begin(); - forall_edges(c_e,*c_support) { - if (wIt.valid()) c_w[c_e] = (*wIt); - wIt++; - } - - // Residue graph is determined and stored in \a c_support. - List clusterNodes; - c->getClusterNodes(clusterNodes); - ListIterator it; - node cCopy1, cCopy2; - for (it=clusterNodes.begin(); it.valid(); ++it) { - cCopy1 = support.copy(*it); - cCopy2 = c_support->copy(cCopy1); - c_support->delNode(cCopy2); - } - - // Checking if Graph is connected. - if (isConnected(*c_support)) { - - MinCut mc(*c_support,c_w); - List cutEdges; - double mincutV = mc.minimumCut(); - if (mincutV < 1.0-master()->eps()-minViolate) { - - mc.cutEdges(cutEdges,*c_support); - - List cutNodePairs; - ListConstIterator cutEdgesIt; - node v,w,cv,cw,ccv,ccw; - nodePair np; - for (cutEdgesIt=cutEdges.begin();cutEdgesIt.valid();cutEdgesIt++) { - v = (*cutEdgesIt)->source(); - w = (*cutEdgesIt)->target(); - cv = c_support->original(v); - cw = c_support->original(w); - ccv = support.original(cv); - ccw = support.original(cw); - np.v1 = ccv; - np.v2 = ccw; - cutNodePairs.pushBack(np); - } - - // Create constraint - bufferedForCreation.push(new CutConstraint((Master*)master(),this, cutNodePairs)); - count++; - } - - }//end Graph is connected - - else { - NodeArray comp(*c_support); - connectedComponents(*c_support,comp); - List partition; - NodeArray isInPartition(*c_support); - isInPartition.fill(false); - node v; - forall_nodes(v,*c_support) { - if (comp[v] == 0) { - partition.pushBack(v); - isInPartition[v] = true; - } - } - - // Computing nodePairs defining the cut. - List cutEdges; - ListConstIterator it; - nodePair np; - for (it=partition.begin(); it.valid(); ++it) { - node w,cv,cw; - forall_nodes(w,*c_support) { - if ( (w!=(*it)) && !isInPartition[w] ) { - cw = c_support->original(w); - cv = c_support->original(*it); - np.v1 = support.original(cw); - np.v2 = support.original(cv); - cutEdges.pushBack(np); - } - } - } - - // Create cut-constraint - bufferedForCreation.push(new CutConstraint((Master*)master(), this, cutEdges)); // always violated enough - count++; - - }//end Graph is not connected - delete c_support; - - }//end forall_clusters - - // INTRA-CLUSTER CONNECTIVITY - - // The initial constraints can not guarantee the connectivity of a cluster. - // Thus, for each cluster we have to check, if the induced Graph is connected. - // If so, we compute the mincut and create a corresponding constraint. - // Otherwise a constraint is created in the same way as above. - - forall_clusters(c,*((Master*)master_)->getClusterGraph()) { - - c_support = new GraphCopy((const Graph&)support); - c_w.init(*c_support); - - List weights; - edge e,c_e; - forall_edges(e,support) { - weights.pushBack(w[e]); - } - ListConstIterator wIt = weights.begin(); - forall_edges(c_e,*c_support) { - if (wIt.valid()) c_w[c_e] = (*wIt); - wIt++; - } - - // Cluster induced Graph is determined and stored in \a c_support. - ListIterator it; - List clusterNodes; - c->getClusterNodes(clusterNodes); - NodeArray isInCluster(*c_support); - isInCluster.fill(false); - node cv; - for (it=clusterNodes.begin(); it.valid(); ++it) { - cv = support.copy(*it); - isInCluster[c_support->copy(cv)] = true; - } - node v = c_support->firstNode(); - node succ; - while (v!=0) { - succ = v->succ(); - if (!isInCluster[v]) { - c_support->delNode(v); - } - v = succ; - } - - // Checking if Graph is connected. - if (isConnected(*c_support)) { - - MinCut mc(*c_support,c_w); - List cutEdges; - double x = mc.minimumCut(); - if (x < 1.0-master()->eps()-minViolate) { - mc.cutEdges(cutEdges,*c_support); - List cutNodePairs; - ListConstIterator cutEdgesIt; - node v,w,cv,cw,ccv,ccw; - nodePair np; - for (cutEdgesIt=cutEdges.begin();cutEdgesIt.valid();cutEdgesIt++) { - v = (*cutEdgesIt)->source(); - w = (*cutEdgesIt)->target(); - cv = c_support->original(v); - cw = c_support->original(w); - ccv = support.original(cv); - ccw = support.original(cw); - np.v1 = ccv; - np.v2 = ccw; - cutNodePairs.pushBack(np); - } - - // Create constraint - bufferedForCreation.push(new CutConstraint((Master*)master(),this, cutNodePairs)); - count++; - } - }//end Graph is connected - - else { - NodeArray comp(*c_support); - connectedComponents(*c_support,comp); - List partition; - NodeArray isInPartition(*c_support); - isInPartition.fill(false); - node v; - forall_nodes(v,*c_support) { - if (comp[v] == 0) { - partition.pushBack(v); - isInPartition[v] = true; - } - } - - List cutEdges; - ListConstIterator it; - nodePair np; - for (it=partition.begin(); it.valid(); ++it) { - node w,cv,cw; - forall_nodes(w,*c_support) { - if ( (w!=(*it)) && !isInPartition[w] ) { - cw = c_support->original(w); - cv = c_support->original(*it); - np.v1 = support.original(cw); - np.v2 = support.original(cv); - cutEdges.pushBack(np); - } - } - } - - // Create Cut-constraint - bufferedForCreation.push(new CutConstraint((Master*)master(), this, cutEdges)); // always violated enough. - - count++; - }//end Graph is not connected - delete c_support; - } - - // Adding constraints - if(count>0) { - if(master()->pricing()) - nGenerated = createVariablesForBufferedConstraints(); - if(nGenerated==0) { - ABA_BUFFER cons(master(),count); - while(!bufferedForCreation.empty()) { - Logger::slout() <<"\n"; ((CutConstraint*&)bufferedForCreation.top())->printMe(Logger::slout()); - cons.push( bufferedForCreation.popRet() ); - } - OGDF_ASSERT( bufferedForCreation.size()==0 ); - nGenerated = addCutCons(cons); - OGDF_ASSERT( nGenerated == count ); - master()->updateAddedCCons(nGenerated); - } - m_constraintsFound = true; - return nGenerated; - } - }//if no regeneration of connectivity cuts was possible - - //------------------------KURATOWSKI-SEPARATION----------------------------// - - // We first try to regenerate cuts from our cutpools - nGenerated = separateKuraPool(minViolate); - if (nGenerated > 0) { - Logger::slout()<<"kura-regeneration."; - return nGenerated; //TODO: Check if/how we can proceed here - } - // Since the Kuratowski support graph is computed from fractional values, an extracted - // Kuratowski subdivision might not be violated by the current solution. - // Thus, the separation algorithm is run several times, each time checking if the first - // extracted subdivision is violated. - // If no violated subdivisions have been extracted after \a nKuratowskiIterations iterations, - // the algorithm behaves like "no constraints have been found". - - GraphCopy *kSupport; - SList kuratowskis; - BoyerMyrvold *bm1; BoyerMyrvold *bm2; - bool violatedFound = false; - - // The Kuratowski support graph is created randomized with probability xVal (1-xVal) to 0 (1). - // Because of this, Kuratowski-constraints might not be found in the current support graph. - // Thus, up to \a m_nKSupportGraphs are computed and checked for planarity. - - for (int i=0; i<((Master*)master_)->getNKuratowskiSupportGraphs(); ++i) { - - // If a violated constraint has been found, no more iterations have to be performed. - if (violatedFound) break; - - kSupport = new GraphCopy (*((Master*)master())->getGraph()); - kuratowskiSupportGraph(*kSupport,((Master*)master_)->getKBoundLow(),((Master*)master_)->getKBoundHigh()); - - if (isPlanar(*kSupport)) { - delete kSupport; - continue; - } - - int iteration = 1; - while(((Master*)master_)->getKIterations() >= iteration) { - - // Testing support graph for planarity. - bm2 = new BoyerMyrvold(); - bool planar = bm2->planarEmbedDestructive(*kSupport, kuratowskis, ((Master*)master_)->getNSubdivisions(),false,false,true); - delete bm2; - - // Checking if first subdivision is violated by current solution - // Performance should be improved somehow!!! - SListConstIterator kw = kuratowskis.begin(); - SListConstIterator succ; - double leftHandSide = subdivisionLefthandSide(kw,kSupport); - - // Only violated constraints are created and added - // if \a leftHandSide is greater than the number of edges in subdivision -1, the constraint is violated by current solution. - if (leftHandSide > (*kw).edgeList.size()-(1-master()->eps()-minViolate)) { - - violatedFound = true; - - // Buffer for new Kuratowski constraints - ABA_BUFFER kConstraints(master_,kuratowskis.size()); - - SListPure subdiv; - SListPure subdivOrig; - SListConstIterator eit; - nodePair np; - node v,w; - - for (eit = (*kw).edgeList.begin(); eit.valid(); ++eit) { - subdiv.pushBack(*eit); - } - for (SListConstIterator sit = subdiv.begin(); sit.valid(); ++sit) { - v = (*sit)->source(); - w = (*sit)->target(); - np.v1 = kSupport->original(v); - np.v2 = kSupport->original(w); - subdivOrig.pushBack(np); - } - - // Adding first Kuratowski constraint to the buffer. - kConstraints.push(new KuratowskiConstraint ((Master*)master(), subdivOrig.size(), subdivOrig)); - count++; - subdiv.clear(); - subdivOrig.clear(); - - // Checking further extracted subdivisions for violation. - kw++; - while(kw.valid()) { - leftHandSide = subdivisionLefthandSide(kw,kSupport); - if (leftHandSide > (*kw).edgeList.size()-(1-master()->eps()-minViolate)) { - - for (eit = (*kw).edgeList.begin(); eit.valid(); ++eit) { - subdiv.pushBack(*eit); - } - for (SListConstIterator sit = subdiv.begin(); sit.valid(); ++sit) { - v = (*sit)->source(); - w = (*sit)->target(); - np.v1 = kSupport->original(v); - np.v2 = kSupport->original(w); - subdivOrig.pushBack(np); - } - - // Adding Kuratowski constraint to the buffer. - kConstraints.push(new KuratowskiConstraint ((Master*)master(), subdivOrig.size(), subdivOrig) ); - count++; - subdiv.clear(); - subdivOrig.clear(); - } - kw++; - } - - // Adding constraints to the pool. - for(int i=0; iprintMe(Logger::slout()); - } - nGenerated += addKuraCons(kConstraints); - if (nGenerated != count) - cerr << "Number of added constraints doesn't match number of created constraints" << endl; - break; - - } else { - kuratowskis.clear(); - iteration++; - } - } - delete kSupport; - } - - if (nGenerated > 0) { - ((Master*)master_)->updateAddedKCons(nGenerated); - m_constraintsFound = true; - } - return nGenerated; -} - -int Sub::createVariablesForBufferedConstraints() { - List crit; - for(int i = bufferedForCreation.size(); i-->0;) { -// ((CutConstraint*)bufferedForCreation[i])->printMe(); Logger::slout() << ": "; - for(int j=nVar(); j-->0;) { -// ((EdgeVar*)variable(j))->printMe(); -// Logger::slout() << "=" << bufferedForCreation[i]->coeff(variable(j)) << "/ "; - if(bufferedForCreation[i]->coeff(variable(j))!=0.0) { -// Logger::slout() << "!"; - goto nope; - } - } - crit.pushBack(bufferedForCreation[i]); - nope:; - } - if(crit.size()==0) return 0; - ArrayBuffer > creationBuffer(crit.size()); - forall_nonconst_listiterators(nodePair, npit, master()->m_inactiveVariables) { - bool select = false; - ListIterator ccit = crit.begin(); - while(ccit.valid()) { - if(((BaseConstraint*)(*ccit))->coeff(*npit)) { - ListIterator delme = ccit; - ++ccit; - crit.del(delme); - select = true; - } else - ++ccit; - } - if(select) creationBuffer.push(npit); - if(crit.size()==0) break; - } - if( crit.size() ) { // something remained here... - for(int i = bufferedForCreation.size(); i-->0;) { - delete bufferedForCreation[i]; - } - detectedInfeasibility = true; - return 0; // a positive value denotes infeasibility - } - OGDF_ASSERT(crit.size()==0); - ABA_BUFFER vars(master(),creationBuffer.size()); - master()->m_varsCut += creationBuffer.size(); - int gen = creationBuffer.size(); - for(int j = gen; j-->0;) { - vars.push( master()->createVariable( creationBuffer[j] ) ); - } - myAddVars(vars); - return -gen; -} - -int Sub::pricingReal(double minViolate) { - if(!master()->pricing()) return 0; // no pricing - Top10Heap > > goodVar(master()->m_numAddVariables); - forall_nonconst_listiterators(nodePair, it, master()->m_inactiveVariables) { - double rc; - EdgeVar v(master(), -master()->m_epsilon, EdgeVar::CONNECT, (*it).v1, (*it).v2); - if(v.violated(rc) && rc>=minViolate) { - Prioritized > entry(it,rc); - goodVar.pushBlind( entry ); - } - } - - int nv = goodVar.size(); - if(nv > 0) { - ABA_BUFFER vars(master(),nv); - for(int i = nv; i-->0;) { - ListIterator it = goodVar[i].item(); - vars.push( master()->createVariable(it) ); - } - myAddVars(vars); - } - return nv; -} - -int Sub::repair() { - //warning. internal abacus stuff BEGIN - bInvRow_ = new double[nCon()]; - lp_->getInfeas(infeasCon_, infeasVar_, bInvRow_); - //warning. internal abacus stuff END - - // only output begin - Logger::slout() << "lpInfeasCon=" << lp_->infeasCon()->number() - << " var="<< infeasVar_ - << " con="<< infeasCon_<< "\n"; - for(int i=0; i(constraint(i)); - if(chc) chc->printMe(Logger::slout()); - CutConstraint* cuc = dynamic_cast(constraint(i)); - if(cuc) cuc->printMe(Logger::slout()); - KuratowskiConstraint* kc = dynamic_cast(constraint(i)); - if(kc) kc->printMe(Logger::slout()); - Logger::slout() << "\n" << flush; - } - } - // only output end - - int added = 0; - ABA_BUFFER nv(master(),1); - for(int i=0; i(constraint(i)); - if(!b) continue; // was: oversatisfied kura. nothing we can do here - OGDF_ASSERT(b); - forall_nonconst_listiterators(nodePair, it, master()->m_inactiveVariables) { - if(b->coeff(*it)) { - Logger::slout() << "\tFeasibility Pricing: "; - nv.push( master()->createVariable(it) ); - Logger::slout() << "\n"; - myAddVars(nv); - added = 1; - goto done; - } - } - } - } -done: - //warning. internal abacus stuff BEGIN - delete[] bInvRow_; - //warning. internal abacus stuff END - master()->m_varsKura += added; - return added; -} - -int Sub::solveLp() { - m_reportCreation = 0; - const double minViolation = 0.001; // value fixed by abacus... - - Logger::slout() << "SolveLp\tNode=" << this->id() << "\titeration=" << this->nIter_ << "\n"; - - - if(master()->pricing() && id()>1 && nIter_==1) { // ensure that global variables are really added... - ABA_STANDARDPOOL* vp = master()->varPool(); - int addMe = vp->number() - nVar(); - OGDF_ASSERT(addMe >=0 ); - if(addMe) { - Logger::slout() << "ARRRGGGG!!!! ABACUS SUCKS!!\n"; - Logger::slout() << nVar() << " variables of " << vp->number() << " in model. Fetching " << addMe << ".\n" << flush; - //master()->activeVars->loadIndices(this); // current indexing scheme - m_reportCreation = 0; - for(int i=0; isize(); ++i ) { - ABA_POOLSLOT * slot = vp->slot(i); - ABA_VARIABLE* v = slot->conVar(); - if(v && !v->active()) { - addVarBuffer_->insert(slot,true); - --m_reportCreation; - } - } - OGDF_ASSERT(m_reportCreation == -addMe); - return 0; // rerun; - } - } - - - if(master()->m_checkCPlanar && master()->feasibleFound()) { - Logger::slout() << "Feasible Solution Found. That's good enough! C-PLANAR\n"; - master()->clearActiveRepairs(); - return 1; - } - - if(bufferedForCreation.size()) { - m_reportCreation = bufferedForCreation.size(); - ABA_BUFFER cons(master(),bufferedForCreation.size()); - while(!bufferedForCreation.empty()) { - ((CutConstraint*&)bufferedForCreation.top())->printMe(Logger::slout());Logger::slout() <<"\n"; - cons.push( bufferedForCreation.popRet() ); - } - OGDF_ASSERT( bufferedForCreation.size()==0 ); - addCutCons(cons); - master()->updateAddedCCons(m_reportCreation); - master()->clearActiveRepairs(); - return 0; - } - - inOrigSolveLp = true; - ++(master()->m_solvesLP); - int ret = ABA_SUB::solveLp(); - inOrigSolveLp = false; - if(ret) { - if(!(master()->m_checkCPlanar)) - return ret; - if(master()->pricing()) { - if(criticalSinceBranching.size()) { - ListIterator best; - Array > bestKickout; - int bestCCnt = 0; - forall_nonconst_listiterators(nodePair, nit, master()->m_inactiveVariables) { - ArrayBuffer > kickout(criticalSinceBranching.size()); - forall_nonconst_listiterators(ABA_CONSTRAINT*, cit, criticalSinceBranching) { - BaseConstraint* bc = dynamic_cast(*cit); - OGDF_ASSERT(bc); - if( bc->coeff(*nit) > 0.99) { - kickout.push(cit); - } - } - if(kickout.size() > bestCCnt) { - bestCCnt = kickout.size(); - best = nit; - kickout.compactMemcpy(bestKickout); - } - } - if(bestCCnt>0) { - ABA_BUFFER vars(master(),1); - vars.push( master()->createVariable(best) ); - myAddVars(vars); - int i; - forall_arrayindices(i,bestKickout) - criticalSinceBranching.del(bestKickout[i]); - m_reportCreation = -1; - ++(master()->m_varsBranch); - master()->clearActiveRepairs(); - return 0; - } - criticalSinceBranching.clear(); // nothing helped... resorting to full repair -// master()->clearActiveRepairs(); -// return 0; - } //else { - m_reportCreation = -repair(); - if(m_reportCreation<0) { - ++(master()->m_activeRepairs); - return 0; - } - //} - } - master()->clearActiveRepairs(); - dualBound_ = -master()->infinity(); - - -#ifdef OGDF_DEBUG - forall_listiterators(nodePair, it, master()->m_inactiveVariables) { - int t = (*it).v1->index(); - if(t==0) { - if( (*it).v2->index()==35 ) - Logger::slout() << "VAR MISSING: 0-35\n"; - } - else { - if(t%6==0) continue; - if((*it).v2->index()==t+5 ) - Logger::slout() << "VAR MISSING: " << t << "-" << (t+5) << "\n"; - } - } - for(int t = 0; tsourceNode()->index()==27 && v->targetNode()->index()==32 ) || - ( v->sourceNode()->index()==32 && v->targetNode()->index()==27 )) { - Logger::slout() << "VAR 27-32: " << xVal(t) << "(" << lBound(t) << "," << uBound(t) << ")\n"; - } - } - for(int t = 0; ttheEdgeType()==EdgeVar::CONNECT) { - if(lBound(t)==uBound(t)) { - Logger::slout() << "VAR FIXED: "; - v->printMe(Logger::slout()); - Logger::slout() << " TO " << lBound(t) << "\n"; - } - } - } -#endif //OGDF_DEBUG - - // infeasibleSub(); // great! a virtual function that is private... - Logger::slout() << "\tInfeasible\n"; - return 1; // report any errors - } - master()->clearActiveRepairs(); - OGDF_ASSERT( !lp_->infeasible() ); - //is set here for pricing only - if(master()->m_checkCPlanar) // was: master()->pricing() - dualBound_=master()->infinity();//666 - Logger::slout() << "\t\tLP-relaxation: " << lp_->value() << "\n"; - Logger::slout() << "\t\tLocal/Global dual bound: " << dualBound() << "/" << master_->dualBound() << endl; - realDualBound = lp_->value(); - - //if(master()->m_checkCPlanar2 && dualBound()m_G->numberOfEdges()-0.79) { - // dualBound(-master()->infinity()); - // return 1; - //} - - - if(!master()->pricing()) { - m_reportCreation = separateReal(minViolation);//use ...O for output - } else { - m_sepFirst = !m_sepFirst; - if(m_sepFirst) { - if( m_reportCreation = separateRealO(master()->m_strongConstraintViolation) ) return 0; - if( detectedInfeasibility ) { Logger::slout() << "Infeasibility detected (a)"<< endl; return 1; } - if( m_reportCreation = -pricingRealO(master()->m_strongVariableViolation) ) return 0; - if( m_reportCreation = separateRealO(minViolation)) return 0; - if( detectedInfeasibility ) { Logger::slout() << "Infeasibility detected (b)"<< endl; return 1; } - m_reportCreation = -pricingRealO(minViolation); - } else { - if( m_reportCreation = -pricingRealO(master()->m_strongVariableViolation) ) return 0; - if( m_reportCreation = separateRealO(master()->m_strongConstraintViolation) ) return 0; - if( detectedInfeasibility ) { Logger::slout() << "Infeasibility detected (c)"<< endl; return 1; } - if( m_reportCreation = -pricingRealO(minViolation)) return 0; - m_reportCreation = separateRealO(minViolation); - if( detectedInfeasibility ) { Logger::slout() << "Infeasibility detected (d)"<< endl; return 1; } - } - } - return 0; -} - - -#endif // USE_ABACUS diff --git a/ext/OGDF/src/cluster/MaximumCPlanarSubgraph.cpp b/ext/OGDF/src/cluster/MaximumCPlanarSubgraph.cpp deleted file mode 100644 index 2a06b0868..000000000 --- a/ext/OGDF/src/cluster/MaximumCPlanarSubgraph.cpp +++ /dev/null @@ -1,547 +0,0 @@ - /* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class MaximumCPlanarSubgraph - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_ABACUS - -#include -#include -#include -#include - -//#define writefeasiblegraphs - -namespace ogdf { - -struct connStruct { - bool connected; - node v1, v2; - edge e; -}; - -Module::ReturnType MaximumCPlanarSubgraph::doCall(const ClusterGraph &G, - List &delEdges, - List &addedEdges) -{ -#ifdef OGDF_DEBUG - cout << "Creating new Masterproblem for clustergraph with "<setPortaFile(m_portaOutput); - cplanMaster->useDefaultCutPool() = m_defaultCutPool; -#ifdef OGDF_DEBUG - cout << "Starting Optimization\n"; -#endif - ABA_MASTER::STATUS status; - try { - status = cplanMaster->optimize(); - } - catch (...) - { - #ifdef OGDF_DEBUG - cout << "ABACUS Optimization failed...\n"; - #endif - } - m_totalTime = getDoubleTime(*cplanMaster->totalTime()); - m_heurTime = getDoubleTime(*cplanMaster->improveTime()); - m_sepTime = getDoubleTime(*cplanMaster->separationTime()); - m_lpTime = getDoubleTime(*cplanMaster->lpTime()); - m_lpSolverTime = getDoubleTime(*cplanMaster->lpSolverTime()); - m_totalWTime = getDoubleTime(*cplanMaster->totalCowTime()); - m_numKCons = cplanMaster->addedKConstraints(); - m_numCCons = cplanMaster->addedCConstraints(); - m_numLPs = cplanMaster->nLp(); - m_numBCs = cplanMaster->nSub(); - m_numSubSelected = cplanMaster->nSubSelected(); - m_numVars = cplanMaster->nMaxVars()-cplanMaster->getNumInactiveVars(); -#ifdef OGDF_DEBUG - m_solByHeuristic = cplanMaster->m_solByHeuristic; -#endif -#ifdef OGDF_DEBUG - if(cplanMaster->pricing()) - Logger::slout() << "Pricing was ON\n"; - Logger::slout()<<"ABACUS returned with status '"<< ABA_MASTER::STATUS_[status] <<"'\n"< allEdges; - cplanMaster->getDeletedEdges(delEdges); - cplanMaster->getConnectionOptimalSolutionEdges(addedEdges); - cplanMaster->getAllOptimalSolutionEdges(allEdges); - int delE = delEdges.size(); - int addE = addedEdges.size(); - -#ifdef OGDF_DEBUG - cout< & theList) -{ - ListConstIterator it = c->cBegin(); - while (it.valid()) - { - getBottomUpClusterList((*it), theList); - it++; - } - theList.pushBack(c); -} - -//outputs the set of feasible solutions -void MaximumCPlanarSubgraph::writeFeasible(const String &filename, - Master &master, - ABA_MASTER::STATUS &status) -{ - const ClusterGraph& CG = *(master.getClusterGraph()); - const Graph& G = CG.getGraph(); - node v; - //first compute the nodepairs that are potential candidates to connect - //chunks in a cluster - //potential connection edges - NodeArray< NodeArray > potConn(G); - forall_nodes(v, G) - { - potConn[v].init(G, false); - } - //we perform a bottom up cluster tree traversal - List< cluster > clist; - getBottomUpClusterList(CG.rootCluster(), clist); - //could use postordertraversal instead - - List< nodePair > connPairs; //holds all connection node pairs - //counts the number of potential connectivity edges - //int potCount = 0; //equal to number of true values in potConn - - //we run through the clusters and check connected components - //we consider all possible edges connecting CCs in a cluster, - //even if they may be connected by edges in a child cluster - //(to get the set of all feasible solutions) - - ListConstIterator< cluster > it = clist.begin(); - while (it.valid()) - { - cluster c = (*it); - //we compute the subgraph induced by vertices in c - GraphCopy gcopy; - gcopy.createEmpty(G); - List clusterNodes; - //would be more efficient if we would just merge the childrens' vertices - //and add c's - c->getClusterNodes(clusterNodes); - NodeArray activeNodes(G, false); //true for all cluster nodes - EdgeArray copyEdge(G); //holds the edge copy - ListConstIterator itn = clusterNodes.begin(); - while (itn.valid()) - { - activeNodes[(*itn)] = true; - itn++; - } - gcopy.initByActiveNodes(clusterNodes, activeNodes, copyEdge); - //gcopy now represents the cluster induced subgraph - - //we compute the connected components and store all nodepairs - //that connect two of them - NodeArray component(gcopy); - connectedComponents(gcopy, component); - //now we run over all vertices and compare the component - //number of adjacent vertices. If they differ, we found a - //potential connection edge. We do not care if we find them twice. - forall_nodes(v, gcopy) - { - node w; - forall_nodes(w, gcopy) - { - if (component[v] != component[w]) - { - cout <<"Indizes: "<index()<<":"<index()<<"\n"; - node vg = gcopy.original(v); - node wg = gcopy.original(w); - bool newConn = !((vg->index() < wg->index()) ? potConn[vg][wg] : potConn[wg][vg]); - if (newConn) - { - nodePair np; np.v1 = vg; np.v2 = wg; - connPairs.pushBack(np); - if (vg->index() < wg->index()) - potConn[vg][wg] = true; - else - potConn[wg][vg] = true; - } - } - }//nodes - }//nodes - - it++; - }//while - - cout << "Potentielle Verbindungskanten: "<< connPairs.size()<<"\n"; - - //we run through our candidates and save them in an array - //that can be used for dynamic graph updates - int i = 0; - connStruct *cons = new connStruct[connPairs.size()]; - ListConstIterator< nodePair > itnp = connPairs.begin(); - while (itnp.valid()) - { - connStruct cs; - cs.connected = false; - cs.v1 = (*itnp).v1; - cs.v2 = (*itnp).v2; - cs.e = 0; - - cons[i] = cs; - i++; - itnp++; - }//while - - //------------------------------------------------------------------------- - // WARNING: this is extremely slow for graphs with a large number of cluster - // chunks now we test all possible connection edge combinations for c-planarity - Graph G2; - - NodeArray origNodes(CG.getGraph()); - ClusterArray origCluster(CG); - EdgeArray origEdges(CG.getGraph()); - ClusterGraph testCopy(CG, G2, origCluster, origNodes, origEdges); - - ofstream os(filename.cstr()); - - // Output dimension of the LP (number of variables) - os << "DIM = " << connPairs.size() << "\n"; - os << "COMMENT\n"; - char* stat = new char[10]; - std::sprintf(stat, "%s \n","unknown"); - switch (status) { - case ABA_MASTER::Optimal: std::sprintf(stat, "%s \n", "Optimal"); break; - case ABA_MASTER::Error: std::sprintf(stat, "%s \n", "Error"); break; - default: break; - }//switch - os << stat << "\n"; - delete[] stat; - for (i = 0; i < connPairs.size(); i++) - { - os << "Var " << i << ": " << origNodes[cons[i].v1]->index() << "->" << origNodes[cons[i].v2] << "\n"; - } - - os << "CONV_SECTION\n"; - - int j = 0; //debug - if (connPairs.size() > 0) - while (true) - { - //we create the next test configuration by incrementing the edge selection array - //we create the corresponding graph dynamically on the fly - i = 0; - while ( (i < connPairs.size()) && (cons[i].connected == true) ) - { - cons[i].connected = false; - OGDF_ASSERT(cons[i].e != 0); - G2.delEdge(cons[i].e); - i++; - }//while - if (i >= connPairs.size()) break; - //cout<<"v1graph: "<<&(*(cons[i].v1->graphOf()))<<"\n"; - //cout<<"origNodesgraph: "<<&(*(origNodes.graphOf()))<<"\n"; - cons[i].connected = true; //i.e., (false) will never be a feasible solution - cons[i].e = G2.newEdge(origNodes[cons[i].v1], origNodes[cons[i].v2]); - - - //and test it for c-planarity - CconnectClusterPlanar CCCP; - bool cplanar = CCCP.call(testCopy); - - //c-planar graphs define a feasible solution - if (cplanar) - { - cout << "Feasible solution found\n"; - for (int j = 0; j < connPairs.size(); j++) - { - char ch = (cons[j].connected ? '1' : '0'); - cout << ch; - os << ch << " "; - } - cout << "\n"; - os << "\n"; -#ifdef writefeasiblegraphs - char* fn = new char[20]; - std::sprintf(fn, "cGraph%d.gml",j++); - testCopy.writeGML(fn); - delete[] fn; -#endif - } - }//while counting - - delete[] cons; - - os << "\nEND" <<"\n"; - os.close(); - - //return; - - os.open(getIeqFileName()); - os << "DIM = " << m_numVars << "\n"; - // Output the status as a comment - os << "COMMENT\n"; - char* lstat = new char[10]; - std::sprintf(stat, "%s \n","unknown"); - switch (status) { - case ABA_MASTER::Optimal: std::sprintf(lstat, "%s \n", "Optimal"); break; - case ABA_MASTER::Error: std::sprintf(lstat, "%s \n", "Error"); break; - default: break; - }//switch - os << lstat << "\n"; - delete[] lstat; - // In case 0 is not a valid solution, some PORTA functions need - //a valid solution in the ieq file - os << "VALID\n"; - - os << "\nLOWER_BOUNDS\n"; - - for (i = 0; i < m_numVars; i++) os << "0 "; - os << "\n"; - - os << "\nHIGHER_BOUNDS\n"; - for (i = 0; i < m_numVars; i++) os << "1 "; - os << "\n"; - - os << "\nINEQUALITIES_SECTION\n"; - //we first read the standard constraint that are written - //into a text file by the optimization master - ifstream isf(master.getStdConstraintsFileName()); - if (!isf) - { - cerr << "Could not open optimization master's standard constraint file\n"; - os << "#No standard constraints read\n"; - } - else - { - char* fileLine = new char[maxConLength()]; - while (isf.getline(fileLine, maxConLength())) - { - //skip commment lines - if (fileLine[0] == '#') continue; - int count = 1; - std::istringstream iss(fileLine); - char d; - bool rhs = false; - while (iss >> d) - { - if ( rhs || ( (d == '<') || (d == '>') || (d == '=') ) ) - { - os << d; - rhs = true; - } - else - { - if (d != '0') - { - os <<"+"<< d <<"x"< *connCon = master.cutPool(); - } - else - { - ABA_STANDARDPOOL *connCon = master.getCutConnPool(); - ABA_STANDARDPOOL *kuraCon = master.getCutKuraPool(); - ABA_STANDARDPOOL *stdVar = master.varPool(); - OGDF_ASSERT(connCon != 0); - OGDF_ASSERT(kuraCon != 0); - cout << connCon->number() << " Constraints im MasterConnpool \n"; - cout << kuraCon->number() << " Constraints im MasterKurapool \n"; - cout << connCon->size() << " Größe ConnPool"<<"\n"; - outputCons(os, connCon, stdVar); - outputCons(os, kuraCon, stdVar); - }//else - os << "\nEND" <<"\n"; - os.close(); - cout << "Cutting is set: "< *spool = master.conPool(); - ABA_STANDARDPOOL< ABA_CONSTRAINT, ABA_VARIABLE > *cpool = master.cutPool(); - - cout << spool->size() << " Constraints im Masterpool \n"; - cout << cpool->size() << " Constraints im Mastercutpool \n"; - - cout << "ConPool Constraints \n"; - for ( i = 0; i < spool->size(); i++) - { - ABA_POOLSLOT< ABA_CONSTRAINT, ABA_VARIABLE > * sloty = spool->slot(i); - ABA_CONSTRAINT *mycon = sloty->conVar(); - switch (mycon->sense()->sense()) - { - case ABA_CSENSE::Less: cout << "<" << "\n"; break; - case ABA_CSENSE::Greater: cout << ">" << "\n"; break; - case ABA_CSENSE::Equal: cout << "=" << "\n"; break; - default: cout << "Inequality sense doesn't make any sense \n"; break; - }//switch - } - cout << "CutPool Constraints \n"; - for ( i = 0; i < cpool->size(); i++) - { - ABA_POOLSLOT< ABA_CONSTRAINT, ABA_VARIABLE > * sloty = cpool->slot(i); - ABA_CONSTRAINT *mycon = sloty->conVar(); - switch (mycon->sense()->sense()) - { - case ABA_CSENSE::Less: cout << "<" << "\n"; break; - case ABA_CSENSE::Greater: cout << ">" << "\n"; break; - case ABA_CSENSE::Equal: cout << "=" << "\n"; break; - default: cout << "Inequality sense doesn't make any sense \n"; break; - }//switch - } - */ - /* - for ( i = 0; i < theSub.nCon(); i++) - { - ABA_CONSTRAINT &theCon = *(theSub.constraint(i)); - - for ( i = 0; i < theSub.nVar(); i++) - { - double c = theCon.coeff(theSub.variable(i)); - if (c != 0) - cout << c; - else cout << " "; - } - switch (theCon.sense()->sense()) - { - case ABA_CSENSE::Less: cout << "<" << "\n"; break; - case ABA_CSENSE::Greater: cout << ">" << "\n"; break; - case ABA_CSENSE::Equal: cout << "=" << "\n"; break; - default: cout << "doesn't make any sense \n"; break; - }//switch - #include //for numeric_limits - float fl; - while(!(std::cin >> fl)) - { - std::cin.clear(); - std::cin.ignore(std::numeric_limits::max(),'\n'); - } - }*/ -}//writeportaieq - -void MaximumCPlanarSubgraph::outputCons(ofstream &os, - ABA_STANDARDPOOL *connCon, - ABA_STANDARDPOOL *stdVar) -{ - int i; - for ( i = 0; i < connCon->number(); i++) - { - ABA_POOLSLOT< ABA_CONSTRAINT, ABA_VARIABLE > * sloty = connCon->slot(i); - ABA_CONSTRAINT *mycon = sloty->conVar(); - OGDF_ASSERT(mycon != 0); - int count; - for (count = 0; count < stdVar->size(); count++) - { - ABA_POOLSLOT< ABA_VARIABLE, ABA_CONSTRAINT > * slotv = stdVar->slot(count); - ABA_VARIABLE *myvar = slotv->conVar(); - double d = mycon->coeff(myvar); - if (d != 0.0) //precision! - { - os <<"+"<< d <<"x"<sense()->sense()) - { - case ABA_CSENSE::Less: os << " <= "; break; - case ABA_CSENSE::Greater: os << " >= "; break; - case ABA_CSENSE::Equal: os << " = "; break; - default: os << "Inequality sense doesn't make any sense \n"; - cerr << "Inequality sense unknown \n"; - break; - }//switch - os << mycon->rhs(); - os << "\n"; - } -} - -} //end namespace ogdf - -#endif //USE_ABACUS diff --git a/ext/OGDF/src/decomposition/BCTree.cpp b/ext/OGDF/src/decomposition/BCTree.cpp deleted file mode 100644 index 809438f9a..000000000 --- a/ext/OGDF/src/decomposition/BCTree.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class BCTree - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void BCTree::init (node vG) -{ - m_numB = 0; - m_numC = 0; - - m_gNode_isMarked.init(m_G,false); - m_gNode_hNode.init(m_G,0); - m_gEdge_hEdge.init(m_G); - - m_bNode_type.init(m_B); - m_bNode_isMarked.init(m_B); - m_bNode_hRefNode.init(m_B); - m_bNode_hParNode.init(m_B); - m_bNode_hEdges.init(m_B); - m_bNode_numNodes.init(m_B); - - m_hNode_bNode.init(m_H); - m_hEdge_bNode.init(m_H); - m_hNode_gNode.init(m_H); - m_hEdge_gEdge.init(m_H); - - m_count = 0; - m_number.init(m_G,0); - m_lowpt.init(m_G); - m_gtoh.init(m_G); - - biComp(0,vG); - - m_number.init(); - m_lowpt.init(); - m_eStack.clear(); - m_gtoh.init(); - - node uB; - forall_nodes (uB,m_B) { - node vB = parent(uB); - if (vB) m_B.newEdge(uB,vB); - } -} - - -void BCTree::initNotConnected (node vG) -{ - m_numB = 0; - m_numC = 0; - - m_gNode_isMarked.init(m_G,false); - m_gNode_hNode.init(m_G,0); - m_gEdge_hEdge.init(m_G); - - m_bNode_type.init(m_B); - m_bNode_isMarked.init(m_B); - m_bNode_hRefNode.init(m_B); - m_bNode_hParNode.init(m_B); - m_bNode_hEdges.init(m_B); - m_bNode_numNodes.init(m_B); - - m_hNode_bNode.init(m_H); - m_hEdge_bNode.init(m_H); - m_hNode_gNode.init(m_H); - m_hEdge_gEdge.init(m_H); - - m_count = 0; - m_number.init(m_G,0); - m_lowpt.init(m_G); - m_gtoh.init(m_G); - - biComp(0,vG); - // cout << m_count << endl << flush; - - node v; - - // call biComp for all nodes that are not in the - // first connected component - forall_nodes(v, m_G) - if (m_number[v] == 0){ - m_eStack.clear(); - biComp(0, v); - } - - m_lowpt.init(); - m_eStack.clear(); - m_gtoh.init(); - - node uB; - forall_nodes (uB,m_B) { - node vB = parent(uB); - if (vB) m_B.newEdge(uB,vB); - } -} - - -void BCTree::biComp (adjEntry adjuG, node vG) -{ - m_lowpt[vG] = m_number[vG] = ++m_count; - - adjEntry adj; - forall_adj (adj,vG) { - //edge eG = adj->theEdge(); - node wG = adj->twinNode(); - if ((adjuG != 0) && (adj == adjuG->twin())) continue; - if (m_number[wG]==0) { - m_eStack.push(adj); - biComp(adj,wG); - if (m_lowpt[wG]=m_number[vG]) { - node bB = m_B.newNode(); - m_bNode_type[bB] = BComp; - m_bNode_isMarked[bB] = false; - m_bNode_hRefNode[bB] = 0; - m_bNode_hParNode[bB] = 0; - m_bNode_numNodes[bB] = 0; - m_numB++; - adjEntry adjfG; - do { - adjfG = m_eStack.pop(); - edge fG = adjfG->theEdge(); - for (int i=0; i<=1; ++i) { - node xG = i ? fG->target() : fG->source(); - if (m_gNode_isMarked[xG]) continue; - m_gNode_isMarked[xG] = true; - m_nodes.pushBack(xG); - m_bNode_numNodes[bB]++; - node zH = m_H.newNode(); - m_hNode_bNode[zH] = bB; - m_hNode_gNode[zH] = xG; - m_gtoh[xG] = zH; - node xH = m_gNode_hNode[xG]; - if (!xH) m_gNode_hNode[xG] = zH; - else { - node xB = m_hNode_bNode[xH]; - if (!m_bNode_hRefNode[xB]) { - node cB = m_B.newNode(); - node yH = m_H.newNode(); - m_hNode_bNode[yH] = cB; - m_hNode_gNode[yH] = xG; - m_gNode_hNode[xG] = yH; - m_bNode_type[cB] = CComp; - m_bNode_isMarked[cB] = false; - m_bNode_hRefNode[xB] = xH; - m_bNode_hParNode[xB] = yH; - m_bNode_hRefNode[cB] = yH; - m_bNode_hParNode[cB] = zH; - m_bNode_numNodes[cB] = 1; - m_numC++; - } - else { - node yH = m_bNode_hParNode[xB]; - node yB = m_hNode_bNode[yH]; - m_bNode_hParNode[yB] = xH; - m_bNode_hRefNode[yB] = yH; - m_bNode_hParNode[xB] = zH; - } - } - } - edge fH = m_H.newEdge(m_gtoh[fG->source()],m_gtoh[fG->target()]); - m_bNode_hEdges[bB].pushBack(fH); - m_hEdge_bNode[fH] = bB; - m_hEdge_gEdge[fH] = fG; - m_gEdge_hEdge[fG] = fH; - } while (adj!=adjfG); - while (!m_nodes.empty()) m_gNode_isMarked[m_nodes.popFrontRet()] = false; - } - } - else if (m_number[wG]& BCTree::findPath (node sG, node tG) const -{ - SList& pB = *OGDF_NEW SList; - node sB = bcproper(sG); - node tB = bcproper(tG); - node nB = findNCA(sB,tB); - for (pB.pushBack(sB); sB!=nB; pB.pushBack(sB)) sB = parent(sB); - for (SListIterator iB=pB.rbegin(); tB!=nB; tB=parent(tB)) pB.insertAfter(tB,iB); - return pB; -} - - -SList* BCTree::findPathBCTree (node sB, node tB) const -{ - SList *pB = OGDF_NEW SList; - node nB = findNCA(sB,tB); - for (pB->pushBack(sB); sB!=nB; pB->pushBack(sB)) sB = parent(sB); - for (SListIterator iB=pB->rbegin(); tB!=nB; tB=parent(tB)) pB->insertAfter(tB,iB); - return pB; -} - - -node BCTree::repVertex (node uG, node vB) const -{ - node uB = bcproper(uG); - if (uB==vB) return m_gNode_hNode[uG]; - if (typeOfBNode(uB)==BComp) return 0; - if (parent(uB)==vB) return m_bNode_hParNode[uB]; - if (uB==parent(vB)) return m_bNode_hRefNode[vB]; - return 0; -} - -node BCTree::cutVertex (node uB, node vB) const -{ - if (uB==vB) return typeOfBNode(uB)==CComp ? m_bNode_hRefNode[vB] : 0; - if (parent(uB)==vB) return m_bNode_hParNode[uB]; - if (uB==parent(vB)) return m_bNode_hRefNode[vB]; - return 0; -} - - -} diff --git a/ext/OGDF/src/decomposition/DynamicBCTree.cpp b/ext/OGDF/src/decomposition/DynamicBCTree.cpp deleted file mode 100644 index 74151ae8c..000000000 --- a/ext/OGDF/src/decomposition/DynamicBCTree.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class DynamicBCTree - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void DynamicBCTree::init () -{ - m_bNode_owner.init(m_B); - m_bNode_degree.init(m_B); - node vB; - forall_nodes (vB,m_B) { - m_bNode_owner[vB] = vB; - m_bNode_degree[vB] = vB->degree(); - } -} - - -node DynamicBCTree::unite (node uB, node vB, node wB) -{ - node uH = cutVertex(vB,uB); - node vH = cutVertex(vB,vB); - node wH = cutVertex(vB,wB); - - node mH,sH; - if (uH->degree()>=wH->degree()) { mH = uH; sH = wH; } else { mH = wH; sH = uH; } - - node mB,sB,tB; - if (m_bNode_numNodes[uB]>=m_bNode_numNodes[wB]) { mB = uB; sB = wB; } else { mB = wB; sB = uB; } - if (m_bNode_degree[vB]==2) { - if (m_bNode_numNodes[mB]==0) { mB = vB; sB = uB; tB = wB; } else tB = vB; - } - - if (m_bNode_hParNode[vB]==uH) { - m_bNode_hParNode[vB] = mH; - m_bNode_hRefNode[mB] = m_bNode_hRefNode[uB]; - m_bNode_hParNode[mB] = m_bNode_hParNode[uB]; - } - else if (m_bNode_hParNode[vB]==wH) { - m_bNode_hParNode[vB] = mH; - m_bNode_hRefNode[mB] = m_bNode_hRefNode[wB]; - m_bNode_hParNode[mB] = m_bNode_hParNode[wB]; - } - else if (m_bNode_degree[vB]==2) { - m_bNode_hRefNode[mB] = 0; - m_bNode_hParNode[mB] = 0; - } - else { - m_bNode_hRefNode[mB] = mH; - m_bNode_hParNode[mB] = vH; - } - - adjEntry aH = sH->firstAdj(); - while (aH) { - adjEntry bH = aH->succ(); - if (aH->theEdge()->source()==sH) m_H.moveSource(aH->theEdge(),mH); - else m_H.moveTarget(aH->theEdge(),mH); - aH = bH; - } - m_H.delNode(sH); - - m_numB--; - m_bNode_owner[sB] = mB; - m_bNode_hEdges[mB].conc(m_bNode_hEdges[sB]); - m_bNode_numNodes[mB] = m_bNode_numNodes[uB] + m_bNode_numNodes[wB] - 1; - m_bNode_degree[mB] = m_bNode_degree[uB] + m_bNode_degree[wB] - 1; - - if (m_bNode_degree[vB]==2) { - m_numC--; - m_bNode_type[vB] = BComp; - m_gNode_hNode[m_hNode_gNode[vH]] = mH; - m_H.delNode(vH); - m_bNode_owner[tB] = mB; - m_bNode_hEdges[mB].conc(m_bNode_hEdges[tB]); - m_bNode_degree[mB]--; - } - else m_bNode_degree[vB]--; - - return mB; -} - - -node DynamicBCTree::find (node vB) const -{ - if (!vB) return 0; - if (m_bNode_owner[vB]==vB) return vB; - return m_bNode_owner[vB] = find(m_bNode_owner[vB]); -} - - -node DynamicBCTree::bcproper (node vG) const -{ - if (!vG) return 0; - node vH = m_gNode_hNode[vG]; - return m_hNode_bNode[vH] = find(m_hNode_bNode[vH]); -} - - -node DynamicBCTree::bcproper (edge eG) const -{ - if (!eG) return 0; - edge eH = m_gEdge_hEdge[eG]; - return m_hEdge_bNode[eH] = find(m_hEdge_bNode[eH]); -} - - -node DynamicBCTree::parent (node vB) const -{ - if (!vB) return 0; - node vH = m_bNode_hParNode[vB]; - if (!vH) return 0; - return m_hNode_bNode[vH] = find(m_hNode_bNode[vH]); -} - - -node DynamicBCTree::condensePath (node sG, node tG) -{ - SList& pB = findPath(sG,tG); - SListConstIterator iB = pB.begin(); - node uB = *iB++; - if (iB.valid()) { - if (m_bNode_type[uB]==CComp) uB = *iB++; - while (iB.valid()) { - node vB = *iB++; - if (!iB.valid()) break; - node wB = *iB++; - uB = unite(uB,vB,wB); - } - } - delete &pB; - return uB; -} - - -edge DynamicBCTree::updateInsertedEdge (edge eG) -{ - node vB = condensePath(eG->source(),eG->target()); - edge eH = m_H.newEdge(repVertex(eG->source(),vB),repVertex(eG->target(),vB)); - m_bNode_hEdges[vB].pushBack(eH); - m_hEdge_bNode[eH] = vB; - m_hEdge_gEdge[eH] = eG; - m_gEdge_hEdge[eG] = eH; - return eG; -} - - -node DynamicBCTree::updateInsertedNode (edge eG, edge fG) -{ - node eB = bcproper(eG); - node uG = fG->source(); - m_gNode_isMarked[uG] = false; - - if (numberOfEdges(eB)==1) { - node tG = fG->target(); - node sH = m_gEdge_hEdge[eG]->target(); - m_hNode_gNode[sH] = uG; - - node uB = m_B.newNode(); - node uH = m_H.newNode(); - m_bNode_type[uB] = CComp; - m_bNode_owner[uB] = uB; - m_bNode_numNodes[uB] = 1; - m_bNode_degree[uB] = 2; - m_bNode_isMarked[uB] = false; - m_bNode_hRefNode[uB] = uH; - m_hNode_bNode[uH] = uB; - m_hNode_gNode[uH] = uG; - m_gNode_hNode[uG] = uH; - - node fB = m_B.newNode(); - node vH = m_H.newNode(); - node wH = m_H.newNode(); - edge fH = m_H.newEdge(vH,wH); - m_bNode_type[fB] = BComp; - m_bNode_owner[fB] = fB; - m_bNode_numNodes[fB] = 2; - m_bNode_degree[fB] = 2; - m_bNode_isMarked[fB] = false; - m_bNode_hEdges[fB].pushBack(fH); - m_hNode_bNode[vH] = fB; - m_hNode_bNode[wH] = fB; - m_hEdge_bNode[fH] = fB; - m_hNode_gNode[vH] = uG; - m_hNode_gNode[wH] = tG; - m_hEdge_gEdge[fH] = fG; - m_gEdge_hEdge[fG] = fH; - - node tH = m_gNode_hNode[tG]; - if (m_bNode_hParNode[eB]==tH) { - m_bNode_hParNode[eB] = uH; - m_bNode_hParNode[uB] = vH; - m_bNode_hRefNode[fB] = wH; - m_bNode_hParNode[fB] = tH; - } - else { - node tB = bcproper(tG); - m_bNode_hParNode[tB] = wH; - m_bNode_hRefNode[fB] = vH; - m_bNode_hParNode[fB] = uH; - m_bNode_hParNode[uB] = sH; - } - } - else { - edge fH = m_H.split(m_gEdge_hEdge[eG]); - m_bNode_hEdges[eB].pushBack(fH); - m_hEdge_bNode[fH] = eB; - m_hEdge_gEdge[fH] = fG; - m_gEdge_hEdge[fG] = fH; - node uH = fH->source(); - m_bNode_numNodes[eB]++; - m_hNode_bNode[uH] = eB; - m_hNode_gNode[uH] = uG; - m_gNode_hNode[uG] = uH; - } - return uG; -} - - -node DynamicBCTree::bComponent (node uG, node vG) const -{ - node uB = this->bcproper(uG); - node vB = this->bcproper(vG); - if (uB==vB) return uB; - if (typeOfBNode(uB)==BComp) { - if (typeOfBNode(vB)==BComp) return 0; - if (this->parent(uB)==vB) return uB; - if (this->parent(vB)==uB) return uB; - return 0; - } - if (typeOfBNode(vB)==BComp) { - if (this->parent(uB)==vB) return vB; - if (this->parent(vB)==uB) return vB; - return 0; - } - node pB = this->parent(uB); - node qB = this->parent(vB); - if (pB==qB) return pB; - if (this->parent(pB)==vB) return pB; - if (this->parent(qB)==uB) return qB; - return 0; -} - - - -} diff --git a/ext/OGDF/src/decomposition/DynamicSPQRForest.cpp b/ext/OGDF/src/decomposition/DynamicSPQRForest.cpp deleted file mode 100644 index dcfb54edf..000000000 --- a/ext/OGDF/src/decomposition/DynamicSPQRForest.cpp +++ /dev/null @@ -1,837 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class DynamicSPQRForest - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include "../decomposition/TricComp.h" - - -namespace ogdf { - - -void DynamicSPQRForest::init () -{ - m_bNode_SPQR.init(m_B,0); - m_bNode_numS.init(m_B,0); - m_bNode_numP.init(m_B,0); - m_bNode_numR.init(m_B,0); - m_tNode_type.init(m_T,SComp); - m_tNode_owner.init(m_T); - m_tNode_hRefEdge.init(m_T); - m_tNode_hEdges.init(m_T); - m_tNode_isMarked.init(m_T,false); - m_hEdge_position.init(m_H); - m_hEdge_tNode.init(m_H); - m_hEdge_twinEdge.init(m_H,0); - m_htogc.init(m_H); -} - - -void DynamicSPQRForest::createSPQR (node vB) const -{ - Graph GC; - NodeArray origNode(GC,0); - EdgeArray origEdge(GC,0); - SListConstIterator iH; - - for (iH=m_bNode_hEdges[vB].begin(); iH.valid(); ++iH) - m_htogc[(*iH)->source()] = m_htogc[(*iH)->target()] = 0; - - for (iH=m_bNode_hEdges[vB].begin(); iH.valid(); ++iH) { - edge eH = *iH; - node sH = eH->source(); - node tH = eH->target(); - node& sGC = m_htogc[sH]; - node& tGC = m_htogc[tH]; - if (!sGC) { sGC = GC.newNode(); origNode[sGC] = sH; } - if (!tGC) { tGC = GC.newNode(); origNode[tGC] = tH; } - origEdge[GC.newEdge(sGC,tGC)] = eH; - } - - TricComp tricComp(GC); - - const GraphCopySimple& GCC = *tricComp.m_pGC; - - EdgeArray partnerNode(GCC,0); - EdgeArray partnerEdge(GCC,0); - - for (int i=0; i iGCC=C.m_edges.begin(); iGCC.valid(); ++iGCC) { - edge eGCC = *iGCC; - edge eH = GCC.original(eGCC); - if (eH) eH = origEdge[eH]; - else { - node uH = origNode[GCC.original(eGCC->source())]; - node vH = origNode[GCC.original(eGCC->target())]; - eH = m_H.newEdge(uH,vH); - - if (!partnerNode[eGCC]) { - partnerNode[eGCC] = vT; - partnerEdge[eGCC] = eH; - } - else { - m_T.newEdge(partnerNode[eGCC],vT); - m_hEdge_twinEdge[eH] = partnerEdge[eGCC]; - m_hEdge_twinEdge[partnerEdge[eGCC]] = eH; - } - } - m_hEdge_position[eH] = m_tNode_hEdges[vT].pushBack(eH); - m_hEdge_tNode[eH] = vT; - } - } - - m_bNode_SPQR[vB] = m_hEdge_tNode[origEdge[GC.firstEdge()]]; - m_tNode_hRefEdge[m_bNode_SPQR[vB]] = 0; - - SList lT; - lT.pushBack(m_bNode_SPQR[vB]); - lT.pushBack(0); - while (!lT.empty()) { - node vT = lT.popFrontRet(); - node wT = lT.popFrontRet(); - for (ListConstIterator iH=m_tNode_hEdges[vT].begin(); iH.valid(); ++iH) { - edge eH = *iH; - edge fH = m_hEdge_twinEdge[eH]; - if (!fH) continue; - node uT = m_hEdge_tNode[fH]; - if (uT==wT) m_tNode_hRefEdge[vT] = eH; - else { - lT.pushBack(uT); - lT.pushBack(vT); - } - } - } -} - - -node DynamicSPQRForest::uniteSPQR (node vB, node sT, node tT) -{ - if (m_tNode_type[tT]==SComp) m_bNode_numS[vB]--; - else if (m_tNode_type[tT]==PComp) m_bNode_numP[vB]--; - else if (m_tNode_type[tT]==RComp) m_bNode_numR[vB]--; - if (!sT) { - m_bNode_numR[vB]++; - sT = tT; - } - else { - if (m_tNode_hEdges[sT].size()& DynamicSPQRForest::findPathSPQR (node sH, node tH, node& rT) const -{ - SList& pT = *OGDF_NEW SList; - node sT = spqrproper(sH->firstAdj()->theEdge()); - node tT = spqrproper(tH->firstAdj()->theEdge()); - node nT = findNCASPQR(sT,tT); - while (sT!=nT) { - edge eH = m_tNode_hRefEdge[sT]; - node uH = eH->source(); - node vH = eH->target(); - if (uH!=sH && vH!=sH) pT.pushBack(sT); - if (uH==tH || vH==tH) { rT = sT; return pT; } - sT = spqrproper(m_hEdge_twinEdge[eH]); - } - SListIterator iT = pT.rbegin(); - while (tT!=nT) { - edge eH = m_tNode_hRefEdge[tT]; - node uH = eH->source(); - node vH = eH->target(); - if (uH!=tH && vH!=tH) { - if (iT.valid()) pT.insertAfter(tT,iT); - else pT.pushFront(tT); - } - if (uH==sH || vH==sH) { rT = tT; return pT; } - tT = spqrproper(m_hEdge_twinEdge[eH]); - } - if (iT.valid()) pT.insertAfter(nT,iT); - else pT.pushFront(nT); - rT = nT; return pT; -} - - -SList& DynamicSPQRForest::findPathSPQR (node sH, node tH) const -{ - node vB = bComponent(m_hNode_gNode[sH],m_hNode_gNode[tH]); - if (!vB) return *OGDF_NEW SList; - if (!m_bNode_SPQR[vB]) { - if (m_bNode_hEdges[vB].size()<3) return *OGDF_NEW SList; - createSPQR(vB); - } - node rT; - SList& pT = findPathSPQR(sH,tH,rT); - if (pT.empty()) if (rT) pT.pushBack(rT); - return pT; -} - - -edge DynamicSPQRForest::virtualEdge (node vT, node wT) const -{ - edge eH = m_tNode_hRefEdge[vT]; - if (eH) { - eH = m_hEdge_twinEdge[eH]; - if (spqrproper(eH)==wT) return eH; - } - eH = m_tNode_hRefEdge[wT]; - if (eH) { - if (spqrproper(m_hEdge_twinEdge[eH])==vT) return eH; - } - return 0; -} - - -edge DynamicSPQRForest::updateInsertedEdgeSPQR (node vB, edge eG) -{ - node sG = eG->source(); - node tG = eG->target(); - node sH = repVertex(sG,vB); - node tH = repVertex(tG,vB); - edge eH = m_H.newEdge(sH,tH); - m_gEdge_hEdge[eG] = eH; - m_hEdge_gEdge[eH] = eG; - - adjEntry aH; - forall_adj (aH,sH) { - edge fH = aH->theEdge(); - if (fH==eH) continue; - if (fH->opposite(sH)!=tH) continue; - node vT = spqrproper(fH); - if (m_tNode_type[vT]==PComp) { - m_hEdge_position[eH] = m_tNode_hEdges[vT].pushBack(eH); - m_hEdge_tNode[eH] = vT; - return eG; - } - edge gH = m_hEdge_twinEdge[fH]; - if (!gH) { - m_bNode_numP[vB]++; - node nT = m_T.newNode(); - m_tNode_type[nT] = PComp; - m_tNode_owner[nT] = nT; - edge v1 = m_H.newEdge(sH,tH); - edge v2 = m_H.newEdge(sH,tH); - m_hEdge_position[v1] = m_tNode_hEdges[vT].insertAfter(v1,m_hEdge_position[fH]); - m_tNode_hEdges[vT].del(m_hEdge_position[fH]); - m_hEdge_position[v2] = m_tNode_hEdges[nT].pushBack(v2); - m_hEdge_position[fH] = m_tNode_hEdges[nT].pushBack(fH); - m_hEdge_position[eH] = m_tNode_hEdges[nT].pushBack(eH); - m_hEdge_tNode[v1] = vT; - m_hEdge_twinEdge[v1] = m_tNode_hRefEdge[nT] = v2; - m_hEdge_tNode[v2] = m_hEdge_tNode[eH] = m_hEdge_tNode[fH] = nT; - m_hEdge_twinEdge[v2] = v1; - return eG; - } - node wT = spqrproper(gH); - if (m_tNode_type[wT]==PComp) { - m_hEdge_position[eH] = m_tNode_hEdges[vT].pushBack(eH); - m_hEdge_tNode[eH] = vT; - } - else { - m_bNode_numP[vB]++; - node nT = m_T.newNode(); - m_tNode_type[nT] = PComp; - m_tNode_owner[nT] = nT; - edge v1 = m_tNode_hRefEdge[vT]; - if (!v1) v1 = m_tNode_hRefEdge[wT]; - else if (spqrproper(m_hEdge_twinEdge[v1])!=wT) v1 = m_tNode_hRefEdge[wT]; - edge v4 = m_hEdge_twinEdge[v1]; - edge v2 = m_H.newEdge(v1->source(),v1->target()); - edge v3 = m_H.newEdge(v4->source(),v4->target()); - m_hEdge_twinEdge[v1] = v2; - m_hEdge_twinEdge[v2] = v1; - m_hEdge_twinEdge[v3] = v4; - m_hEdge_twinEdge[v4] = v3; - m_hEdge_position[v2] = m_tNode_hEdges[nT].pushBack(v2); - m_hEdge_position[eH] = m_tNode_hEdges[nT].pushBack(eH); - m_hEdge_position[v3] = m_tNode_hEdges[nT].pushBack(v3); - m_hEdge_tNode[v2] = m_hEdge_tNode[eH] = m_hEdge_tNode[v3] = nT; - m_tNode_hRefEdge[nT] = v3; - } - return eG; - } - - node rT; - SList& pT = findPathSPQR(sH,tH,rT); - if (pT.size()<2) { - if (m_tNode_type[rT]==RComp) { - m_hEdge_position[eH] = m_tNode_hEdges[rT].pushBack(eH); - m_hEdge_tNode[eH] = rT; - } - else { - List& aH = m_tNode_hEdges[rT]; - SList bH; - bool a_is_parent = true; - ListIterator iH = aH.begin(); - node uH = sH; - while (uH!=tH) { - node xH = (*iH)->source(); - node yH = (*iH)->target(); - if (xH==uH) uH = yH; - else if (yH==uH) uH = xH; - else { iH = aH.cyclicSucc(iH); continue; } - if (*iH==m_tNode_hRefEdge[rT]) a_is_parent = false; - bH.pushBack(*iH); - ListIterator jH = iH; - iH = aH.cyclicSucc(iH); - aH.del(jH); - } - m_bNode_numS[vB]++; - m_bNode_numP[vB]++; - node sT = m_T.newNode(); - node pT = m_T.newNode(); - m_tNode_type[sT] = SComp; - m_tNode_type[pT] = PComp; - m_tNode_owner[sT] = sT; - m_tNode_owner[pT] = pT; - edge v1 = m_H.newEdge(sH,tH); - edge v2 = m_H.newEdge(sH,tH); - edge v3 = m_H.newEdge(sH,tH); - edge v4 = m_H.newEdge(sH,tH); - m_hEdge_twinEdge[v1] = v2; - m_hEdge_twinEdge[v2] = v1; - m_hEdge_twinEdge[v3] = v4; - m_hEdge_twinEdge[v4] = v3; - m_hEdge_position[v1] = m_tNode_hEdges[sT].pushBack(v1); - m_hEdge_position[v2] = m_tNode_hEdges[pT].pushBack(v2); - m_hEdge_position[eH] = m_tNode_hEdges[pT].pushBack(eH); - m_hEdge_position[v3] = m_tNode_hEdges[pT].pushBack(v3); - m_hEdge_position[v4] = m_tNode_hEdges[rT].pushBack(v4); - m_hEdge_tNode[v1] = sT; - m_hEdge_tNode[v2] = m_hEdge_tNode[eH] = m_hEdge_tNode[v3] = pT; - m_hEdge_tNode[v4] = rT; - for (SListConstIterator iH=bH.begin(); iH.valid(); ++iH) { - m_hEdge_position[*iH] = m_tNode_hEdges[sT].pushBack(*iH); - m_hEdge_tNode[*iH] = sT; - } - if (a_is_parent) { - m_tNode_hRefEdge[sT] = v1; - m_tNode_hRefEdge[pT] = v3; - } - else { - m_tNode_hRefEdge[sT] = m_tNode_hRefEdge[rT]; - m_tNode_hRefEdge[pT] = v2; - m_tNode_hRefEdge[rT] = v4; - if (!m_tNode_hRefEdge[sT]) m_bNode_SPQR[vB] = sT; - } - } - } - else { - node xT = 0; - SList absorbedEdges; - SList virtualEdgesInPath; - SList newVirtualEdges; - - edge rH = m_tNode_hRefEdge[rT]; - - SListIterator iT = pT.begin(); - SListIterator jT = iT; - - virtualEdgesInPath.pushBack(0); - for (++jT; jT.valid(); ++iT, ++jT) { - edge gH,fH = m_tNode_hRefEdge[*iT]; - if (!fH) { - gH = m_tNode_hRefEdge[*jT]; - fH = m_hEdge_twinEdge[gH]; - } - else { - gH = m_hEdge_twinEdge[fH]; - if (spqrproper(gH)!=*jT) { - gH = m_tNode_hRefEdge[*jT]; - fH = m_hEdge_twinEdge[gH]; - } - } - virtualEdgesInPath.pushBack(fH); - virtualEdgesInPath.pushBack(gH); - } - virtualEdgesInPath.pushBack(0); - - for (iT=pT.begin(); iT.valid(); ++iT) { - edge fH = virtualEdgesInPath.popFrontRet(); - edge gH = virtualEdgesInPath.popFrontRet(); - if (m_tNode_type[*iT]==SComp) { - List& aH = m_tNode_hEdges[*iT]; - SList bH; - ListIterator iH,jH; - node zH; - - node uH = 0; - if (!fH) { fH = gH; uH = sH; } - else if (!gH) uH = tH; - - node vH = fH->source(); - node wH = fH->target(); - - if (uH) { - iH = jH = m_hEdge_position[fH]; - for( ; ; ) { - iH = aH.cyclicSucc(iH); - node xH = (*iH)->source(); - node yH = (*iH)->target(); - if (xH==vH) { zH = vH; vH = yH; break; } - if (xH==wH) { zH = wH; wH = vH; vH = yH; break; } - if (yH==vH) { zH = vH; vH = xH; break; } - if (yH==wH) { zH = wH; wH = vH; vH = xH; break; } - } - m_H.delEdge(*jH); - aH.del(jH); - jH = iH; - iH = aH.cyclicSucc(iH); - bH.pushBack(*jH); - aH.del(jH); - while (vH!=uH) { - for( ; ; ) { - node xH = (*iH)->source(); - node yH = (*iH)->target(); - if (xH==vH) { vH = yH; break; } - if (yH==vH) { vH = xH; break; } - iH = aH.cyclicSucc(iH); - } - jH = iH; - iH = aH.cyclicSucc(iH); - bH.pushBack(*jH); - aH.del(jH); - } - if (bH.size()==1) { - edge nH = bH.front(); - if (nH==rH) rT = 0; - absorbedEdges.pushBack(nH); - } - else { - m_bNode_numS[vB]++; - node nT = m_T.newNode(); - m_tNode_type[nT] = SComp; - m_tNode_owner[nT] = nT; - while (!bH.empty()) { - edge nH = bH.popFrontRet(); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - if (nH==rH) rT = nT; - } - edge nH = m_H.newEdge(vH,zH); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - if (nT==rT) { - m_tNode_hRefEdge[nT] = rH; - if (!rH) m_bNode_SPQR[vB] = nT; - rH = nH; - } - else m_tNode_hRefEdge[nT] = nH; - newVirtualEdges.pushBack(nH); - } - if (m_tNode_hEdges[*iT].size()==1) xT = uniteSPQR(vB,xT,*iT); - else { - edge nH = m_H.newEdge(wH,vH); - m_hEdge_position[nH] = m_tNode_hEdges[*iT].pushBack(nH); - m_hEdge_tNode[nH] = *iT; - if (*iT==rT) rH = nH; - else m_tNode_hRefEdge[*iT] = nH; - newVirtualEdges.pushBack(nH); - } - } - else if (aH.size()==3) { - aH.del(m_hEdge_position[fH]); - aH.del(m_hEdge_position[gH]); - m_H.delEdge(fH); - m_H.delEdge(gH); - xT = uniteSPQR(vB,xT,*iT); - } - else { - node xH = gH->source(); - node yH = gH->target(); - edge nH = 0; - if (vH==xH) nH = m_H.newEdge(wH,yH); - else if (vH==yH) nH = m_H.newEdge(wH,xH); - else if (wH==xH) nH = m_H.newEdge(vH,yH); - else if (wH==yH) nH = m_H.newEdge(vH,xH); - if (nH) { - m_hEdge_position[nH] = aH.insertAfter(nH,m_hEdge_position[gH]); - m_hEdge_tNode[nH] = *iT; - if (*iT==rT) rH = nH; - else m_tNode_hRefEdge[*iT] = nH; - aH.del(m_hEdge_position[fH]); - aH.del(m_hEdge_position[gH]); - m_H.delEdge(fH); - m_H.delEdge(gH); - newVirtualEdges.pushBack(nH); - } - else { - iH = jH = m_hEdge_position[fH]; - for( ; ; ) { - iH = aH.cyclicSucc(iH); - node xH = (*iH)->source(); - node yH = (*iH)->target(); - if (xH==vH) { zH = vH; vH = yH; break; } - if (xH==wH) { zH = wH; wH = vH; vH = yH; break; } - if (yH==vH) { zH = vH; vH = xH; break; } - if (yH==wH) { zH = wH; wH = vH; vH = xH; break; } - } - m_H.delEdge(*jH); - aH.del(jH); - jH = iH; - iH = aH.cyclicSucc(iH); - bH.pushBack(*jH); - aH.del(jH); - node pH = gH->source(); - node qH = gH->target(); - while (vH!=pH && vH!=qH) { - for( ; ; ) { - node xH = (*iH)->source(); - node yH = (*iH)->target(); - if (xH==vH) { vH = yH; break; } - if (yH==vH) { vH = xH; break; } - iH = aH.cyclicSucc(iH); - } - jH = iH; - iH = aH.cyclicSucc(iH); - bH.pushBack(*jH); - aH.del(jH); - } - aH.del(m_hEdge_position[gH]); - m_H.delEdge(gH); - if (bH.size()==1) { - edge nH = bH.front(); - if (nH==rH) rT = 0; - absorbedEdges.pushBack(nH); - } - else { - m_bNode_numS[vB]++; - node nT = m_T.newNode(); - m_tNode_type[nT] = SComp; - m_tNode_owner[nT] = nT; - while (!bH.empty()) { - edge nH = bH.popFrontRet(); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - if (nH==rH) rT = nT; - } - edge nH = m_H.newEdge(vH,zH); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - if (nT==rT) { - m_tNode_hRefEdge[nT] = rH; - if (!rH) m_bNode_SPQR[vB] = nT; - rH = nH; - } - else m_tNode_hRefEdge[nT] = nH; - newVirtualEdges.pushBack(nH); - } - if (m_tNode_hEdges[*iT].size()==1) xT = uniteSPQR(vB,xT,*iT); - else { - edge nH = m_H.newEdge(wH,vH==pH?qH:pH); - m_hEdge_position[nH] = m_tNode_hEdges[*iT].pushBack(nH); - m_hEdge_tNode[nH] = *iT; - if (*iT==rT) rH = nH; - else m_tNode_hRefEdge[*iT] = nH; - newVirtualEdges.pushBack(nH); - } - } - } - } - else { - if (fH) { - m_tNode_hEdges[*iT].del(m_hEdge_position[fH]); - m_H.delEdge(fH); - } - if (gH) { - m_tNode_hEdges[*iT].del(m_hEdge_position[gH]); - m_H.delEdge(gH); - } - if (m_tNode_type[*iT]==PComp) { - if (m_tNode_hEdges[*iT].size()>1) { - edge nH = m_tNode_hEdges[*iT].front(); - nH = m_H.newEdge(nH->source(),nH->target()); - m_hEdge_position[nH] = m_tNode_hEdges[*iT].pushBack(nH); - m_hEdge_tNode[nH] = *iT; - if (*iT==rT) rH = nH; - else m_tNode_hRefEdge[*iT] = nH; - newVirtualEdges.pushBack(nH); - } - else xT = uniteSPQR(vB,xT,*iT); - } - else xT = uniteSPQR(vB,xT,*iT); - } - } - if (!xT) { - m_bNode_numR[vB]++; - xT = m_T.newNode(); - m_tNode_type[xT] = RComp; - m_tNode_owner[xT] = xT; - } - while (!newVirtualEdges.empty()) { - edge oH = newVirtualEdges.popFrontRet(); - edge nH = m_H.newEdge(oH->source(),oH->target()); - m_hEdge_position[nH] = m_tNode_hEdges[xT].pushBack(nH); - m_hEdge_tNode[nH] = xT; - m_hEdge_twinEdge[nH] = oH; - m_hEdge_twinEdge[oH] = nH; - } - while (!absorbedEdges.empty()) { - edge nH = absorbedEdges.popFrontRet(); - m_hEdge_position[nH] = m_tNode_hEdges[xT].pushBack(nH); - m_hEdge_tNode[nH] = xT; - } - m_hEdge_position[eH] = m_tNode_hEdges[xT].pushBack(eH); - m_hEdge_tNode[eH] = xT; - if (!rT) m_tNode_hRefEdge[xT] = rH; - else if (findSPQR(rT)!=xT) m_tNode_hRefEdge[xT] = m_hEdge_twinEdge[rH]; - else { - m_tNode_hRefEdge[xT] = rH; - if (!rH) m_bNode_SPQR[vB] = xT; - } - } - delete &pT; - return eG; -} - - -node DynamicSPQRForest::updateInsertedNodeSPQR (node vB, edge eG, edge fG) -{ - node vG = fG->source(); - node wG = fG->target(); - node vH = m_H.newNode(); - node wH = repVertex(wG,vB); - m_gNode_hNode[vG] = vH; - m_hNode_gNode[vH] = vG; - edge fH = m_H.newEdge(vH,wH); - m_gEdge_hEdge[fG] = fH; - m_hEdge_gEdge[fH] = fG; - edge eH = m_gEdge_hEdge[eG]; - m_H.moveTarget(eH,vH); - node vT = spqrproper(eH); - if (m_tNode_type[vT]==SComp) { - m_hEdge_position[fH] = m_tNode_hEdges[vT].insertAfter(fH,m_hEdge_position[eH]); - m_hEdge_tNode[fH] = vT; - } - else { - m_bNode_numS[vB]++; - node nT = m_T.newNode(); - m_tNode_type[nT] = SComp; - m_tNode_owner[nT] = nT; - node uH = eH->source(); - node wH = fH->target(); - edge v1 = m_H.newEdge(uH,wH); - edge v2 = m_H.newEdge(uH,wH); - m_hEdge_position[v1] = m_tNode_hEdges[vT].insertAfter(v1,m_hEdge_position[eH]); - m_tNode_hEdges[vT].del(m_hEdge_position[eH]); - m_hEdge_position[v2] = m_tNode_hEdges[nT].pushBack(v2); - m_hEdge_position[eH] = m_tNode_hEdges[nT].pushBack(eH); - m_hEdge_position[fH] = m_tNode_hEdges[nT].pushBack(fH); - m_hEdge_tNode[v1] = vT; - m_hEdge_twinEdge[v1] = m_tNode_hRefEdge[nT] = v2; - m_hEdge_tNode[v2] = m_hEdge_tNode[eH] = m_hEdge_tNode[fH] = nT; - m_hEdge_twinEdge[v2] = v1; - } - return vG; -} - - -edge DynamicSPQRForest::updateInsertedEdge (edge eG) -{ - node sG = eG->source(); - node tG = eG->target(); - node vB = bComponent(sG,tG); - if (vB) { - if (m_bNode_SPQR[vB]) { - edge eH = m_gEdge_hEdge[updateInsertedEdgeSPQR(vB,eG)]; - m_bNode_hEdges[vB].pushBack(eH); - m_hEdge_bNode[eH] = vB; - } - else DynamicBCTree::updateInsertedEdge(eG); - } - else { - node nT = 0; - int numS,numP,numR; - SList& pB = findPath(sG,tG); - SListIterator jB = pB.begin(); - SListIterator iB = jB; - while (iB.valid()) { if (m_bNode_SPQR[*iB]) break; ++iB; } - if (iB.valid()) { - nT = m_T.newNode(); - m_tNode_type[nT] = SComp; - m_tNode_owner[nT] = nT; - m_tNode_hRefEdge[nT] = 0; - numS = 1; - numP = 0; - numR = 0; - node sH = repVertex(sG,*jB); - for (iB=jB; iB.valid(); ++iB) { - node tH = (++jB).valid() ? cutVertex(*jB,*iB) : repVertex(tG,*iB); - node mT; - edge mH,nH; - switch (numberOfEdges(*iB)) { - case 0: - break; - case 1: - nH = m_bNode_hEdges[*iB].front(); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - break; - case 2: - mT = m_T.newNode(); - m_tNode_type[mT] = PComp; - m_tNode_owner[mT] = mT; - mH = m_bNode_hEdges[*iB].front(); - m_hEdge_position[mH] = m_tNode_hEdges[mT].pushBack(mH); - m_hEdge_tNode[mH] = mT; - mH = m_bNode_hEdges[*iB].back(); - m_hEdge_position[mH] = m_tNode_hEdges[mT].pushBack(mH); - m_hEdge_tNode[mH] = mT; - mH = m_H.newEdge(sH,tH); - m_hEdge_position[mH] = m_tNode_hEdges[mT].pushBack(mH); - m_hEdge_tNode[mH] = mT; - nH = m_H.newEdge(sH,tH); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - m_hEdge_twinEdge[mH] = nH; - m_hEdge_twinEdge[nH] = mH; - m_tNode_hRefEdge[mT] = mH; - numP++; - break; - default: - if (!m_bNode_SPQR[*iB]) createSPQR(*iB); - edge mG = m_G.newEdge(m_hNode_gNode[sH],m_hNode_gNode[tH]); - updateInsertedEdgeSPQR(*iB,mG); - mH = m_gEdge_hEdge[mG]; - mT = spqrproper(mH); - m_G.delEdge(mG); - m_hEdge_gEdge[mH] = 0; - nH = m_H.newEdge(sH,tH); - m_hEdge_position[nH] = m_tNode_hEdges[nT].pushBack(nH); - m_hEdge_tNode[nH] = nT; - m_hEdge_twinEdge[mH] = nH; - m_hEdge_twinEdge[nH] = mH; - for( ; ; ) { - nH = m_tNode_hRefEdge[mT]; - m_tNode_hRefEdge[mT] = mH; - if (!nH) break; - mH = m_hEdge_twinEdge[nH]; - mT = spqrproper(mH); - } - numS += m_bNode_numS[*iB]; - numP += m_bNode_numP[*iB]; - numR += m_bNode_numR[*iB]; - } - if (jB.valid()) sH = cutVertex(*iB,*jB); - } - } - delete &pB; - DynamicBCTree::updateInsertedEdge(eG); - if (nT) { - edge eH = m_gEdge_hEdge[eG]; - m_hEdge_position[eH] = m_tNode_hEdges[nT].pushBack(eH); - m_hEdge_tNode[eH] = nT; - node eB = bcproper(eG); - m_bNode_SPQR[eB] = nT; - m_bNode_numS[eB] = numS; - m_bNode_numP[eB] = numP; - m_bNode_numR[eB] = numR; - } - } - return eG; -} - - -node DynamicSPQRForest::updateInsertedNode (edge eG, edge fG) -{ - node vB = bcproper(eG); - if (m_bNode_SPQR[vB]) { - node uG = updateInsertedNodeSPQR(vB,eG,fG); - m_gNode_isMarked[uG] = false; - edge fH = m_gEdge_hEdge[fG]; - m_bNode_hEdges[vB].pushBack(fH); - m_hEdge_bNode[fH] = vB; - m_hNode_bNode[fH->source()] = vB; - m_bNode_numNodes[vB]++; - return uG; - } - return DynamicBCTree::updateInsertedNode(eG,fG); -} - - -} diff --git a/ext/OGDF/src/decomposition/DynamicSPQRTree.cpp b/ext/OGDF/src/decomposition/DynamicSPQRTree.cpp deleted file mode 100644 index 27cf557fe..000000000 --- a/ext/OGDF/src/decomposition/DynamicSPQRTree.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of classes DynamicSkeleton and DynamicSPQRTree - * - * \author Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - -//------------------------------------------------------------------- -// DynamicSkeleton -//------------------------------------------------------------------- - -DynamicSkeleton::DynamicSkeleton (const DynamicSPQRTree* T, node vB) : Skeleton(vB), m_owner(T) -{ - m_origNode.init(m_M,0); - m_origEdge.init(m_M,0); -} - - -const SPQRTree &DynamicSkeleton::owner () const -{ - return *m_owner; -} - - -node DynamicSkeleton::original (node vM) const -{ - return m_owner->m_hNode_gNode[m_origNode[vM]]; -} - - -edge DynamicSkeleton::realEdge (edge eM) const -{ - return m_owner->m_hEdge_gEdge[m_origEdge[eM]]; -} - - -edge DynamicSkeleton::twinEdge (edge eM) const -{ - edge eH = m_owner->m_hEdge_twinEdge[m_origEdge[eM]]; - if (!eH) return 0; - m_owner->skeleton(m_owner->spqrproper(eH)); - return m_owner->m_skelEdge[eH]; -} - - -node DynamicSkeleton::twinTreeNode (edge eM) const -{ - edge eH = m_owner->m_hEdge_twinEdge[m_origEdge[eM]]; - if (!eH) return 0; - return m_owner->spqrproper(eH); -} - - -//------------------------------------------------------------------- -// DynamicSPQRTree -//------------------------------------------------------------------- - -// -// initialization: builds tree, skeleton graphs and cross references -// -void DynamicSPQRTree::init (edge eG) -{ - createSPQR(bcproper(eG)); - rootTreeAt(eG); - m_sk.init(m_T,0); - m_skelEdge.init(m_H,0); - m_mapV.init(m_H,0); - m_cpV = 0; -} - - -// -// createSkeleton: creates a skeleton graph -// -DynamicSkeleton& DynamicSPQRTree::createSkeleton (node vT) const -{ - DynamicSkeleton& S = *OGDF_NEW DynamicSkeleton(this,vT); - - SList inMapV; - - for (ListConstIterator itH=m_tNode_hEdges[vT].begin(); itH.valid(); ++itH) - { - edge eH = *itH; - node sH = eH->source(); - node tH = eH->target(); - - edge& eM = m_skelEdge[eH]; - node& sM = m_mapV[sH]; - node& tM = m_mapV[tH]; - - if (!sM) { - sM = S.m_M.newNode(); - S.m_origNode[sM] = sH; - inMapV.pushBack(sH); - } - - if (!tM) { - tM = S.m_M.newNode(); - S.m_origNode[tM] = tH; - inMapV.pushBack(tH); - } - - eM = S.m_M.newEdge(sM,tM); - S.m_origEdge[eM] = eH; - } - - while(!inMapV.empty()) m_mapV[inMapV.popFrontRet()] = 0; - - S.m_referenceEdge = m_tNode_hRefEdge[vT]; - if(S.m_referenceEdge) S.m_referenceEdge = m_skelEdge[S.m_referenceEdge]; - - m_sk[vT] = &S; - return S; -} - - -// -// destructor: deletes skeleton graphs -// -DynamicSPQRTree::~DynamicSPQRTree () -{ - node vB; - forall_nodes (vB,m_T) delete m_sk[vB]; - - delete m_cpV; -} - - -List DynamicSPQRTree::nodesOfType (NodeType t) const -{ - TNodeType tt = (TNodeType)t; - List L; - node vT; - forall_nodes (vT,m_T) { - if (m_tNode_owner[vT]!=vT) continue; - if (m_tNode_type[vT]==tt) L.pushBack(vT); - } - return L; -} - - -node DynamicSPQRTree::rootTreeAt (edge eG) -{ - node vT = rootTreeAt(spqrproper(m_gEdge_hEdge[eG])); - m_rootEdge = eG; - return vT; -} - - -node DynamicSPQRTree::rootTreeAt (node vT) -{ - vT = findSPQR(vT); - node uT = vT; - edge eH = 0; - for( ; ; ) { - edge fH = m_tNode_hRefEdge[uT]; - m_tNode_hRefEdge[uT] = eH; - if (!fH) break; - eH = m_hEdge_twinEdge[fH]; - uT = spqrproper(eH); - } - m_rootEdge = 0; - return m_bNode_SPQR[m_B.firstNode()] = vT; -} - - -edge DynamicSPQRTree::updateInsertedEdge (edge eG) -{ - SList marked; - node sH = m_gNode_hNode[eG->source()]; - node tH = m_gNode_hNode[eG->target()]; - adjEntry aH; - forall_adj (aH,sH) { - edge fH = aH->theEdge(); - node vT = spqrproper(fH); - if (fH->opposite(sH)==tH) { - if (m_tNode_type[vT]==PComp) { - DynamicSPQRForest::updateInsertedEdge(eG); - if (m_sk[vT]) { - edge eH = m_gEdge_hEdge[eG]; - edge fM = m_skelEdge[fH]; - node sM = fM->source(); - node tM = fM->target(); - if (eH->source()==m_sk[vT]->m_origNode[tM]) { node uM = sM; sM = tM; tM = uM; } - m_skelEdge[eH] = m_sk[vT]->getGraph().newEdge(sM,tM); - m_sk[vT]->m_origEdge[m_skelEdge[eH]] = eH; - } - return eG; - } - else if (!m_hEdge_twinEdge[fH]) { - DynamicSPQRForest::updateInsertedEdge(eG); - if (m_sk[vT]) { - edge gH = m_hEdge_twinEdge[m_tNode_hEdges[m_hEdge_tNode[fH]].front()]; - m_skelEdge[gH] = m_skelEdge[fH]; - m_sk[vT]->m_origEdge[m_skelEdge[gH]] = gH; - } - return eG; - } - else { - m_tNode_isMarked[vT] = true; - marked.pushBack(vT); - } - } - else { - m_tNode_isMarked[vT] = true; - marked.pushBack(vT); - } - } - int count = 0; - node found[2]; - forall_adj (aH,tH) { - edge fH = aH->theEdge(); - node vT = spqrproper(fH); - if (!m_tNode_isMarked[vT]) continue; - found[count++] = vT; - m_tNode_isMarked[vT] = false; - } - while (!marked.empty()) m_tNode_isMarked[marked.popFrontRet()] = false; - if (count==0) { - node rT; - SList& pT = findPathSPQR(sH,tH,rT); - for (SListIterator iT=pT.begin(); iT.valid(); ++iT) - if (m_sk[*iT]) { - delete m_sk[*iT]; - m_sk[*iT] = 0; - } - delete &pT; - } - else if (count==1) { - node vT = found[0]; - if (m_sk[vT]) { - delete m_sk[vT]; - m_sk[vT] = 0; - } - } - return DynamicSPQRForest::updateInsertedEdge(eG); -} - - -node DynamicSPQRTree::updateInsertedNode (edge eG, edge fG) -{ - edge eH = m_gEdge_hEdge[eG]; - node vT = spqrproper(eH); - if (m_tNode_type[vT]==SComp) { - DynamicSPQRForest::updateInsertedNode(eG,fG); - if (m_sk[vT]) { - edge fH = m_gEdge_hEdge[fG]; - edge fM = m_skelEdge[fH] = m_sk[vT]->getGraph().split(m_skelEdge[eH]); - m_sk[vT]->m_origNode[fM->source()] = fH->source(); - m_sk[vT]->m_origEdge[fM] = fH; - } - } - else { - DynamicSPQRForest::updateInsertedNode(eG,fG); - if (m_sk[vT]) { - edge gH = m_hEdge_twinEdge[m_tNode_hEdges[spqrproper(eH)].front()]; - edge gM = m_skelEdge[gH] = m_skelEdge[eH]; - m_sk[vT]->m_origEdge[gM] = gH; - } - } - return fG->source(); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/decomposition/NonPlanarCore.cpp b/ext/OGDF/src/decomposition/NonPlanarCore.cpp deleted file mode 100644 index 6527a2fd1..000000000 --- a/ext/OGDF/src/decomposition/NonPlanarCore.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements the class NonPlanarCore. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -NonPlanarCore::NonPlanarCore(const Graph &G) : m_pOriginal(&G), m_orig(m_graph), - m_real(m_graph,0), m_mincut(m_graph), m_cost(m_graph) -{ - if(G.numberOfNodes() <= 4) - return; // nothing to do; planar graph => empty core - - // Build SPQR-tree of graph - StaticSPQRTree T(G); - - // mark tree nodes in the core - NodeArray mark; - markCore(T,mark); - - NodeArray map(G,0); - NodeArray mapAux(G,0); - const Graph &tree = T.tree(); - - node v; - forall_nodes(v,tree) { - if(mark[v] == false) - continue; - - Skeleton &S = T.skeleton(v); - edge e; - forall_edges(e,S.getGraph()) { - node src = S.original(e->source()); - node tgt = S.original(e->target()); - - if(map[src] == 0) { - m_orig[map[src] = m_graph.newNode()] = S.original(e->source()); - } - if(map[tgt] == 0) { - m_orig[map[tgt] = m_graph.newNode()] = S.original(e->target()); - } - - if(S.isVirtual(e)) { - node w = S.twinTreeNode(e); - if(mark[w] == false) { - // new virtual edge in core graph - edge eC = m_graph.newEdge(map[src],map[tgt]); - traversingPath(S,e,m_mincut[eC],mapAux); - } - - } else { - // new real edge in core graph - edge eC = m_graph.newEdge(map[src],map[tgt]); - m_real[eC] = S.realEdge(e); - m_mincut[eC].pushBack(S.realEdge(e)); - } - } - } - - edge e; - forall_edges(e, m_graph) { - m_cost[e] = m_mincut[e].size(); - } -} - - -// This function marks all nodes in the SPQR-tree which induce the -// non-planar core. -void NonPlanarCore::markCore(const SPQRTree &T, NodeArray &mark) -{ - const Graph &tree = T.tree(); - - // We mark every tree node that belongs to the core - mark.init(tree,true); // start with all nodes and unmark planar leaves - NodeArray degree(tree); - - Queue Q; - - node v; - forall_nodes(v,tree) { - degree[v] = v->degree(); - if(degree[v] <= 1) // also append deg-0 node (T has only one node) - Q.append(v); - } - - while(!Q.empty()) - { - v = Q.pop(); - - // if v has a planar skeleton - if(T.typeOf(v) != SPQRTree::RNode || - isPlanar(T.skeleton(v).getGraph()) == true) - { - mark[v] = false; // unmark this leaf - - node w = 0; - adjEntry adj; - forall_adj(adj,v) { - node x = adj->twinNode(); - if(mark[x] == true) { - w = x; break; - } - } - - if(w != 0) { - --degree[w]; - if(degree[w] == 1) - Q.append(w); - } - } - } -} - -struct OGDF_EXPORT QueueEntry -{ - QueueEntry(node p, node v) : m_parent(p), m_current(v) { } - - node m_parent; - node m_current; -}; - -void NonPlanarCore::traversingPath(Skeleton &Sv, edge eS, List &path, NodeArray &mapV) -{ - const SPQRTree &T = Sv.owner(); - - //----------------------------------------------------- - // Build the graph representing the planar st-component - Graph H; - EdgeArray mapE(H,0); - SListPure nodes; - - Queue Q; - Q.append(QueueEntry(Sv.treeNode(),Sv.twinTreeNode(eS))); - - while(!Q.empty()) - { - QueueEntry x = Q.pop(); - node parent = x.m_parent; - node current = x.m_current; - - const Skeleton &S = T.skeleton(current); - - edge e; - forall_edges(e,S.getGraph()) { - if(S.isVirtual(e) == true) - continue; - - node src = S.original(e->source()); - node tgt = S.original(e->target()); - - if(mapV[src] == 0) { - nodes.pushBack(src); - mapV[src] = H.newNode(); - } - if(mapV[tgt] == 0) { - nodes.pushBack(tgt); - mapV[tgt] = H.newNode(); - } - - mapE[H.newEdge(mapV[src],mapV[tgt])] = S.realEdge(e); - } - - adjEntry adj; - forall_adj(adj,current) { - node w = adj->twinNode(); - if(w != parent) - Q.append(QueueEntry(current,w)); - } - } - - // add st-edge - edge e_st = H.newEdge(mapV[Sv.original(eS->source())],mapV[Sv.original(eS->target())]); - - // Compute planar embedding of H -#ifdef OGDF_DEBUG - bool ok = -#endif - planarEmbed(H); - OGDF_ASSERT(ok) - CombinatorialEmbedding E(H); - - //--------------------------------- - // Compute corresponding dual graph - Graph dual; - FaceArray nodeOf(E); - EdgeArray primalAdj(dual); - - // insert a node in the dual graph for each face in E - face f; - forall_faces(f,E) - nodeOf[f] = dual.newNode(); - - - node s = nodeOf[E.rightFace(e_st->adjSource())]; - node t = nodeOf[E.rightFace(e_st->adjTarget())]; - - // Insert an edge into the dual graph for each adjacency entry in E. - // The edges are directed from the left face to the right face. - node v; - forall_nodes(v,H) - { - adjEntry adj; - forall_adj(adj,v) - { - // do not insert edges crossing e_st - if(adj->theEdge() == e_st) - continue; - - node vLeft = nodeOf[E.leftFace (adj)]; - node vRight = nodeOf[E.rightFace(adj)]; - - primalAdj[dual.newEdge(vLeft,vRight)] = adj; - } - } - - //--------------------------- - // Find shortest path in dual - NodeArray spPred(dual,0); - QueuePure queue; - - edge eDual; - forall_adj_edges(eDual,s) { - if(s == eDual->source()) - queue.append(eDual); - } - - // actual search (using bfs on directed dual) - for( ; ; ) - { - // next candidate edge - edge eCand = queue.pop(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == t) - { - // ... then search is done. - // constructed list of used edges (translated to crossed - // edges entries in G) from t back to s (including first - // and last!) - - do { - edge eDual = spPred[v]; - edge eG = mapE[primalAdj[eDual]->theEdge()]; - OGDF_ASSERT(eG != 0) - path.pushFront(eG); - v = eDual->source(); - } while(v != s); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if (v == e->source()) - queue.append(e); - } - } - } - - - //--------- - // Clean-up - SListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - mapV[*it] = 0; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/decomposition/PlanarSPQRTree.cpp b/ext/OGDF/src/decomposition/PlanarSPQRTree.cpp deleted file mode 100644 index fef63ac62..000000000 --- a/ext/OGDF/src/decomposition/PlanarSPQRTree.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class PlanarSPQRTree - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - -//------------------------------------------------------------------- -// PlanarSPQRTree -//------------------------------------------------------------------- - -// -// initialization: additionally embeds skeleton graphs or adpots embedding -// given by original graph -void PlanarSPQRTree::init(bool isEmbedded) -{ - if (isEmbedded) { - adoptEmbedding(); - - } else { - - node v; - forall_nodes(v,tree()) - planarEmbed(skeleton(v).getGraph()); - } -} - - -void PlanarSPQRTree::adoptEmbedding() -{ - OGDF_ASSERT_IF(dlExtendedChecking, originalGraph().representsCombEmbedding()); - - // ordered list of adjacency entries (for one original node) in all - // skeletons (where this node occurs) - NodeArray > adjEdges(tree()); - // copy in skeleton of current original node - NodeArray currentCopy(tree(),0); - NodeArray lastAdj(tree(),0); - SListPure current; // currently processed nodes - - node vOrig; - forall_nodes(vOrig,originalGraph()) - { - adjEntry adjOrig; - forall_adj(adjOrig,vOrig) - { - edge eOrig = adjOrig->theEdge(); - const Skeleton &S = skeletonOfReal(eOrig); - edge eCopy = copyOfReal(eOrig); - - adjEntry adjCopy = (S.original(eCopy->source()) == vOrig) ? - eCopy->adjSource() : eCopy->adjTarget(); - - setPosInEmbedding(adjEdges,currentCopy,lastAdj,current,S,adjCopy); - } - - SListConstIterator it; - for(it = current.begin(); it.valid(); ++it) { - node vT = *it; - - skeleton(vT).getGraph().sort(currentCopy[vT],adjEdges[vT]); - - adjEdges[vT].clear(); - currentCopy[vT] = 0; - } - - current.clear(); - } -} - - -void PlanarSPQRTree::setPosInEmbedding( - NodeArray > &adjEdges, - NodeArray ¤tCopy, - NodeArray &lastAdj, - SListPure ¤t, - const Skeleton &S, - adjEntry adj) -{ - node vT = S.treeNode(); - - adjEdges[vT].pushBack(adj); - - node vCopy = adj->theNode(); - node vOrig = S.original(vCopy); - - if(currentCopy[vT] == 0) { - currentCopy[vT] = vCopy; - current.pushBack(vT); - - adjEntry adjVirt; - forall_adj(adjVirt,vCopy) { - edge eCopy = S.twinEdge(adjVirt->theEdge()); - if (eCopy == 0) continue; - if (adjVirt == adj) { - lastAdj[vT] = adj; - continue; - } - - const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge())); - - adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ? - eCopy->adjSource() : eCopy->adjTarget(); - - setPosInEmbedding(adjEdges,currentCopy,lastAdj,current, - STwin, adjCopy); - } - - } else if (lastAdj[vT] != 0 && lastAdj[vT] != adj) { - adjEntry adjVirt = lastAdj[vT]; - edge eCopy = S.twinEdge(adjVirt->theEdge()); - - const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge())); - - adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ? - eCopy->adjSource() : eCopy->adjTarget(); - - setPosInEmbedding(adjEdges,currentCopy,lastAdj,current, - STwin, adjCopy); - - lastAdj[vT] = 0; - } - -} - - -// -// embed original graph according to embedding of skeletons -// -// The procedure also handles the case when some (real or virtual) -// edges are reversed (used in upward-planarity algorithms) -void PlanarSPQRTree::embed(Graph &G) -{ - OGDF_ASSERT(&G == &originalGraph()); - - const Skeleton &S = skeleton(rootNode()); - const Graph &M = S.getGraph(); - - node v; - forall_nodes(v,M) - { - node vOrig = S.original(v); - SListPure adjEdges; - - adjEntry adj; - forall_adj(adj,v) { - edge e = adj->theEdge(); - edge eOrig = S.realEdge(e); - - if (eOrig != 0) { - adjEntry adjOrig = (vOrig == eOrig->source()) ? - eOrig->adjSource() : eOrig->adjTarget(); - OGDF_ASSERT(adjOrig->theNode() == S.original(v)); - adjEdges.pushBack(adjOrig); - - } else { - node wT = S.twinTreeNode(e); - edge eTwin = S.twinEdge(e); - expandVirtualEmbed(wT, - (vOrig == skeleton(wT).original(eTwin->source())) ? - eTwin->adjSource() : eTwin->adjTarget(), - adjEdges); - } - } - - G.sort(vOrig,adjEdges); - } - - edge e; - forall_adj_edges(e,rootNode()) { - node wT = e->target(); - if (wT != rootNode()) - createInnerVerticesEmbed(G, wT); - } -} - - -void PlanarSPQRTree::expandVirtualEmbed(node vT, - adjEntry adjVirt, - SListPure &adjEdges) -{ - const Skeleton &S = skeleton(vT); - - node v = adjVirt->theNode(); - node vOrig = S.original(v); - - adjEntry adj; - for (adj = adjVirt->cyclicSucc(); adj != adjVirt; adj = adj->cyclicSucc()) - { - edge e = adj->theEdge(); - edge eOrig = S.realEdge(e); - - if (eOrig != 0) { - adjEntry adjOrig = (vOrig == eOrig->source()) ? - eOrig->adjSource() : eOrig->adjTarget(); - OGDF_ASSERT(adjOrig->theNode() == S.original(v)); - adjEdges.pushBack(adjOrig); - - } else { - node wT = S.twinTreeNode(e); - edge eTwin = S.twinEdge(e); - expandVirtualEmbed(wT, - (vOrig == skeleton(wT).original(eTwin->source())) ? - eTwin->adjSource() : eTwin->adjTarget(), - adjEdges); - } - } -} - - -void PlanarSPQRTree::createInnerVerticesEmbed(Graph &G, node vT) -{ - const Skeleton &S = skeleton(vT); - const Graph& M = S.getGraph(); - - node src = S.referenceEdge()->source(); - node tgt = S.referenceEdge()->target(); - - node v; - forall_nodes(v,M) - { - if (v == src || v == tgt) continue; - - node vOrig = S.original(v); - SListPure adjEdges; - - adjEntry adj; - forall_adj(adj,v) { - edge e = adj->theEdge(); - edge eOrig = S.realEdge(e); - - if (eOrig != 0) { - adjEntry adjOrig = (vOrig == eOrig->source()) ? - eOrig->adjSource() : eOrig->adjTarget(); - OGDF_ASSERT(adjOrig->theNode() == S.original(v)); - adjEdges.pushBack(adjOrig); - } else { - node wT = S.twinTreeNode(e); - edge eTwin = S.twinEdge(e); - expandVirtualEmbed(wT, - (vOrig == skeleton(wT).original(eTwin->source())) ? - eTwin->adjSource() : eTwin->adjTarget(), - adjEdges); - } - } - - G.sort(vOrig,adjEdges); - } - - edge e; - forall_adj_edges(e,vT) { - node wT = e->target(); - if (wT != vT) - createInnerVerticesEmbed(G, wT); - } -} - - - -// -// basic update functions for manipulating embeddings - -// reversing the skeleton of an R- or P-node -void PlanarSPQRTree::reverse(node vT) -{ - skeleton(vT).getGraph().reverseAdjEdges(); -} - - -// swapping two adjacency entries in the skeleton of a P-node -void PlanarSPQRTree::swap(node vT, adjEntry adj1, adjEntry adj2) -{ - OGDF_ASSERT(typeOf(vT) == PNode); - - Graph &M = skeleton(vT).getGraph(); - - M.swapAdjEdges(adj1,adj2); - M.swapAdjEdges(adj1->twin(),adj2->twin()); -} - - -// swapping two edges in the skeleton of a P-node -void PlanarSPQRTree::swap(node vT, edge e1, edge e2) -{ - OGDF_ASSERT(typeOf(vT) == PNode); - - if (e1->source() == e2->source()) - swap(vT,e1->adjSource(),e2->adjSource()); - else - swap(vT,e1->adjSource(),e2->adjTarget()); -} - - -// -// number of possible embeddings of original graph -// -double PlanarSPQRTree::numberOfEmbeddings(node vT) const -{ - double num = 1.0; - - switch(typeOf(vT)) { - case RNode: - num = 2; break; - case PNode: - //node vFirst = skeleton(vT).getGraph().firstNode(); - for (int i = skeleton(vT).getGraph().firstNode()->degree()-1; i >= 2; --i) - num *= i; - break; - case SNode: - break; - } - - edge e; - forall_adj_edges(e,vT) { - node wT = e->target(); - if(wT != vT) - num *= numberOfEmbeddings(wT); - } - - return num; -} - - - -// -// randomly embed skeleton graphs -// -void PlanarSPQRTree::randomEmbed() -{ - node vT; - forall_nodes(vT,tree()) { - if (typeOf(vT) == RNode) { - int doReverse = randomNumber(0,1); - - if (doReverse == 1) - reverse(vT); - - } else if (typeOf(vT) == PNode) { - const Skeleton &S = skeleton(vT); - adjEntry adjRef = S.referenceEdge()->adjSource(); - - SList adjEdges; - adjEntry adj; - for (adj = adjRef->cyclicSucc(); adj != adjRef; adj = adj->cyclicSucc()) - adjEdges.pushBack(adj); - - adjEdges.permute(); - - adj = adjRef->cyclicSucc(); - SListConstIterator it; - for (it = adjEdges.begin(); it.valid(); ++it) - { - adjEntry adjNext = *it; - if (adjNext != adj) { - swap(vT,adj,adjNext); - adj = adjNext; - } - adj = adj->cyclicSucc(); - } - } - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/decomposition/StaticSPQRTree.cpp b/ext/OGDF/src/decomposition/StaticSPQRTree.cpp deleted file mode 100644 index ec9c8f731..000000000 --- a/ext/OGDF/src/decomposition/StaticSPQRTree.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements classes StaticSkeleton and StaticSPQRTree - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include "TricComp.h" - - -namespace ogdf { - -//------------------------------------------------------------------- -// StaticSkeleton -//------------------------------------------------------------------- - -StaticSkeleton::StaticSkeleton(const StaticSPQRTree *T, node vT) : Skeleton(vT), m_owner(T) -{ - m_orig.init(m_M,0); - m_real.init(m_M,0); - m_treeEdge.init(m_M,0); -} - - -const SPQRTree &StaticSkeleton::owner() const -{ - return *m_owner; -} - - -edge StaticSkeleton::twinEdge (edge e) const -{ - edge et = m_treeEdge[e]; - if (et == 0) - return 0; - - return (et->source() == m_treeNode) ? - m_owner->m_skEdgeTgt[et] : m_owner->m_skEdgeSrc[et]; -} - - -node StaticSkeleton::twinTreeNode (edge e) const -{ - edge et = m_treeEdge[e]; - if (et == 0) - return 0; - return et->opposite(m_treeNode); -} - - -//------------------------------------------------------------------- -// StaticSPQRTree -//------------------------------------------------------------------- - -// -// initialization: builds tree, skeleton graphs and cross references -// -void StaticSPQRTree::init(edge eRef) -{ - TricComp tricComp(*m_pGraph); - init(eRef,tricComp); -} - -void StaticSPQRTree::init(edge eRef, TricComp &tricComp) -{ - m_cpV = 0; - const GraphCopySimple &GC = *tricComp.m_pGC; - - m_type.init(m_tree,SNode); - m_sk.init(m_tree,0); - - m_skEdgeSrc.init(m_tree,0); - m_skEdgeTgt.init(m_tree,0); - - NodeArray mapV(GC,0); - BoundedStack inMapV(GC.numberOfNodes()); - - EdgeArray partnerNode(GC,0); - EdgeArray partnerEdge(GC,0); - - m_numS = m_numP = m_numR = 0; - - for (int i = 0; i < tricComp.m_numComp; i++) { - const TricComp::CompStruct &C = tricComp.m_component[i]; - - if (C.m_edges.empty()) continue; - - node vT = m_tree.newNode(); - - switch(C.m_type) { - case TricComp::bond: - m_type[vT] = PNode; - m_numP++; break; - - case TricComp::polygon: - m_type[vT] = SNode; - m_numS++; break; - - case TricComp::triconnected: - m_type[vT] = RNode; - m_numR++; break; - } - - m_sk[vT] = OGDF_NEW StaticSkeleton(this,vT); - StaticSkeleton &S = *m_sk[vT]; - - ListConstIterator itE; - for(itE = C.m_edges.begin(); itE.valid(); ++itE) - { - edge e = *itE; - edge eG = GC.original(e); - - node uGC = e->source(), vGC = e->target(); - node uM = mapV[uGC], vM = mapV[vGC]; - - if (uM == 0) { - uM = mapV[uGC] = S.m_M.newNode(); - inMapV.push(uGC); - S.m_orig[uM] = GC.original(uGC); - } - if (vM == 0) { - vM = mapV[vGC] = S.m_M.newNode(); - inMapV.push(vGC); - S.m_orig[vM] = GC.original(vGC); - } - - // normalize direction of virtual edges - if(eG == 0 && GC.original(vGC) < GC.original(uGC)) - swap(uM,vM); - - edge eM = S.m_M.newEdge(uM,vM); - - if (eG == 0) { - if (partnerNode[e] == 0) { - partnerNode[e] = vT; - partnerEdge[e] = eM; - - } else { - edge eT = m_tree.newEdge(partnerNode[e],vT); - StaticSkeleton &pS = *m_sk[partnerNode[e]]; - pS.m_treeEdge[partnerEdge[e]] = S.m_treeEdge[eM] = eT; - m_skEdgeSrc[eT] = partnerEdge[e]; - m_skEdgeTgt[eT] = eM; - } - - } else { - S.m_real[eM] = eG; - m_copyOf[eG] = eM; - if (eG->source() != S.original(eM->source())) - S.m_M.reverseEdge(eM); - m_skOf [eG] = &S; - } - } - - while(!inMapV.empty()) - mapV[inMapV.pop()] = 0; - } - - rootTreeAt(eRef); -} - - -// -// destructor: deletes skeleton graphs -// -StaticSPQRTree::~StaticSPQRTree() -{ - node vT; - - forall_nodes(vT,m_tree) - delete m_sk[vT]; - - delete m_cpV; -} - - -List StaticSPQRTree::nodesOfType(NodeType t) const -{ - List L; - node v; - forall_nodes(v,m_tree) - if (m_type[v] == t) L.pushBack(v); - - return L; -} - - -// -// rooting of tree at edge e -node StaticSPQRTree::rootTreeAt(edge e) -{ - m_rootEdge = e; - m_rootNode = m_skOf[e]->treeNode(); - - m_sk[m_rootNode]->m_referenceEdge = m_copyOf[e]; - rootRec(m_rootNode,0); - - return m_rootNode; -} - - -node StaticSPQRTree::rootTreeAt(node v) -{ - m_rootEdge = 0; - m_rootNode = v; - - m_sk[m_rootNode]->m_referenceEdge = 0; - rootRec(m_rootNode,0); - - return m_rootNode; -} - - -void StaticSPQRTree::rootRec(node v, edge eFather) -{ - edge e; - forall_adj_edges(e,v) - { - if (e == eFather) continue; - - node w = e->target(); - if (w == v) { - m_tree.reverseEdge(e); - swap(m_skEdgeSrc[e],m_skEdgeTgt[e]); - w = e->target(); - } - - m_sk[w]->m_referenceEdge = m_skEdgeTgt[e]; - rootRec(w,e); - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/decomposition/TricComp.cpp b/ext/OGDF/src/decomposition/TricComp.cpp deleted file mode 100644 index 0f06e5088..000000000 --- a/ext/OGDF/src/decomposition/TricComp.cpp +++ /dev/null @@ -1,1194 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements Hopcroft/Tarjan algorithm for finding the - * triconnected components of a biconnected multi-graph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "TricComp.h" -#include -#include -#include - -//#define TRIC_COMP_OUTPUT - - -namespace ogdf { - - -//---------------------------------------------------------- -// Destructor -// -// deletes GraphCopy -//---------------------------------------------------------- - -TricComp::~TricComp() -{ - delete m_pGC; -} - - -//---------------------------------------------------------- -// Constructor -// -// Divides G into triconnected components. -//---------------------------------------------------------- - -TricComp::TricComp (const Graph& G) : - m_ESTACK(G.numberOfEdges()) -{ - m_pGC = new GraphCopySimple(G); - GraphCopySimple &GC = *m_pGC; - - const int n = GC.numberOfNodes(); - const int m = GC.numberOfEdges(); - -#ifdef TRIC_COMP_OUTPUT - cout << "Dividing G into triconnected components.\n" << endl; - cout << "n = " << n << ", m = " << m << endl << endl; -#endif - - m_component = Array(3*m-6); - m_numComp = 0; - - // special cases - OGDF_ASSERT(n >= 2); - OGDF_ASSERT_IF(dlExtendedChecking, isBiconnected(G)); - - if (n <= 2) { - OGDF_ASSERT(m >= 3); - CompStruct &C = newComp(); - edge e; - forall_edges(e,GC) - C << e; - C.m_type = bond; - return; - } - - m_TYPE.init(GC,unseen); - splitMultiEdges(); - - // initialize arrays - m_NUMBER.init(GC,0); m_LOWPT1.init(GC); - m_LOWPT2.init(GC); m_FATHER.init(GC,0); - m_ND .init(GC); m_DEGREE.init(GC); - m_TREE_ARC.init(GC,0); - m_NODEAT = Array(1,n); - - m_numCount = 0; - m_start = GC.firstNode(); - DFS1(GC,m_start,0); - - edge e; - forall_edges(e,GC) { - bool up = (m_NUMBER[e->target()] - m_NUMBER[e->source()] > 0); - if ((up && m_TYPE[e] == frond) || (!up && m_TYPE[e] == tree)) - GC.reverseEdge(e); - } - -#ifdef TRIC_COMP_OUTPUT - cout << "\nnode\tNUMBER\tFATHER\tLOWPT1\tLOWPT2\tND" << endl; - node v; - forall_nodes(v,GC) { - cout << GC.original(v) << ": \t" << m_NUMBER[v] << " \t"; - if (m_FATHER[v] == 0) cout << "nil \t"; - else cout << GC.original(m_FATHER[v]) << " \t"; - cout << m_LOWPT1[v] << " \t" << m_LOWPT2[v] << " \t" << m_ND[v] << endl; - } -#endif - - m_A.init(GC); - m_IN_ADJ.init(GC,0); - buildAcceptableAdjStruct(GC); - -#ifdef TRIC_COMP_OUTPUT - cout << "\nadjaceny lists:" << endl; - forall_nodes(v,GC) { - cout << v << "\t"; - ListConstIterator itE; - for(itE = m_A[v].begin(); itE.valid(); ++itE) { - printOs(*itE); - } - cout << endl; - } -#endif - - DFS2(GC); - -#ifdef TRIC_COMP_OUTPUT - cout << "\nnode\tNEWNUM\tLOWPT1\tLOWPT2\tHIGHPT" << endl; - forall_nodes(v,GC) { - cout << GC.original(v) << ": \t" << m_NEWNUM[v] << " \t"; - cout << m_LOWPT1[v] << " \t" << m_LOWPT2[v] << " \t"; - ListConstIterator itH; - for(itH = m_HIGHPT[v].begin(); itH.valid(); ++itH) - cout << *itH << " "; - cout << endl; - } - - cout << "\nedges starting a path:" << endl; - forall_edges(e,GC) { - if (m_START[e]) { - printOs(e); - } - } -#endif - - - m_TSTACK_h = new int[2*m+1]; - m_TSTACK_a = new int[2*m+1]; - m_TSTACK_b = new int[2*m+1]; - m_TSTACK_a[m_top = 0] = -1; // start with EOS - - pathSearch(G,m_start); - - // last split component - CompStruct &C = newComp(); - while(!m_ESTACK.empty()) { - C << m_ESTACK.pop(); - } - C.m_type = (C.m_edges.size() > 4) ? triconnected : polygon; - -#ifdef TRIC_COMP_OUTPUT - printStacks(); -#endif - - delete [] m_TSTACK_h; - delete [] m_TSTACK_a; - delete [] m_TSTACK_b; - - // free resources - m_NUMBER.init(); m_LOWPT1.init(); - m_LOWPT2.init(); m_FATHER.init(); - m_ND .init(); m_TYPE .init(); - m_A .init(); m_NEWNUM.init(); - m_HIGHPT.init(); m_START .init(); - m_DEGREE.init(); m_TREE_ARC.init(); - m_IN_ADJ.init(); m_IN_HIGH.init(); - m_NODEAT.init(); - m_ESTACK.clear(); - - assembleTriconnectedComponents(); - - // Caution: checkComp() assumes that the graph is simple! - //OGDF_ASSERT(checkComp()); - -#ifdef TRIC_COMP_OUTPUT - cout << "\n\nTriconnected components:\n"; - for (int i = 0; i < m_numComp; i++) { - const List &L = m_component[i].m_edges; - if (L.size() == 0) continue; - cout << "[" << i << "] "; - switch(m_component[i].m_type) { - case bond: cout << "bond "; break; - case polygon: cout << "polygon "; break; - case triconnected: cout << "triconnected "; break; - } - - ListConstIterator itE; - for(itE = L.begin(); itE.valid(); ++itE) - printOs(*itE); - cout << "\n"; - } -#endif -} - - -//---------------------------------------------------------- -// Constructor -// -// Tests G for triconnectivity and returns a cut vertex in -// s1 or a separation pair in (s1,s2). -//---------------------------------------------------------- - -TricComp::TricComp(const Graph &G, bool &isTric, node &s1, node &s2) -{ - m_pGC = new GraphCopySimple(G); - GraphCopySimple &GC = *m_pGC; - - const int n = GC.numberOfNodes(); - const int m = GC.numberOfEdges(); - - s1 = s2 = 0; - - if(n == 0) { - isTric = true; return; - } - - makeLoopFree(GC); - makeParallelFreeUndirected(GC); - - // initialize arrays - m_TYPE.init(GC,unseen); - m_NUMBER.init(GC,0); m_LOWPT1.init(GC); - m_LOWPT2.init(GC); m_FATHER.init(GC,0); - m_ND .init(GC); m_DEGREE.init(GC); - m_NODEAT.init(1,n); - - m_TREE_ARC.init(GC,0); // probably not required - - m_numCount = 0; - m_start = GC.firstNode(); - DFS1(GC,m_start,0,s1); - - // graph not even connected? - if(m_numCount < n) { - s1 = 0; isTric = false; - return; - } - - // graph no biconnected? - if(s1 != 0) { - s1 = GC.original(s1); - isTric = false; // s1 is a cut vertex - return; - } - - edge e; - forall_edges(e,GC) { - bool up = (m_NUMBER[e->target()] - m_NUMBER[e->source()] > 0); - if ((up && m_TYPE[e] == frond) || (!up && m_TYPE[e] == tree)) - GC.reverseEdge(e); - } - - m_A.init(GC); - m_IN_ADJ.init(GC,0); - buildAcceptableAdjStruct(GC); - - DFS2(GC); - - m_TSTACK_h = new int[m]; - m_TSTACK_a = new int[m]; - m_TSTACK_b = new int[m]; - m_TSTACK_a[m_top = 0] = -1; // start with EOS - - isTric = pathSearch(G,m_start,s1,s2); - if(s1) { - s1 = GC.original(s1); - s2 = GC.original(s2); - } - - delete [] m_TSTACK_h; - delete [] m_TSTACK_a; - delete [] m_TSTACK_b; - - // free resources - m_NUMBER.init(); m_LOWPT1.init(); - m_LOWPT2.init(); m_FATHER.init(); - m_ND .init(); m_TYPE .init(); - m_A .init(); m_NEWNUM.init(); - m_HIGHPT.init(); m_START .init(); - m_DEGREE.init(); m_TREE_ARC.init(); - m_IN_ADJ.init(); m_IN_HIGH.init(); - m_NODEAT.init(); -} - - -//---------------------------------------------------------- -// splitMultiEdges -// -// Splits bundles of multi-edges into bonds and creates -// a new virtual edge in GC. -//---------------------------------------------------------- - -void TricComp::splitMultiEdges() -{ - GraphCopySimple &GC = *m_pGC; - - SListPure edges; - EdgeArray minIndex(GC), maxIndex(GC); - parallelFreeSortUndirected(GC,edges,minIndex,maxIndex); - - SListIterator it; - for (it = edges.begin(); it.valid(); ) { - edge e = *it; - int minI = minIndex[e], maxI = maxIndex[e]; - ++it; - if (it.valid() && minI == minIndex[*it] && maxI == maxIndex[*it]) { - CompStruct &C = newComp(bond); - C << GC.newEdge(e->source(),e->target()) << e << *it; - m_TYPE[e] = m_TYPE[*it] = removed; - - for (++it; it.valid() && - minI == minIndex[*it] && maxI == maxIndex[*it]; ++it) - { - C << *it; - m_TYPE[*it] = removed; - } - } - } -} - - - -//---------------------------------------------------------- -// checkComp -// -// Checks if computed triconnected components are correct. -//---------------------------------------------------------- - -bool TricComp::checkSepPair(edge eVirt) -{ - GraphCopySimple G(*m_pGC); - - G.delNode(G.copy(m_pGC->original(eVirt->source()))); - G.delNode(G.copy(m_pGC->original(eVirt->target()))); - - return !isConnected(G); -} - -bool TricComp::checkComp() -{ - bool ok = true; - - GraphCopySimple &GC = *m_pGC; - GraphCopySimple GTest(GC.original()); - - if (!isLoopFree(GC)) { - ok = false; - cout << "GC contains loops!" << endl; - } - - int i; - edge e; - node v; - - EdgeArray count(GC,0); - for (i = 0; i < m_numComp; i++) { - ListIterator itE; - for(itE = m_component[i].m_edges.begin(); itE.valid(); ++itE) - count[*itE]++; - } - - forall_edges(e,GC) { - if (GC.original(e) == 0) { - if (count[e] != 2) { - ok = false; - cout << "virtual edge contained " << count[e]; - printOs(e); cout << endl; - } - if (checkSepPair(e) == false) { - ok = false; - cout << "virtual edge"; printOs(e); - cout << " does not correspond to a sep. pair." << endl; - } - - } else { - if (count[e] != 1) { - ok = false; - cout << "real edge contained " << count[e]; - printOs(e); cout << endl; - } - } - } - - NodeSet S(GC); - NodeArray map(GC); - - for(i = 0; i < m_numComp; i++) { - CompStruct &C = m_component[i]; - const List &L = C.m_edges; - if (L.size() == 0) continue; - - S.clear(); - - ListConstIterator itE; - for(itE = L.begin(); itE.valid(); ++itE) { - S.insert((*itE)->source()); - S.insert((*itE)->target()); - } - - const int n = S.size(); - - switch(C.m_type) { - case bond: - if (n != 2) { - ok = false; - cout << "bond [" << i << "] with " << n << " nodes!" << endl; - } - break; - - case polygon: - if (n < 3) { - ok = false; - cout << "polygon [" << i << "] with " << n << " nodes!" << endl; - } - - if (L.size() != n) { - ok = false; - cout << "polygon [" << i << "] with " << n << " vertices and " << L.size() << " edges!" << endl; - - } else { - Graph Gp; - ListConstIterator itV; - for(itV = S.nodes().begin(); itV.valid(); ++itV) - map[*itV] = Gp.newNode(); - for(itE = L.begin(); itE.valid(); ++itE) - Gp.newEdge(map[(*itE)->source()],map[(*itE)->target()]); - - forall_nodes(v,Gp) - if (v->degree() != 2) { - ok = false; - cout << "polygon [" << i << "] contains node with degree " << v->degree() << endl; - } - if (!isConnected(Gp)) { - ok = false; - cout << "polygon [" << i << "] not connected." << endl; - } - } - break; - - case triconnected: - if (n < 4) { - ok = false; - cout << "triconnected component [" << i << "] with " << n << " nodes!" << endl; - } - - { - Graph Gp; - ListConstIterator itV; - for(itV = S.nodes().begin(); itV.valid(); ++itV) - map[*itV] = Gp.newNode(); - for(itE = L.begin(); itE.valid(); ++itE) - Gp.newEdge(map[(*itE)->source()],map[(*itE)->target()]); - - if (!isTriconnectedPrimitive(Gp)) { - ok = false; - cout << "component [" << i << "] not triconnected!" << endl; - } - if (!isSimple(Gp)) { - ok = false; - cout << "triconnected component [" << i << "] not simple!" << endl; - } - } - break; - - default: - ok = false; - cout << "component [" << i << "] with undefined type!" << endl; - } - } - - return ok; -} - - -//---------------------------------------------------------- -// assembleTriconnectedComponents -// -// joins bonds and polygons with common virtual edge in -// order to build the triconnected components. -//---------------------------------------------------------- - -void TricComp::assembleTriconnectedComponents() -{ - GraphCopySimple &GC = *m_pGC; - - EdgeArray comp1(GC), comp2(GC); - EdgeArray > item1(GC,ListIterator()); - EdgeArray > item2(GC); - - bool *visited = new bool[m_numComp]; - - int i; - for(i = 0; i < m_numComp; i++) { - visited[i] = false; - List &L = m_component[i].m_edges; - - ListIterator it; - for(it = L.begin(); it.valid(); ++it) { - edge e = *it; - if (!item1[e].valid()) { - comp1[e] = i; item1[e] = it; - } else { - comp2[e] = i; item2[e] = it; - } - } - } - - for(i = 0; i < m_numComp; i++) { - CompStruct &C1 = m_component[i]; - List &L1 = C1.m_edges; - visited[i] = true; - - if (L1.size() == 0) continue; - - if (C1.m_type == polygon || C1.m_type == bond) { - ListIterator it, itNext; - for(it = L1.begin(); it.valid(); it = itNext) { - itNext = it.succ(); - edge e = *it; - - if (GC.original(e) != 0) continue; - - int j = comp1[e]; - ListIterator it2; - if (visited[j]) { - j = comp2[e]; - if (visited[j]) continue; - it2 = item2[e]; - } else - it2 = item1[e]; - - CompStruct &C2 = m_component[j]; - - if (C2.m_type != C1.m_type) continue; - - visited[j] = true; - List &L2 = C2.m_edges; - - L2.del(it2); - L1.conc(L2); - if (!itNext.valid()) - itNext = it.succ(); - L1.del(it); - - GC.delEdge(e); - } - } - } - - delete [] visited; -} - - - -//---------------------------------------------------------- -// The first dfs-search -// -// computes NUMBER[v], FATHER[v], LOWPT1[v], LOWPT2[v], -// ND[v], TYPE[e], DEGREE[v] -//---------------------------------------------------------- - -void TricComp::DFS1 (const Graph& G, node v, node u) -{ - edge e; - - m_NUMBER[v] = ++m_numCount; - m_FATHER[v] = u; - m_DEGREE[v] = v->degree(); - - m_LOWPT1[v] = m_LOWPT2[v] = m_NUMBER[v]; - m_ND[v] = 1; - - forall_adj_edges (e,v) { - - if (m_TYPE[e] != unseen) - continue; - - node w = e->opposite(v); - - if (m_NUMBER[w] == 0) { - m_TYPE[e] = tree; - - m_TREE_ARC[w] = e; - - DFS1(G,w,v); - - if (m_LOWPT1[w] < m_LOWPT1[v]) { - m_LOWPT2[v] = min(m_LOWPT1[v],m_LOWPT2[w]); - m_LOWPT1[v] = m_LOWPT1[w]; - - } else if (m_LOWPT1[w] == m_LOWPT1[v]) { - m_LOWPT2[v] = min(m_LOWPT2[v],m_LOWPT2[w]); - - } else { - m_LOWPT2[v] = min(m_LOWPT2[v],m_LOWPT1[w]); - } - - m_ND[v] += m_ND[w]; - - } else { - - m_TYPE[e] = frond; - - if (m_NUMBER[w] < m_LOWPT1[v]) { - m_LOWPT2[v] = m_LOWPT1[v]; - m_LOWPT1[v] = m_NUMBER[w]; - - } else if (m_NUMBER[w] > m_LOWPT1[v]) { - m_LOWPT2[v] = min(m_LOWPT2[v],m_NUMBER[w]); - } - } - } -} - -void TricComp::DFS1 (const Graph& G, node v, node u, node &s1) -{ - node firstSon = 0; - edge e; - - m_NUMBER[v] = ++m_numCount; - m_FATHER[v] = u; - m_DEGREE[v] = v->degree(); - - m_LOWPT1[v] = m_LOWPT2[v] = m_NUMBER[v]; - m_ND[v] = 1; - - forall_adj_edges (e,v) { - - if (m_TYPE[e] != unseen) - continue; - - node w = e->opposite(v); - - if (m_NUMBER[w] == 0) { - m_TYPE[e] = tree; - if(firstSon == 0) firstSon = w; - - m_TREE_ARC[w] = e; - - DFS1(G,w,v,s1); - - // check for cut vertex - if(m_LOWPT1[w] >= m_NUMBER[v] && (w != firstSon || u != 0)) - s1 = v; - - if (m_LOWPT1[w] < m_LOWPT1[v]) { - m_LOWPT2[v] = min(m_LOWPT1[v],m_LOWPT2[w]); - m_LOWPT1[v] = m_LOWPT1[w]; - - } else if (m_LOWPT1[w] == m_LOWPT1[v]) { - m_LOWPT2[v] = min(m_LOWPT2[v],m_LOWPT2[w]); - - } else { - m_LOWPT2[v] = min(m_LOWPT2[v],m_LOWPT1[w]); - } - - m_ND[v] += m_ND[w]; - - } else { - - m_TYPE[e] = frond; - - if (m_NUMBER[w] < m_LOWPT1[v]) { - m_LOWPT2[v] = m_LOWPT1[v]; - m_LOWPT1[v] = m_NUMBER[w]; - - } else if (m_NUMBER[w] > m_LOWPT1[v]) { - m_LOWPT2[v] = min(m_LOWPT2[v],m_NUMBER[w]); - } - } - } -} - - -//---------------------------------------------------------- -// Construction of ordered adjaceny lists -//---------------------------------------------------------- - -void TricComp::buildAcceptableAdjStruct(const Graph& G) -{ - edge e; - int max = 3*G.numberOfNodes()+2; - Array > BUCKET(1,max); - - forall_edges(e,G) { - edgeType t = m_TYPE[e]; - if (t == removed) continue; - - node w = e->target(); - int phi = (t == frond) ? 3*m_NUMBER[w]+1 : ( - (m_LOWPT2[w] < m_NUMBER[e->source()]) ? 3*m_LOWPT1[w] : - 3*m_LOWPT1[w]+2); - BUCKET[phi].pushBack(e); - } - - for (int i = 1; i <= max; i++) { - ListConstIterator it; - for(it = BUCKET[i].begin(); it.valid(); ++it) { - e = *it; - m_IN_ADJ[e] = m_A[e->source()].pushBack(e); - } - } -} - - -//---------------------------------------------------------- -// The second dfs-search -//---------------------------------------------------------- - -void TricComp::pathFinder(const Graph& G, node v) -{ - m_NEWNUM[v] = m_numCount - m_ND[v] + 1; - - ListConstIterator it; - for(it = m_A[v].begin(); it.valid(); ++it) { - edge e = *it; - node w = e->opposite(v); - - if (m_newPath) { - m_newPath = false; - m_START[e] = true; - } - - if (m_TYPE[e] == tree) { - pathFinder(G,w); - m_numCount--; - - } else { - m_IN_HIGH[e] = m_HIGHPT[w].pushBack(m_NEWNUM[v]); - m_newPath = true; - } - } -} - -void TricComp::DFS2 (const Graph& G) -{ - m_NEWNUM .init(G,0); - m_HIGHPT .init(G); - m_IN_HIGH.init(G,ListIterator()); - m_START .init(G,false); - - m_numCount = G.numberOfNodes(); - m_newPath = true; - - pathFinder(G,m_start); - - node v; - Array old2new(1,G.numberOfNodes()); - - forall_nodes(v,G) - old2new[m_NUMBER[v]] = m_NEWNUM[v]; - - forall_nodes(v,G) { - m_NODEAT[m_NEWNUM[v]] = v; - m_LOWPT1[v] = old2new[m_LOWPT1[v]]; - m_LOWPT2[v] = old2new[m_LOWPT2[v]]; - } -} - - -//---------------------------------------------------------- -// pathSearch() -// -// recognition of split components -//---------------------------------------------------------- - -void TricComp::pathSearch (const Graph& G, node v) -{ - node w; - edge e; - int y, vnum = m_NEWNUM[v], wnum; - int a, b; - - List &Adj = m_A[v]; - int outv = Adj.size(); - - ListIterator it, itNext; - for(it = Adj.begin(); it.valid(); it=itNext) - { - itNext = it.succ(); - e = *it; - w = e->target(); wnum = m_NEWNUM[w]; - - if (m_TYPE[e] == tree) { - - if (m_START[e]) { - y = 0; - if (m_TSTACK_a[m_top] > m_LOWPT1[w]) { - do { - y = max(y,m_TSTACK_h[m_top]); - b = m_TSTACK_b[m_top--]; - } while (m_TSTACK_a[m_top] > m_LOWPT1[w]); - TSTACK_push(y,m_LOWPT1[w],b); - } else { - TSTACK_push(wnum+m_ND[w]-1,m_LOWPT1[w],vnum); - } - TSTACK_pushEOS(); - } - - pathSearch(G,w); - - m_ESTACK.push(m_TREE_ARC[w]); // add (v,w) to ESTACK (can differ from e!) - - node x; - - while (vnum != 1 && ((m_TSTACK_a[m_top] == vnum) || - (m_DEGREE[w] == 2 && m_NEWNUM[m_A[w].front()->target()] > wnum))) - { - a = m_TSTACK_a[m_top]; - b = m_TSTACK_b[m_top]; - - edge eVirt; - - if (a == vnum && m_FATHER[m_NODEAT[b]] == m_NODEAT[a]) { - m_top--; - } - - else { - edge e_ab = 0; - - if (m_DEGREE[w] == 2 && m_NEWNUM[m_A[w].front()->target()] > wnum) { -#ifdef TRIC_COMP_OUTPUT - cout << endl << "\nfound type-2 separation pair " << - m_pGC->original(v) << ", " << - m_pGC->original(m_A[w].front()->target()); -#endif - - edge e1 = m_ESTACK.pop(); - edge e2 = m_ESTACK.pop(); - m_A[w].del(m_IN_ADJ[e2]); - - x = e2->target(); - - eVirt = m_pGC->newEdge(v,x); - m_DEGREE[x]--; m_DEGREE[v]--; - - OGDF_ASSERT(e2->source() == w); - CompStruct &C = newComp(polygon); - C << e1 << e2 << eVirt; - - if (!m_ESTACK.empty()) { - e1 = m_ESTACK.top(); - if (e1->source() == x && e1->target() == v) { - e_ab = m_ESTACK.pop(); - m_A[x].del(m_IN_ADJ[e_ab]); - delHigh(e_ab); - } - } - - } else { -#ifdef TRIC_COMP_OUTPUT - cout << "\nfound type-2 separation pair " << - m_pGC->original(m_NODEAT[a]) << ", " << - m_pGC->original(m_NODEAT[b]); -#endif - - int h = m_TSTACK_h[m_top--]; - - CompStruct &C = newComp(); - while(true) { - edge xy = m_ESTACK.top(); - x = xy->source(); node y = xy->target(); - if (!(a <= m_NEWNUM[x] && m_NEWNUM[x] <= h && - a <= m_NEWNUM[y] && m_NEWNUM[y] <= h)) break; - - if ((m_NEWNUM[x] == a && m_NEWNUM[y] == b) || - (m_NEWNUM[y] == a && m_NEWNUM[x] == b)) - { - e_ab = m_ESTACK.pop(); - m_A[e_ab->source()].del(m_IN_ADJ[e_ab]); - delHigh(e_ab); - - } else { - edge eh = m_ESTACK.pop(); - if (it != m_IN_ADJ[eh]) { - m_A[eh->source()].del(m_IN_ADJ[eh]); - delHigh(eh); - } - C << eh; - m_DEGREE[x]--; m_DEGREE[y]--; - } - } - - eVirt = m_pGC->newEdge(m_NODEAT[a],m_NODEAT[b]); - C.finishTricOrPoly(eVirt); - x = m_NODEAT[b]; - } - - if (e_ab != 0) { - CompStruct &C = newComp(bond); - C << e_ab << eVirt; - - eVirt = m_pGC->newEdge(v,x); - C << eVirt; - - m_DEGREE[x]--; m_DEGREE[v]--; - } - - m_ESTACK.push(eVirt); - *it = eVirt; - m_IN_ADJ[eVirt] = it; - - m_DEGREE[x]++; m_DEGREE[v]++; - m_FATHER[x] = v; - m_TREE_ARC[x] = eVirt; - m_TYPE[eVirt] = tree; - - w = x; wnum = m_NEWNUM[w]; - } - } - - if (m_LOWPT2[w] >= vnum && m_LOWPT1[w] < vnum && (m_FATHER[v] != m_start || outv >= 2)) - { -#ifdef TRIC_COMP_OUTPUT - cout << "\nfound type-1 separation pair " << - m_pGC->original(m_NODEAT[m_LOWPT1[w]]) << ", " << - m_pGC->original(v); -#endif - - CompStruct &C = newComp(); - edge xy; - int x; - while (!m_ESTACK.empty()) { - xy = m_ESTACK.top(); - x = m_NEWNUM[xy->source()]; - y = m_NEWNUM[xy->target()]; - - if (!((wnum <= x && x < wnum+m_ND[w]) || (wnum <= y && y < wnum+m_ND[w]))) - break; - - C << m_ESTACK.pop(); - delHigh(xy); - m_DEGREE[m_NODEAT[x]]--; m_DEGREE[m_NODEAT[y]]--; - } - - edge eVirt = m_pGC->newEdge(v,m_NODEAT[m_LOWPT1[w]]); - C.finishTricOrPoly(eVirt); - - if ((x == vnum && y == m_LOWPT1[w]) || (y == vnum && x == m_LOWPT1[w])) { - CompStruct &C = newComp(bond); - edge eh = m_ESTACK.pop(); - if (m_IN_ADJ[eh] != it) { - m_A[eh->source()].del(m_IN_ADJ[eh]); - } - C << eh << eVirt; - eVirt = m_pGC->newEdge(v,m_NODEAT[m_LOWPT1[w]]); - C << eVirt; - m_IN_HIGH[eVirt] = m_IN_HIGH[eh]; - m_DEGREE[v]--; - m_DEGREE[m_NODEAT[m_LOWPT1[w]]]--; - } - - if (m_NODEAT[m_LOWPT1[w]] != m_FATHER[v]) { - m_ESTACK.push(eVirt); - *it = eVirt; - m_IN_ADJ[eVirt] = it; - if (!m_IN_HIGH[eVirt].valid() && high(m_NODEAT[m_LOWPT1[w]]) < vnum) - m_IN_HIGH[eVirt] = m_HIGHPT[m_NODEAT[m_LOWPT1[w]]].pushFront(vnum); - - m_DEGREE[v]++; - m_DEGREE[m_NODEAT[m_LOWPT1[w]]]++; - - } else { - Adj.del(it); - - CompStruct &C = newComp(bond); - C << eVirt; - eVirt = m_pGC->newEdge(m_NODEAT[m_LOWPT1[w]],v); - C << eVirt; - - edge eh = m_TREE_ARC[v]; - - C << m_TREE_ARC[v]; - - m_TREE_ARC[v] = eVirt; - m_TYPE[eVirt] = tree; - - m_IN_ADJ[eVirt] = m_IN_ADJ[eh]; - *m_IN_ADJ[eh] = eVirt; - } - } - - if (m_START[e]) { - while (TSTACK_notEOS()) { - m_top--; - } - m_top--; - } - - while (TSTACK_notEOS() && - m_TSTACK_b[m_top] != vnum && high(v) > m_TSTACK_h[m_top]) { - m_top--; - } - - outv--; - - } else { // frond arc - if (m_START[e]) { - y = 0; - if (m_TSTACK_a[m_top] > wnum) { - do { - y = max(y,m_TSTACK_h[m_top]); - b = m_TSTACK_b[m_top--]; - } while (m_TSTACK_a[m_top] > wnum); - TSTACK_push(y,wnum,b); - } else { - TSTACK_push(vnum,wnum,vnum); - } - } - - m_ESTACK.push(e); // add (v,w) to ESTACK - } - } -} - -// simplified path search for triconnectivity test -bool TricComp::pathSearch (const Graph &G, node v, node &s1, node &s2) -{ - node w; - edge e; - int y, vnum = m_NEWNUM[v], wnum; - int a, b; - - List &Adj = m_A[v]; - int outv = Adj.size(); - - ListIterator it, itNext; - for(it = Adj.begin(); it.valid(); it=itNext) - { - itNext = it.succ(); - e = *it; - w = e->target(); wnum = m_NEWNUM[w]; - - if (m_TYPE[e] == tree) { - - if (m_START[e]) { - y = 0; - if (m_TSTACK_a[m_top] > m_LOWPT1[w]) { - do { - y = max(y,m_TSTACK_h[m_top]); - b = m_TSTACK_b[m_top--]; - } while (m_TSTACK_a[m_top] > m_LOWPT1[w]); - TSTACK_push(y,m_LOWPT1[w],b); - } else { - TSTACK_push(wnum+m_ND[w]-1,m_LOWPT1[w],vnum); - } - TSTACK_pushEOS(); - } - - if(pathSearch(G,w,s1,s2) == false) - return false; - - while (vnum != 1 && ((m_TSTACK_a[m_top] == vnum) || - (m_DEGREE[w] == 2 && m_NEWNUM[m_A[w].front()->target()] > wnum))) - { - a = m_TSTACK_a[m_top]; - b = m_TSTACK_b[m_top]; - - if (a == vnum && m_FATHER[m_NODEAT[b]] == m_NODEAT[a]) { - m_top--; - - } else if (m_DEGREE[w] == 2 && m_NEWNUM[m_A[w].front()->target()] > wnum) - { - s1 = v; - s2 = m_A[w].front()->target(); - return false; - - } else { - s1 = m_NODEAT[a]; - s2 = m_NODEAT[b]; - return false; - } - } - - if (m_LOWPT2[w] >= vnum && m_LOWPT1[w] < vnum && (m_FATHER[v] != m_start || outv >= 2)) - { - s1 = m_NODEAT[m_LOWPT1[w]]; - s2 = v; - return false; - } - - if (m_START[e]) { - while (TSTACK_notEOS()) { - m_top--; - } - m_top--; - } - - while (TSTACK_notEOS() && - m_TSTACK_b[m_top] != vnum && high(v) > m_TSTACK_h[m_top]) { - m_top--; - } - - outv--; - - } else { // frond arc - if (m_START[e]) { - y = 0; - if (m_TSTACK_a[m_top] > wnum) { - do { - y = max(y,m_TSTACK_h[m_top]); - b = m_TSTACK_b[m_top--]; - } while (m_TSTACK_a[m_top] > wnum); - TSTACK_push(y,wnum,b); - } else { - TSTACK_push(vnum,wnum,vnum); - } - } - } - } - - return true; -} - - -// triconnectivity test -bool isTriconnected(const Graph &G, node &s1, node &s2) -{ - bool isTric; - TricComp tric2(G,isTric,s1,s2); - - return isTric; -} - - -//---------------------------------------------------------- -// debugging stuff -//---------------------------------------------------------- - -void TricComp::printOs(edge e) -{ -#ifdef TRIC_COMP_OUTPUT - cout << " (" << m_pGC->original(e->source()) << "," << - m_pGC->original(e->target()) << "," << e->index() << ")"; - if (m_pGC->original(e) == 0) cout << "v"; -#endif -} - -void TricComp::printStacks() -{ -#ifdef TRIC_COMP_OUTPUT - cout << "\n\nTSTACK:" << endl; - - for (int i = m_top; i >= 0; i--) - cout << "(" << m_TSTACK_h[i] << "," << m_TSTACK_a[i] << "," << m_TSTACK_b[i] << ")\n"; - - cout << "\nESTACK\n"; - while(!m_ESTACK.empty()) { - printOs(m_ESTACK.pop()); cout << endl; - } -#endif -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/decomposition/TricComp.h b/ext/OGDF/src/decomposition/TricComp.h deleted file mode 100644 index c807d5a68..000000000 --- a/ext/OGDF/src/decomposition/TricComp.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares class TricComp which realizes the Hopcroft/Tarjan - * algorithm for finding the triconnected components of a biconnected - * multi-graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - - -#ifndef OGDF_TRIC_COMP_H -#define OGDF_TRIC_COMP_H - - -#include -#include -#include -#include - - -namespace ogdf { - - class GraphCopySimple; - - -//--------------------------------------------------------- -// TricComp -// realizes Hopcroft/Tarjan algorithm for finding the triconnected -// components of a biconnected multi-graph -//--------------------------------------------------------- -class TricComp -{ -public: - // construction - TricComp(const Graph &G); - - TricComp(const Graph &G, bool &isTric, node &s1, node &s2); - - // destruction - ~TricComp(); - - // type of split-components / triconnected components - enum CompType { bond, polygon, triconnected }; - - // representation of a component - struct CompStruct { - List m_edges; - CompType m_type; - - CompStruct &operator<<(edge e) { - m_edges.pushBack(e); - return *this; - } - - void finishTricOrPoly(edge e) { - m_edges.pushBack(e); - m_type = (m_edges.size() >= 4) ? triconnected : polygon; - } - }; - - // copy of G containing also virtual edges - GraphCopySimple *m_pGC; - // array of components - Array m_component; - // number of components - int m_numComp; - - // check if computed triconnected componets are correct - bool checkComp(); - - -private: - bool checkSepPair(edge eVirt); - - // splits bundles of multi-edges into bonds and creates - // a new virtual edge in GC. - void splitMultiEdges(); - - // stack of triples - int *m_TSTACK_h, *m_TSTACK_a, *m_TSTACK_b; - int m_top; - - // push a triple on TSTACK - void TSTACK_push (int h, int a, int b) { - m_TSTACK_h[++m_top] = h; - m_TSTACK_a[m_top] = a; - m_TSTACK_b[m_top] = b; - } - - // push end-of-stack marker on TSTACK - void TSTACK_pushEOS() { - m_TSTACK_a[++m_top] = -1; - } - - // returns true iff end-of-stack marker is not on top of TSTACK - bool TSTACK_notEOS() { - return (m_TSTACK_a[m_top] != -1); - } - - // create a new empty component - CompStruct &newComp() { - return m_component[m_numComp++]; - } - - // create a new empty component of type t - CompStruct &newComp(CompType t) { - CompStruct &C = m_component[m_numComp++]; - C.m_type = t; - return C; - } - - // type of edges with respect to palm tree - enum edgeType { unseen, tree, frond, removed }; - - // first dfs traversal - void DFS1 (const Graph& G, node v, node u); - // special version for triconnectivity tes - void DFS1 (const Graph& G, node v, node u, node &s1); - - // constructs ordered adjaceny lists - void buildAcceptableAdjStruct (const Graph& G); - // the second dfs traversal - void DFS2 (const Graph& G); - void pathFinder(const Graph& G, node v); - - // finding of split components - void pathSearch (const Graph& G, node v); - - bool pathSearch (const Graph &G, node v, node &s1, node &s2); - - // merges split-components into triconnected components - void assembleTriconnectedComponents(); - - // debugging stuff - void printOs(edge e); - void printStacks(); - - // returns high(v) value - int high(node v) { - return (m_HIGHPT[v].empty()) ? 0 : m_HIGHPT[v].front(); - } - - void delHigh(edge e) { - ListIterator it = m_IN_HIGH[e]; - if (it.valid()) { - node v = e->target(); - m_HIGHPT[v].del(it); - } - } - - NodeArray m_NUMBER; // (first) dfs-number of v - NodeArray m_LOWPT1; - NodeArray m_LOWPT2; - NodeArray m_ND; // number of descendants in palm tree - NodeArray m_DEGREE; // degree of v - Array m_NODEAT; // node with number i - NodeArray m_FATHER; // father of v in palm tree - EdgeArray m_TYPE; // type of edge e - NodeArray > m_A; // adjacency list of v - NodeArray m_NEWNUM; // (second) dfs-number of v - EdgeArray m_START; // edge starts a path - NodeArray m_TREE_ARC; // tree arc entering v - NodeArray > m_HIGHPT; // list of fronds entering v in the order they are visited - EdgeArray > m_IN_ADJ; // pointer to element in adjacency list containing e - EdgeArray > m_IN_HIGH; // pointer to element in HIGHPT list containing e - BoundedStack m_ESTACK; // stack of currently active edges - - node m_start; // start node of dfs traversal - int m_numCount; // counter for dfs-traversal - bool m_newPath; // true iff we start a new path -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/src/energybased/AdjacencyOracle.cpp b/ext/OGDF/src/energybased/AdjacencyOracle.cpp deleted file mode 100644 index 0ab1c43a8..000000000 --- a/ext/OGDF/src/energybased/AdjacencyOracle.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class AjacencyOracle - * - * This class is used to efficiently test if two vertices - * are adjacent. It is basically a wrapper for a 2D-Matrix. - * This file contains the code for the construction of the - * matrix and the query function. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - - //! Builds a 2D-array indexed by the numbers of vertices. - /** - * It uses only the part - * of the matrix left of the diagonal (where the first index is smaller than the - * second. For each pair of vertices, the corresponding entry in the matrix is set true - * if and only if the two vertices are adjacent. - */ - AdjacencyOracle::AdjacencyOracle(const Graph &G) : m_nodeNum(G) - { - int i = 1; - node v; - forall_nodes(v,G) m_nodeNum[v] = i++; - int nodeNum = i-1; - m_adjacencyMatrix = new Array2D (1,i,1,i); - for(i = 1; i < nodeNum; i++) - for(int j = i+1; j <= nodeNum; j++) - (*m_adjacencyMatrix)(i,j) = false; - edge e; - forall_edges(e,G) { - int num1 = m_nodeNum[e->source()]; - int num2 = m_nodeNum[e->target()]; - (*m_adjacencyMatrix)(min(num1,num2),max(num1,num2)) = true; - } - } - - - //! Returns true if two vertices are adjacent. - /** - * Note that only the entries in the 2D matrix where the first - * index is smaller than the second is used and so wehave to - * pay attention that the first index is smaller than the second. - */ - bool AdjacencyOracle::adjacent(const node v, const node w) const - { - int num1 = m_nodeNum[v]; - int num2 = m_nodeNum[w]; - return (*m_adjacencyMatrix)(min(num1,num2),max(num1,num2)); - } -} diff --git a/ext/OGDF/src/energybased/ArrayGraph.cpp b/ext/OGDF/src/energybased/ArrayGraph.cpp deleted file mode 100644 index 6ca7d44b8..000000000 --- a/ext/OGDF/src/energybased/ArrayGraph.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class ArrayGraph. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "ArrayGraph.h" -#include "FastUtils.h" - -namespace ogdf { - -ArrayGraph::ArrayGraph(): m_numNodes(0), - m_numEdges(0), - m_nodeXPos(0), - m_nodeYPos(0), - m_nodeSize(0), - m_nodeMoveRadius(0), - m_desiredEdgeLength(0), - m_nodeAdj(0), - m_edgeAdj(0) -{ -} - -ArrayGraph::ArrayGraph(__uint32 maxNumNodes, __uint32 maxNumEdges) : - m_numNodes(maxNumNodes), - m_numEdges(maxNumEdges), - m_nodeXPos(0), - m_nodeYPos(0), - m_nodeSize(0), - m_nodeMoveRadius(0), - m_desiredEdgeLength(0), - m_nodeAdj(0), - m_edgeAdj(0) -{ - allocate(maxNumNodes, maxNumEdges); -} - -ArrayGraph::ArrayGraph(const GraphAttributes& GA, const EdgeArray& edgeLength, const NodeArray& nodeSize) : - m_numNodes(0), - m_numEdges(0), - m_nodeXPos(0), - m_nodeYPos(0), - m_nodeSize(0), - m_nodeMoveRadius(0), - m_desiredEdgeLength(0), - m_nodeAdj(0), - m_edgeAdj(0) -{ - allocate(GA.constGraph().numberOfNodes(), GA.constGraph().numberOfEdges()); - readFrom(GA, edgeLength, nodeSize); -} - -ArrayGraph::~ArrayGraph(void) -{ - if (m_nodeXPos) - deallocate(); -} - -void ArrayGraph::allocate(__uint32 numNodes, __uint32 numEdges) -{ - m_nodeXPos = (float*)MALLOC_16(numNodes*sizeof(float)); - m_nodeYPos = (float*)MALLOC_16(numNodes*sizeof(float)); - m_nodeSize = (float*)MALLOC_16(numNodes*sizeof(float)); - m_nodeMoveRadius = (float*)MALLOC_16(numNodes*sizeof(float)); - m_nodeAdj = (NodeAdjInfo*)MALLOC_16(numNodes*sizeof(NodeAdjInfo)); - m_desiredEdgeLength = (float*)MALLOC_16(numEdges*sizeof(float)); - m_edgeAdj = (EdgeAdjInfo*)MALLOC_16(numEdges*sizeof(EdgeAdjInfo)); - - for (__uint32 i=0; i < numNodes; i++) - nodeInfo(i).degree = 0; -} - -void ArrayGraph::deallocate() -{ - FREE_16(m_nodeXPos); - FREE_16(m_nodeYPos); - FREE_16(m_nodeSize); - FREE_16(m_nodeMoveRadius); - FREE_16(m_nodeAdj); - FREE_16(m_desiredEdgeLength); - FREE_16(m_edgeAdj); -} - -void ArrayGraph::pushBackEdge(__uint32 a, __uint32 b, float desiredEdgeLength) -{ - // get the index of a free element - __uint32 e_index = m_numEdges++; - - // get the pair entry - EdgeAdjInfo& e = edgeInfo(e_index); - - // (a,b) is the pair we are adding - e.a = a; - e.b = b; - - m_desiredEdgeLength[e_index] = desiredEdgeLength; - m_desiredAvgEdgeLength += (double)desiredEdgeLength; - // get the node info - NodeAdjInfo& aInfo = nodeInfo(a); - NodeAdjInfo& bInfo = nodeInfo(b); - - // if a is part of at least one edge - if (aInfo.degree) - { - // adjust the links - EdgeAdjInfo& a_e = edgeInfo(aInfo.lastEntry); - // check which one is a - if (a==a_e.a) - a_e.a_next = e_index; - else - a_e.b_next = e_index; - } else - { - // this edge is the first for a => set the firstEntry link - aInfo.firstEntry = e_index; - } - - // same for b: if b is part of at least one edge - if (bInfo.degree) - { - // adjust the links - EdgeAdjInfo& b_e = edgeInfo(bInfo.lastEntry); - // check which one is b - if (b==b_e.a) - b_e.a_next = e_index; - else - b_e.b_next = e_index; - } else - { - // this edge is the first for b => set the firstEntry link - bInfo.firstEntry = e_index; - } - // and the lastEntry link - aInfo.lastEntry = e_index; - bInfo.lastEntry = e_index; - // one more edge for each node - aInfo.degree++; - bInfo.degree++; -} - -void ArrayGraph::readFrom(const GraphAttributes& GA, const EdgeArray& edgeLength, const NodeArray& nodeSize) -{ - const Graph& G = GA.constGraph(); - NodeArray<__uint32> nodeIndex(G); - - node v; - m_numNodes = 0; - m_numEdges = 0; - m_avgNodeSize = 0; - m_desiredAvgEdgeLength = 0; - forall_nodes(v, G) - { - m_nodeXPos[m_numNodes] = (float)GA.x(v); - m_nodeYPos[m_numNodes] = (float)GA.y(v); - m_nodeSize[m_numNodes] = nodeSize[v]; - nodeIndex[v] = m_numNodes; - m_avgNodeSize += nodeSize[v]; - m_numNodes++; - } - m_avgNodeSize = m_avgNodeSize / (double)m_numNodes; - - edge e; - forall_edges(e, G) - { - pushBackEdge(nodeIndex[e->source()], nodeIndex[e->target()], (float)edgeLength[e]); - } - m_desiredAvgEdgeLength = m_desiredAvgEdgeLength / (double)m_numEdges; -} - -void ArrayGraph::writeTo(GraphAttributes& GA) -{ - const Graph& G = GA.constGraph(); - node v; - __uint32 i = 0; - forall_nodes(v, G) - { - GA.x(v) = m_nodeXPos[i]; - GA.y(v) = m_nodeYPos[i]; - i++; - } -} - -void ArrayGraph::transform(float translate, float scale) -{ - for (__uint32 i=0; i < m_numNodes; i++) - { - m_nodeXPos[i] = (m_nodeXPos[i] + translate)*scale; - m_nodeYPos[i] = (m_nodeYPos[i] + translate)*scale; - } -} - -void ArrayGraph::centerGraph() -{ - double dx_sum = 0; - double dy_sum = 0; - - for (__uint32 i=0; i < m_numNodes; i++) - { - dx_sum += m_nodeXPos[i]; - dy_sum += m_nodeYPos[i]; - }; - - dx_sum /= (double)m_numNodes; - dy_sum /= (double)m_numNodes; - for (__uint32 i=0; i < m_numNodes; i++) - { - m_nodeXPos[i] -= (float)dx_sum; - m_nodeYPos[i] -= (float)dy_sum; - } -} - -} // end of namespace ogdf - diff --git a/ext/OGDF/src/energybased/ArrayGraph.h b/ext/OGDF/src/energybased/ArrayGraph.h deleted file mode 100644 index e2b25840e..000000000 --- a/ext/OGDF/src/energybased/ArrayGraph.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class ArrayGraph. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_ARRAY_GRAPH_H -#define OGDF_ARRAY_GRAPH_H - -#include - -namespace ogdf { - -//! struct which keeps information aboout incident edges (16 bytes) -struct NodeAdjInfo -{ - __uint32 degree; // total count of pairs where is either the first or second node - __uint32 firstEntry; // the first pair in the edges chain - __uint32 lastEntry; // the last pair in the edges chain - __uint32 unused; // not used yet -}; - -//! struct which keeps information about an edge (16 bytes) -struct EdgeAdjInfo -{ - __uint32 a; // first node of the pair - __uint32 b; // second node of the pair - __uint32 a_next;// next pair in the chain of the first node - __uint32 b_next;// next pair in the chain of the second node -}; - - -class ArrayGraph -{ -public: - ArrayGraph(); - ArrayGraph(__uint32 maxNumNodes, __uint32 maxNumEdges); - ArrayGraph(const GraphAttributes& GA, const EdgeArray& edgeLength, const NodeArray& nodeSize); - ~ArrayGraph(); - - //! returns the number of nodes - /** - * \return the number of nodes - */ - inline __uint32 numNodes() const { return m_numNodes; } - - //! returns the number of nodes - /** - * \return the number of nodes - */ - inline __uint32 numEdges() const { return m_numEdges; } - - //! updates an array graph from GraphAttributes with the given edge lenghts and node sizes and creates the edges; - /** - * The nodes and edges are ordered in the same way like in the Graph instance. - * @param GA the GraphAttributes to read from - * @param edgeLength the desired edge length - */ - void readFrom(const GraphAttributes& GA, const EdgeArray& edgeLength, const NodeArray& nodeSize); - - //! updates an array graph with the given positions, edge lenghts and node sizes and creates the edges - /** - * The nodes and edges are ordered in the same way like in the Graph instance. - * @param G the Graph to traverse - * @param xPos the x coordinate for each node - * @param yPos the y coordinate for each node - * @param nodeSize the x coordinate for each node in G - * @param edgeLength the desired edge length for each edge - */ - template - void readFrom(const Graph& G, NodeArray& xPos, NodeArray& yPos, const EdgeArray& edgeLength, const NodeArray& nodeSize) - { - m_numNodes = 0; - m_numEdges = 0; - NodeArray<__uint32> nodeIndex(G); - node v; - m_numNodes = 0; - m_numEdges = 0; - m_desiredAvgEdgeLength = 0; - m_avgNodeSize = 0; - forall_nodes(v, G) - { - m_nodeXPos[m_numNodes] = (float)xPos[v]; - m_nodeYPos[m_numNodes] = (float)yPos[v]; - m_nodeSize[m_numNodes] = (float)nodeSize[v]; - m_avgNodeSize += nodeSize[v]; - nodeIndex[v] = m_numNodes; - m_numNodes++; - } - m_avgNodeSize = m_avgNodeSize / (double)m_numNodes; - - edge e; - forall_edges(e, G) - { - pushBackEdge(nodeIndex[e->source()], nodeIndex[e->target()], (float)edgeLength[e]); - } - m_desiredAvgEdgeLength = m_desiredAvgEdgeLength / (double)m_numEdges; - } - - //! writes the data back to GraphAttributes - /** - * The function does not require to be the same Graph, only the order of nodes and edges - * is important - * @param GA the GraphAttributes to update - */ - void writeTo(GraphAttributes& GA); - - //! writes the data back to node arrays with the given coordinate type - /** - * The function does not require to be the same Graph, only the order of nodes and edges - * is important - * @param xPos the x coordinate array to update - * @param yPos the y coordinate array to update - */ - template - void writeTo(const Graph& G, NodeArray& xPos, NodeArray& yPos) - { - node v; - __uint32 i = 0; - forall_nodes(v, G) - { - xPos[v] = m_nodeXPos[i]; - yPos[v] = m_nodeYPos[i]; - i++; - } - } - - //! returns the adjacency information for a node - inline NodeAdjInfo& nodeInfo(__uint32 i) { return m_nodeAdj[i]; } - - //! returns the adjacency information for a node - inline const NodeAdjInfo& nodeInfo(__uint32 i) const { return m_nodeAdj[i]; } - - //! returns the adjacency information for an edge - inline EdgeAdjInfo& edgeInfo(__uint32 i) { return m_edgeAdj[i]; } - - //! returns the adjacency information for an edge - inline const EdgeAdjInfo& edgeInfo(__uint32 i) const { return m_edgeAdj[i]; } - - //! returns the NodeAdjInfo array for all nodes - /** - * The array is 16 byte aligned - */ - inline NodeAdjInfo* nodeInfo() { return m_nodeAdj; } - - //! returns the NodeAdjInfo array for all nodes - /** - * The array is 16 byte aligned - */ - inline const NodeAdjInfo* nodeInfo() const { return m_nodeAdj; } - - //! returns the EdgeAdjInfo array for all edges - /** - * The array is 16 byte aligned - */ - inline EdgeAdjInfo* edgeInfo() { return m_edgeAdj; } - - //! returns the EdgeAdjInfo array for all edges - /** - * The array is 16 byte aligned - */ - inline const EdgeAdjInfo* edgeInfo() const { return m_edgeAdj; } - - //! returns the x coord array for all nodes - /** - * The array is 16 byte aligned - */ - inline float* nodeXPos() { return m_nodeXPos; } - - //! returns the x coord array for all nodes - /** - * The array is 16 byte aligned - */ - inline const float* nodeXPos() const { return m_nodeXPos; } - - //! returns the y coord array for all nodes - /** - * The array is 16 byte aligned - */ - inline float* nodeYPos() { return m_nodeYPos; } - - //! returns the y coord array for all nodes - /** - * The array is 16 byte aligned - */ - inline const float* nodeYPos() const { return m_nodeYPos; } - - //! returns the node size array for all nodes - /** - * The array is 16 byte aligned - */ - inline float* nodeSize() { return m_nodeSize; } - - - //! returns the node movement radius array for all nodes - /** - * The array is 16 byte aligned - */ - inline float* nodeMoveRadius() { return m_nodeMoveRadius; } - - //! returns the node size array for all nodes - /** - * The array is 16 byte aligned - */ - inline const float* nodeSize() const { return m_nodeSize; } - - //! returns the edge length array for all edges - /** - * The array is 16 byte aligned - */ - inline float* desiredEdgeLength() { return m_desiredEdgeLength; } - - //! returns the edge length array for all edges - /** - * The array is 16 byte aligned - */ - inline const float* desiredEdgeLength() const { return m_desiredEdgeLength; } - - //! returns the index of the first pair of node node - inline __uint32 firstEdgeAdjIndex(__uint32 nodeIndex) const - { - return nodeInfo(nodeIndex).firstEntry; - }; - - //! returns the index of the next pair of curr for node a - inline __uint32 nextEdgeAdjIndex(__uint32 currEdgeAdjIndex, __uint32 nodeIndex) const - { - const EdgeAdjInfo& currInfo = edgeInfo(currEdgeAdjIndex); - if (currInfo.a == nodeIndex) - return currInfo.a_next; - return currInfo.b_next; - } - - //! returns the other node a is paired with in pair with the given index - inline __uint32 twinNodeIndex(__uint32 currEdgeAdjIndex, __uint32 nodeIndex) const - { - const EdgeAdjInfo& currInfo = edgeInfo(currEdgeAdjIndex); - if (currInfo.a == nodeIndex) - return currInfo.b; - return currInfo.a; - } - - template - void for_all_nodes(__uint32 begin, __uint32 end, Func func) - { - for(__uint32 i=begin; i <=end; i++) - func(i); - } - - - inline float avgDesiredEdgeLength() const { return (float)m_desiredAvgEdgeLength; } - - inline float avgNodeSize() const { return (float)m_avgNodeSize; } - - void transform(float translate, float scale); - void centerGraph(); - -private: - - //! internal function used by readFrom - void pushBackEdge(__uint32 a, __uint32 b, float desiredEdgeLength); - - //! internal function used allocate all arrays - void allocate(__uint32 numNodes, __uint32 numEdges); - - //! internal function used allocate all arrays - void deallocate(); - - //! internal function used to clear the arrays - void clear() - { - for (__uint32 i=0; i < m_numNodes; i++) - nodeInfo(i).degree = 0; - - m_numNodes = 0; - m_numEdges = 0; - } - - //! number of nodes in the graph - __uint32 m_numNodes; - - //! number of edges in the graph - __uint32 m_numEdges; - - //! x coordinates - float* m_nodeXPos; - - //! x coordinates - float* m_nodeYPos; - - //! size of the node - float* m_nodeSize; - - //! avg node size - double m_avgNodeSize; - - //! maximum node movement length - float* m_nodeMoveRadius; - - //! edge length - float* m_desiredEdgeLength; - - double m_currentAvgEdgeLength; - - //! avg edge length - double m_desiredAvgEdgeLength; - - //! information about adjacent edges - NodeAdjInfo* m_nodeAdj; - - //! information about adjacent nodes - EdgeAdjInfo* m_edgeAdj; -}; - -} // end of namespace ogdf - -#endif - diff --git a/ext/OGDF/src/energybased/Attraction.cpp b/ext/OGDF/src/energybased/Attraction.cpp deleted file mode 100644 index 39847dc08..000000000 --- a/ext/OGDF/src/energybased/Attraction.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class Attraction. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -const double Attraction::MULTIPLIER = 2.0; - - -//initializes internal data, like name and layout -Attraction::Attraction(GraphAttributes &AG) : NodePairEnergy("Attraction", AG) { - - reinitializeEdgeLength(MULTIPLIER); -} - - -//computes preferred edge length as the average of all widths and heights of the vertices -//multiplied by the multiplier -void Attraction::reinitializeEdgeLength(double multi) -{ - double lengthSum(0.0); - node v; - forall_nodes(v,m_G) { - const IntersectionRectangle &i = shape(v); - lengthSum += i.width(); - lengthSum += i.height(); - } - lengthSum /= (2*m_G.numberOfNodes()); - // lengthSum is now the average of all lengths and widths - m_preferredEdgeLength = multi * lengthSum; - -}//reinitializeEdgeLength - - -//the energy of a pair of vertices is computed as the square of the difference between the -//actual distance and the preferred edge length -double Attraction::computeCoordEnergy(node v1, node v2, const DPoint &p1, const DPoint &p2) -const -{ - double energy = 0.0; - if(adjacent(v1,v2)) { - IntersectionRectangle i1(shape(v1)), i2(shape(v2)); - i1.move(p1); - i2.move(p2); - energy = i1.distance(i2) - m_preferredEdgeLength; - energy *= energy; - } - return energy; -} - - -#ifdef OGDF_DEBUG -void Attraction::printInternalData() const { - NodePairEnergy::printInternalData(); - cout << "\nPreferred edge length: " << m_preferredEdgeLength; -} -#endif - -}// namespace ogdf diff --git a/ext/OGDF/src/energybased/CoinTutteLayout.cpp b/ext/OGDF/src/energybased/CoinTutteLayout.cpp deleted file mode 100644 index cefcf0ca2..000000000 --- a/ext/OGDF/src/energybased/CoinTutteLayout.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Tutte's Algorithm - * - * \author David Alberts \and Andrea Wagner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_COIN - -#include -#include -#include -#include - -namespace ogdf { - -// solves a system of linear equations with a linear solver for optimization problems. -// I'm sorry but there is no Gauss-Algorithm (or some numerical stuff) in OGDF... -bool solveLP( - int cols, - const CoinPackedMatrix &Matrix, - const Array &rightHandSide, - Array &x) -{ - int i; - - OsiSolverInterface *osi = CoinManager::createCorrectOsiSolverInterface(); - - // constructs a dummy optimization problem. - // The given system of equations is used as constraint. - osi->setObjSense(-1); // maximize... - Array obj(0,cols-1,1); // ...the sum of variables - Array lowerBound(0,cols-1,-1*(osi->getInfinity())); - Array upperBound(0,cols-1,osi->getInfinity()); - - // loads the problem to Coin-Osi - osi->loadProblem(Matrix, &lowerBound[0], &upperBound[0], &obj[0], &rightHandSide[0], &rightHandSide[0]); - - // solves the linear program - osi->initialSolve(); - - // gets the solution and returns true if it is optimal - const double *sol = osi->getColSolution(); - for(i=0; iisProvenOptimal()) { - delete osi; - return true; - } - else { - delete osi; - return false; - } -} - -TutteLayout::TutteLayout() -{ - m_bbox = DRect (0.0, 0.0, 250.0, 250.0); -} - - - -// sets the positions of the nodes in a largest face of G in the form -// of a regular k-gon. The corresponding nodes and their positions are -// stored in nodes and pos, respectively. -void TutteLayout::setFixedNodes( - const Graph &G, - List& nodes, - List& pos, - double radius) -{ - // compute faces of a copy of G - GraphCopy GC(G); - - // compute a planar embedding if \a G is planar - if(isPlanar(G)) planarEmbed(GC); - //FIXME this stuff above seems wrong!! - - CombinatorialEmbedding E(GC); - E.computeFaces(); - - // search for largest face - face maxFace = E.maximalFace(); - - // delete possible old entries in nodes and pos - nodes.clear(); - pos.clear(); - - // set nodes and pos - NodeArray addMe(GC,true); - adjEntry adj; - - List maxNodes; - forall_face_adj(adj,maxFace) { - maxNodes.pushBack(adj->theNode()); - } - - forall_nonconst_listiterators(node, it, maxNodes) { - node &w = *it; - if(addMe[w]) { - nodes.pushBack(w); - addMe[w] = false; - } - } - - double step = 2.0 * Math::pi / (double)(nodes.size()); - double alpha = 0.0; - forall_listiterators(node, it, nodes) { - pos.pushBack(DPoint(radius * cos(alpha), radius * sin(alpha))); - alpha += step; - } -} - -// Overload setFixedNodes for given nodes -void TutteLayout::setFixedNodes( - const Graph &G, - List& nodes, - const List& givenNodes, - List& pos, - double radius) -{ - GraphCopy GC(G); - - // delete possible old entries in nodes and pos - nodes.clear(); - pos.clear(); - - // set nodes and pos - - forall_listiterators(node, it, givenNodes) { - node theOrig = *it; - node theCopy = GC.copy(theOrig); - nodes.pushBack(theCopy); - } - - double step = 2.0 * Math::pi / (double)(nodes.size()); - double alpha = 0.0; - forall_listiterators(node, it, nodes) { - pos.pushBack(DPoint(radius * cos(alpha), radius * sin(alpha))); - alpha += step; - } -} - -void TutteLayout::call(GraphAttributes &AG, const List &givenNodes) -{ - const Graph &G = AG.constGraph(); - - List fixedNodes; - List positions; - - double diam = - sqrt((m_bbox.width()) * (m_bbox.width()) - + (m_bbox.height()) * (m_bbox.height())); - - // handle graphs with less than two nodes - switch (G.numberOfNodes()) { - case 0: - return; - case 1: - node v = G.firstNode(); - - DPoint center(0.5 * m_bbox.width(),0.5 * m_bbox.height()); - center = center + m_bbox.p1(); - - AG.x(v) = center.m_x; - AG.y(v) = center.m_y; - - return; - } - - // increase radius to have no overlap on the outer circle - node v = G.firstNode(); - - double r = diam/2.8284271; - int n = G.numberOfNodes(); - double nodeDiam = 2.0*sqrt((AG.width(v)) * (AG.width(v)) - + (AG.height(v)) * (AG.height(v))); - - if(r fixedNodes; - List positions; - - double diam = - sqrt((m_bbox.width()) * (m_bbox.width()) - + (m_bbox.height()) * (m_bbox.height())); - - // handle graphs with less than two nodes - switch (G.numberOfNodes()) { - case 0: - return; - case 1: - node v = G.firstNode(); - - DPoint center(0.5 * m_bbox.width(),0.5 * m_bbox.height()); - center = center + m_bbox.p1(); - - AG.x(v) = center.m_x; - AG.y(v) = center.m_y; - - return; - } - - // increase radius to have no overlap on the outer circle - node v = G.firstNode(); - - double r = diam/2.8284271; - int n = G.numberOfNodes(); - double nodeDiam = 2.0*sqrt((AG.width(v)) * (AG.width(v)) - + (AG.height(v)) * (AG.height(v))); - - if(r &fixedNodes, - List &fixedPositions) -{ - node v, w; - edge e; - - const Graph &G = AG.constGraph(); - GraphCopy GC(G); - GraphCopyAttributes AGC(GC, AG); - - // mark fixed nodes and set their positions in a - NodeArray fixed(GC,false); - forall_listiterators(node, it, fixedNodes) { - fixed[*it] = true; - DPoint p = fixedPositions.popFrontRet(); // slightly dirty... - fixedPositions.pushBack(p); // ... - - AGC.x(*it) = p.m_x; - AGC.y(*it) = p.m_y; - } - - if(fixedNodes.size() == G.numberOfNodes()) { - forall_nodes(v,GC) { - AG.x(GC.original(v)) = AGC.x(v); - AG.y(GC.original(v)) = AGC.y(v); - } - return true; - } - // all nodes have fixed positions - nothing left to do - - // collect other nodes - List otherNodes; - forall_nodes(v,GC) if(!fixed[v]) otherNodes.pushBack(v); - - NodeArray ind(GC); // position of v in otherNodes and A - - int i = 0; - - forall_listiterators(node, it, otherNodes) ind[*it] = i++; - - int n = otherNodes.size(); // #other nodes - Array coord(n); // coordinates (first x then y) - Array rhs(n); // right hand side - double oneOverD = 0.0; - - CoinPackedMatrix A(false,0,0); // equations - A.setDimensions(n,n); - - // initialize non-zero entries in matrix A - forall_listiterators(node, it, otherNodes) { - oneOverD = (double)(1.0/((*it)->degree())); - forall_adj_edges(e,*it) { - // get second node of e - w = (*it == e->source()) ? e->target() : e->source(); - if(!fixed[w]) { - A.modifyCoefficient(ind[*it],ind[w],oneOverD); - } - } - A.modifyCoefficient(ind[*it],ind[*it],-1); - } - - // compute right hand side for x coordinates - forall_listiterators(node, it, otherNodes) { - rhs[ind[*it]] = 0; - oneOverD = (double)(1.0/((*it)->degree())); - forall_adj_edges(e,*it) { - // get second node of e - w = (*it == e->source()) ? e->target() : e->source(); - if(fixed[w]) rhs[ind[*it]] -= (oneOverD*AGC.x(w)); - } - } - - // compute x coordinates - if(!(solveLP(n, A, rhs, coord))) return false; - forall_listiterators(node, it, otherNodes) AGC.x(*it) = coord[ind[*it]]; - - // compute right hand side for y coordinates - forall_listiterators(node, it, otherNodes) { - rhs[ind[*it]] = 0; - oneOverD = (double)(1.0/((*it)->degree())); - forall_adj_edges(e,*it) { - // get second node of e - w = (*it == e->source()) ? e->target() : e->source(); - if(fixed[w]) rhs[ind[*it]] -= (oneOverD*AGC.y(w)); - } - } - - // compute y coordinates - if(!(solveLP(n, A, rhs, coord))) return false; - forall_listiterators(node, it, otherNodes) AGC.y(*it) = coord[ind[*it]]; - - // translate coordinates, such that the center lies in - // the center of the bounding box - DPoint center(0.5 * m_bbox.width(),0.5 * m_bbox.height()); - - forall_nodes (v, GC) { - AGC.x(v) += center.m_x; - AGC.y(v) += center.m_y; - } - - forall_nodes(v,GC) { - AG.x(GC.original(v)) = AGC.x(v); - AG.y(GC.original(v)) = AGC.y(v); - } - - return true; -} -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/src/energybased/ComplexDouble.h b/ext/OGDF/src/energybased/ComplexDouble.h deleted file mode 100644 index defc32f4d..000000000 --- a/ext/OGDF/src/energybased/ComplexDouble.h +++ /dev/null @@ -1,479 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definition of class ComplexDouble for fast complex number arithmetic. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_COMPLEX_DOUBLE_H -#define OGDF_COMPLEX_DOUBLE_H - -#include "FastUtils.h" -#include - -namespace ogdf { -namespace sse { - -//! Class to generate instrinsics for complex number arithmetic functions -#ifdef OGDF_FME_KERNEL_USE_SSE -class ComplexDouble -{ -public: - __m128d reg; - - // --------------------------------------------------- - // CONSTRUCTORS - // --------------------------------------------------- - inline ComplexDouble() - { - reg = _mm_setzero_pd(); - } - - inline ComplexDouble(const ComplexDouble& other) - { - reg = other.reg; - } - - inline ComplexDouble(double x) - { - reg = _mm_setr_pd((x), (0)); - } - - inline ComplexDouble(double x, double y) - { - reg = _mm_setr_pd((x), (y)); - } - - inline ComplexDouble(const double* ptr) - { - reg = _mm_load_pd(ptr); - } - - - inline ComplexDouble(__m128d r) : reg(r) - { - } - - inline ComplexDouble(float x, float y) - { - reg = _mm_cvtps_pd(_mm_setr_ps((x), (y), 0, 0)); - } - - // --------------------------------------------------- - // Standard arithmetic - // --------------------------------------------------- - inline ComplexDouble operator+(const ComplexDouble& other) const - { - return ComplexDouble( _mm_add_pd(reg, other.reg) ); - } - - inline ComplexDouble operator-(const ComplexDouble& other) const - { - return ComplexDouble( _mm_sub_pd(reg, other.reg) ); - } - - inline ComplexDouble operator-(void) const - { - return ComplexDouble( _mm_sub_pd(_mm_setzero_pd(), reg) ); - } - - inline ComplexDouble operator*(const ComplexDouble& other) const - { - // --------------------------------- - // | a0*b0 - a1*b1 | a0*b1 + a1*b0 | - // --------------------------------- - // bt = | b1 | b0 | - __m128d b_t = _mm_shuffle_pd(other.reg, other.reg, _MM_SHUFFLE2(0, 1)); - // left = | a0*b0 | a1*b1 | - __m128d left = _mm_mul_pd(reg, other.reg); - // right = | a0*b1 | a1*b0 | - __m128d right = _mm_mul_pd(reg, b_t); - // left = | a0*b0 | -a1*b1 | - left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0) ) ; - // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 | - return ComplexDouble( _mm_hadd_pd ( left, right ) ); - } - - inline ComplexDouble operator/(const ComplexDouble& other) const - { - // 1/(length(other)^2 * this * other.conj; - // bt = | b0 | -b1 | - __m128d conj_reg = _mm_mul_pd(other.reg, _mm_setr_pd(1.0, -1.0) ) ; - // bt = | b1 | b0 | - __m128d b_t = _mm_shuffle_pd(conj_reg, conj_reg, _MM_SHUFFLE2(0, 1)); - // left = | a0*b0 | a1*b1 | - __m128d left = _mm_mul_pd(reg, conj_reg); - // right = | a0*b1 | a1*b0 | - __m128d right = _mm_mul_pd(reg, b_t); - // left = | a0*b0 | -a1*b1 | - left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0) ) ; - // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 | - __m128d product = _mm_hadd_pd ( left, right ) ; - // product = reg*other.reg.conj - // l = b0*b0 | b1*b1 - __m128d l = _mm_mul_pd(conj_reg, conj_reg ); - // l = b0*b0 + b1*b1 | b0*b0 + b1*b1 - l = _mm_hadd_pd(l, l); - // l = length^2 | length^2 - return ComplexDouble( _mm_div_pd(product, l)); - } - - inline ComplexDouble operator*(double scalar) const - { - return ComplexDouble( _mm_mul_pd(reg, _mm_setr_pd(scalar, scalar)) ); - } - - inline ComplexDouble operator/(double scalar) const - { - //double rcp = 1.0/scalar; - return ComplexDouble( _mm_div_pd(reg, _mm_setr_pd(scalar, scalar)) ); - } - - inline ComplexDouble operator*(unsigned int scalar) const - { - return ComplexDouble( _mm_mul_pd(reg, _mm_setr_pd((double)scalar, (double)scalar)) ); - } - - inline void operator+=(const ComplexDouble& other) - { - reg = _mm_add_pd(reg, other.reg); - } - - inline void operator-=(const ComplexDouble& other) - { - reg = _mm_sub_pd(reg, other.reg); - } - - inline void operator*=(const ComplexDouble& other) - { - // bt = | b1 | b0 | - __m128d b_t = _mm_shuffle_pd(other.reg, other.reg, _MM_SHUFFLE2(0, 1)); - // left = | a0*b0 | a1*b1 | - __m128d left = _mm_mul_pd(reg, other.reg); - // right = | a0*b1 | a1*b0 | - __m128d right = _mm_mul_pd(reg, b_t); - // left = | a0*b0 | -a1*b1 | - left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0) ) ; - // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 | - reg = _mm_hadd_pd ( left, right ) ; - } - - inline void operator*=(double scalar) - { - // (real*scalar, imag*scalar) - reg = _mm_mul_pd(reg, _mm_setr_pd(scalar, scalar)); - } - - inline void operator/=(const ComplexDouble& other) - { - // 1/(length(other)^2 * this * other.conj; - // bt = | b0 | -b1 | - __m128d conj_reg = _mm_mul_pd(other.reg, _mm_setr_pd(1.0, -1.0) ) ; - // bt = | b1 | b0 | - __m128d b_t = _mm_shuffle_pd(conj_reg, conj_reg, _MM_SHUFFLE2(0, 1)); - // left = | a0*b0 | a1*b1 | - __m128d left = _mm_mul_pd(reg, conj_reg); - // right = | a0*b1 | a1*b0 | - __m128d right = _mm_mul_pd(reg, b_t); - // left = | a0*b0 | -a1*b1 | - left = _mm_mul_pd(left, _mm_setr_pd(1.0, -1.0) ) ; - // left = | a0*b0 + (-a1*b1) | a0*b1 + a1*b0 | - __m128d product = _mm_hadd_pd ( left, right ) ; - // l = b0*b0 | b1*b1 - __m128d l = _mm_mul_pd(conj_reg, conj_reg ); - // l = b0*b0 + b1*b1 | b0*b0 + b1*b1 - l = _mm_hadd_pd(l, l); - // l = length^2 | length^2 - reg = _mm_div_pd(product, l); - } - - // --------------------------------------------------- - // Additional arithmetic - // --------------------------------------------------- - inline double length() const - { - // sqrt(real*real + imag*imag) - double res; - __m128d r = _mm_mul_pd(reg, reg ); - r = _mm_hadd_pd(r, _mm_setzero_pd()); - r = _mm_sqrt_sd(r, r); - _mm_store_sd(&res, r); - return res; - } - - inline ComplexDouble conj() const - { - // (real, -imag) - return ComplexDouble( _mm_mul_pd(reg, _mm_setr_pd(1.0, -1.0) ) ); - } - - // --------------------------------------------------- - // Assignment - // --------------------------------------------------- - inline void operator=(const ComplexDouble& other) - { - reg = other.reg; - } - - //! load from 16byte aligned ptr - inline void operator=(double* ptr) - { - reg = _mm_load_pd(ptr); - } - - - // --------------------------------------------------- - // LOAD, STORE - // --------------------------------------------------- - - //! load from 16byte aligned ptr - inline void load(const double* ptr) - { - reg = _mm_load_pd(ptr); - } - - //! load from unaligned ptr - inline void load_unaligned(const double* ptr) - { - reg = _mm_loadu_pd(ptr); - } - - //! store to 16byte aligned ptr - inline void store(double* ptr) const - { - _mm_store_pd(ptr, reg); - } - - //! store to unaligned ptr - inline void store_unaligned(double* ptr) const - { - _mm_storeu_pd(ptr, reg); - } -}; - -#else -class ComplexDouble -{ -public: - double reg[2]; - - // --------------------------------------------------- - // CONSTRUCTORS - // --------------------------------------------------- - inline ComplexDouble( ) - { - reg[0] = 0.0; - reg[1] = 0.0; - } - - inline ComplexDouble(const ComplexDouble& other) - { - reg[0] = other.reg[0]; - reg[1] = other.reg[1]; - } - - inline ComplexDouble(double x) - { - reg[0] = x; - reg[1] = 0; - } - - inline ComplexDouble(double x, double y) - { - reg[0] = x; - reg[1] = y; - } - - inline ComplexDouble(double* ptr) - { - reg[0] = ptr[0]; - reg[1] = ptr[1]; - } - - // --------------------------------------------------- - // Standard arithmetic - // --------------------------------------------------- - inline ComplexDouble operator+(const ComplexDouble& other) const - { - return ComplexDouble( reg[0] + other.reg[0], reg[1] + other.reg[1] ); - } - - inline ComplexDouble operator-(const ComplexDouble& other) const - { - return ComplexDouble( reg[0] - other.reg[0], reg[1] - other.reg[1] ); - } - - inline ComplexDouble operator-(void) const - { - return ComplexDouble( -reg[0] , -reg[1] ); - } - - inline ComplexDouble operator*(const ComplexDouble& other) const - { - return ComplexDouble( reg[0]*other.reg[0] - reg[1]*other.reg[1], reg[0]*other.reg[1] + reg[1]*other.reg[0] ); - } - - inline ComplexDouble operator/(const ComplexDouble& other) const - { - return ((*this) *other.conj() / (other.reg[0]*other.reg[0] + other.reg[1]*other.reg[1])); - } - - inline ComplexDouble operator*(double scalar) const - { - return ComplexDouble( reg[0]*scalar, reg[1]*scalar ); - } - - inline ComplexDouble operator/(double scalar) const - { - return ComplexDouble( reg[0]/scalar, reg[1]/scalar ); - } - - inline ComplexDouble operator*(unsigned int scalar) const - { - return ComplexDouble( reg[0]*(double)scalar, reg[1]*(double)scalar ); - } - - inline void operator+=(const ComplexDouble& other) - { - reg[0] += other.reg[0]; - reg[1] += other.reg[1]; - } - - inline void operator-=(const ComplexDouble& other) - { - reg[0] -= other.reg[0]; - reg[1] -= other.reg[1]; - } - - inline void operator*=(const ComplexDouble& other) - { - double t[2]; - t[0] = reg[0]*other.reg[0] - reg[1]*other.reg[1]; - t[1] = reg[0]*other.reg[1] + reg[1]*other.reg[0]; - reg[0] = t[0]; - reg[1] = t[1]; - } - - inline void operator*=(double scalar) - { - reg[0] *= scalar; - reg[1] *= scalar; - } - - inline void operator/=(const ComplexDouble& other) - { - ComplexDouble t = other.conj() / (other.reg[0]*other.reg[0] + other.reg[1]*other.reg[1]); - double r[2]; - r[0] = reg[0]*t.reg[0] - reg[1]*t.reg[1]; - r[1] = reg[0]*t.reg[1] + reg[1]*t.reg[0]; - reg[0] = r[0]; - reg[1] = r[1]; - } - - // --------------------------------------------------- - // Additional arithmetic - // --------------------------------------------------- - inline double length() const - { - // sqrt(real*real + imag*imag) - return sqrt(reg[0]*reg[0] + reg[1]*reg[1]); - } - - inline ComplexDouble conj() const - { - // (real, -imag) - return ComplexDouble( reg[0], -reg[1] ); - } - - - // --------------------------------------------------- - // Assignment - // --------------------------------------------------- - inline void operator=(const ComplexDouble& other) - { - reg[0] = other.reg[0]; - reg[1] = other.reg[1]; - } - - //! load from 16byte aligned ptr - inline void operator=(double* ptr) - { - reg[0] = ptr[0]; - reg[1] = ptr[1]; - } - - // --------------------------------------------------- - // LOAD, STORE - // --------------------------------------------------- - - //! load from 16byte aligned ptr - inline void load(const double* ptr) - { - reg[0] = ptr[0]; - reg[1] = ptr[1]; - } - - //! load from unaligned ptr - inline void load_unaligned(const double* ptr) - { - reg[0] = ptr[0]; - reg[1] = ptr[1]; - } - - //! store to 16byte aligned ptr - inline void store(double* ptr) const - { - ptr[0] = reg[0]; - ptr[1] = reg[1]; - } - - //! store to unaligned ptr - inline void store_unaligned(double* ptr) const - { - ptr[0] = reg[0]; - ptr[1] = reg[1]; - } -}; - -#endif -}; - -} // end of namespace ogdf::sse - -#endif // _COMPLEX_DOUBLE_H_ - diff --git a/ext/OGDF/src/energybased/DavidsonHarel.cpp b/ext/OGDF/src/energybased/DavidsonHarel.cpp deleted file mode 100644 index 43773975a..000000000 --- a/ext/OGDF/src/energybased/DavidsonHarel.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Iimplementation of class DavidsonHarel - * - * This class realizes the Davidson Harel Algorithm for - * automtatic graph drawing. It minimizes the energy - * of the drawing using simulated annealing. This file - * contains the main simulated annealing algorithm and - * the fnction for computing the next candidate layout - * that should be considered. - * - * \author - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -//TODO: in addition to the layout size, node sizes should be used in -//the initial radius computation in case of "all central" layouts with -//huge nodes -//the combinations for parameters should be checked: its only useful -//to have a slow shrinking if you have enough time to shrink down to -//small radius - -namespace ogdf { - - const int DavidsonHarel::m_defaultTemp = 1000; - const double DavidsonHarel::m_defaultRadius = 100.0; - const int DavidsonHarel::m_iterationMultiplier = 25; //best//30;ori - const double DavidsonHarel::m_coolingFactor = 0.80; //0.75;ori - const double DavidsonHarel::m_shrinkFactor = 0.8; - - //initializes internal data and the random number generator - DavidsonHarel::DavidsonHarel(): - m_temperature(m_defaultTemp), - m_shrinkingFactor(m_shrinkFactor), - m_diskRadius(m_defaultRadius), - m_energy(0.0), - m_numberOfIterations(0) - { - srand((unsigned)time(NULL)); - } - - - //allow resetting in between subsequent calls - void DavidsonHarel::initParameters() - { - m_diskRadius = m_defaultRadius; - m_energy = 0.0; - //m_numberOfIterations = 0; //is set in member function - m_shrinkingFactor = m_shrinkFactor; - - } - - - void DavidsonHarel::setStartTemperature(int startTemp) - { - OGDF_ASSERT(startTemp >= 0); - m_temperature=startTemp; - } - - void DavidsonHarel::setNumberOfIterations(int steps) - { - OGDF_ASSERT(steps >= 0); - m_numberOfIterations = steps; - } - - //whenever an energy function is added, the initial energy of the new function - //is computed and added to the initial energy of the layout - void DavidsonHarel::addEnergyFunction(EnergyFunction *F, double weight) - { - m_energyFunctions.pushBack(F); - OGDF_ASSERT(weight >= 0); - m_weightsOfEnergyFunctions.pushBack(weight); - F->computeEnergy(); - m_energy += F->energy(); - } - - List DavidsonHarel::returnEnergyFunctionNames() - { - List names; - ListIterator it; - for(it = m_energyFunctions.begin(); it.valid(); it = it.succ()) - names.pushBack((*it)->getName()); - return names; - } - - List DavidsonHarel::returnEnergyFunctionWeights() - { - List weights; - ListIterator it; - for(it = m_weightsOfEnergyFunctions.begin(); it.valid(); it = it.succ()) - weights.pushBack(*it); - return weights; - } - - //newVal is the energy value of a candidate layout. It is accepted if it is lower - //than the previous energy of the layout or if m_fineTune is not tpFine and - //the difference to the old energy divided by the temperature is smaller than a - //random number between zero and one - bool DavidsonHarel::testEnergyValue(double newVal) - { - bool accepted = true; - if(newVal > m_energy) { - accepted = false; - - double testval = exp((m_energy-newVal)/ m_temperature); - double compareVal = randNum(); // number between 0 and 1 - - if(compareVal < testval) - accepted = true; - - } - return accepted; - } - - //divides number returned by rand by RAND_MAX to get number between zero and one - inline double DavidsonHarel::randNum() const - { - double val = rand(); - val /= RAND_MAX; - return val; - } - - //chooses random vertex and a new random position for it on a circle with radius m_diskRadius - //around its previous position - node DavidsonHarel::computeCandidateLayout( - const GraphAttributes &AG, - DPoint &newPos) const - { - int randomPos = randomNumber(0,m_nonIsolatedNodes.size()-1); - node v = *(m_nonIsolatedNodes.get(randomPos)); - double oldx = AG.x(v); - double oldy = AG.y(v); - double randomAngle = randNum() * 2.0 * Math::pi; - newPos.m_y = oldy+sin(randomAngle)*m_diskRadius; - newPos.m_x = oldx+cos(randomAngle)*m_diskRadius; -#ifdef OGDF_DEBUG - double dist = sqrt((newPos.m_x - oldx)*(newPos.m_x - oldx)+(newPos.m_y-oldy)*(newPos.m_y-oldy)); - OGDF_ASSERT(dist > 0.99 * m_diskRadius && dist < 1.01 * m_diskRadius); -#endif - return v; - } - - //chooses the initial radius of the disk as half the maximum of width and height of - //the initial layout or depending on the value of m_fineTune - void DavidsonHarel::computeFirstRadius(const GraphAttributes &AG) - { - const Graph &G = AG.constGraph(); - node v = G.firstNode(); - double minX = AG.x(v); - double minY = AG.y(v); - double maxX = minX; - double maxY = minY; - forall_nodes(v,G) { - minX = min(minX,AG.x(v)); - maxX = max(maxX,AG.x(v)); - minY = min(minY,AG.y(v)); - maxY = max(maxY,AG.y(v)); - } - // compute bounding box of current layout - // make values nonzero - double w = maxX-minX+1.0; - double h = maxY-minY+1.0; - - double ratio = h/w; - - double W = sqrt(G.numberOfNodes() / ratio); - - m_diskRadius = W / 5.0;//allow to move by a significant part of current layout size - m_diskRadius=max(m_diskRadius,max(maxX-minX,maxY-minY)/5.0); - - //TODO: also use node sizes - /* - double lengthSum(0.0); - node v; - forall_nodes(v,m_G) { - const IntersectionRectangle &i = shape(v); - lengthSum += i.width(); - lengthSum += i.width(); - } - lengthSum /= (2*m_G.numberOfNodes()); - // lengthSum is now the average of all lengths and widths - */ - //change the initial radius depending on the settings - //this is legacy crap -// double divo = 2.0; -// if (m_fineTune == tpCoarse) { -// m_diskRadius = 1000.0; -// divo = 0.5; -// } -// if (m_fineTune == tpFine) { -// m_diskRadius = 10.0; -// divo = 15.0; -// } -// //m_diskRadius=max(m_diskRadius,max(maxX-minX,maxY-minY)); -// m_diskRadius = max(maxX-minX,maxY-minY); -// m_diskRadius /= divo; - } - - //steps through all energy functions and adds the initial energy computed by each - //function for the start layout - void DavidsonHarel::computeInitialEnergy() - { - OGDF_ASSERT(!m_energyFunctions.empty()); - ListIterator it; - ListIterator it2; - it2 = m_weightsOfEnergyFunctions.begin(); - for(it = m_energyFunctions.begin(); it.valid() && it2.valid(); it=it.succ(), it2 = it2.succ()) - m_energy += (*it)->energy() * (*it2); - } - - //the vertices with degree zero are placed below all other vertices on a horizontal - // line centered with repect to the rest of the drawing - void DavidsonHarel::placeIsolatedNodes(GraphAttributes &AG) const { - double minX = 0.0; - double minY = 0.0; - double maxX = 0.0; - double maxY = 0.0; - - if(!m_nonIsolatedNodes.empty()) { - //compute a rectangle that includes all non-isolated vertices - node v = m_nonIsolatedNodes.front(); - minX = AG.x(v); - minY = AG.y(v); - maxX = minX; - maxY = minY; - ListConstIterator it; - for(it = m_nonIsolatedNodes.begin(); it.valid(); ++it) { - v = *it; - double xVal = AG.x(v); - double yVal = AG.y(v); - double halfHeight = AG.height(v) / 2.0; - double halfWidth = AG.width(v) / 2.0; - if(xVal - halfWidth < minX) minX = xVal - halfWidth; - if(xVal + halfWidth > maxX) maxX = xVal + halfWidth; - if(yVal - halfHeight < minY) minY = yVal - halfHeight; - if(yVal + halfHeight > maxY) maxY = yVal + halfHeight; - } - } - - // compute the width and height of the largest isolated node - List isolated; - node v; - const Graph &G = AG.constGraph(); - double maxWidth = 0; - double maxHeight = 0; - forall_nodes(v,G) if(v->degree() == 0) { - isolated.pushBack(v); - if(AG.height(v) > maxHeight) maxHeight = AG.height(v); - if(AG.width(v) > maxWidth) maxWidth = AG.width(v); - } - // The nodes are placed on a line in the middle under the non isolated vertices. - // Each node gets a box sized 2 maxWidth. - double boxWidth = 2.0*maxWidth; - double commonYCoord = minY-(1.5*maxHeight); - double XCenterOfDrawing = minX + ((maxX-minX)/2.0); - double startXCoord = XCenterOfDrawing - 0.5*(isolated.size()*boxWidth); - ListIterator it; - double xcoord = startXCoord; - for(it = isolated.begin(); it.valid(); ++it) { - v = *it; - AG.x(v) = xcoord; - AG.y(v) = commonYCoord; - xcoord += boxWidth; - } - } - - //this is the main optimization routine with the loop that lowers the temperature - //and the disk radius geometrically until the temperature is zero. For each - //temperature, a certain number of new positions for a random vertex are tried - void DavidsonHarel::call(GraphAttributes &AG) - { - initParameters(); - - m_shrinkingFactor = m_shrinkFactor; - - OGDF_ASSERT(!m_energyFunctions.empty()); - - const Graph &G = AG.constGraph(); - //compute the list of vertices with degree greater than zero - G.allNodes(m_nonIsolatedNodes); - ListIterator it,itSucc; - for(it = m_nonIsolatedNodes.begin(); it.valid(); it = itSucc) { - itSucc = it.succ(); - if((*it)->degree() == 0) m_nonIsolatedNodes.del(it); - } - if(G.numberOfEdges() > 0) { //else only isolated nodes - computeFirstRadius(AG); - computeInitialEnergy(); - if(m_numberOfIterations == 0) - m_numberOfIterations = m_nonIsolatedNodes.size() * m_iterationMultiplier; - //this is the main optimization loop - while(m_temperature > 0) { - //iteration loop for each temperature - for(int ic = 1; ic <= m_numberOfIterations; ic ++) { - DPoint newPos; - //choose random vertex and new position for vertex - node v = computeCandidateLayout(AG,newPos); - //compute candidate energy and decide if new layout is chosen - ListIterator it; - ListIterator it2 = m_weightsOfEnergyFunctions.begin(); - double newEnergy = 0.0; - for(it = m_energyFunctions.begin(); it.valid(); it = it.succ()) { - newEnergy += (*it)->computeCandidateEnergy(v,newPos) * (*it2); - it2 = it2.succ(); - } - OGDF_ASSERT(newEnergy >= 0.0); - //this tests if the new layout is accepted. If this is the case, - //all energy functions are informed that the new layout is accepted - if(testEnergyValue(newEnergy)) { - for(it = m_energyFunctions.begin(); it.valid(); it = it.succ()) - (*it)->candidateTaken(); - AG.x(v) = newPos.m_x; - AG.y(v) = newPos.m_y; - m_energy = newEnergy; - } - } - //lower the temperature and decrease the disk radius - m_temperature = (int)floor(m_temperature*m_coolingFactor); - m_diskRadius *= m_shrinkingFactor; - } - } - //if there are zero degree vertices, they are placed using placeIsolatedNodes - if(m_nonIsolatedNodes.size() != G.numberOfNodes()) - placeIsolatedNodes(AG); - - } -} //namespace diff --git a/ext/OGDF/src/energybased/DavidsonHarelLayout.cpp b/ext/OGDF/src/energybased/DavidsonHarelLayout.cpp deleted file mode 100644 index b48bd1a7e..000000000 --- a/ext/OGDF/src/energybased/DavidsonHarelLayout.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation for DavidsonHarelLayout - * - * This is the frontend for the DavidsonHarel optimization - * function. It adds the energy functions to the problem and - * sets their weights. It also contains functions for setting - * and returning the parameters that influence the quality of - * the solution and the speed of the optimization process. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include - - -#define DEFAULT_REPULSION_WEIGHT 1e6 -#define DEFAULT_ATTRACTION_WEIGHT 1e2 -#define DEFAULT_OVERLAP_WEIGHT 100 -#define DEFAULT_PLANARITY_WEIGHT 500 -#define DEFAULT_ITERATIONS 0 -#define DEFAULT_START_TEMPERATURE 500 - -namespace ogdf { - -struct InputValueInvalid : Exception { InputValueInvalid() : Exception(__FILE__, __LINE__) { } }; - -struct WeightLessThanZeroException : InputValueInvalid { }; - -struct IterationsNonPositive : InputValueInvalid { }; - -struct TemperatureNonPositive : InputValueInvalid { }; - - -DavidsonHarelLayout::DavidsonHarelLayout() -{ - m_repulsionWeight = DEFAULT_REPULSION_WEIGHT; - m_attractionWeight = DEFAULT_ATTRACTION_WEIGHT; - m_nodeOverlapWeight = DEFAULT_OVERLAP_WEIGHT; - m_planarityWeight = DEFAULT_PLANARITY_WEIGHT; - m_numberOfIterations = DEFAULT_ITERATIONS; - m_itAsFactor = false; - m_startTemperature = DEFAULT_START_TEMPERATURE; - m_speed = sppMedium; - m_multiplier = 2.0; - m_prefEdgeLength = 0.0; - m_crossings = false; -} - - -void DavidsonHarelLayout::fixSettings(SettingsParameter sp) -{ - double r, a, p, o; - switch (sp) { - case spStandard: - r = 900; a = 250; o = 1450; p = 300; m_crossings = false; - break; - case spRepulse: - r = 9000; a = 250; o = 1450; p = 300; m_crossings = false; - break; - case spPlanar: - r = 900; a = 250; o = 1450; p = 3000; m_crossings = true; - break; - default: - OGDF_THROW_PARAM(AlgorithmFailureException, afcIllegalParameter); - }//switch - setRepulsionWeight(r); - setAttractionWeight(a); - setNodeOverlapWeight(o); - setPlanarityWeight(p); -}//fixSettings - - -void DavidsonHarelLayout::setSpeed(SpeedParameter sp) -{ - m_speed = sp; - m_numberOfIterations = 0; -}//setSpeed - - -void DavidsonHarelLayout::setRepulsionWeight(double w) -{ - if(w < 0) throw WeightLessThanZeroException(); - else m_repulsionWeight = w; -} - - -void DavidsonHarelLayout::setAttractionWeight(double w) -{ - if(w < 0) throw WeightLessThanZeroException(); - else m_attractionWeight = w; -} - - -void DavidsonHarelLayout::setNodeOverlapWeight(double w) -{ - if(w < 0) throw WeightLessThanZeroException(); - else m_nodeOverlapWeight = w; -} - - -void DavidsonHarelLayout::setPlanarityWeight(double w) -{ - if(w < 0) throw WeightLessThanZeroException(); - else m_planarityWeight = w; -} - - -void DavidsonHarelLayout::setNumberOfIterations(int w) -{ - if(w < 0) throw IterationsNonPositive(); - else m_numberOfIterations = w; -} - - -void DavidsonHarelLayout::setStartTemperature (int w) -{ - if(w < 0) throw TemperatureNonPositive(); - else m_startTemperature = w; -} - - -//this sets the parameters of the class DavidsonHarel, adds the energy functions and -//starts the optimization process -void DavidsonHarelLayout::call(GraphAttributes &AG) -{ - // all edges straight-line - AG.clearAllBends(); - - DavidsonHarel dh; - Repulsion rep(AG); - Attraction atr(AG); - Overlap over(AG); - Planarity plan(AG); - //PlanarityGrid plan(AG); - //PlanarityGrid2 plan(AG); - //NodeIntersection ni(AG); - - // Either use a fixed value... - if (DIsGreater(m_prefEdgeLength, 0.0)) - { - atr.setPreferredEdgelength(m_prefEdgeLength); - } - // ...or set it depending on vertex sizes - else atr.reinitializeEdgeLength(m_multiplier); - - - dh.addEnergyFunction(&rep,m_repulsionWeight); - dh.addEnergyFunction(&atr,m_attractionWeight); - dh.addEnergyFunction(&over,m_nodeOverlapWeight); - if (m_crossings) dh.addEnergyFunction(&plan,m_planarityWeight); - //dh.addEnergyFunction(&ni,2000.0); - - //dh.setNumberOfIterations(m_numberOfIterations); - //dh.setStartTemperature(m_startTemperature); - const Graph& G = AG.constGraph(); - //TODO: Number of iterations always depending on size - if (m_numberOfIterations == 0) - { - switch (m_speed) //todo: function setSpeedParameters - { - case sppFast: - m_numberOfIterations = max(75, 3*G.numberOfNodes()); - m_startTemperature = 400; - break; - case sppMedium: - m_numberOfIterations = 10*G.numberOfNodes(); - m_startTemperature = 1500; - break; - case sppHQ: - m_numberOfIterations = 2500*G.numberOfNodes(); //should be: isolate - m_startTemperature = 2000; - break; - default: - OGDF_THROW_PARAM(AlgorithmFailureException, afcIllegalParameter); - }//switch - }//if - else - { - if (m_itAsFactor) - dh.setNumberOfIterations(200+m_numberOfIterations*G.numberOfNodes()); - else - dh.setNumberOfIterations(m_numberOfIterations); - } - dh.setStartTemperature(m_startTemperature); - dh.call(AG); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/Edge.h b/ext/OGDF/src/energybased/Edge.h deleted file mode 100644 index c4c3d2a58..000000000 --- a/ext/OGDF/src/energybased/Edge.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Edge. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_EDGE_H -#define OGDF_EDGE_H - - -#include - - -namespace ogdf { - -class Edge -{ - //helping data structure for deleting parallel edges in class FMMMLayout and - //Multilevel (needed for the bucket sort algorithm) - - //outputstream for Edge - friend ostream &operator<< (ostream & output, const Edge & E) - { - output <<"edge_index " << E.e->index() << " Graph_ptr " << E.Graph_ptr << " angle" - << E.angle << " cut vertex " << E.cut_vertex->index(); - return output; - } - - //inputstream for Edge - friend istream &operator>> (istream & input, Edge & E) - { - input >> E;//.e>>E.Graph_ptr; - return input; - } - -public: - //constructor - Edge() { - e = NULL; - Graph_ptr = NULL; - angle = 0; - cut_vertex = NULL; - } - - ~Edge() { } //destructor - - void set_Edge (edge f,Graph* g_ptr) { - Graph_ptr = g_ptr; - e = f; - } - - void set_Edge(edge f,double i,node c) { - angle = i; - e = f; - cut_vertex = c; - } - - Graph* get_Graph_ptr() const { return Graph_ptr; } - edge get_edge() const { return e; } - double get_angle() const { return angle; } - node get_cut_vertex() const { return cut_vertex; } - -private: - edge e; - Graph* Graph_ptr; - double angle; - node cut_vertex; -}; - - -class EdgeMaxBucketFunc : public BucketFunc -{ -public: - EdgeMaxBucketFunc() {}; - - int getBucket(const Edge& E) { return get_max_index(E); } - -private: - //returns the maximum index of e - int get_max_index(const Edge& E) { - int source_index = E.get_edge()->source()->index(); - int target_index = E.get_edge()->target()->index(); - OGDF_ASSERT(source_index != target_index); - if(source_index < target_index) return target_index; - else /*if (source_index > target_index)*/ return source_index; - //else cout<<"Error Edge::get_max_index() The Graph has a self loop"< -{ -public: - EdgeMinBucketFunc() { } - - int getBucket(const Edge& E) { return get_min_index(E); } - -private: - - //returns the minimum index of e - int get_min_index(const Edge& E) - { - int source_index = E.get_edge()->source()->index(); - int target_index = E.get_edge()->target()->index(); - OGDF_ASSERT(source_index != target_index); - if(source_index < target_index) return source_index; - else /*if (source_index > target_index)*/ return target_index; - //else cout<<"Error Edge::get_min_index() The Graph has a self loop"< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - -ostream &operator<< (ostream & output, const EdgeAttributes & A) -{ - output <<"length: "<< A.length; - output<<" index of original edge "; - if (A.e_original == NULL) - output <<"NULL"; - else output<index(); - output<<" index of subgraph edge "; - if (A.e_subgraph == NULL) - output <<"NULL"; - if (A.moon_edge) - output<<" is moon edge "; - else - output <<" no moon edge "; - if (A.extra_edge) - output<<" is extra edge "; - else - output <<" no extra edge "; - return output; -} - - -istream &operator>> (istream & input, EdgeAttributes & A) -{ - input >> A.length; - return input; -} - - -EdgeAttributes::EdgeAttributes() -{ - length = 0; - e_original = NULL; - e_subgraph = NULL; - moon_edge = false; - extra_edge = false; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/EnergyFunction.cpp b/ext/OGDF/src/energybased/EnergyFunction.cpp deleted file mode 100644 index 604c5dcc1..000000000 --- a/ext/OGDF/src/energybased/EnergyFunction.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class EnergyFunction. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - -EnergyFunction::EnergyFunction(const String &funcname, GraphAttributes &AG) : - m_G(AG.constGraph()), - m_name(funcname), - m_candidateEnergy(0), - m_energy(0), - m_AG(AG), - m_testNode(NULL), - m_testPos(0.0,0.0) { } - - -void EnergyFunction::candidateTaken() -{ - m_energy=m_candidateEnergy; - m_candidateEnergy = 0.0; - m_AG.x(m_testNode)=m_testPos.m_x; - m_AG.y(m_testNode)=m_testPos.m_y; - m_testPos = DPoint(0.0,0.0); - internalCandidateTaken(); - m_testNode=NULL; -} - - -double EnergyFunction::computeCandidateEnergy(const node v, const DPoint &testPos) -{ - m_testPos = testPos; - m_testNode = v; - compCandEnergy(); - OGDF_ASSERT(m_candidateEnergy >= 0.0); - return m_candidateEnergy; -} - - -#ifdef OGDF_DEBUG -void EnergyFunction::printStatus() const{ - cout << "\nEnergy function name: " << m_name; - cout << "\nCurrent energy: " << m_energy; - node v; - cout << "\nPosition of nodes in current solution:"; - NodeArray num(m_G); - int count = 1; - forall_nodes(v,m_G) num[v] = count ++; - forall_nodes(v,m_G) { - cout << "\nNode: " << num[v] << " Position: " << currentPos(v); - } - cout << "\nTest Node: " << m_testNode << " New coordinates: " << m_testPos; - cout << "\nCandidate energy: " << m_candidateEnergy; - printInternalData(); -} -#endif - -} //namespace diff --git a/ext/OGDF/src/energybased/FMEFunc.h b/ext/OGDF/src/energybased/FMEFunc.h deleted file mode 100644 index 9338fd550..000000000 --- a/ext/OGDF/src/energybased/FMEFunc.h +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definitions of various auxiliary classes for FME layout. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FME_FUNC_H -#define OGDF_FME_FUNC_H - -#include "ArrayGraph.h" -#include "LinearQuadtree.h" -#include "LinearQuadtreeExpansion.h" -#include "LinearQuadtreeBuilder.h" -#include "WSPD.h" -#include "FMEKernel.h" -#include - -namespace ogdf { - -//! struct for distributing subtrees to the threads -struct FMETreePartition -{ - std::list nodes; - __uint32 pointCount; - - template - void for_loop(Func& func) - { - for (std::list<__uint32>::const_iterator it = nodes.begin();it!=nodes.end(); it++) - func(*it); - } -}; - -struct FMENodeChainPartition -{ - __uint32 begin; - __uint32 numNodes; -}; - - -//! the main global options for a run -struct FMEGlobalOptions -{ - float preProcTimeStep; //!< time step factor for the preprocessing step - float preProcEdgeForceFactor; //!< edge force factor for the preprocessing step - __uint32 preProcMaxNumIterations; //!< number of iterations the preprocessing is applied - - float timeStep; //!< time step factor for the main step - float edgeForceFactor; //!< edge force factor for the main step - float repForceFactor; //!< repulsive force factor for the main step - float normEdgeLength; //!< average edge length when desired edge length are normalized - float normNodeSize; //!< average node size when node sizes are normalized - __uint32 maxNumIterations; //!< maximum number of iterations in the main step - __uint32 minNumIterations; //!< minimum number of iterations to be done regardless of any other conditions - - bool doPrepProcessing; //!< enable preprocessing - bool doPostProcessing; //!< enable postprocessing - - double stopCritForce; //!< stopping criteria - double stopCritAvgForce; //!< stopping criteria - double stopCritConstSq; //!< stopping criteria - - __uint32 multipolePrecision; -}; - - -//! forward decl of local context struct -struct FMELocalContext; - -/*! - * Global Context -*/ -struct FMEGlobalContext -{ - FMELocalContext** pLocalContext; //!< all local contexts - __uint32 numThreads; //!< number of threads, local contexts - ArrayGraph* pGraph; //!< pointer to the array graph - LinearQuadtree* pQuadtree; //!< pointer to the quadtree - LinearQuadtreeExpansion* pExpansion; //!< pointer to the coeefficients - WSPD* pWSPD; //!< pointer to the well separated pairs decomposition - float* globalForceX; //!< the global node force x array - float* globalForceY; //!< the global node force y array - FMEGlobalOptions* pOptions; //!< pointer to the global options - bool earlyExit; //!< var for the main thread to notify the other threads that they are done - float scaleFactor; //!< var - float coolDown; - float min_x; //!< global point, node min x coordinate for bounding box calculations - float max_x; //!< global point, node max x coordinate for bounding box calculations - float min_y; //!< global point, node min y coordinate for bounding box calculations - float max_y; //!< global point, node max y coordinate for bounding box calculations - double currAvgEdgeLength; -}; - - -/*! - * Local Thread Context -*/ -struct FMELocalContext -{ - FMEGlobalContext* pGlobalContext; //!< pointer to the global context - float* forceX; //!< local force array for all nodes, points - float* forceY; //!< local force array for all nodes, points - double maxForceSq; //!< local maximum force - double avgForce; //!< local maximum force - float min_x; //!< global point, node min x coordinate for bounding box calculations - float max_x; //!< global point, node max x coordinate for bounding box calculations - float min_y; //!< global point, node min y coordinate for bounding box calculations - float max_y; //!< global point, node max y coordinate for bounding box calculations - double currAvgEdgeLength; - FMETreePartition treePartition; //!< tree partition assigned to the thread - FMENodeChainPartition innerNodePartition; //!< chain of inner nodes assigned to the thread - FMENodeChainPartition leafPartition; //!< chain of leaf nodes assigned to the thread - - LinearQuadtree::NodeID firstInnerNode; //!< first inner nodes the thread prepared - LinearQuadtree::NodeID lastInnerNode; //!< last inner nodes the thread prepared - __uint32 numInnerNodes; //!< number of inner nodes the thread prepared - - LinearQuadtree::NodeID firstLeaf; //!< first leaves the thread prepared - LinearQuadtree::NodeID lastLeaf; //!< last leaves the thread prepared - __uint32 numLeaves; //!< number of leaves the thread prepared -}; - - -//! creates a min max functor for the x coords of the node -static inline min_max_functor min_max_x_function(FMELocalContext* pLocalContext) -{ - return min_max_functor(pLocalContext->pGlobalContext->pGraph->nodeXPos(), pLocalContext->min_x, pLocalContext->max_x); -} - -//! creates a min max functor for the y coords of the node -static inline min_max_functor min_max_y_function(FMELocalContext* pLocalContext) -{ - return min_max_functor(pLocalContext->pGlobalContext->pGraph->nodeYPos(), pLocalContext->min_y, pLocalContext->max_y); -} - -class LQMortonFunctor -{ -public: - inline LQMortonFunctor ( FMELocalContext* pLocalContext ) - { - x = pLocalContext->pGlobalContext->pGraph->nodeXPos(); - y = pLocalContext->pGlobalContext->pGraph->nodeYPos(); - s = pLocalContext->pGlobalContext->pGraph->nodeSize(); - quadtree = pLocalContext->pGlobalContext->pQuadtree; - translate_x = -quadtree->minX(); - translate_y = -quadtree->minY(); - scale = quadtree->scaleInv(); - } - - inline __uint32 operator()(void) const - { - return quadtree->numberOfPoints(); - } - - inline void operator()(__uint32 i) - { - LinearQuadtree::LQPoint& p = quadtree->point(i); - __uint32 ref = p.ref; - p.mortonNr = mortonNumber<__uint64, __uint32>((__uint32)((x[ref] + translate_x)*scale), (__uint32)((y[ref] + translate_y)*scale)); - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - LinearQuadtree* quadtree; - float translate_x; - float translate_y; - double scale; - float* x; - float* y; - float* s; -}; - - -//! Point-to-Multipole functor -struct p2m_functor -{ - const LinearQuadtree& tree; - LinearQuadtreeExpansion& expansions; - - p2m_functor(const LinearQuadtree& t, LinearQuadtreeExpansion& e) : tree(t), expansions(e) { } - - inline void operator()(LinearQuadtree::NodeID nodeIndex) - { - __uint32 numPointsInLeaf = tree.numberOfPoints(nodeIndex); - __uint32 firstPointOfLeaf = tree.firstPoint(nodeIndex); - for (__uint32 pointIndex=firstPointOfLeaf; pointIndex < (firstPointOfLeaf+numPointsInLeaf); pointIndex++) - { - expansions.P2M(pointIndex, nodeIndex); - } - } -}; - - -//! creates a Point-to-Multipole functor -static inline p2m_functor p2m_function(FMELocalContext* pLocalContext) -{ - return p2m_functor(*pLocalContext->pGlobalContext->pQuadtree, *pLocalContext->pGlobalContext->pExpansion); -} - - -//! Multipole-to-Multipole functor -struct m2m_functor -{ - const LinearQuadtree& tree; - LinearQuadtreeExpansion& expansions; - - m2m_functor(const LinearQuadtree& t, LinearQuadtreeExpansion& e) : tree(t), expansions(e) { } - - inline void operator()(LinearQuadtree::NodeID parent, LinearQuadtree::NodeID child) - { - expansions.M2M(child, parent); - } - - inline void operator()(LinearQuadtree::NodeID nodeIndex) - { - tree.forall_children(pair_call(*this, nodeIndex))(nodeIndex); - } -}; - - -//! creates Multipole-to-Multipole functor -static inline m2m_functor m2m_function(FMELocalContext* pLocalContext) -{ - return m2m_functor(*pLocalContext->pGlobalContext->pQuadtree, *pLocalContext->pGlobalContext->pExpansion); -} - - -//! Multipole-to-Local functor -struct m2l_functor -{ - LinearQuadtreeExpansion& expansions; - - m2l_functor(LinearQuadtreeExpansion& e) : expansions(e) { } - - inline void operator()(LinearQuadtree::NodeID nodeIndexSource, LinearQuadtree::NodeID nodeIndexReceiver) - { - expansions.M2L(nodeIndexSource, nodeIndexReceiver); - } -}; - - -//! creates Multipole-to-Local functor -static inline m2l_functor m2l_function(FMELocalContext* pLocalContext) -{ - return m2l_functor(*pLocalContext->pGlobalContext->pExpansion); -} - - -//! Local-to-Local functor -struct l2l_functor -{ - const LinearQuadtree& tree; - LinearQuadtreeExpansion& expansions; - - l2l_functor(const LinearQuadtree& t, LinearQuadtreeExpansion& e) : tree(t), expansions(e) { } - - inline void operator()(LinearQuadtree::NodeID parent, LinearQuadtree::NodeID child) - { - expansions.L2L(parent, child); - } - - inline void operator()(LinearQuadtree::NodeID nodeIndex) - { - tree.forall_children(pair_call(*this, nodeIndex))(nodeIndex); - } -}; - - -//! creates Local-to-Local functor -static inline l2l_functor l2l_function(FMELocalContext* pLocalContext) -{ - return l2l_functor(*pLocalContext->pGlobalContext->pQuadtree, *pLocalContext->pGlobalContext->pExpansion); -} - - -//! Local-to-Point functor -struct l2p_functor -{ - const LinearQuadtree& tree; - LinearQuadtreeExpansion& expansions; - float* fx; - float* fy; - - l2p_functor(const LinearQuadtree& t, LinearQuadtreeExpansion& e, float* x, float* y) : tree(t), expansions(e), fx(x), fy(y) { } - - inline void operator()(LinearQuadtree::NodeID nodeIndex, LinearQuadtree::PointID pointIndex) - { - expansions.L2P(nodeIndex, pointIndex, fx[pointIndex], fy[pointIndex]); - } - - inline void operator()(LinearQuadtree::PointID pointIndex) - { - LinearQuadtree::NodeID nodeIndex = tree.pointLeaf(pointIndex); - this->operator ()(nodeIndex, pointIndex); - } -}; - - -//! creates Local-to-Point functor -static inline l2p_functor l2p_function(FMELocalContext* pLocalContext) -{ - return l2p_functor(*pLocalContext->pGlobalContext->pQuadtree, *pLocalContext->pGlobalContext->pExpansion, pLocalContext->forceX, pLocalContext->forceY); -} - - -//! Local-to-Point functor -struct p2p_functor -{ - const LinearQuadtree& tree; - float* fx; - float* fy; - - p2p_functor(const LinearQuadtree& t, float* x, float* y) : tree(t), fx(x), fy(y) { } - - inline void operator()(LinearQuadtree::NodeID nodeIndexA, LinearQuadtree::NodeID nodeIndexB) - { - __uint32 offsetA = tree.firstPoint(nodeIndexA); - __uint32 offsetB = tree.firstPoint(nodeIndexB); - __uint32 numPointsA = tree.numberOfPoints(nodeIndexA); - __uint32 numPointsB = tree.numberOfPoints(nodeIndexB); - eval_direct_fast(tree.pointX() + offsetA, tree.pointY() + offsetA, tree.pointSize() + offsetA, fx + offsetA, fy + offsetA, numPointsA, - tree.pointX() + offsetB, tree.pointY() + offsetB, tree.pointSize() + offsetB, fx + offsetB, fy + offsetB, numPointsB); - } - - inline void operator()(LinearQuadtree::NodeID nodeIndex) - { - __uint32 offset = tree.firstPoint(nodeIndex); - __uint32 numPoints = tree.numberOfPoints(nodeIndex); - eval_direct_fast(tree.pointX() + offset, tree.pointY() + offset, tree.pointSize() + offset, fx + offset, fy + offset, numPoints); - } -}; - - -//! creates Local-to-Point functor -static inline p2p_functor p2p_function(FMELocalContext* pLocalContext) -{ - return p2p_functor(*pLocalContext->pGlobalContext->pQuadtree, pLocalContext->forceX, pLocalContext->forceY); -} - - -//! The partitioner which partitions the quadtree into subtrees and partitions the sequence of inner nodes and leaves -class LQPartitioner -{ -public: - LQPartitioner( FMELocalContext* pLocalContext ) - { - numThreads = pLocalContext->pGlobalContext->numThreads; - tree = pLocalContext->pGlobalContext->pQuadtree; - localContexts = pLocalContext->pGlobalContext->pLocalContext; - } - - void partitionNodeChains() - { - __uint32 numInnerNodesPerThread = tree->numberOfInnerNodes() / numThreads; - if (numInnerNodesPerThread < 25) - { - localContexts[0]->innerNodePartition.begin = tree->firstInnerNode(); - localContexts[0]->innerNodePartition.numNodes = tree->numberOfInnerNodes(); - for (__uint32 i=1; i< numThreads; i++) - { - localContexts[i]->innerNodePartition.numNodes = 0; - } - } else - { - - LinearQuadtree::NodeID curr = tree->firstInnerNode(); - currThread = 0; - localContexts[0]->innerNodePartition.begin = curr; - localContexts[0]->innerNodePartition.numNodes = 0; - for (__uint32 i=0; i< tree->numberOfInnerNodes(); i++) - { - localContexts[currThread]->innerNodePartition.numNodes++; - curr = tree->nextNode(curr); - if ((localContexts[currThread]->innerNodePartition.numNodes>=numInnerNodesPerThread) && (currThread < numThreads-1)) - { - currThread++; - localContexts[currThread]->innerNodePartition.numNodes = 0; - localContexts[currThread]->innerNodePartition.begin = curr; - } - } - - } - - __uint32 numLeavesPerThread = tree->numberOfLeaves() / numThreads; - if (numLeavesPerThread < 25) - { - localContexts[0]->leafPartition.begin = tree->firstLeaf(); - localContexts[0]->leafPartition.numNodes = tree->numberOfLeaves(); - for (__uint32 i=1; i< numThreads; i++) - { - localContexts[i]->leafPartition.numNodes = 0; - } - } else - { - LinearQuadtree::NodeID curr = tree->firstLeaf(); - currThread = 0; - localContexts[0]->leafPartition.begin = curr; - localContexts[0]->leafPartition.numNodes = 0; - for (__uint32 i=0; i< tree->numberOfLeaves(); i++) - { - localContexts[currThread]->leafPartition.numNodes++; - curr = tree->nextNode(curr); - if ((localContexts[currThread]->leafPartition.numNodes>=numLeavesPerThread) && (currThread < numThreads-1)) - { - currThread++; - localContexts[currThread]->leafPartition.numNodes = 0; - localContexts[currThread]->leafPartition.begin = curr; - } - } - } - } - - void partition() - { - partitionNodeChains(); - currThread = 0; - numPointsPerThread = tree->numberOfPoints() / numThreads; - for (__uint32 i=0; i < numThreads; i++) - { - localContexts[i]->treePartition.nodes.clear(); - localContexts[i]->treePartition.pointCount = 0; - } - if (numThreads>1) - newPartition(); - } - - void newPartition(__uint32 node) - { - __uint32 bound = tree->numberOfPoints() / (numThreads*numThreads); - - if (tree->isLeaf(node) || (tree->numberOfPoints(node) < bound)) - l_par.push_back(node); - else - for (__uint32 i = 0; i < tree->numberOfChilds(node); i++) - newPartition(tree->child(node, i)); - } - - void newPartition() - { - l_par.clear(); - newPartition(tree->root()); - __uint32 bound = (tree->numberOfPoints() / (numThreads)) + (tree->numberOfPoints() / (numThreads*numThreads*2)); - while (!l_par.empty()) - { - FMETreePartition* partition = currPartition(); - __uint32 v = l_par.front(); - if (((partition->pointCount + tree->numberOfPoints(v)) <= bound) || - (currThread==numThreads-1)) - { - partition->pointCount += tree->numberOfPoints(v); - partition->nodes.push_back(v); - tree->nodeFence(v); - l_par.pop_front(); - } else - { - currThread++; - } - } - } - - FMETreePartition* currPartition() - { - return &localContexts[currThread]->treePartition; - } - -private: - __uint32 numPointsPerThread; - __uint32 numThreads; - __uint32 currThread; - __uint32 currPointCount; - std::list<__uint32> l_par; - LinearQuadtree* tree; - FMELocalContext** localContexts; -}; - - -class LQPointUpdateFunctor -{ -public: - inline LQPointUpdateFunctor ( FMELocalContext* pLocalContext ) - { - x = pLocalContext->pGlobalContext->pGraph->nodeXPos(); - y = pLocalContext->pGlobalContext->pGraph->nodeYPos(); - s = pLocalContext->pGlobalContext->pGraph->nodeSize(); - quadtree = pLocalContext->pGlobalContext->pQuadtree; - } - - inline __uint32 operator()(void) const - { - return quadtree->numberOfPoints(); - } - - inline void operator()(__uint32 i) - { - LinearQuadtree::LQPoint& p = quadtree->point(i); - __uint32 ref = p.ref; - quadtree->setPoint(i, x[ref], y[ref], s[ref]); - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - LinearQuadtree* quadtree; - float* x; - float* y; - float* s; -}; - - -/*! - * Computes the coords and size of the i-th node in the LinearQuadtree - */ -class LQCoordsFunctor -{ -public: - inline LQCoordsFunctor( FMELocalContext* pLocalContext ) - { - quadtree = pLocalContext->pGlobalContext->pQuadtree; - quadtreeExp = pLocalContext->pGlobalContext->pExpansion; - } - - inline __uint32 operator()(void) const - { - return quadtree->numberOfNodes(); - } - - inline void operator()( __uint32 i ) - { - quadtree->computeCoords(i); - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - LinearQuadtree* quadtree; - LinearQuadtreeExpansion* quadtreeExp; -}; - - -/*! - * Converts the multipole expansion coefficients from all nodes which are well separated from the i-th node - * to local expansion coefficients and adds them to the local expansion coefficients of the i-th node - */ -class M2LFunctor -{ -public: - inline M2LFunctor( FMELocalContext* pLocalContext ) - { - quadtree = pLocalContext->pGlobalContext->pQuadtree; - quadtreeExp = pLocalContext->pGlobalContext->pExpansion; - wspd = pLocalContext->pGlobalContext->pWSPD; - } - - inline __uint32 operator()(void) const - { - return quadtree->numberOfNodes(); - } - - inline void operator()(__uint32 i) - { - __uint32 currEntryIndex = wspd->firstPairEntry(i); - for (__uint32 k = 0; k < wspd->numWSNodes(i); k++) - { - __uint32 j = wspd->wsNodeOfPair(currEntryIndex, i); - quadtreeExp->M2L(j, i); - currEntryIndex = wspd->nextPair(currEntryIndex, i); - } - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - LinearQuadtree* quadtree; - LinearQuadtreeExpansion* quadtreeExp; - WSPD* wspd; -}; - - -/*! - * Calculates the repulsive forces acting between all nodes inside the cell of the i-th LinearQuadtree node. - */ -class NDFunctor -{ -public: - inline NDFunctor( FMELocalContext* pLocalContext ) - { - quadtree = pLocalContext->pGlobalContext->pQuadtree; - quadtreeExp = pLocalContext->pGlobalContext->pExpansion; - forceArrayX = pLocalContext->forceX; - forceArrayY = pLocalContext->forceY; - } - - inline __uint32 operator()(void) const - { - return quadtree->numberOfDirectNodes(); - } - - inline void operator()(__uint32 i) - { - __uint32 node = quadtree->directNode(i); - __uint32 offset = quadtree->firstPoint(node); - __uint32 numPoints = quadtree->numberOfPoints(node); - eval_direct_fast(quadtree->pointX() + offset, quadtree->pointY() + offset, quadtree->pointSize() + offset, forceArrayX + offset, forceArrayY + offset, numPoints); - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - LinearQuadtree* quadtree; - LinearQuadtreeExpansion* quadtreeExp; - float* forceArrayX; - float* forceArrayY; -}; - - -/*! - * Calculates the repulsive forces acting between all nodes of the direct interacting cells of the i-th node - */ -class D2DFunctor -{ -public: - inline D2DFunctor( FMELocalContext* pLocalContext ) - { - quadtree = pLocalContext->pGlobalContext->pQuadtree; - quadtreeExp = pLocalContext->pGlobalContext->pExpansion; - forceArrayX = pLocalContext->forceX; - forceArrayY = pLocalContext->forceY; - } - - inline __uint32 operator()(void) const - { - return quadtree->numberOfDirectPairs(); - } - - inline void operator()(__uint32 i) - { - __uint32 nodeA = quadtree->directNodeA(i); - __uint32 nodeB = quadtree->directNodeB(i); - __uint32 offsetA = quadtree->firstPoint(nodeA); - __uint32 offsetB = quadtree->firstPoint(nodeB); - __uint32 numPointsA = quadtree->numberOfPoints(nodeA); - __uint32 numPointsB = quadtree->numberOfPoints(nodeB); - eval_direct_fast(quadtree->pointX() + offsetA, quadtree->pointY() + offsetA, quadtree->pointSize() + offsetA, forceArrayX + offsetA, forceArrayY + offsetA, numPointsA, - quadtree->pointX() + offsetB, quadtree->pointY() + offsetB, quadtree->pointSize() + offsetB, forceArrayX + offsetB, forceArrayY + offsetB, numPointsB); - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - LinearQuadtree* quadtree; - LinearQuadtreeExpansion* quadtreeExp; - float* forceArrayX; - float* forceArrayY; -}; - - -enum -{ - EDGE_FORCE_SUB_REP = 0x2, - EDGE_FORCE_DIV_DEGREE = 0x8 -}; - - -template -class EdgeForceFunctor -{ -public: - inline EdgeForceFunctor( FMELocalContext* pLocalContext ) - { - pGraph = pLocalContext->pGlobalContext->pGraph; - x = pGraph->nodeXPos(); - y = pGraph->nodeYPos(); - edgeInfo = pGraph->edgeInfo(); - nodeInfo = pGraph->nodeInfo(); - desiredEdgeLength = pGraph->desiredEdgeLength(); - nodeSize = pGraph->nodeSize(); - forceArrayX = pLocalContext->forceX; - forceArrayY = pLocalContext->forceY; - } - - inline __uint32 operator()(void) const - { - return pGraph->numEdges(); - } - - inline void operator()(__uint32 i) - { - const EdgeAdjInfo& e_info = edgeInfo[i]; - const NodeAdjInfo& a_info = nodeInfo[e_info.a]; - const NodeAdjInfo& b_info = nodeInfo[e_info.b]; - - float d_x = x[e_info.a] - x[e_info.b]; - float d_y = y[e_info.a] - y[e_info.b]; - float d_sq = d_x*d_x + d_y*d_y; - - float f = (float)(logf(d_sq)*0.5f-logf(desiredEdgeLength[i])); - - float fa = f*0.25f; - float fb = f*0.25f; - - if (FLAGS & EDGE_FORCE_DIV_DEGREE) - { - fa = (float)(fa/((float)a_info.degree)); - fb = (float)(fb/((float)b_info.degree)); - } - - if (FLAGS & EDGE_FORCE_SUB_REP) - { - fa += (nodeSize[e_info.b] / d_sq); - fb += (nodeSize[e_info.a] / d_sq); - } - forceArrayX[e_info.a] -= fa*d_x; - forceArrayY[e_info.a] -= fa*d_y; - forceArrayX[e_info.b] += fb*d_x; - forceArrayY[e_info.b] += fb*d_y; - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - float* x; - float* y; - EdgeAdjInfo* edgeInfo; - NodeAdjInfo* nodeInfo; - - ArrayGraph* pGraph; - float* desiredEdgeLength; - float* nodeSize; - float* forceArrayX; - float* forceArrayY; -}; - - -template -static inline EdgeForceFunctor edge_force_function( FMELocalContext* pLocalContext ) -{ - return EdgeForceFunctor( pLocalContext ); -} - - -enum -{ - COLLECT_NO_FACTOR = 0x00, - COLLECT_EDGE_FACTOR = 0x01, - COLLECT_REPULSIVE_FACTOR = 0x02, - COLLECT_EDGE_FACTOR_PREP = 0x04, - COLLECT_TREE_2_GRAPH_ORDER = 0x08, - COLLECT_ZERO_THREAD_ARRAY = 0x10 -}; - - -template -class CollectForceFunctor -{ -public: - - inline CollectForceFunctor( FMELocalContext* pLocalContext ) - { - numContexts = pLocalContext->pGlobalContext->numThreads; - globalContext = pLocalContext->pGlobalContext; - localContexts = pLocalContext->pGlobalContext->pLocalContext; - globalArrayX = globalContext->globalForceX; - globalArrayY = globalContext->globalForceY; - pGraph = pLocalContext->pGlobalContext->pGraph; - if (FLAGS & COLLECT_EDGE_FACTOR) - factor = pLocalContext->pGlobalContext->pOptions->edgeForceFactor; - else - if (FLAGS & COLLECT_REPULSIVE_FACTOR) - factor = pLocalContext->pGlobalContext->pOptions->repForceFactor; - else - if (FLAGS & COLLECT_EDGE_FACTOR_PREP) - factor = pLocalContext->pGlobalContext->pOptions->preProcEdgeForceFactor; - else - factor = 1.0; - } - - inline __uint32 operator()(void) const - { - return pGraph->numNodes(); - } - - - inline void operator()(__uint32 i) - { - float sumX = 0.0f; - float sumY = 0.0f; - for (__uint32 j=0; j < numContexts; j++) - { - float* localArrayX = localContexts[j]->forceX; - float* localArrayY = localContexts[j]->forceY; - sumX += localArrayX[i]; - sumY += localArrayY[i]; - if (FLAGS & COLLECT_ZERO_THREAD_ARRAY) - { - localArrayX[i] = 0.0f; - localArrayY[i] = 0.0f; - } - } - - if (FLAGS & COLLECT_TREE_2_GRAPH_ORDER) - { - __uint32 l = (globalContext->pQuadtree->refOfPoint(i)); - if (FLAGS & COLLECT_REPULSIVE_FACTOR) - { - // prevent some evil effects - if (pGraph->nodeInfo(l).degree > 100) - { - sumX /= (float)pGraph->nodeInfo(l).degree; - sumY /= (float)pGraph->nodeInfo(l).degree; - } - } - globalArrayX[l] += sumX*factor; - globalArrayY[l] += sumY*factor; - - } - else - { - if (FLAGS & COLLECT_REPULSIVE_FACTOR) - { - // prevent some evil effects - if (pGraph->nodeInfo(i).degree > 100) - { - sumX /= (float)pGraph->nodeInfo(i).degree; - sumY /= (float)pGraph->nodeInfo(i).degree; - } - } - globalArrayX[i] += sumX*factor; - globalArrayY[i] += sumY*factor; - } - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - ArrayGraph* pGraph; - FMEGlobalContext* globalContext; - FMELocalContext** localContexts; - float* globalArrayX; - float* globalArrayY; - __uint32 numContexts; - float factor; -}; - - -template -static inline CollectForceFunctor collect_force_function( FMELocalContext* pLocalContext ) -{ - return CollectForceFunctor( pLocalContext ); -} - - -enum { - TIME_STEP_NORMAL = 0x1, - TIME_STEP_PREP = 0x2, - ZERO_GLOBAL_ARRAY = 0x4, - USE_NODE_MOVE_RAD = 0x8 -}; - -template -class NodeMoveFunctor -{ -public: - inline NodeMoveFunctor( FMELocalContext* pLocalContext )// float* xCoords, float* yCoords, float ftimeStep, float* globalForceArray): x(xCoords), y(yCoords), timeStep(ftimeStep), forceArray(globalForceArray) - { - if (FLAGS & TIME_STEP_NORMAL) - timeStep = pLocalContext->pGlobalContext->pOptions->timeStep * pLocalContext->pGlobalContext->coolDown; - else - if (FLAGS & TIME_STEP_PREP) - timeStep = pLocalContext->pGlobalContext->pOptions->preProcTimeStep; - else - timeStep = 1.0; - pGraph = pLocalContext->pGlobalContext->pGraph; - x = pGraph->nodeXPos(); - y = pGraph->nodeYPos(); - nodeMoveRadius = pGraph->nodeMoveRadius(); - forceArrayX = pLocalContext->pGlobalContext->globalForceX; - forceArrayY = pLocalContext->pGlobalContext->globalForceY; - localContext = pLocalContext; - currentEdgeLength = pLocalContext->pGlobalContext->pGraph->desiredEdgeLength(); - } - -/* inline void operator()(void) const - { - return pGraph->numNodes(); - }; */ - - inline void operator()(__uint32 i) - { - float d_x = forceArrayX[i]* timeStep; - float d_y = forceArrayY[i]* timeStep; - double dsq = (d_x*d_x + d_y*d_y); - double d = sqrt(dsq); - - localContext->maxForceSq = max(localContext->maxForceSq, (double)dsq ); - localContext->avgForce += d; - if (d < FLT_MAX) - { - x[i] += (float)((d_x)); - y[i] += (float)((d_y)); - if (FLAGS & ZERO_GLOBAL_ARRAY) - { - forceArrayX[i] = 0.0; - forceArrayY[i] = 0.0; - } else - { - forceArrayX[i] = (float)((d_x));; - forceArrayY[i] = (float)((d_y));; - } - } else - { - forceArrayX[i] = 0.0; - forceArrayY[i] = 0.0; - } - } - - inline void operator()(__uint32 begin, __uint32 end) - { - for (__uint32 i = begin; i <= end; i++) - { - this->operator()(i); - } - } - -private: - float timeStep; - float* x; - float* y; - float* forceArrayX; - float* forceArrayY; - float* nodeMoveRadius; - float* currentEdgeLength; - ArrayGraph* pGraph; - FMELocalContext* localContext; -}; - - -template -static inline NodeMoveFunctor node_move_function( FMELocalContext* pLocalContext ) -{ - return NodeMoveFunctor( pLocalContext ); -} - - -template -inline void for_loop_array_set(__uint32 threadNr, __uint32 numThreads, TYP* a, __uint32 n, TYP value) -{ - __uint32 s = n/numThreads; - __uint32 o = s*threadNr; - if (threadNr == numThreads-1) - s = s + (n % numThreads); - - for (__uint32 i = 0; i < s; i++ ) { a[o+i] = value; } -} - -} // end of namespace - -#endif - diff --git a/ext/OGDF/src/energybased/FMEFunctional.h b/ext/OGDF/src/energybased/FMEFunctional.h deleted file mode 100644 index ca0a522df..000000000 --- a/ext/OGDF/src/energybased/FMEFunctional.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definitions of functors used in FME layout. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_FME_FUNCTIONAL_H -#define OGDF_FME_FUNCTIONAL_H - -namespace ogdf { - -//! the useless do nothing function -struct do_nothing -{ - template inline void operator()(A a) { } - template inline void operator()(A a, B b) { } -}; - -//! condition functor for returning a constant boolean value -template -struct const_condition -{ - template inline bool operator()(A a) { return result; } - template inline bool operator()(A a, B b) { return result; } -}; - -//! the corresponding typedefs -typedef const_condition true_condition; -typedef const_condition false_condition; - -//! functor for negating a condition -template -struct not_condition_functor -{ - Func cond_func; - - not_condition_functor(const Func& cond) : cond_func(cond) { } - - template inline bool operator()(A a) { return !cond_func(a); } - template inline void operator()(A a, B b) { return !cond_func(a, b); } -}; - -//! creator of the negator -template -static inline not_condition_functor not_condition(const Func& func) -{ - return not_condition_functor(func); -}; - -//! Functor for conditional usage of a functor -template -struct if_then_else_functor -{ - CondType condFunc; - ThenType thenFunc; - ElseType elseFunc; - - if_then_else_functor(const CondType& c, const ThenType& f1) : condFunc(c), thenFunc(f1) { } - - if_then_else_functor(const CondType& c, const ThenType& f1, const ElseType& f2) : condFunc(c), thenFunc(f1), elseFunc(f2) { } - - template - inline void operator()(A a) - { - if (condFunc(a)) - thenFunc(a); - else - elseFunc(a); - } - - template - inline void operator()(A a, B b) - { - if (condFunc(a, b)) - thenFunc(a, b); - else - elseFunc(a, b); - } -}; - -//! creates an if then else functor with a condition and a then and an else functor -template -static inline if_then_else_functor if_then_else(const CondType& cond, const ThenType& thenFunc, const ElseType& elseFunc) -{ - return if_then_else_functor(cond, thenFunc, elseFunc); -} - -//! creates an if then functor with a condition and a then functor -template -static inline if_then_else_functor if_then(const CondType& cond, const ThenType& thenFunc) -{ - return if_then_else_functor(cond, thenFunc); -} - - -//! helper functor to generate a pair as parameters -template -struct pair_call_functor -{ - F func; - A first; - pair_call_functor(F f, A a) : func(f), first(a) {}; - - template - inline void operator()(B second) - { - func(first, second); - } -}; - - -//! creates a pair call resulting in a call f(a, *) -template -static inline pair_call_functor pair_call(F f, A a) -{ - return pair_call_functor(f, a); -} - - -//! Functor for composing two other functors -template -struct composition_functor -{ - FuncFirst firstFunc; - FuncSecond secondFunc; - - composition_functor(const FuncFirst& first, const FuncSecond& second) : firstFunc(first), secondFunc(second) {}; - template - void operator()(A a) - { - firstFunc(a); - secondFunc(a); - } - - template - void operator()(A a, B b) - { - firstFunc(a, b); - secondFunc(a, b); - } -}; - - -//! create a functor composition of two functors -template -static inline composition_functor func_comp(const FuncFirst& first, const FuncSecond& second) -{ - return composition_functor(first, second); -} - - -//! functor for invoking a functor for a pair(u,v) and then (v,u) -template -struct pair_vice_versa_functor -{ - Func func; - - pair_vice_versa_functor(const Func& f) : func(f) { } - - template - void operator()(A a, B b) - { - func(a, b); - func(b, a); - } -}; - - -//! creates a functor for invoking a functor for a pair(u,v) and then (v,u) -template -static inline pair_vice_versa_functor pair_vice_versa(const Func& f) -{ - return pair_vice_versa_functor(f); -} - - -//! generic min max functor for an array -template -struct min_max_functor -{ - const T* a; - T& min_value; - T& max_value; - - min_max_functor(const T* ptr, T& min_var, T& max_var) : a(ptr), min_value(min_var), max_value(max_var) - { - min_value = a[0]; - max_value = a[0]; - } - - inline void operator()(__uint32 i) - { - min_value = min(min_value, a[i]); - max_value = max(max_value, a[i]); - } -}; - -} - -#endif diff --git a/ext/OGDF/src/energybased/FMEKernel.cpp b/ext/OGDF/src/energybased/FMEKernel.cpp deleted file mode 100644 index 70d143ff2..000000000 --- a/ext/OGDF/src/energybased/FMEKernel.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of FME kernel. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "FMEKernel.h" -#include "ComplexDouble.h" - -using namespace ogdf::sse; - -namespace ogdf { - -#ifdef OGDF_FME_KERNEL_USE_SSE_DIRECT - -inline void eval_direct_aligned_SSE( - float* ptr_x1, float* ptr_y1, float* ptr_s1, float* ptr_fx1, float* ptr_fy1, size_t n1, - float* ptr_x2, float* ptr_y2, float* ptr_s2, float* ptr_fx2, float* ptr_fy2, size_t n2) -{ - for (__uint32 i=0; i < n1; i+=4) - { - // register for i - __m128 x = _mm_load_ps( ptr_x1 + i ); - __m128 y = _mm_load_ps( ptr_y1 + i ); - __m128 s = _mm_load_ps( ptr_s1 + i ); - __m128 fx_sum = _mm_load_ps( ptr_fx1+ i ); - __m128 fy_sum = _mm_load_ps( ptr_fy1+ i ); - - __m128 x_shuffled; - __m128 y_shuffled; - __m128 s_shuffled; - __m128 fx_sum_shuffled; - __m128 fy_sum_shuffled; - - for (__uint32 j=i+4; j < n2; j+=4) - { - x_shuffled = _mm_load_ps( ptr_x2 +j ); - y_shuffled = _mm_load_ps( ptr_y2 +j ); - s_shuffled = _mm_load_ps( ptr_s2 +j ); - fx_sum_shuffled = _mm_load_ps( ptr_fx2+j ); - fy_sum_shuffled = _mm_load_ps( ptr_fy2+j ); - - for (int k=0;k<4;k++) - { - __m128 dx = _mm_sub_ps(x, x_shuffled); - __m128 dy = _mm_sub_ps(y, y_shuffled); - __m128 s_sum = _mm_add_ps(s, s_shuffled); - __m128 f = _MM_COMPUTE_FORCE(dx,dy,s_sum); -// __m128 dsq= _mm_add_ps(_mm_mul_ps(dx, dx), _mm_mul_ps(dy, dy)); -// __m128 f = _mm_div_ps(_mm_add_ps(s, s_shuffled), dsq); - __m128 fx = _mm_mul_ps(dx, f); - __m128 fy = _mm_mul_ps(dy, f); - // add forces to i's sum - fx_sum = _mm_add_ps(fx_sum, fx); - fy_sum = _mm_add_ps(fy_sum, fy); - // sub forces from j's sum - fx_sum_shuffled = _mm_sub_ps(fx_sum_shuffled, fx); - fy_sum_shuffled = _mm_sub_ps(fy_sum_shuffled, fy); - // shuffle everything for the next pairing - x_shuffled = _mm_shuffle_ps(x_shuffled, x_shuffled, _MM_SHUFFLE(0,3,2,1)); - y_shuffled = _mm_shuffle_ps(y_shuffled, y_shuffled, _MM_SHUFFLE(0,3,2,1)); - s_shuffled = _mm_shuffle_ps(s_shuffled, s_shuffled, _MM_SHUFFLE(0,3,2,1)); - fx_sum_shuffled = _mm_shuffle_ps(fx_sum_shuffled, fx_sum_shuffled, _MM_SHUFFLE(0,3,2,1)); - fy_sum_shuffled = _mm_shuffle_ps(fy_sum_shuffled, fy_sum_shuffled, _MM_SHUFFLE(0,3,2,1)); - } - // note: after shuffling 4 times we are back to original order - _mm_store_ps(ptr_fx2 + j, fx_sum_shuffled); - _mm_store_ps(ptr_fy2 + j, fy_sum_shuffled); - } - _mm_store_ps( ptr_fx1 + i, fx_sum ); - _mm_store_ps( ptr_fy1 + i, fy_sum ); - } -} - -//! kernel function to evaluate forces between 4 points with coords x, y (16 byte aligned) directly. result is stored in fx, fy -inline void eval_direct_aligned_SSE(float* ptr_x, float* ptr_y, float* ptr_s, float* ptr_fx, float* ptr_fy) -{ -/* // SSE 2 implementation - // A = (a, b, c, d) (original order) - __m128 x_A = _mm_load_ps( ptr_x ); - __m128 y_A = _mm_load_ps( ptr_y ); - __m128 s_A = _mm_load_ps( ptr_s ); - __m128 fx_A = _mm_load_ps( ptr_fx ); - __m128 fy_A = _mm_load_ps( ptr_fy ); - - // B = (b, c, d, a) (1x left rotate) - __m128 x_B = _mm_shuffle_ps( x_A, x_A, _MM_SHUFFLE(0,3,2,1) ); - __m128 y_B = _mm_shuffle_ps( y_A, y_A, _MM_SHUFFLE(0,3,2,1) ); - __m128 s_B = _mm_shuffle_ps( s_A, s_A, _MM_SHUFFLE(0,3,2,1) ); - - // C = (c, d, a, b) (2x left rotate) - __m128 x_C = _mm_shuffle_ps( x_B, x_B, _MM_SHUFFLE(0,3,2,1) ); - __m128 y_C = _mm_shuffle_ps( y_B, y_B, _MM_SHUFFLE(0,3,2,1) ); - __m128 s_C = _mm_shuffle_ps( s_B, s_B, _MM_SHUFFLE(0,3,2,1) ); - - // A x B = ( f(a,b), f(b,c), f(c,d), f(d,a) ) - __m128 x_AB = _mm_sub_ps( x_A, x_B ); // dx = Ax - Bx - __m128 y_AB = _mm_sub_ps( y_A, y_B ); // dy = Ay - By - __m128 s_AB = _mm_add_ps( s_A, s_B ); // s = As + Bs - __m128 dsq_AB = _mm_add_ps( _mm_mul_ps( x_AB, x_AB ), _mm_mul_ps( y_AB, y_AB ) ); // f = s/d^2 - __m128 f_AB = _mm_div_ps( s_AB, dsq_AB ); - __m128 fx_AB = _mm_mul_ps( x_AB, f_AB ); // fx(a,b), fx(b,c), fx(c,d), fx(d,a) - __m128 fy_AB = _mm_mul_ps( y_AB, f_AB ); // fy(a,b), fy(b,c), fy(c,d), fy(d,a) - // unshuffle - __m128 fx_AB_shuffled = _mm_shuffle_ps( fx_AB, fx_AB, _MM_SHUFFLE(2,1,0,3) ); // fx(d,a), fx(a,b), fx(b,c), fx(c,d) - __m128 fy_AB_shuffled = _mm_shuffle_ps( fy_AB, fy_AB, _MM_SHUFFLE(2,1,0,3) ); // fy(d,a), fy(a,b), fy(b,c), fy(c,d) - - // A x C = ( f(a,c), f(b,d), f(c,a), f(d,b) ) - __m128 x_AC = _mm_sub_ps( x_A, x_C ); // dx = Ax - Cx - __m128 y_AC = _mm_sub_ps( y_A, y_C ); // dy = Ay - Cy - __m128 s_AC = _mm_add_ps( s_A, s_C ); // s = As + Cs - __m128 dsq_AC = _mm_add_ps( _mm_mul_ps( x_AC, x_AC ), _mm_mul_ps(y_AC, y_AC)); // f = s/d^2 - __m128 f_AC = _mm_div_ps( s_AC, dsq_AC ); - __m128 fx_AC = _mm_mul_ps( x_AC, f_AC ); // fx(a,c), fx(b,d), fx(c,a), fx(d,b) - __m128 fy_AC = _mm_mul_ps( y_AC, f_AC ); // fy(a,c), fy(b,d), fy(c,a), fy(d,b) - - // Note: f(x,y) = -f(y,x) - // f(a) = f(a,b) - f(d,a) + f(a,c) = f(a,b) + f(a,d) + f(a,c) - // f(b) = f(b,c) - f(a,b) + f(b,d) = f(b,c) + f(b,a) + f(b,d) - // f(c) = f(c,d) - f(b,c) + f(c,a) = f(c,d) + f(c,b) + f(c,a) - // f(d) = f(d,a) - f(c,d) + f(d,b) = f(d,a) + f(d,c) + f(d,b) - fx_A = _mm_add_ps(fx_A, fx_AB); - fy_A = _mm_add_ps(fy_A, fy_AB); - - fx_A = _mm_sub_ps(fx_A, fx_AB_shuffled); - fy_A = _mm_sub_ps(fy_A, fy_AB_shuffled); - - fx_A = _mm_add_ps(fx_A, fx_AC); - fy_A = _mm_add_ps(fy_A, fy_AC); - - _mm_store_ps(ptr_fx, fx_A); - _mm_store_ps(ptr_fy, fy_A); -*/ - // SSE 2 implementation (compressed) - // A = (a, b, c, d) (original order) - __m128 x = _mm_load_ps( ptr_x ); - __m128 y = _mm_load_ps( ptr_y ); - __m128 s = _mm_load_ps( ptr_s ); - __m128 fx_sum = _mm_load_ps( ptr_fx ); - __m128 fy_sum = _mm_load_ps( ptr_fy ); - - // B = (b, c, d, a) (1x left rotate) - __m128 x_shuffled = _mm_shuffle_ps( x, x, _MM_SHUFFLE(0,3,2,1) ); - __m128 y_shuffled = _mm_shuffle_ps( y, y, _MM_SHUFFLE(0,3,2,1) ); - __m128 s_shuffled = _mm_shuffle_ps( s, s, _MM_SHUFFLE(0,3,2,1) ); - - // A x B = ( f(a,b), f(b,c), f(c,d), f(d,a) ) - __m128 dx = _mm_sub_ps( x, x_shuffled ); // dx = x_A - x_B - __m128 dy = _mm_sub_ps( y, y_shuffled ); // dy = y_A - y_B - __m128 s_sum = _mm_add_ps(s, s_shuffled); - __m128 f = _MM_COMPUTE_FORCE(dx,dy,s_sum); -// __m128 dsq = _mm_add_ps( _mm_mul_ps( dx, dx ), -// _mm_mul_ps( dy, dy ) ); // dsq = (dx*dx + dy*dy) -// __m128 f = _mm_div_ps( _mm_add_ps( s, s_shuffled ), dsq ); // f = (s_A+s_B)/d^2 - __m128 fx = _mm_mul_ps( dx, f ); // ( fx(a,b), fx(b,c), fx(c,d), fx(d,a) ) - __m128 fy = _mm_mul_ps( dy, f ); // ( fy(a,b), fy(b,c), fy(c,d), fy(d,a) ) - - fx_sum = _mm_add_ps( fx_sum, _mm_sub_ps( fx, _mm_shuffle_ps( fx, fx, _MM_SHUFFLE(2,1,0,3) ) ) ); // ( fx(a,b), fx(b,c), fx(c,d), fx(d,a) ) - ( fx(d,a), fx(a,b), fx(b,c), fx(c,d) ) - fy_sum = _mm_add_ps( fy_sum, _mm_sub_ps( fy, _mm_shuffle_ps( fy, fy, _MM_SHUFFLE(2,1,0,3) ) ) ); // ( fy(a,b), fy(b,c), fy(c,d), fy(d,a) ) - ( fy(d,a), fy(a,b), fy(b,c), fy(c,d) ) - - // B = (c, d, a, b) (2x left rotate) - x_shuffled = _mm_shuffle_ps( x_shuffled, x_shuffled, _MM_SHUFFLE(0,3,2,1) ); - y_shuffled = _mm_shuffle_ps( y_shuffled, y_shuffled, _MM_SHUFFLE(0,3,2,1) ); - s_shuffled = _mm_shuffle_ps( s_shuffled, s_shuffled, _MM_SHUFFLE(0,3,2,1) ); - - // A x B = ( f(a,c), f(b,d), f(c,a), f(d,b) ) - dx = _mm_sub_ps( x, x_shuffled ); // dx = x_A - x_B - dy = _mm_sub_ps( y, y_shuffled ); // dy = y_A - y_B -// dsq = _mm_add_ps( _mm_mul_ps( dx, dx ), -// _mm_mul_ps( dy, dy ) ); // dsq = (dx*dx + dy*dy) -// f = _mm_div_ps( _mm_add_ps( s, s_shuffled ), dsq ); // f = (s_A+s_B)/d^2 - s_sum = _mm_add_ps(s, s_shuffled); - f = _MM_COMPUTE_FORCE(dx,dy,s_sum); - fx = _mm_mul_ps( dx, f ); // fx(a,c), fx(b,d), fx(c,a), fx(d,b) - fy = _mm_mul_ps( dy, f ); // fy(a,c), fy(b,d), fy(c,a), fy(d,b) - - fx_sum = _mm_add_ps(fx_sum, fx); // ( fx(a,c), fx(b,d), fx(c,a), fx(d,b) ) - fy_sum = _mm_add_ps(fy_sum, fy); // ( fy(a,c), fy(b,d), fy(c,a), fy(d,b) ) - - // Note: f(x,y) = -f(y,x) - // f(a) = f(a,b) - f(d,a) + f(a,c) = f(a,b) + f(a,d) + f(a,c) - // f(b) = f(b,c) - f(a,b) + f(b,d) = f(b,c) + f(b,a) + f(b,d) - // f(c) = f(c,d) - f(b,c) + f(c,a) = f(c,d) + f(c,b) + f(c,a) - // f(d) = f(d,a) - f(c,d) + f(d,b) = f(d,a) + f(d,c) + f(d,b) - _mm_store_ps( ptr_fx, fx_sum ); - _mm_store_ps( ptr_fy, fy_sum ); -} - -inline void eval_direct_aligned_SSE(float* ptr_x, float* ptr_y, float* ptr_s, float* ptr_fx, float* ptr_fy, size_t n) -{ - for (__uint32 i=0; i < n; i+=4) - { - // register for i - __m128 x = _mm_load_ps( ptr_x + i ); - __m128 y = _mm_load_ps( ptr_y + i ); - __m128 s = _mm_load_ps( ptr_s + i ); - __m128 fx_sum = _mm_load_ps( ptr_fx+ i ); - __m128 fy_sum = _mm_load_ps( ptr_fy+ i ); - - // register for j, first we need to deal with Block(i,i) - __m128 x_shuffled = _mm_shuffle_ps( x, x, _MM_SHUFFLE(0,3,2,1) ); - __m128 y_shuffled = _mm_shuffle_ps( y, y, _MM_SHUFFLE(0,3,2,1) ); - __m128 s_shuffled = _mm_shuffle_ps( s, s, _MM_SHUFFLE(0,3,2,1) ); - __m128 fx_sum_shuffled; - __m128 fy_sum_shuffled; - - // begin copy paste from above - __m128 dx = _mm_sub_ps( x, x_shuffled ); // dx = x_A - x_B - __m128 dy = _mm_sub_ps( y, y_shuffled ); // dy = y_A - y_B -// __m128 dsq = _mm_add_ps( _mm_mul_ps( dx, dx ), -// _mm_mul_ps( dy, dy ) ); // dsq = (dx*dx + dy*dy) -// __m128 f = _mm_div_ps( _mm_add_ps( s, s_shuffled ), dsq ); // f = (s_A+s_B)/d^2 - __m128 s_sum = _mm_add_ps(s, s_shuffled); - __m128 f = _MM_COMPUTE_FORCE(dx,dy,s_sum); - __m128 fx = _mm_mul_ps( dx, f ); // ( fx(a,b), fx(b,c), fx(c,d), fx(d,a) ) - __m128 fy = _mm_mul_ps( dy, f ); // ( fy(a,b), fy(b,c), fy(c,d), fy(d,a) ) - - fx_sum = _mm_add_ps( fx_sum, _mm_sub_ps( fx, _mm_shuffle_ps( fx, fx, _MM_SHUFFLE(2,1,0,3) ) ) ); // ( fx(a,b), fx(b,c), fx(c,d), fx(d,a) ) - ( fx(d,a), fx(a,b), fx(b,c), fx(c,d) ) - fy_sum = _mm_add_ps( fy_sum, _mm_sub_ps( fy, _mm_shuffle_ps( fy, fy, _MM_SHUFFLE(2,1,0,3) ) ) ); // ( fy(a,b), fy(b,c), fy(c,d), fy(d,a) ) - ( fy(d,a), fy(a,b), fy(b,c), fy(c,d) ) - - x_shuffled = _mm_shuffle_ps( x_shuffled, x_shuffled, _MM_SHUFFLE(0,3,2,1) ); - y_shuffled = _mm_shuffle_ps( y_shuffled, y_shuffled, _MM_SHUFFLE(0,3,2,1) ); - s_shuffled = _mm_shuffle_ps( s_shuffled, s_shuffled, _MM_SHUFFLE(0,3,2,1) ); - - dx = _mm_sub_ps( x, x_shuffled ); // dx = x_A - x_B - dy = _mm_sub_ps( y, y_shuffled ); // dy = y_A - y_B -// dsq = _mm_add_ps( _mm_mul_ps( dx, dx ), -// _mm_mul_ps( dy, dy ) ); // dsq = (dx*dx + dy*dy) -// f = _mm_div_ps( _mm_add_ps( s, s_shuffled ), dsq ); // f = (s_A+s_B)/d^2 - s_sum = _mm_add_ps(s, s_shuffled); - f = _MM_COMPUTE_FORCE(dx,dy,s_sum); - fx = _mm_mul_ps( dx, f ); // fx(a,c), fx(b,d), fx(c,a), fx(d,b) - fy = _mm_mul_ps( dy, f ); // fy(a,c), fy(b,d), fy(c,a), fy(d,b) - - fx_sum = _mm_add_ps(fx_sum, fx); // ( fx(a,c), fx(b,d), fx(c,a), fx(d,b) ) - fy_sum = _mm_add_ps(fy_sum, fy); - - // end copy paste from above - for (__uint32 j=i+4; j < n; j+=4) - { - x_shuffled = _mm_load_ps( ptr_x +j ); - y_shuffled = _mm_load_ps( ptr_y +j ); - s_shuffled = _mm_load_ps( ptr_s +j ); - fx_sum_shuffled = _mm_load_ps( ptr_fx+j ); - fy_sum_shuffled = _mm_load_ps( ptr_fy+j ); - - for (int k=0;k<4;k++) - { - dx = _mm_sub_ps(x, x_shuffled); - dy = _mm_sub_ps(y, y_shuffled); -// dsq= _mm_add_ps(_mm_mul_ps(dx, dx), _mm_mul_ps(dy, dy)); -// f = _mm_div_ps(_mm_add_ps(s, s_shuffled), dsq); - s_sum = _mm_add_ps(s, s_shuffled); - f = _MM_COMPUTE_FORCE(dx,dy,s_sum); - fx = _mm_mul_ps(dx, f); - fy = _mm_mul_ps(dy, f); - // add forces to i's sum - fx_sum = _mm_add_ps(fx_sum, fx); - fy_sum = _mm_add_ps(fy_sum, fy); - // sub forces from j's sum - fx_sum_shuffled = _mm_sub_ps(fx_sum_shuffled, fx); - fy_sum_shuffled = _mm_sub_ps(fy_sum_shuffled, fy); - // shuffle everything for the next pairing - x_shuffled = _mm_shuffle_ps(x_shuffled, x_shuffled, _MM_SHUFFLE(0,3,2,1)); - y_shuffled = _mm_shuffle_ps(y_shuffled, y_shuffled, _MM_SHUFFLE(0,3,2,1)); - s_shuffled = _mm_shuffle_ps(s_shuffled, s_shuffled, _MM_SHUFFLE(0,3,2,1)); - fx_sum_shuffled = _mm_shuffle_ps(fx_sum_shuffled, fx_sum_shuffled, _MM_SHUFFLE(0,3,2,1)); - fy_sum_shuffled = _mm_shuffle_ps(fy_sum_shuffled, fy_sum_shuffled, _MM_SHUFFLE(0,3,2,1)); - } - // note: after shuffling 4 times we are back to original order - _mm_store_ps(ptr_fx + j, fx_sum_shuffled); - _mm_store_ps(ptr_fy + j, fy_sum_shuffled); - } - _mm_store_ps( ptr_fx + i, fx_sum ); - _mm_store_ps( ptr_fy + i, fy_sum ); - } -} - -void eval_direct_fast(float* x, float* y, float* s, float* fx, float* fy, size_t n) -{ - if (n>8) - { - const float* ptr = x; - const float* fence1 = align_16_next_ptr(ptr); - const float* fence2 = align_16_prev_ptr(ptr+n); - const size_t numA = fence1 - ptr; - const size_t numB = fence2 - fence1; - const size_t numC = (ptr+n) - fence2; - const size_t numAB = fence2 - ptr; - - // eval AxA - eval_direct(x, y, s, fx, fy, numA); - - // eval BxA - eval_direct(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB, - x, y, s, fx, fy, numA); - // eval AxC - eval_direct(x, y, s, fx, fy, numA, - x+numAB, y+numAB, s+numAB, fx+numAB, fy+numAB, numC); - // eval BxB - //eval_direct(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB); - eval_direct_aligned_SSE(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB); - // eval BxC - eval_direct(x+ numA, y+ numA, s+ numA, fx+ numA, fy+ numA, numB, - x+numAB, y+numAB, s+numAB, fx+numAB, fy+numAB, numC); - - // eval CxC - eval_direct(x+numAB, y+numAB, s+numAB, fx+numAB, fy+numAB, numC); - } else - { - eval_direct(x, y, s, fx, fy, n); - } -} -//! kernel function to evaluate forces between two sets of points with coords x1, y1 (x2, y2) directly. result is stored in fx1, fy1 (fx2, fy2 -void eval_direct_fast(float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1, - float* x2, float* y2, float* s2, float* fx2, float* fy2, size_t n2) -{ - if ((n1>8) && (n2>8)) - { - const float* ptr1 = x1; - const float* ptr2 = x2; - const float* fence11 = align_16_next_ptr(ptr1); - const float* fence21 = align_16_next_ptr(ptr2); - const float* fence12 = align_16_prev_ptr(ptr1+n1); - const float* fence22 = align_16_prev_ptr(ptr2+n2); - const size_t numA1 = fence11 - ptr1; - const size_t numA2 = fence21 - ptr2; - const size_t numB1 = fence12 - fence11; - const size_t numB2 = fence22 - fence21; - const size_t numC1 = (ptr1+n1) - fence12; - const size_t numC2 = (ptr2+n2) - fence22; - const size_t numAB1 = fence12 - ptr1; - const size_t numAB2 = fence22 - ptr2; - - // eval A1 x ALL2 - eval_direct(x1, y1, s1, fx1, fy1, numA1, - x2, y2, s2, fx2, fy2, n2); - - // eval C1x ALL2 - eval_direct(x1, y1, s1, fx1, fy1, numC1, - x2, y2, s2, fx2, fy2, n2); - - // eval B1x A2 - eval_direct(x1+numA1, y1+numA1, s1+numA1, fx1+numA1, fy1+numA1, numB1, - x2 , y2 , s2 , fx2 , fy2 , numA2); - - // eval B1x C2 - eval_direct(x1+ numA1 , y1+ numA1, s1+ numA1, fx1+ numA1, fy1+ numA1, numB1, - x2+ numAB2, y2+numAB2, s2+numAB2, fx2+numAB2, fy2+numAB2, numC2); - - // finally B1xB2 - eval_direct_aligned_SSE(x1+numA1, y1+numA1, s1+numA1, fx1+numA1, fy1+numA1, numB1, - x2+numA2, y2+numA2, s2+numA2, fx2+numA2, fy2+numA2, numB2); - } else - { - eval_direct(x1, y1, s1, fx1, fy1, n1, x2, y2, s2, fx2, fy2, n2); - } -} -#endif - - -/*template -inline __w64 int align_16_begin(T* ptr) -{ - return align_16_next_ptr(ptr) - ptr; - //return ((T*)((((int)ptr) + 15) &~ 0x0F)) - ptr; -} - -template -inline __w64 int align_16_end(T* ptr, const N n) -{ - return (n) - ( (ptr+n) - align_16_prev_ptr( ptr+n ) ); - //return ((T*)(((int)(ptr + n)) &~ 0x0F)) - ptr; -}*/ - -// -// ______________________ -// |AxC| BxC |CxC| -// |___|____________|___| -// | | | | -// |AxB| | | -// | | BxB | | -// | | | | -// |___|____________|___| -// |AxA| | | -// |___|____________|___| -// x fence1 fence2 x+n -/*void eval_direct_sse(float* x, float* y, float* s, float* fx, float* fy, __uint32 n) -{ - if (n>8) - { - const float* ptr = x; - const float* fence1 = align_16_next_ptr(ptr); - const float* fence2 = align_16_prev_ptr(ptr+n); - const __w64 int numA = fence1 - ptr; - const __w64 int numB = fence2 - fence1; - const __w64 int numC = (ptr+n) - fence2; - const __w64 int numAB = fence2 - ptr; - - // eval AxA - eval_direct(x, y, s, fx, fy, numA); - - // eval BxA - eval_direct(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB, - x, y, s, fx, fy, numA); - // eval AxC - eval_direct(x, y, s, fx, fy, numA, - x+numAB, y+numAB, s+numAB, fx+numAB, fy+numAB, numC); - // eval BxB - //eval_direct(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB); - eval_direct_aligned_aligned_sse(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB); - //eval_direct_aligned_aligned_sse(x+numA, y+numA, s+numA, fx+numA, fy+numA, numB); - // eval BxC - eval_direct(x+ numA, y+ numA, s+ numA, fx+ numA, fy+ numA, numB, - x+numAB, y+numAB, s+numAB, fx+numAB, fy+numAB, numC); - - // eval CxC - eval_direct(x+numAB, y+numAB, s+numAB, fx+numAB, fy+numAB, numC); - } else - { - for (__uint32 i=0; i < n; i++) - { - for (__uint32 j=i+1; j < n; j++) - { - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; - float dsq = dx*dx + dy*dy; - float f = (s[i]+s[j]) / dsq; - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - } - }*/ - -/* //const void* start16 = (void*)(((int)x + 15) &~ 0x0F); - //const void* end16 = (void*)(((int)(y + n)) &~ 0x0F); - //std::cout << x << " " << n << " begin i: " << x+align_16_begin(x) << " end i: " << x+align_16_end(x, n) << std::endl; - int i = 0; - // i beginning (not 16 byte aligned) - for (i = 0; i < (align_16_begin(x)); i++) - { - const float* inner_ptr = x + i + 1; - int j; - // i beginning (not 16 byte aligned) - // j beginning (not 16 byte aligned) - for (j = i + 1; j < (i+1+align_16_begin(inner_ptr)); j++) - { - // 1 vs 1 - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; - float dsq = dx*dx + dy*dy; - float f = (s[i]+s[j]) / dsq; - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - // i beginning (not 16 byte aligned) - // j 16 byte aligned blocks - for ( ; j < (i+1+align_16_end(inner_ptr, n-i)); j += 4) - { - if (!is_align_16(x+j)) std::cout << "Not aligned j 1 vs 4"<< std::endl; - // 1 vs 4 - Vec4f dx(x[i] - Vec4f(x+j)); - Vec4f dy(y[i] - Vec4f(y+j)); - Vec4f dsq(dx*dx + dy*dy); - Vec4f f = (s[i] + Vec4f(s+j)) / dsq; - Vec4f fxv(dx*f); - Vec4f fyv(dy*f); - Vec4f fx_j(fx+j); - Vec4f fy_j(fy+j); - fx[i] += fxv.hsum(); - fy[i] += fyv.hsum(); - fx_j -= fxv; - fy_j -= fyv; - - fx_j.store(fx+j); - fy_j.store(fy+j); - } - // i beginning (not 16 byte aligned) - // j end (not 16 byte aligned) - for ( ; j < (n); j++) - { - // 1 vs 1 - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; - float dsq = dx*dx + dy*dy; - float f = (s[i]+s[j]) / dsq; - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - } - // i 16 byte aligned blocks - for ( ; i < (align_16_end(x, n)); i += 4) - { - if (!is_align_16(x+i)) std::cout << "Not aligned 4 vs 1"<< std::endl; - Vec4f x_i(x+i); - Vec4f y_i(y+i); - Vec4f s_i(s+i); - Vec4f fx_i(fx+i); - Vec4f fy_i(fy+i); - - const float* inner_ptr = x + i + 1; - int j; - // i 16 byte aligned blocks - // j beginning (not 16 byte aligned) - for (j = i + 1; j < (i+1+align_16_begin(inner_ptr)); j++) - { - if (!is_align_16(x+i)) std::cout << "Not aligned i 4 vs 1 "<< j<< std::endl; - // 4 vs 1 - Vec4f dx = x_i - x[j]; - Vec4f dy = y_i - y[j]; - Vec4f dsq = dx*dx + dy*dy; - Vec4f f = (s_i + s[j]) / dsq; - Vec4f fxv(dx*f); - Vec4f fyv(dy*f); - fx_i += fxv; - fy_i += fyv; - fx[j] -= fxv.hsum(); - fy[j] -= fyv.hsum(); - } - // i 16 byte aligned blocks - // j 16 byte aligned blocks - for ( ; j < i+1+align_16_end(inner_ptr, n-i); j += 4) - { - //std::cout << j << std::endl; - //std::cout << x+align_16_begin(inner_ptr) << std::endl; - //if (!is_align_16(x+i)) std::cout << "Not aligned i 4 vs 4 " << x+i<< std::endl; - //if (!is_align_16(x+j)) std::cout << "Not aligned j 4 vs 4 "<< n-i << " "<< x+j<< std::endl; - - // 4 vs 4 - Vec4f fx_j(fx+j); - Vec4f fy_j(fy+j); - - Vec4f dx(x_i - Vec4f(x+j)); - Vec4f dy(y_i - Vec4f(y+j)); - - Vec4f dsq(dx*dx + dy*dy); - Vec4f f = (s_i + Vec4f(s+j)) / dsq; - - Vec4f fxv(dx*f); - Vec4f fyv(dy*f); - - fx_i += fxv; - fy_i += fyv; - fx_j -= fxv; - fy_j -= fyv; - - fx_j.store(fx+j); - fy_j.store(fy+j); - } - // i 16 byte aligned blocks - // j end (not 16 byte aligned) - for ( ; j < (n); j++) - { - // 4 vs 1 - Vec4f dx = x_i - x[j]; - Vec4f dy = y_i - y[j]; - Vec4f dsq = dx*dx + dy*dy; - Vec4f f = (s_i + s[j]) / dsq; - Vec4f fxv(dx*f); - Vec4f fyv(dy*f); - fx_i += fxv; - fy_i += fyv; - fx[j] -= fxv.hsum(); - fy[j] -= fyv.hsum(); - } - fx_i.store(fx+i); - fy_i.store(fy+i); - } - // i end (not 16 byte aligned) - for ( ; i < (n); i++) - { - const float* inner_ptr = x + i + 1; - int j; - //std::cout << x << " " << n << " begin j: " << align_16_begin(inner_ptr) << " end j: " << align_16_end(inner_ptr, n-i-1) << std::endl; - // i end (not 16 byte aligned) - // j beginning (not 16 byte aligned) - //std::cout << "before first loop i: " << i<< std::endl; - for (j = i + 1; j < i+1+(align_16_begin(inner_ptr)); j++) - { - //std::cout << i << " " << j << std::endl; - // 1 vs 1 - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; - float dsq = dx*dx + dy*dy; - float f = (s[i]+s[j]) / dsq; - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - - //std::cout << "after first loop" << std::endl; - // i beginning (not 16 byte aligned) - // j 16 byte aligned blocks - for ( ; j < i+1+(align_16_end(inner_ptr, n-i)); j += 4) - { - if (!is_align_16(x+j)) std::cout << "Not aligned"<< std::endl; - // 1 vs 4 - Vec4f dx(x[i] - Vec4f(x+j)); - Vec4f dy(y[i] - Vec4f(y+j)); - Vec4f dsq(dx*dx + dy*dy); - Vec4f f = (s[i] + Vec4f(s+j)) / dsq; - Vec4f fxv(dx*f); - Vec4f fyv(dy*f); - Vec4f fx_j(fx+j); - Vec4f fy_j(fy+j); - fx[i] += fxv.hsum(); - fy[i] += fyv.hsum(); - fx_j -= fxv; - fy_j -= fyv; - - fx_j.store(fx+j); - fy_j.store(fy+j); - } - // i beginning (not 16 byte aligned) - // j end (not 16 byte aligned) - for ( ; j < (n); j++) - { - // 1 vs 1 - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; - float dsq = dx*dx + dy*dy; - float f = (s[i]+s[j]) / dsq; - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - } - } else - { - for (__uint32 i=0; i < n; i++) - { - for (__uint32 j=i+1; j < n; j++) - { - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; - float dsq = dx*dx + dy*dy; - float f = (s[i]+s[j]) / dsq; - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - } - }*/ -//} - - - -void fast_multipole_l2p(double* localCoeffiecients, __uint32 numCoeffiecients, double centerX, double centerY, - float x, float y, float q, float& fx, float&fy) -{ - double* source_coeff = localCoeffiecients; //+ source*(m_numCoeff << 1); - ComplexDouble ak; - ComplexDouble res; - ComplexDouble delta(ComplexDouble(x,y) - ComplexDouble(centerX, centerY));// + (source << 1))); //m_x[source], y - m_y[source]); - ComplexDouble delta_k(1); - for (__uint32 k=1; k - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FME_KERNEL_H -#define OGDF_FME_KERNEL_H - -#include -#include "FastUtils.h" -#include "ArrayGraph.h" -#include "FMEThread.h" -#include - -namespace ogdf { - -class FMEKernel -{ -public: - FMEKernel(FMEThread* pThread) : m_pThread(pThread) { } - - inline void sync() { m_pThread->sync(); } - - //! returns the index of the thread ( 0.. numThreads()-1 ) - inline __uint32 threadNr() const { return m_pThread->threadNr(); } - - //! returns the total number of threads in the pool - inline __uint32 numThreads() const { return m_pThread->numThreads(); } - - //! returns true if this is the main thread ( the main thread is always the first thread ) - inline bool isMainThread() const { return m_pThread->isMainThread(); } - - //! returns true if this run only uses one thread ) - inline bool isSingleThreaded() const { return (m_pThread->numThreads() == 1); }; - -private: - FMEThread* m_pThread; -}; - - -#define FME_KERNEL_USE_OLD - -#define COMPUTE_FORCE_PROTECTION_FACTOR 0.25f -// makro for force computation via SSE s / max(s*0.5, (dx*dx + dy*dy)) -#define _MM_COMPUTE_FORCE(dx,dy,s) _mm_div_ps((s),_mm_max_ps(_mm_mul_ps((s),_mm_set1_ps(COMPUTE_FORCE_PROTECTION_FACTOR)), _mm_add_ps(_mm_mul_ps((dx),(dx)), _mm_mul_ps((dy),(dy))))) -#define COMPUTE_FORCE(dx,dy,s) (s/(max(s*COMPUTE_FORCE_PROTECTION_FACTOR, (dx)*(dx) + (dy)*(dy)))) - -inline double move_nodes(float* x, float* y, const __uint32 begin, const __uint32 end, const float* fx, const float* fy, const float t) -{ - double dsq_max = 0.0; - for (__uint32 i=begin; i <= end; i++) - { - double dsq = fx[i]*fx[i] + fy[i]*fy[i]; - x[i] += fx[i]*t; - y[i] += fy[i]*t; - dsq_max = max(dsq_max, dsq); - } - return dsq_max; -} - - -inline void eval_edges(const ArrayGraph& graph, const __uint32 begin, const __uint32 end, float* fx, float* fy) -{ - const float* x = graph.nodeXPos(); - const float* y = graph.nodeYPos(); - const float* e = graph.desiredEdgeLength(); - for (__uint32 i=begin; i <= end; i++) - { - const EdgeAdjInfo& e_info = graph.edgeInfo(i); - const __uint32 a = e_info.a; - const __uint32 b = e_info.b; - const NodeAdjInfo& a_info = graph.nodeInfo(a); - const NodeAdjInfo& b_info = graph.nodeInfo(b); - - float dx = x[a] - x[b]; - float dy = y[a] - y[b]; - float dsq = dx*dx + dy*dy; - float f = (logf(dsq)*0.5f-logf(e[i])) * 0.25f; - float fa = (float)(f/((float)a_info.degree)); - float fb = (float)(f/((float)b_info.degree)); - fx[a] -= dx*fa; - fy[a] -= dy*fa; - fx[b] += dx*fb; - fy[b] += dy*fb; - } -} - - -//! kernel function to evaluate forces between n points with coords x, y directly. result is stored in fx, fy -inline void eval_direct(float* x, float* y, float* s, float* fx, float* fy, size_t n) -{ - for (__uint32 i=0; i < n; i++) - { - for (__uint32 j=i+1; j < n; j++) - { - float dx = x[i] - x[j]; - float dy = y[i] - y[j]; -#ifdef FME_KERNEL_USE_OLD - float s_sum = s[i]+s[j]; -#else - float s_sum = s[i]*s[j]; -#endif - float f = COMPUTE_FORCE(dx, dy, s_sum); - fx[i] += dx*f; - fy[i] += dy*f; - fx[j] -= dx*f; - fy[j] -= dy*f; - } - } -} - - -//! kernel function to evaluate forces between two sets of points with coords x1, y1 (x2, y2) directly. result is stored in fx1, fy1 (fx2, fy2 -inline void eval_direct(float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1, - float* x2, float* y2, float* s2, float* fx2, float* fy2, size_t n2) -{ - for (__uint32 i=0; i < n1; i++) - { - for (__uint32 j=0; j < n2; j++) - { - float dx = x1[i] - x2[j]; - float dy = y1[i] - y2[j]; -#ifdef FME_KERNEL_USE_OLD - float s_sum = s1[i]+s2[j]; -#else - float s_sum = s1[i]*s2[j]; -#endif - float f = COMPUTE_FORCE(dx, dy, s_sum); - fx1[i] += dx*f; - fy1[i] += dy*f; - fx2[j] -= dx*f; - fy2[j] -= dy*f; - } - } -} - - -#ifndef OGDF_FME_KERNEL_USE_SSE_DIRECT -//! kernel function to evaluate forces between n points with coords x, y directly. result is stored in fx, fy -inline void eval_direct_fast(float* x, float* y, float* s, float* fx, float* fy, size_t n) -{ - eval_direct(x, y, s, fx, fy, n); -} - -//! kernel function to evaluate forces between two sets of points with coords x1, y1 (x2, y2) directly. result is stored in fx1, fy1 (fx2, fy2 -inline void eval_direct_fast(float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1, - float* x2, float* y2, float* s2, float* fx2, float* fy2, size_t n2) -{ - eval_direct(x1, y1, s1, fx1, fy1, n1, - x2, y2, s2, fx2, fy2, n2); -} - -#else -//! kernel function to evaluate forces between n points with coords x, y directly. result is stored in fx, fy -void eval_direct_fast(float* x, float* y, float* s, float* fx, float* fy, size_t n); -//! kernel function to evaluate forces between two sets of points with coords x1, y1 (x2, y2) directly. result is stored in fx1, fy1 (fx2, fy2 -void eval_direct_fast( - float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1, - float* x2, float* y2, float* s2, float* fx2, float* fy2, size_t n2); -#endif - -//! kernel function to evalute a local expansion at point x,y result is added to fx, fy -void fast_multipole_l2p(double* localCoeffiecients, __uint32 numCoeffiecients, double centerX, double centerY, - float x, float y, float q, float& fx, float &fy); - -void fast_multipole_p2m(double* mulitCoeffiecients, __uint32 numCoeffiecients, double centerX, double centerY, - float x, float y, float q); - -class FMEBasicKernel -{ -public: - inline void edgeForces(const ArrayGraph& graph, float* fx, float* fy) - { - eval_edges(graph, 0, graph.numEdges()-1, fx, fy); - } - - inline void repForces(ArrayGraph& graph, float* fx, float* fy) - { - eval_direct_fast(graph.nodeXPos(), graph.nodeYPos(), graph.nodeSize(), fx, fy, graph.numNodes()); - } - - inline double moveNodes(ArrayGraph& graph, float* fx, float* fy, float timeStep) - { - return move_nodes(graph.nodeXPos(), graph.nodeYPos(), 0, graph.numNodes()-1, fx, fy, timeStep); - } - - inline double simpleIteration(ArrayGraph& graph, float* fx, float* fy, float timeStep) - { - repForces(graph, fx, fy); - edgeForces(graph, fx, fy); - return moveNodes(graph, fx, fy, timeStep); - } - - - inline double simpleEdgeIteration(ArrayGraph& graph, float* fx, float* fy, float timeStep) - { - edgeForces(graph, fx, fy); - return moveNodes(graph, fx, fy, timeStep); - } - - - inline void simpleForceDirected(ArrayGraph& graph, float timeStep, __uint32 minIt, __uint32 maxIt, __uint32 preProcIt, double threshold) - { - bool earlyExit = false; - float* fx = (float*)MALLOC_16(sizeof(float)*graph.numNodes()); - float* fy = (float*)MALLOC_16(sizeof(float)*graph.numNodes()); - - for (__uint32 i = 0; i(minIt)) - earlyExit = true; - } - - FREE_16(fx); - FREE_16(fy); - } - -private: -}; - - -class FMESingleKernel : FMEBasicKernel -{ -public: - //FMESingleKernel(FMEThread* pThread) : FMEKernel(pThread) {}; - void operator()(ArrayGraph& graph, float timeStep, __uint32 minIt, __uint32 maxIt, double threshold) - { - simpleForceDirected(graph, timeStep, minIt, maxIt, 20, threshold); - } -}; - -} // end of namespace ogdf - -#endif diff --git a/ext/OGDF/src/energybased/FMEMultipoleKernel.cpp b/ext/OGDF/src/energybased/FMEMultipoleKernel.cpp deleted file mode 100644 index b9978df3f..000000000 --- a/ext/OGDF/src/energybased/FMEMultipoleKernel.cpp +++ /dev/null @@ -1,650 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class FMEMultipoleKernel. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "FMEMultipoleKernel.h" -#include "ArrayGraph.h" -#include "LinearQuadtree.h" -#include "LinearQuadtreeBuilder.h" -#include "LinearQuadtreeExpansion.h" -#include "WSPD.h" -#include - -namespace ogdf { - -void FMEMultipoleKernel::quadtreeConstruction(ArrayPartition& pointPartition) -{ - FMELocalContext* localContext = m_pLocalContext; - FMEGlobalContext* globalContext = m_pGlobalContext; - LinearQuadtree& tree = *globalContext->pQuadtree; - - // precompute the bounding box for the quadtree points from the graph nodes - for_loop(pointPartition, min_max_x_function(localContext)); - for_loop(pointPartition, min_max_y_function(localContext)); - - // wait until the thread's bounding box is computed - sync(); - - // let the main thread computed the bounding box of the bounding boxes - if (isMainThread()) - { - globalContext->min_x = globalContext->pLocalContext[0]->min_x; - globalContext->min_y = globalContext->pLocalContext[0]->min_y; - globalContext->max_x = globalContext->pLocalContext[0]->max_x; - globalContext->max_y = globalContext->pLocalContext[0]->max_y; - for (__uint32 j=1; j < numThreads(); j++) - { - globalContext->min_x = min(globalContext->min_x, globalContext->pLocalContext[j]->min_x); - globalContext->min_y = min(globalContext->min_y, globalContext->pLocalContext[j]->min_y); - globalContext->max_x = max(globalContext->max_x, globalContext->pLocalContext[j]->max_x); - globalContext->max_y = max(globalContext->max_y, globalContext->pLocalContext[j]->max_y); - } - tree.init(globalContext->min_x, globalContext->min_y, globalContext->max_x, globalContext->max_y); - globalContext->coolDown *= 0.999f; - tree.clear(); - } - // wait because the morton number computation needs the bounding box - sync(); - // udpate morton number to prepare them for sorting - for_loop(pointPartition, LQMortonFunctor(localContext)); - // wait so we can sort them by morton number - sync(); - -#ifdef OGDF_FME_PARALLEL_QUADTREE_SORT - // use a simple parallel sorting algorithm - LinearQuadtree::LQPoint* points = tree.pointArray(); - sort_parallel(points, tree.numberOfPoints(), LQPointComparer); -#else - if (isMainThread()) - { - LinearQuadtree::LQPoint* points = tree.pointArray(); - sort_single(points, tree.numberOfPoints(), LQPointComparer); - } -#endif - // wait because the quadtree builder needs the sorted order - sync(); - // if not a parallel run, we can do the easy way - if (isSingleThreaded()) - { - LinearQuadtreeBuilder builder(tree); - // prepare the tree - builder.prepareTree(); - // and link it - builder.build(); - LQPartitioner partitioner( localContext ); - partitioner.partition(); - } else // the more difficult part - { - // snap the left point of the interval of the thread to the first in the cell - LinearQuadtree::PointID beginPoint = tree.findFirstPointInCell(pointPartition.begin); - LinearQuadtree::PointID endPoint_plus_one; - // if this thread is the last one, no snapping required for the right point - if (threadNr()==numThreads()-1) - endPoint_plus_one = tree.numberOfPoints(); - else // find the left point of the next thread - endPoint_plus_one = tree.findFirstPointInCell(pointPartition.end+1); - - // now we can prepare the snapped interval - LinearQuadtreeBuilder builder(tree); - // this function prepares the tree from begin point to endPoint_plus_one-1 (EXCLUDING endPoint_plus_one) - builder.prepareTree(beginPoint, endPoint_plus_one); - // save the start, end and count of the inner node chain in the context - localContext->firstInnerNode = builder.firstInner; - localContext->lastInnerNode = builder.lastInner; - localContext->numInnerNodes = builder.numInnerNodes; - // save the start, end and count of the leaf node chain in the context - localContext->firstLeaf = builder.firstLeaf; - localContext->lastLeaf = builder.lastLeaf; - localContext->numLeaves = builder.numLeaves; - // wait until all are finished - sync(); - - // now the main thread has to link the tree - if (isMainThread()) - { - // with his own builder - LinearQuadtreeBuilder sbuilder(tree); - // first we need the complete chain data - sbuilder.firstInner = globalContext->pLocalContext[0]->firstInnerNode; - sbuilder.firstLeaf = globalContext->pLocalContext[0]->firstLeaf; - sbuilder.numInnerNodes = globalContext->pLocalContext[0]->numInnerNodes; - sbuilder.numLeaves = globalContext->pLocalContext[0]->numLeaves; - for (__uint32 j=1; j < numThreads(); j++) - { - sbuilder.numLeaves += globalContext->pLocalContext[j]->numLeaves; - sbuilder.numInnerNodes += globalContext->pLocalContext[j]->numInnerNodes; - } - sbuilder.lastInner = globalContext->pLocalContext[numThreads()-1]->lastInnerNode; - sbuilder.lastLeaf = globalContext->pLocalContext[numThreads()-1]->lastLeaf; - // Link the tree - sbuilder.build(); - // and run the partitions - LQPartitioner partitioner(localContext); - partitioner.partition(); - } - } - // wait for tree to finish - sync(); - // now update the copy of the point data - for_loop(pointPartition, LQPointUpdateFunctor(localContext)); - // compute the nodes coordinates and sizes - tree.forall_tree_nodes(LQCoordsFunctor(localContext), localContext->innerNodePartition.begin, localContext->innerNodePartition.numNodes)(); - tree.forall_tree_nodes(LQCoordsFunctor(localContext), localContext->leafPartition.begin, localContext->leafPartition.numNodes)(); -} - - - - - -void FMEMultipoleKernel::multipoleApproxSingleThreaded(ArrayPartition& nodePointPartition) -{ - FMELocalContext* localContext = m_pLocalContext; - FMEGlobalContext* globalContext = m_pGlobalContext; - LinearQuadtree& tree = *globalContext->pQuadtree; - if (isMainThread()) - { - tree.bottom_up_traversal( // do a bottom up traversal M2M pass - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ) - )(tree.root()); - - tree.forall_well_separated_pairs( // do a wspd traversal M2L direct eval - pair_vice_versa(m2l_function(localContext)),// M2L for a well-separated pair - p2p_function(localContext), // direct evaluation - p2p_function(localContext) // direct evaluation - )(tree.root()); - - tree.top_down_traversal( // top down traversal - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with this case later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ) - )(tree.root());// start at the root - - // evaluate all leaves and store the forces in the threads array - for_loop(nodePointPartition, // loop over points - func_comp( // composition of two statements - l2p_function(localContext), // evaluate the forces due to the local expansion in the corresponding leaf - collect_force_function // collect the forces of all threads with the following options: - < - COLLECT_REPULSIVE_FACTOR | // multiply by the repulsive factor stored in the global options - COLLECT_TREE_2_GRAPH_ORDER | // threads data is stored in quadtree leaf order, transform it into graph order - COLLECT_ZERO_THREAD_ARRAY // reset threads array - >(localContext) - ) - ); - } -} - -//! the original algorithm which runs the WSPD completely single threaded -void FMEMultipoleKernel::multipoleApproxSingleWSPD(ArrayPartition& nodePointPartition) -{ - FMELocalContext* localContext = m_pLocalContext; - FMEGlobalContext* globalContext = m_pGlobalContext; - LinearQuadtree& tree = *globalContext->pQuadtree; - - // let the main thread run the WSPD - if (isMainThread()) - { - // The Well-separated pairs decomposition - tree.forall_well_separated_pairs( // do a wspd traversal - tree.StoreWSPairFunction(), // store the ws pairs in the WSPD - tree.StoreDirectPairFunction(), // store the direct pairs - tree.StoreDirectNodeFunction() // store the direct nodes - )(tree.root()); // start at the root - } - - // Note: dont wait for the WSPD to finish. We dont need it yet for - // the big multihreaded bottom up traversal. - for_tree_partition( // for all roots in the threads tree partition - tree.bottom_up_traversal( // do a bottom up traversal - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ) - ) - ); - sync(); - // top of the tree has to be done by the main thread - if (isMainThread()) - { - tree.bottom_up_traversal( // start a bottom up traversal - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ), - not_condition(tree.is_fence_condition()) // stop when the fence to the threads is reached - )(tree.root());// start at the root - } - // wait until all nodes in the quadtree have their mulipole coeff - sync(); - // M2L pass with the WSPD - tree.forall_tree_nodes(M2LFunctor(localContext), localContext->innerNodePartition.begin, localContext->innerNodePartition.numNodes)(); - tree.forall_tree_nodes(M2LFunctor(localContext), localContext->leafPartition.begin, localContext->leafPartition.numNodes)(); - // D2D pass and store in the thread force array - for_loop(arrayPartition(tree.numberOfDirectPairs()), D2DFunctor(localContext)); - // D pass and store in the thread force array - for_loop(arrayPartition(tree.numberOfDirectNodes()), NDFunctor(localContext)); - // wait until all local coeffs and all direct forces are computed - sync(); - // big multihreaded top down traversal. top of the tree has to be done by the main thread - if (isMainThread()) - { - tree.top_down_traversal( // top down traversal - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with L2P pass later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ), - not_condition(tree.is_fence_condition()) //stop when the fence to the threads is reached - )(tree.root());// start at the root - } - sync(); - // the rest is done by the threads - for_tree_partition( // for all roots in the threads tree partition - tree.top_down_traversal( // do a top down traversal - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with L2P pass later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ) - ) - ); - // wait until the traversal is finished and all leaves have their accumulated local coeffs - sync(); - // evaluate all leaves and store the forces in the threads array (Note: we can store them in the global array but then we have to use random access) - // we can start immediately to collect the forces because we evaluated before point by point - for_loop(nodePointPartition, // loop over threads points - func_comp( // composition of two statements - l2p_function(localContext), // evaluate the forces due to the local expansion in the corresponding leaf - collect_force_function // collect the forces of all threads with the following options: - < - COLLECT_REPULSIVE_FACTOR | // multiply by the repulsive factor stored in the global options - COLLECT_TREE_2_GRAPH_ORDER | // threads data is stored in quadtree leaf order, transform it into graph order - COLLECT_ZERO_THREAD_ARRAY // reset threads array to zero - >(localContext) - ) - ); -} - - -//! new but slower method, parallel wspd computation without using the wspd structure -void FMEMultipoleKernel::multipoleApproxNoWSPDStructure(ArrayPartition& nodePointPartition) -{ - FMELocalContext* localContext = m_pLocalContext; - FMEGlobalContext* globalContext = m_pGlobalContext; - LinearQuadtree& tree = *globalContext->pQuadtree; - // big multihreaded bottom up traversal. - for_tree_partition( // for all roots in the threads tree partition - tree.bottom_up_traversal( // do a bottom up traversal - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ) - ) - ); - sync(); - - // top of the tree has to be done by the main thread - if (isMainThread()) - { - tree.bottom_up_traversal( // start a bottom up traversal - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ), - not_condition(tree.is_fence_condition()))(tree.root());// start at the root, stop when the fence to the threads is reached - - tree.forall_well_separated_pairs( // do a wspd traversal - pair_vice_versa(m2l_function(localContext)), // M2L for a well-separated pair - p2p_function(localContext), // direct evaluation - p2p_function(localContext), // direct evaluation - not_condition(tree.is_fence_condition()))(tree.root()); - } - // wait until all local coeffs and all direct forces are computed - sync(); - - // now a wspd traversal for the roots in the tree partition - for_tree_partition( - tree.forall_well_separated_pairs( // do a wspd traversal - pair_vice_versa(m2l_function(localContext)), // M2L for a well-separated pair - p2p_function(localContext), // direct evaluation - p2p_function(localContext) // direct evaluation - ) - ); - // wait until all local coeffs and all direct forces are computed - sync(); - - // big multihreaded top down traversal. Top of the tree has to be done by the main thread - if (isMainThread()) - { - tree.top_down_traversal( // top down traversal - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with this case later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ), - not_condition(tree.is_fence_condition()) //stop when the fence to the threads is reached - )(tree.root()); // start at the root - } - // wait until the traversal is finished and all roots of the threads have their coefficients - sync(); - - for_tree_partition( // for all roots in the threads tree partition - tree.top_down_traversal( // do a top down traversal - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with this case later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ) - ) - ); - // wait until the traversal is finished and all leaves have their accumulated local coeffs - sync(); - // evaluate all leaves and store the forces in the threads array (Note we can store them in the global array but then we have to use random access) - // we can start immediately to collect the forces because we evaluated before point by point - for_loop(nodePointPartition, // loop over threads points - func_comp( // composition of two statements - l2p_function(localContext), // evaluate the forces due to the local expansion in the corresponding leaf - collect_force_function // collect the forces of all threads with the following options: - < - COLLECT_REPULSIVE_FACTOR | // multiply by the repulsive factor stored in the global options - COLLECT_TREE_2_GRAPH_ORDER | // threads data is stored in quadtree leaf order, transform it into graph order - COLLECT_ZERO_THREAD_ARRAY // reset threads array - >(localContext) - ) - ); -} - - -//! the final approximation algorithm which runs the wspd parallel without storing it in the threads subtrees -void FMEMultipoleKernel::multipoleApproxFinal(ArrayPartition& nodePointPartition) -{ - FMELocalContext* localContext = m_pLocalContext; - FMEGlobalContext* globalContext = m_pGlobalContext; - LinearQuadtree& tree = *globalContext->pQuadtree; - // big multihreaded bottom up traversal. - for_tree_partition( // for all roots in the threads tree partition - tree.bottom_up_traversal( // do a bottom up traversal - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ) - ) - ); - sync(); - // top of the tree has to be done by the main thread - if (isMainThread()) - { - tree.bottom_up_traversal( // start a bottom up traversal - if_then_else(tree.is_leaf_condition(), // if the current node is a leaf - p2m_function(localContext), // then calculate the multipole coeff. due to the points in the leaf - m2m_function(localContext) // else shift the coefficents of all children to center of the inner node - ), - not_condition(tree.is_fence_condition()))(tree.root());// start at the root, stop when the fence to the threads is reached - - tree.forall_well_separated_pairs( // do a wspd traversal - tree.StoreWSPairFunction(), // store the ws pairs in the WSPD - tree.StoreDirectPairFunction(), // store the direct pairs - tree.StoreDirectNodeFunction(), // store the direct nodes - not_condition(tree.is_fence_condition()))(tree.root()); - } - // wait for the main thread to finish - sync(); - - // M2L pass with the WSPD for the result of the single threaded pass above - tree.forall_tree_nodes(M2LFunctor(localContext), localContext->innerNodePartition.begin, localContext->innerNodePartition.numNodes)(); - tree.forall_tree_nodes(M2LFunctor(localContext), localContext->leafPartition.begin, localContext->leafPartition.numNodes)(); - - // D2D pass and store in the thread force array - for_loop(arrayPartition(tree.numberOfDirectPairs()), D2DFunctor(localContext)); - for_loop(arrayPartition(tree.numberOfDirectNodes()), NDFunctor(localContext)); - - // wait until all local coeffs and all direct forces are computed - sync(); - - // the rest of the WSPD can be done on the fly by the thread - for_tree_partition( - tree.forall_well_separated_pairs( // do a wspd traversal - pair_vice_versa(m2l_function(localContext)), // M2L for a well-separated pair - p2p_function(localContext), // direct evaluation - p2p_function(localContext) // direct evaluation - ) - ); - // wait until all local coeffs and all direct forces are computed - sync(); - - // big multihreaded top down traversal. top of the tree has to be done by the main thread - if (isMainThread()) - { - tree.top_down_traversal( // top down traversal L2L pass - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with this case later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ), - not_condition(tree.is_fence_condition()) // stop when the fence to the threads is reached - )(tree.root()); // start at the root, - } - // wait for the top of the tree - sync(); - - for_tree_partition( // for all roots in the threads tree partition L2L pass - tree.top_down_traversal( // do a top down traversal - if_then_else( tree.is_leaf_condition(), // if the node is a leaf - do_nothing(), // then do nothing, we will deal with this case later - l2l_function(localContext) // else shift the nodes local coeffs to the children - ) - ) - ); - // wait until the traversal is finished and all leaves have their accumulated local coeffs - sync(); - // evaluate all leaves and store the forces in the threads array (Note we can store them in the global array but then we have to use random access) - // we can start immediately to collect the forces because we evaluated before point by point - for_loop(nodePointPartition, // loop over threads points - func_comp( // composition of two statements - l2p_function(localContext), // evaluate the forces due to the local expansion in the corresponding leaf - collect_force_function // collect the forces of all threads with the following options: - < - COLLECT_REPULSIVE_FACTOR | // multiply by the repulsive factor stored in the global options - COLLECT_TREE_2_GRAPH_ORDER | // threads data is stored in quadtree leaf order, transform it into graph order - COLLECT_ZERO_THREAD_ARRAY // reset threads array - >(localContext) - ) - ); -} - - - -void FMEMultipoleKernel::operator()(FMEGlobalContext* globalContext) -{ - __uint32 maxNumIterations = globalContext->pOptions->maxNumIterations; - __uint32 minNumIterations = globalContext->pOptions->minNumIterations; - ArrayGraph& graph = *globalContext->pGraph; - LinearQuadtree& tree = *globalContext->pQuadtree; - LinearQuadtreeExpansion& treeExp = *globalContext->pExpansion; - FMELocalContext* localContext = globalContext->pLocalContext[threadNr()]; - FMEGlobalOptions* options = globalContext->pOptions; - float* threadsForceArrayX = localContext->forceX; - float* threadsForceArrayY = localContext->forceY; - float* globalForceArrayX = globalContext->globalForceX; - float* globalForceArrayY = globalContext->globalForceY; - - ArrayPartition edgePartition = arrayPartition(graph.numEdges()); - ArrayPartition nodePointPartition = arrayPartition(graph.numNodes()); - - m_pLocalContext = localContext; - m_pGlobalContext = globalContext; - /****************************/ - /* INIT */ - /****************************/ - //! reset the global force array - for_loop_array_set(threadNr(), numThreads(), globalForceArrayX, tree.numberOfPoints(), 0.0f); - for_loop_array_set(threadNr(), numThreads(), globalForceArrayY, tree.numberOfPoints(), 0.0f); - - // reset the threads force array - for (__uint32 i = 0; i < tree.numberOfPoints(); i++) - { - threadsForceArrayX[i] = 0.0f; - threadsForceArrayY[i] = 0.0f; - } - - __uint32 maxNumIt = options->preProcMaxNumIterations; - for (__uint32 currNumIteration = 0; ((currNumIteration < maxNumIt) ); currNumIteration++) - { - // iterate over all edges and store the resulting forces in the threads array - for_loop(edgePartition, - edge_force_function< EDGE_FORCE_DIV_DEGREE > (localContext) // divide the forces by degree of the node to avoid oscilation - ); - // wait until all edges are done - sync(); - // now collect the forces in parallel and put the sum into the global array and move the nodes accordingly - for_loop(nodePointPartition, - func_comp( - collect_force_function(localContext), - node_move_function(localContext) - ) - ); - } - if (isMainThread()) - { - globalContext->coolDown = 1.0f; - } - sync(); - - for (__uint32 currNumIteration = 0; ((currNumIteration < maxNumIterations) && !globalContext->earlyExit); currNumIteration++) - { - // reset the coefficients - for_loop_array_set(threadNr(), numThreads(), treeExp.m_multiExp, treeExp.m_numExp*(treeExp.m_numCoeff << 1), 0.0); - for_loop_array_set(threadNr(), numThreads(), treeExp.m_localExp, treeExp.m_numExp*(treeExp.m_numCoeff << 1), 0.0); - - localContext->maxForceSq = 0.0; - localContext->avgForce = 0.0; - - // construct the quadtree - quadtreeConstruction(nodePointPartition); - // wait for all threads to finish - sync(); - - if (isSingleThreaded()) // if is single threaded run the simple approximation - multipoleApproxSingleThreaded(nodePointPartition); - else // otherwise use the partitioning - multipoleApproxFinal(nodePointPartition); - // now wait until all forces are summed up in the global array and mapped to graph node order - sync(); - - // run the edge forces - for_loop(edgePartition, // iterate over all edges and sum up the forces in the threads array - edge_force_function< EDGE_FORCE_DIV_DEGREE >(localContext) // divide the forces by degree of the node to avoid oscilation - ); - // wait until edges are finished - sync(); - - // collect the edge forces and move nodes without waiting - for_loop(nodePointPartition, - func_comp( - collect_force_function(localContext), - node_move_function(localContext) - ) - ); - // wait so we can decide if we need another iteration - sync(); - // check the max force square for all threads - if (isMainThread()) - { - double maxForceSq = 0.0; - for (__uint32 j=0; j < numThreads(); j++) - maxForceSq = max(globalContext->pLocalContext[j]->maxForceSq, maxForceSq); - - // if we are allowed to quit and the max force sq falls under the threshold tell all threads we are done - if ((currNumIteration >= minNumIterations) && (maxForceSq < globalContext->pOptions->stopCritForce )) - { - globalContext->earlyExit = true; - } - } - // this is required to wait for the earlyExit result - sync(); - } -} - -//! allcates the global context and for all threads a local context -FMEGlobalContext* FMEMultipoleKernel::allocateContext(ArrayGraph* pGraph, FMEGlobalOptions* pOptions, __uint32 numThreads) -{ - FMEGlobalContext* globalContext = new FMEGlobalContext(); - - globalContext->numThreads = numThreads; - globalContext->pOptions = pOptions; - globalContext->pGraph = pGraph; - globalContext->pQuadtree = new LinearQuadtree(pGraph->numNodes(), pGraph->nodeXPos(), pGraph->nodeYPos(), pGraph->nodeSize()); - globalContext->pWSPD = globalContext->pQuadtree->wspd(); - globalContext->pExpansion = new LinearQuadtreeExpansion(globalContext->pOptions->multipolePrecision, (*globalContext->pQuadtree)); - __uint32 numPoints = globalContext->pQuadtree->numberOfPoints(); - typedef FMELocalContext* FMELocalContextPtr; - - globalContext->pLocalContext = new FMELocalContextPtr[numThreads]; - globalContext->globalForceX = (float*)MALLOC_16(sizeof(float)*numPoints); - globalContext->globalForceY = (float*)MALLOC_16(sizeof(float)*numPoints); - for (__uint32 i=0; i < numThreads; i++) - { - globalContext->pLocalContext[i] = new FMELocalContext; - globalContext->pLocalContext[i]->forceX = (float*)MALLOC_16(sizeof(float)*numPoints); - globalContext->pLocalContext[i]->forceY = (float*)MALLOC_16(sizeof(float)*numPoints); - globalContext->pLocalContext[i]->pGlobalContext = globalContext; - } - return globalContext; -} - -//! frees the memory for all contexts -void FMEMultipoleKernel::deallocateContext(FMEGlobalContext* globalContext) -{ - __uint32 numThreads = globalContext->numThreads; - for (__uint32 i=0; i < numThreads; i++) - { - FREE_16(globalContext->pLocalContext[i]->forceX); - FREE_16(globalContext->pLocalContext[i]->forceY); - delete globalContext->pLocalContext[i]; - } - FREE_16(globalContext->globalForceX); - FREE_16(globalContext->globalForceY); - delete[] globalContext->pLocalContext; - delete globalContext->pExpansion; - delete globalContext->pQuadtree; - delete globalContext; -} - -} diff --git a/ext/OGDF/src/energybased/FMEMultipoleKernel.h b/ext/OGDF/src/energybased/FMEMultipoleKernel.h deleted file mode 100644 index d2ac3a403..000000000 --- a/ext/OGDF/src/energybased/FMEMultipoleKernel.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class FMEMultipoleKernel. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FME_MULTIPOLE_KERNEL_H -#define OGDF_FME_MULTIPOLE_KERNEL_H - -#include "FMEKernel.h" -#include "FMEFunc.h" -#include - -namespace ogdf { - -struct ArrayPartition -{ - __uint32 begin; - __uint32 end; - - template - void for_loop(Func& func) - { - for(__uint32 i=begin; i<=end; i++) func(i); - } -}; - - -class FMEMultipoleKernel : public FMEKernel -{ -public: - FMEMultipoleKernel(FMEThread* pThread) : FMEKernel(pThread) { } - - //! allocate the global and local contexts used by an instance of this kernel - static FMEGlobalContext* allocateContext(ArrayGraph* pGraph, FMEGlobalOptions* pOptions, __uint32 numThreads); - - //! free the global and local context - static void deallocateContext(FMEGlobalContext* globalContext); - - //! sub procedure for quadtree construction - void quadtreeConstruction(ArrayPartition& nodePointPartition); - - //! the single threaded version without fences - void multipoleApproxSingleThreaded(ArrayPartition& nodePointPartition); - - //! the original algorithm which runs the WSPD completely single threaded - void multipoleApproxSingleWSPD(ArrayPartition& nodePointPartition); - - //! new but slower method, parallel wspd computation without using the wspd structure - void multipoleApproxNoWSPDStructure(ArrayPartition& nodePointPartition); - - //! the final version, the wspd structure is only used for the top of the tree - void multipoleApproxFinal(ArrayPartition& nodePointPartition); - - //! main function of the kernel - void operator()(FMEGlobalContext* globalContext); - - //! creates an array partition with a default chunksize of 16 - inline ArrayPartition arrayPartition(__uint32 n) - { - return arrayPartition(n, threadNr(), numThreads(), 16); - } - - //! returns an array partition for the given threadNr and thread count - inline ArrayPartition arrayPartition(__uint32 n, __uint32 threadNr, __uint32 numThreads, __uint32 chunkSize) - { - ArrayPartition result; - if (!n) - { - result.begin = 1; - result.end = 0; - return result; - } - if (n>=numThreads*chunkSize) - { - __uint32 s = n/(numThreads*chunkSize); - __uint32 o = s*chunkSize*threadNr; - if (threadNr == numThreads-1) - { - result.begin = o; - result.end = n-1; - } - else - { - result.begin = o; - result.end = o+s*chunkSize-1; - } - } else - { - if (threadNr == 0) - { - result.begin = 0; - result.end = n-1; - } else - { - result.begin = 1; - result.end = 0; - } - } - return result; - } - - //! for loop on a partition - template - inline void for_loop(const ArrayPartition& partition, F func) - { - if (partition.begin > partition.end) - return; - for (__uint32 i=partition.begin; i<= partition.end; i++) func(i); - } - - //! for loop on the tree partition - template - inline void for_tree_partition(F functor) - { - for (std::list<__uint32>::const_iterator it = m_pLocalContext->treePartition.nodes.begin(); - it!=m_pLocalContext->treePartition.nodes.end(); it++) - { - __uint32 node = *it; - functor(node); - } - } - - //! sorting single threaded - template - inline void sort_single(T* ptr, __uint32 n, C comparer) - { - if (isMainThread()) - { - std::sort(ptr, ptr + n, comparer); - } - } - - //! lazy parallel sorting for num_threads = power of two - template - inline void sort_parallel(T* ptr, __uint32 n, C comparer) - { - if ((n < numThreads()*1000) || (numThreads() == 1)) - sort_single(ptr, n, comparer); - else - sort_parallel(ptr, n, comparer, 0, numThreads()); - } - - //! lazy parallel sorting for num_threads = power of two - template - inline void sort_parallel(T* ptr, __uint32 n, C comparer, __uint32 threadNrBegin, __uint32 numThreads) - { - if (n <= 1) return; - if (numThreads == 1) - { - std::sort(ptr, ptr + n, comparer); - } - else - { - __uint32 half = n >> 1; - __uint32 halfThreads = numThreads >> 1; - if (this->threadNr() < threadNrBegin + halfThreads) - sort_parallel(ptr, half, comparer, threadNrBegin, halfThreads); - else - sort_parallel(ptr + half, n - half, comparer, threadNrBegin + halfThreads, halfThreads); - - // wait until all threads are ready. - sync(); - if (this->threadNr() == threadNrBegin) - std::inplace_merge(ptr, ptr + half, ptr + n, comparer); - } - } - -private: - FMEGlobalContext* m_pGlobalContext; - FMELocalContext* m_pLocalContext; -}; - -}; - -#endif diff --git a/ext/OGDF/src/energybased/FMEThread.cpp b/ext/OGDF/src/energybased/FMEThread.cpp deleted file mode 100644 index d591bce71..000000000 --- a/ext/OGDF/src/energybased/FMEThread.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class FMEThread. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "FMEThread.h" - -namespace ogdf { - -#if defined(OGDF_SYSTEM_UNIX) && defined(OGDF_FME_THREAD_AFFINITY) -#include -#include -#include -#include - -//! helper function for setting the affinity on the test machine. -void CPU_SET_ordered_dual_quad(int cpu, cpu_set_t* set) -{ - int cpuOrdered = cpu; - switch ( cpu ) - { - case 0 : cpuOrdered = 0; break; - case 1 : cpuOrdered = 2; break; - case 2 : cpuOrdered = 4; break; - case 3 : cpuOrdered = 6; break; - - case 4 : cpuOrdered = 1; break; - case 5 : cpuOrdered = 3; break; - case 6 : cpuOrdered = 5; break; - case 7 : cpuOrdered = 7; break; - default: cpuOrdered = 0; break; - } - CPU_SET(cpuOrdered, set); -} - -void FMEThread::unixSetAffinity() -{ - cpu_set_t mask; - CPU_ZERO( &mask ); - CPU_SET_ordered_dual_quad(m_threadNr*(System::numberOfProcessors()/m_numThreads), &mask); - sched_setaffinity( 0, sizeof(mask), &mask ); -} -#endif - - -FMEThread::FMEThread(FMEThreadPool* pThreadPool, __uint32 threadNr) : m_threadNr(threadNr), m_pThreadPool(pThreadPool) -{ - m_numThreads = m_pThreadPool->numThreads(); -} - - -void FMEThread::sync() -{ - if (m_numThreads>1) - m_pThreadPool->syncBarrier()->threadSync(); -} - - - -FMEThreadPool::FMEThreadPool(__uint32 numThreads) : m_numThreads(numThreads) -{ - allocate(); -} - -FMEThreadPool::~FMEThreadPool() -{ - deallocate(); -} - -//! runs one iteration. This call blocks the main thread -void FMEThreadPool::runThreads() -{ - for (__uint32 i=1; i < numThreads(); i++) - { - thread(i)->start(); - } - - thread(0)->doWork(); - - for (__uint32 i=1; i < numThreads(); i++) - { - thread(i)->join(); - } -} - - -void FMEThreadPool::allocate() -{ - typedef FMEThread* FMEThreadPtr; - - m_pSyncBarrier = new Barrier(m_numThreads); - m_pThreads = new FMEThreadPtr[m_numThreads]; - for (__uint32 i=0; i < numThreads(); i++) - { - m_pThreads[i] = new FMEThread(this, i); -#ifdef OGDF_SYSTEM_WINDOWS - m_pThreads[i]->priority(Thread::tpCritical); - m_pThreads[i]->cpuAffinity(1 << i); -#endif - } -} - -void FMEThreadPool::deallocate() -{ - for (__uint32 i=0; i < numThreads(); i++) - { - delete m_pThreads[i]; - } - delete[] m_pThreads; - delete m_pSyncBarrier; -} - -} // end of namespace ogdf - diff --git a/ext/OGDF/src/energybased/FMEThread.h b/ext/OGDF/src/energybased/FMEThread.h deleted file mode 100644 index 149e6ef60..000000000 --- a/ext/OGDF/src/energybased/FMEThread.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class FMEThread. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_FME_THREAD_H -#define OGDF_FME_THREAD_H - -#include -#include -#include "FastUtils.h" - -namespace ogdf { - -class ArrayGraph; -class LinearQuadtree; -class LinearQuadtreeExpansion; -class FMEThreadPool; -class FMEThread; -class WSPD; - -//! AutoLock class to easily lock a scope -class AutoLock -{ -public: - AutoLock(CriticalSection* cs) : m_pCriticalSection(cs) { m_pCriticalSection->enter(); } - - ~AutoLock() { m_pCriticalSection->leave(); } - -private: - CriticalSection* m_pCriticalSection; -}; - - -/*! - * The thread task class - * used only as an interface -*/ -class FMETask -{ -public: - virtual ~FMETask() { } - // the doWork method to override - virtual void doWork() = 0; -}; - - -/*! - * Class used to invoke a functor or function inside a thread. -*/ -template -class FMEFuncInvokerTask : public FMETask -{ -public: - //! constructor with an invoker - FMEFuncInvokerTask(FuncInvokerType f) : funcInvoker(f) { } - - //! overrides the task doWork() method and invokes the function or functor - void doWork() { funcInvoker(); } -private: - //! the invoker - FuncInvokerType funcInvoker; -}; - - -/*! - * The fast multipole embedder work thread class -*/ -class FMEThread : public Thread -{ -public: - //! construtor - FMEThread(FMEThreadPool* pThreadPool, __uint32 threadNr); - - //! returns the index of the thread ( 0.. numThreads()-1 ) - inline __uint32 threadNr() const { return m_threadNr; } - - //! returns the total number of threads in the pool - inline __uint32 numThreads() const { return m_numThreads; } - - //! returns true if this is the main thread ( the main thread is always the first thread ) - inline bool isMainThread() const { return (m_threadNr == 0); } - - //! returns the ThreadPool this thread belongs to - inline FMEThreadPool* threadPool() const { return m_pThreadPool; } - - //! thread sync call - void sync(); -#if defined(OGDF_SYSTEM_UNIX) && defined(OGDF_FME_THREAD_AFFINITY) - void unixSetAffinity(); - - //! the main work function - void doWork() { unixSetAffinity(); m_pTask->doWork(); delete m_pTask; m_pTask = 0; }; -#else - //! the main work function - void doWork() { m_pTask->doWork(); delete m_pTask; m_pTask = 0; } -#endif - //! sets the actual task - void setTask(FMETask* pTask) { m_pTask = pTask; } - -private: - __uint32 m_threadNr; - - __uint32 m_numThreads; - - FMEThreadPool* m_pThreadPool; - - FMETask* m_pTask; -}; - - -class FMEThreadPool -{ -public: - FMEThreadPool(__uint32 numThreads); - - ~FMEThreadPool(); - - //! returns the number of threads in this pool - inline __uint32 numThreads() const { return m_numThreads; } - - //! returns the threadNr-th thread - inline FMEThread* thread(__uint32 threadNr) const { return m_pThreads[threadNr]; } - - //! returns the barrier instance used to sync the threads during execution - inline Barrier* syncBarrier() const { return m_pSyncBarrier; } - - //! runs one iteration. This call blocks the main thread - void runThreads(); - - template - void runKernel(ArgType1 arg1) - { - for (__uint32 i=0; i < numThreads(); i++) - { - KernelType kernel(thread(i)); - FuncInvoker invoker(kernel, arg1); - thread(i)->setTask(new FMEFuncInvokerTask< FuncInvoker< KernelType, ArgType1 > >(invoker)); - } - runThreads(); - } - -private: - void allocate(); - - void deallocate(); - - __uint32 m_numThreads; - - FMEThread** m_pThreads; - - Barrier* m_pSyncBarrier; -}; - -} - -#endif - diff --git a/ext/OGDF/src/energybased/FMMMLayout.cpp b/ext/OGDF/src/energybased/FMMMLayout.cpp deleted file mode 100644 index 0c8046d73..000000000 --- a/ext/OGDF/src/energybased/FMMMLayout.cpp +++ /dev/null @@ -1,1644 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Fast Multipole Multilevel Method (FM^3). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include "numexcept.h" -#include "MAARPacking.h" -#include "Multilevel.h" -#include "Edge.h" -#include -#include - -#include -#include -#include "Rectangle.h" - -namespace ogdf { - - -FMMMLayout::FMMMLayout() -{ - initialize_all_options(); -} - - -//--------------------------- most important functions -------------------------------- - -void FMMMLayout::call(GraphAttributes &GA) -{ - const Graph &G = GA.constGraph(); - EdgeArray edgelength(G,1.0); - call(GA,edgelength); -} - -void FMMMLayout::call(ClusterGraphAttributes &GA) -{ - const Graph &G = GA.constGraph(); - //compute depth of cluster tree, also sets cluster depth values - const ClusterGraph &CG = GA.constClusterGraph(); - int cdepth = CG.treeDepth(); - EdgeArray edgeLength(G); - //compute lca of end vertices for each edge - edge e; - forall_edges(e, G) - { - edgeLength[e] = cdepth - CG.clusterDepth(CG.commonCluster(e->source(),e->target())) + 1; - OGDF_ASSERT(edgeLength[e] > 0) - } - call(GA,edgeLength); - GA.updateClusterPositions(); -} - - -void FMMMLayout::call(GraphAttributes &GA, const EdgeArray &edgeLength) -{ - const Graph &G = GA.constGraph(); - NodeArray A(G); //stores the attributes of the nodes (given by L) - EdgeArray E(G); //stores the edge attributes of G - Graph G_reduced; //stores a undirected simple and loopfree copy - //of G - EdgeArray E_reduced; //stores the edge attributes of G_reduced - NodeArray A_reduced; //stores the node attributes of G_reduced - - if(G.numberOfNodes() > 1) - { - GA.clearAllBends();//all edges are straight-line - if(useHighLevelOptions()) - update_low_level_options_due_to_high_level_options_settings(); - import_NodeAttributes(G,GA,A); - import_EdgeAttributes(G,edgeLength,E); - - double t_total; - usedTime(t_total); - max_integer_position = pow(2.0,maxIntPosExponent()); - init_ind_ideal_edgelength(G,A,E); - make_simple_loopfree(G,A,E,G_reduced,A_reduced,E_reduced); - call_DIVIDE_ET_IMPERA_step(G_reduced,A_reduced,E_reduced); - if(allowedPositions() != apAll) - make_positions_integer(G_reduced,A_reduced); - time_total = usedTime(t_total); - - export_NodeAttributes(G_reduced,A_reduced,GA); - } - else //trivial cases - { - if(G.numberOfNodes() == 1 ) - { - node v = G.firstNode(); - GA.x(v) = 0; - GA.y(v) = 0; - } - } -} - - -void FMMMLayout::call(GraphAttributes &AG, char* ps_file) -{ - call(AG); - create_postscript_drawing(AG,ps_file); -} - - -void FMMMLayout::call( - GraphAttributes &AG, - const EdgeArray &edgeLength, - char* ps_file) -{ - call(AG,edgeLength); - create_postscript_drawing(AG,ps_file); -} - - -void FMMMLayout::call_DIVIDE_ET_IMPERA_step( - Graph& G, - NodeArray& A, - EdgeArray& E) -{ - NodeArray component(G); //holds for each node the index of its component - number_of_components = connectedComponents(G,component);//calculate components of G - Graph* G_sub = new Graph[number_of_components]; - NodeArray* A_sub = new NodeArray[number_of_components]; - EdgeArray* E_sub = new EdgeArray[number_of_components]; - create_maximum_connected_subGraphs(G,A,E,G_sub,A_sub,E_sub,component); - - if(number_of_components == 1) - call_MULTILEVEL_step_for_subGraph(G_sub[0],A_sub[0],E_sub[0],-1); - else - for(int i = 0; i < number_of_components;i++) - call_MULTILEVEL_step_for_subGraph(G_sub[i],A_sub[i],E_sub[i],i); - - pack_subGraph_drawings (A,G_sub,A_sub); - delete_all_subGraphs(G_sub,A_sub,E_sub); -} - - -void FMMMLayout::call_MULTILEVEL_step_for_subGraph( - Graph& G, - NodeArray& A, - EdgeArray& E, - int comp_index) -{ - Multilevel Mult; - - int max_level = 30;//sufficient for all graphs with upto pow(2,30) nodes! - //adapt mingraphsize such that no levels are created beyond input graph. - if (m_singleLevel) m_minGraphSize = G.numberOfNodes(); - Array G_mult_ptr(max_level+1); - Array*> A_mult_ptr (max_level+1); - Array*> E_mult_ptr (max_level+1); - - Mult.create_multilevel_representations(G,A,E,randSeed(), - galaxyChoice(),minGraphSize(), - randomTries(),G_mult_ptr,A_mult_ptr, - E_mult_ptr,max_level); - - for(int i = max_level;i >= 0;i--) - { - if(i == max_level) - create_initial_placement(*G_mult_ptr[i],*A_mult_ptr[i]); - else - { - Mult.find_initial_placement_for_level(i,initialPlacementMult(),G_mult_ptr, A_mult_ptr,E_mult_ptr); - update_boxlength_and_cornercoordinate(*G_mult_ptr[i],*A_mult_ptr[i]); - } - call_FORCE_CALCULATION_step(*G_mult_ptr[i],*A_mult_ptr[i],*E_mult_ptr[i], - i,max_level); - } - Mult.delete_multilevel_representations(G_mult_ptr,A_mult_ptr,E_mult_ptr,max_level); -} - - -void FMMMLayout::call_FORCE_CALCULATION_step( - Graph& G, - NodeArray&A, - EdgeArray& E, - int act_level, - int max_level) -{ - const int ITERBOUND = 10000;//needed to guarantee termination if - //stopCriterion() == scThreshold - if(G.numberOfNodes() > 1) - { - int iter = 1; - int max_mult_iter = get_max_mult_iter(act_level,max_level,G.numberOfNodes()); - double actforcevectorlength = threshold() + 1; - - NodeArray F_rep(G); //stores rep. forces - NodeArray F_attr(G); //stores attr. forces - NodeArray F (G); //stores resulting forces - NodeArray last_node_movement(G);//stores the force vectors F of the last - //iterations (needed to avoid oscillations) - - set_average_ideal_edgelength(G,E);//needed for easy scaling of the forces - make_initialisations_for_rep_calc_classes(G); - - while( ((stopCriterion() == scFixedIterations)&&(iter <= max_mult_iter)) || - ((stopCriterion() == scThreshold)&&(actforcevectorlength >= threshold())&& - (iter <= ITERBOUND)) || - ((stopCriterion() == scFixedIterationsOrThreshold)&&(iter <= max_mult_iter) && - (actforcevectorlength >= threshold())) ) - {//while - calculate_forces(G,A,E,F,F_attr,F_rep,last_node_movement,iter,0); - if(stopCriterion() != scFixedIterations) - actforcevectorlength = get_average_forcevector_length(G,F); - iter++; - }//while - - if(act_level == 0) - call_POSTPROCESSING_step(G,A,E,F,F_attr,F_rep,last_node_movement); - - deallocate_memory_for_rep_calc_classes(); - } -} - - -void FMMMLayout::call_POSTPROCESSING_step( - Graph& G, - NodeArray& A, - EdgeArray& E, - NodeArray& F, - NodeArray& F_attr, - NodeArray& F_rep, - NodeArray& last_node_movement) -{ - for(int i = 1; i<= 10; i++) - calculate_forces(G,A,E,F,F_attr,F_rep,last_node_movement,i,1); - - if((resizeDrawing() == true)) - { - adapt_drawing_to_ideal_average_edgelength(G,A,E); - update_boxlength_and_cornercoordinate(G,A); - } - - for(int i = 1; i<= fineTuningIterations(); i++) - calculate_forces(G,A,E,F,F_attr,F_rep,last_node_movement,i,2); - - if((resizeDrawing() == true)) - adapt_drawing_to_ideal_average_edgelength(G,A,E); -} - - -//------------------------- functions for pre/post-processing ------------------------- - -void FMMMLayout::initialize_all_options() -{ - //setting high level options - useHighLevelOptions(false); pageFormat(pfSquare); unitEdgeLength(100); - newInitialPlacement(false); qualityVersusSpeed(qvsBeautifulAndFast); - - //setting low level options - //setting general options - randSeed(100);edgeLengthMeasurement(elmBoundingCircle); - allowedPositions(apInteger);maxIntPosExponent(40); - - //setting options for the divide et impera step - pageRatio(1.0);stepsForRotatingComponents(10); - tipOverCCs(toNoGrowingRow);minDistCC(100); - presortCCs(psDecreasingHeight); - - //setting options for the multilevel step - minGraphSize(50);galaxyChoice(gcNonUniformProbLowerMass);randomTries(20); - maxIterChange(micLinearlyDecreasing);maxIterFactor(10); - initialPlacementMult(ipmAdvanced); - m_singleLevel = false; - - //setting options for the force calculation step - forceModel(fmNew);springStrength(1);repForcesStrength(1); - repulsiveForcesCalculation(rfcNMM);stopCriterion(scFixedIterationsOrThreshold); - threshold(0.01);fixedIterations(30);forceScalingFactor(0.05); - coolTemperature(false);coolValue(0.99);initialPlacementForces(ipfRandomRandIterNr); - - //setting options for postprocessing - resizeDrawing(true);resizingScalar(1);fineTuningIterations(20); - fineTuneScalar(0.2);adjustPostRepStrengthDynamically(true); - postSpringStrength(2.0);postStrengthOfRepForces(0.01); - - //setting options for different repulsive force calculation methods - frGridQuotient(2); - nmTreeConstruction(rtcSubtreeBySubtree);nmSmallCell(scfIteratively); - nmParticlesInLeaves(25); nmPrecision(4); -} - - -void FMMMLayout::update_low_level_options_due_to_high_level_options_settings() -{ - PageFormatType pf = pageFormat(); - double uel = unitEdgeLength(); - bool nip = newInitialPlacement(); - QualityVsSpeed qvs = qualityVersusSpeed(); - - //update - initialize_all_options(); - useHighLevelOptions(true); - pageFormat(pf); - unitEdgeLength(uel); - newInitialPlacement(nip); - qualityVersusSpeed(qvs); - - if(pageFormat() == pfSquare) - pageRatio(1.0); - else if(pageFormat() ==pfLandscape) - pageRatio(1.4142); - else //pageFormat() == pfPortrait - pageRatio(0.7071); - - if(newInitialPlacement()) - initialPlacementForces(ipfRandomTime); - else - initialPlacementForces(ipfRandomRandIterNr); - - if(qualityVersusSpeed() == qvsGorgeousAndEfficient) - { - fixedIterations(60); - fineTuningIterations(40); - nmPrecision(6); - } - else if(qualityVersusSpeed() == qvsBeautifulAndFast) - { - fixedIterations(30); - fineTuningIterations(20); - nmPrecision(4); - } - else //qualityVersusSpeed() == qvsNiceAndIncredibleSpeed - { - fixedIterations(15); - fineTuningIterations(10); - nmPrecision(2); - } -} - - -void FMMMLayout::import_NodeAttributes( - const Graph& G, - GraphAttributes& GA, - NodeArray& A) -{ - node v; - DPoint position; - - forall_nodes(v,G) - { - position.m_x = GA.x(v); - position.m_y = GA.y(v); - A[v].set_NodeAttributes(GA.width(v),GA.height(v),position,NULL,NULL); - } -} - - -void FMMMLayout::import_EdgeAttributes( - const Graph& G, - const EdgeArray& edgeLength, - EdgeArray& E) -{ - edge e; - double length; - - forall_edges(e,G) - { - if(edgeLength[e] > 0) //no negative edgelength allowed - length = edgeLength[e]; - else - length = 1; - - E[e].set_EdgeAttributes(length,NULL,NULL); - } -} - - -void FMMMLayout::init_ind_ideal_edgelength( - const Graph& G, - NodeArray& A, - EdgeArray& E) -{ - edge e; - - if (edgeLengthMeasurement() == elmMidpoint) - forall_edges(e,G) - E[e].set_length(E[e].get_length() * unitEdgeLength()); - - else //(edgeLengthMeasurement() == elmBoundingCircle) - { - set_radii(G,A); - forall_edges(e,G) - E[e].set_length(E[e].get_length() * unitEdgeLength() + radius[e->source()] - + radius[e->target()]); - } -} - - -void FMMMLayout::set_radii(const Graph& G, NodeArray& A) -{ - node v; - radius.init(G); - double w,h; - forall_nodes(v,G) - { - w = A[v].get_width()/2; - h = A[v].get_height()/2; - radius[v] = sqrt(w*w+ h*h); - } -} - - -void FMMMLayout::export_NodeAttributes( - Graph& G_reduced, - NodeArray& A_reduced, - GraphAttributes& GA) -{ - node v_copy; - forall_nodes(v_copy,G_reduced) - { - GA.x(A_reduced[v_copy].get_original_node()) = A_reduced[v_copy].get_position().m_x; - GA.y(A_reduced[v_copy].get_original_node()) = A_reduced[v_copy].get_position().m_y; - } -} - - -void FMMMLayout::make_simple_loopfree( - const Graph& G, - NodeArray& A, - EdgeArrayE, - Graph& G_reduced, - NodeArray& A_reduced, - EdgeArray& E_reduced) -{ - node u_orig,v_orig,v_reduced; - edge e_reduced,e_orig; - - //create the reduced Graph G_reduced and save in A/E links to node/edges of G_reduced - //create G_reduced as a copy of G without selfloops! - - G_reduced.clear(); - forall_nodes(v_orig,G) - A[v_orig].set_copy_node(G_reduced.newNode()); - forall_edges(e_orig,G) - { - u_orig = e_orig->source(); - v_orig = e_orig->target(); - if(u_orig != v_orig) - E[e_orig].set_copy_edge(G_reduced.newEdge (A[u_orig].get_copy_node(), - A[v_orig].get_copy_node())); - else - E[e_orig].set_copy_edge(NULL);//mark this edge as deleted - } - - //remove parallel (and reversed) edges from G_reduced - EdgeArray new_edgelength(G_reduced); - List S; - S.clear(); - delete_parallel_edges(G,E,G_reduced,S,new_edgelength); - - //make A_reduced, E_reduced valid for G_reduced - A_reduced.init(G_reduced); - E_reduced.init(G_reduced); - - //import information for A_reduced, E_reduced and links to the original nodes/edges - //of the copy nodes/edges - forall_nodes(v_orig,G) - { - v_reduced = A[v_orig].get_copy_node(); - A_reduced[v_reduced].set_NodeAttributes(A[v_orig].get_width(), A[v_orig]. - get_height(),A[v_orig].get_position(), - v_orig,NULL); - } - forall_edges(e_orig,G) - { - e_reduced = E[e_orig].get_copy_edge(); - if(e_reduced != NULL) - E_reduced[e_reduced].set_EdgeAttributes(E[e_orig].get_length(),e_orig,NULL); - } - - //update edgelength of copy edges in G_reduced associated with a set of parallel - //edges in G - update_edgelength(S,new_edgelength,E_reduced); -} - - -void FMMMLayout::delete_parallel_edges( - const Graph& G, - EdgeArray& E, - Graph& G_reduced, - List& S, - EdgeArray& new_edgelength) -{ - EdgeMaxBucketFunc MaxSort; - EdgeMinBucketFunc MinSort; - ListIterator EdgeIterator; - edge e_act,e_save; - Edge f_act; - List sorted_edges; - EdgeArray original_edge (G_reduced); //helping array - int save_s_index,save_t_index,act_s_index,act_t_index; - int counter = 1; - Graph* Graph_ptr = &G_reduced; - - //save the original edges for each edge in G_reduced - forall_edges(e_act,G) - if(E[e_act].get_copy_edge() != NULL) //e_act is no self_loops - original_edge[E[e_act].get_copy_edge()] = e_act; - - forall_edges(e_act,G_reduced) - { - f_act.set_Edge(e_act,Graph_ptr); - sorted_edges.pushBack(f_act); - } - - sorted_edges.bucketSort(0,G_reduced.numberOfNodes()-1,MaxSort); - sorted_edges.bucketSort(0,G_reduced.numberOfNodes()-1,MinSort); - - //now parallel edges are consecutive in sorted_edges - for(EdgeIterator = sorted_edges.begin();EdgeIterator.valid();++EdgeIterator) - {//for - e_act = (*EdgeIterator).get_edge(); - act_s_index = e_act->source()->index(); - act_t_index = e_act->target()->index(); - - if(EdgeIterator != sorted_edges.begin()) - {//if - if( (act_s_index == save_s_index && act_t_index == save_t_index) || - (act_s_index == save_t_index && act_t_index == save_s_index) ) - { - if(counter == 1) //first parallel edge - { - S.pushBack(e_save); - new_edgelength[e_save] = E[original_edge[e_save]].get_length() + - E[original_edge[e_act]].get_length(); - } - else //more then two parallel edges - new_edgelength[e_save] +=E[original_edge[e_act]].get_length(); - - E[original_edge[e_act]].set_copy_edge(NULL); //mark copy of edge as deleted - G_reduced.delEdge(e_act); //delete copy edge in G_reduced - counter++; - } - else - { - if (counter > 1) - { - new_edgelength[e_save]/=counter; - counter = 1; - } - save_s_index = act_s_index; - save_t_index = act_t_index; - e_save = e_act; - } - }//if - else //first edge - { - save_s_index = act_s_index; - save_t_index = act_t_index; - e_save = e_act; - } - }//for - - //treat special case (last edges were multiple edges) - if(counter >1) - new_edgelength[e_save]/=counter; -} - - -void FMMMLayout::update_edgelength( - List& S, - EdgeArray& new_edgelength, - EdgeArray& E_reduced) -{ - edge e; - while (!S.empty()) - { - e = S.popFrontRet(); - E_reduced[e].set_length(new_edgelength[e]); - } -} - - -//inline double FMMMLayout::get_post_rep_force_strength(int n) -//{ -// return min(0.2,400.0/double(n)); -//} - - -void FMMMLayout::make_positions_integer(Graph& G, NodeArray& A) -{ - node v; - double new_x,new_y; - - if(allowedPositions() == apInteger) - {//if - //calculate value of max_integer_position - max_integer_position = 100 * average_ideal_edgelength * G.numberOfNodes() * - G.numberOfNodes(); - }//if - - //restrict positions to lie in [-max_integer_position,max_integer_position] - //X [-max_integer_position,max_integer_position] - forall_nodes(v,G) - if( (A[v].get_x() > max_integer_position) || - (A[v].get_y() > max_integer_position) || - (A[v].get_x() < max_integer_position * (-1.0)) || - (A[v].get_y() < max_integer_position * (-1.0)) ) - { - DPoint cross_point; - DPoint nullpoint (0,0); - DPoint old_pos (A[v].get_x(),A[v].get_y()); - DPoint lt ( max_integer_position * (-1.0),max_integer_position); - DPoint rt ( max_integer_position,max_integer_position); - DPoint lb ( max_integer_position * (-1.0),max_integer_position * (-1.0)); - DPoint rb ( max_integer_position,max_integer_position * (-1.0)); - DLine s (nullpoint,old_pos); - DLine left_bound (lb,lt); - DLine right_bound (rb,rt); - DLine top_bound (lt,rt); - DLine bottom_bound (lb,rb); - - if(s.intersection(left_bound,cross_point)) - { - A[v].set_x(cross_point.m_x); - A[v].set_y(cross_point.m_y); - } - else if(s.intersection(right_bound,cross_point)) - { - A[v].set_x(cross_point.m_x); - A[v].set_y(cross_point.m_y); - } - else if(s.intersection(top_bound,cross_point)) - { - A[v].set_x(cross_point.m_x); - A[v].set_y(cross_point.m_y); - } - else if(s.intersection(bottom_bound,cross_point)) - { - A[v].set_x(cross_point.m_x); - A[v].set_y(cross_point.m_y); - } - else cout<<"Error FMMMLayout:: make_positions_integer()"< x_max) - x_max = AG.x(v); - if(AG.y(v) < y_min) - y_min = AG.y(v); - else if(AG.y(v) > y_max) - y_max = AG.y(v); - } - max_dist = max(x_max -x_min,y_max-y_min); - scale_factor = 500.0/max_dist; - - out_fmmm<<"%!PS-Adobe-2.0 "<source())<<" "<source())<<" " - <target())<<" "<target())<<" e"<& A, - EdgeArray&E, - Graph G_sub[], - NodeArray A_sub[], - EdgeArray E_sub[], - NodeArray& component) -{ - node u_orig,v_orig,v_sub; - edge e_sub,e_orig; - int i; - - //create the subgraphs and save links to subgraph nodes/edges in A - forall_nodes(v_orig,G) - A[v_orig].set_subgraph_node(G_sub[component[v_orig]].newNode()); - forall_edges(e_orig,G) - { - u_orig = e_orig->source(); - v_orig = e_orig->target(); - E[e_orig].set_subgraph_edge( G_sub[component[u_orig]].newEdge - (A[u_orig].get_subgraph_node(),A[v_orig].get_subgraph_node())); - } - - //make A_sub,E_sub valid for the subgraphs - for(i = 0; i< number_of_components;i++) - { - A_sub[i].init(G_sub[i]); - E_sub[i].init(G_sub[i]); - } - - //import information for A_sub,E_sub and links to the original nodes/edges - //of the subGraph nodes/edges - - forall_nodes(v_orig,G) - { - v_sub = A[v_orig].get_subgraph_node(); - A_sub[component[v_orig]][v_sub].set_NodeAttributes(A[v_orig].get_width(), - A[v_orig].get_height(),A[v_orig].get_position(), - v_orig,NULL); - } - forall_edges(e_orig,G) - { - e_sub = E[e_orig].get_subgraph_edge(); - v_orig = e_orig->source(); - E_sub[component[v_orig]][e_sub].set_EdgeAttributes(E[e_orig].get_length(), - e_orig,NULL); - } -} - - -void FMMMLayout::pack_subGraph_drawings( - NodeArray& A, - Graph G_sub[], - NodeArray A_sub[]) -{ - double aspect_ratio_area, bounding_rectangles_area; - MAARPacking P; - List R; - - if(stepsForRotatingComponents() == 0) //no rotation - calculate_bounding_rectangles_of_components(R,G_sub,A_sub); - else - rotate_components_and_calculate_bounding_rectangles(R,G_sub,A_sub); - - P.pack_rectangles_using_Best_Fit_strategy(R,pageRatio(),presortCCs(), - tipOverCCs(),aspect_ratio_area, - bounding_rectangles_area); - export_node_positions(A,R,G_sub,A_sub); -} - - -void FMMMLayout::calculate_bounding_rectangles_of_components( - List& R, - Graph G_sub[], - NodeArray A_sub[]) -{ - int i; - Rectangle r; - R.clear(); - - for(i=0;i& A, - int componenet_index) -{ - Rectangle r; - node v; - double x_min,x_max,y_min,y_max,act_x_min,act_x_max,act_y_min,act_y_max; - double max_boundary;//the maximum of half of the width and half of the height of - //each node; (needed to be able to tipp rectangles over without - //having access to the height and width of each node) - - forall_nodes(v,G) - { - max_boundary = max(A[v].get_width()/2, A[v].get_height()/2); - if(v == G.firstNode()) - { - x_min = A[v].get_x() - max_boundary; - x_max = A[v].get_x() + max_boundary; - y_min = A[v].get_y() - max_boundary; - y_max = A[v].get_y() + max_boundary; - } - else - { - act_x_min = A[v].get_x() - max_boundary; - act_x_max = A[v].get_x() + max_boundary; - act_y_min = A[v].get_y() - max_boundary; - act_y_max = A[v].get_y() + max_boundary; - if(act_x_min < x_min) x_min = act_x_min; - if(act_x_max > x_max) x_max = act_x_max; - if(act_y_min < y_min) y_min = act_y_min; - if(act_y_max > y_max) y_max = act_y_max; - } - } - - //add offset - x_min -= minDistCC()/2; - x_max += minDistCC()/2; - y_min -= minDistCC()/2; - y_max += minDistCC()/2; - - r.set_rectangle(x_max-x_min,y_max-y_min,x_min,y_min,componenet_index); - return r; -} - - -void FMMMLayout::rotate_components_and_calculate_bounding_rectangles( - List&R, - Graph G_sub[], - NodeArray A_sub[]) -{ - int i,j; - double sin_j,cos_j; - double angle,act_area,act_area_PI_half_rotated,best_area; - double ratio,new_width,new_height; - Array > best_coords(number_of_components); - Array > old_coords(number_of_components); - node v_sub; - Rectangle r_act,r_best; - DPoint new_pos,new_dlc; - - R.clear(); //make R empty - - for(i=0;i1) else store placement with minimal aspect ratio area - if(act_area < best_area) - { - r_best = r_act; - best_area = act_area; - forall_nodes(v_sub,G_sub[i]) - best_coords[i][v_sub] = A_sub[i][v_sub].get_position(); - } - else if ((number_of_components == 1) && (act_area_PI_half_rotated < best_area)) - { //test if rotating further with PI_half would be an improvement - r_best = r_act; - best_area = act_area_PI_half_rotated; - forall_nodes(v_sub,G_sub[i]) - best_coords[i][v_sub] = A_sub[i][v_sub].get_position(); - //the needed rotation step follows in the next if statement - } - } - - //tipp the smallest rectangle over by angle PI/2 around the origin if it makes the - //aspect_ratio of r_best more similar to the desired aspect_ratio - ratio = r_best.get_width()/r_best.get_height(); - - if( (pageRatio() < 1 && ratio > 1) || (pageRatio() >= 1 && ratio < 1) ) - { - forall_nodes(v_sub,G_sub[i]) - { - new_pos.m_x = best_coords[i][v_sub].m_y*(-1); - new_pos.m_y = best_coords[i][v_sub].m_x; - best_coords[i][v_sub] = new_pos; - } - - //calculate new rectangle - new_dlc.m_x = r_best.get_old_dlc_position().m_y*(-1)-r_best.get_height(); - new_dlc.m_y = r_best.get_old_dlc_position().m_x; - new_width = r_best.get_height(); - new_height = r_best.get_width(); - r_best.set_width(new_width); - r_best.set_height(new_height); - r_best.set_old_dlc_position(new_dlc); - } - - //save the computed information in A_sub and R - forall_nodes(v_sub,G_sub[i]) - A_sub[i][v_sub].set_position(best_coords[i][v_sub]); - R.pushBack(r_best); - - }//allcomponents -} - - -void FMMMLayout::export_node_positions( - NodeArray& A, - List& R, - Graph G_sub[], - NodeArray A_sub[]) -{ - ListIterator RectIterator; - Rectangle r; - int i; - node v_sub; - DPoint newpos,tipped_pos,tipped_dlc; - - for(RectIterator = R.begin();RectIterator.valid();++RectIterator) - {//for - r = *RectIterator; - i = r.get_component_index(); - if(r.is_tipped_over()) - {//if - //calculate tipped coordinates of the nodes - forall_nodes(v_sub,G_sub[i]) - { - tipped_pos.m_x = A_sub[i][v_sub].get_y()*(-1); - tipped_pos.m_y = A_sub[i][v_sub].get_x(); - A_sub[i][v_sub].set_position(tipped_pos); - } - }//if - - forall_nodes(v_sub,G_sub[i]) - { - newpos = A_sub[i][v_sub].get_position() + r.get_new_dlc_position() - - r.get_old_dlc_position(); - A[A_sub[i][v_sub].get_original_node()].set_position(newpos); - } - }//for -} - - -//----------------------- functions for multilevel step ----------------------------- - -inline int FMMMLayout::get_max_mult_iter(int act_level, int max_level, int node_nr) -{ - int iter; - if(maxIterChange() == micConstant) //nothing to do - iter = fixedIterations(); - else if (maxIterChange() == micLinearlyDecreasing) //linearly decreasing values - { - if(max_level == 0) - iter = fixedIterations() + ((maxIterFactor()-1) * fixedIterations()); - else - iter = fixedIterations() + int((double(act_level)/double(max_level) ) * - ((maxIterFactor()-1)) * fixedIterations()); - } - else //maxIterChange == micRapidlyDecreasing (rapidly decreasing values) - { - if(act_level == max_level) - iter = fixedIterations() + int( (maxIterFactor()-1) * fixedIterations()); - else if(act_level == max_level - 1) - iter = fixedIterations() + int(0.5 * (maxIterFactor()-1) * fixedIterations()); - else if(act_level == max_level - 2) - iter = fixedIterations() + int(0.25 * (maxIterFactor()-1) * fixedIterations()); - else //act_level >= max_level - 3 - iter = fixedIterations(); - } - - //helps to get good drawings for small graphs and graphs with few multilevels - if((node_nr <= 500) && (iter < 100)) - return 100; - else - return iter; -} - - -//-------------------------- functions for force calculation --------------------------- - -inline void FMMMLayout::calculate_forces( - Graph& G, - NodeArray& A, - EdgeArray& E, - NodeArray& F, - NodeArray& F_attr, - NodeArray& F_rep, - NodeArray& last_node_movement, - int iter, - int fine_tuning_step) -{ - if(allowedPositions() != apAll) - make_positions_integer(G,A); - calculate_attractive_forces(G,A,E,F_attr); - calculate_repulsive_forces(G,A,F_rep); - add_attr_rep_forces(G,F_attr,F_rep,F,iter,fine_tuning_step); - prevent_oscilations(G,F,last_node_movement,iter); - move_nodes(G,A,F); - update_boxlength_and_cornercoordinate(G,A); -} - - -void FMMMLayout::init_boxlength_and_cornercoordinate ( - Graph& G, - NodeArray& A) -{ - //boxlength is set - - const double MIN_NODE_SIZE = 10; - const double BOX_SCALING_FACTOR = 1.1; - double w=0,h=0; //helping variables - - node v; - forall_nodes(v,G) - { - w += max(A[v].get_width(),MIN_NODE_SIZE); - h += max(A[v].get_height(),MIN_NODE_SIZE); - } - - boxlength = ceil(max(w,h) * BOX_SCALING_FACTOR); - - //down left corner of comp. box is the origin - down_left_corner.m_x = 0; - down_left_corner.m_y = 0; -} - - -void FMMMLayout::create_initial_placement (Graph& G, NodeArray& A) -{ - const int BILLION = 1000000000; - int i,j,k; - node v; - - if (initialPlacementForces() == ipfKeepPositions) // don't change anything - { - init_boxlength_and_cornercoordinate(G,A); - } - else if (initialPlacementForces() == ipfUniformGrid) //set nodes to the midpoints of a grid - {//(uniform on a grid) - init_boxlength_and_cornercoordinate(G,A); - int level = static_cast( ceil(Math::log4(G.numberOfNodes()))); - int m = static_cast(pow(2.0,level))-1; - bool finished = false; - double blall = boxlength/(m+1); //boxlength for boxes at the lowest level (depth) - Array all_nodes(G.numberOfNodes()); - - k = 0; - forall_nodes(v,G) - { - all_nodes[k] = v; - k++; - } - v = all_nodes[0]; - k = 0; - i = 0; - while ((!finished) && (i <= m)) - {//while1 - j = 0; - while((!finished) && (j <= m)) - {//while2 - A[v].set_x(boxlength*i/(m+1) + blall/2); - A[v].set_y(boxlength*j/(m+1) + blall/2); - if(k == G.numberOfNodes()-1) - finished = true; - else - { - k++; - v = all_nodes[k]; - } - j++; - }//while2 - i++; - }//while1 - }//(uniform on a grid) - else //randomised distribution of the nodes; - {//(random) - init_boxlength_and_cornercoordinate(G,A); - if(initialPlacementForces() == ipfRandomTime)//(RANDOM based on actual CPU-time) - srand((unsigned int)time(0)); - else if(initialPlacementForces() == ipfRandomRandIterNr)//(RANDOM based on seed) - srand(randSeed()); - - forall_nodes(v,G) - { - DPoint rndp; - rndp.m_x = double(randomNumber(0,BILLION))/BILLION;//rand_x in [0,1] - rndp.m_y = double(randomNumber(0,BILLION))/BILLION;//rand_y in [0,1] - A[v].set_x(rndp.m_x*(boxlength-2)+ 1); - A[v].set_y(rndp.m_y*(boxlength-2)+ 1); - } - }//(random) - update_boxlength_and_cornercoordinate(G,A); -} - - -inline void FMMMLayout::init_F(Graph& G, NodeArray& F) -{ - DPoint nullpoint (0,0); - node v; - forall_nodes(v,G) - F[v] = nullpoint; -} - - -inline void FMMMLayout::make_initialisations_for_rep_calc_classes(Graph& G) -{ - if(repulsiveForcesCalculation() == rfcExact) - FR.make_initialisations(boxlength,down_left_corner,frGridQuotient()); - else if(repulsiveForcesCalculation() == rfcGridApproximation) - FR.make_initialisations(boxlength,down_left_corner,frGridQuotient()); - else //(repulsiveForcesCalculation() == rfcNMM - NM.make_initialisations(G,boxlength,down_left_corner, - nmParticlesInLeaves(),nmPrecision(), - nmTreeConstruction(),nmSmallCell()); -} - - -void FMMMLayout::calculate_attractive_forces( - Graph& G, - NodeArray & A, - EdgeArray & E, - NodeArray& F_attr) -{ - numexcept N; - edge e; - node u,v; - double norm_v_minus_u,scalar; - DPoint vector_v_minus_u,f_u; - DPoint nullpoint (0,0); - - //initialisation - init_F(G,F_attr); - - //calculation - forall_edges (e,G) - {//for - u = e->source(); - v = e->target(); - vector_v_minus_u = A[v].get_position() - A[u].get_position(); - norm_v_minus_u = vector_v_minus_u.norm(); - if(vector_v_minus_u == nullpoint) - f_u = nullpoint; - else if(!N.f_near_machine_precision(norm_v_minus_u,f_u)) - { - scalar = f_attr_scalar(norm_v_minus_u,E[e].get_length())/norm_v_minus_u; - f_u.m_x = scalar * vector_v_minus_u.m_x; - f_u.m_y = scalar * vector_v_minus_u.m_y; - } - - F_attr[v] = F_attr[v] - f_u; - F_attr[u] = F_attr[u] + f_u; - }//for -} - - -double FMMMLayout::f_attr_scalar(double d, double ind_ideal_edge_length) -{ - double s; - - if(forceModel() == fmFruchtermanReingold) - s = d*d/(ind_ideal_edge_length*ind_ideal_edge_length*ind_ideal_edge_length); - else if (forceModel() == fmEades) - { - double c = 10; - if (d == 0) - s = -1e10; - else - s = c * Math::log2(d/ind_ideal_edge_length) /(ind_ideal_edge_length); - } - else if (forceModel() == fmNew) - { - double c = Math::log2(d/ind_ideal_edge_length); - if (d > 0) - s = c * d * d / - (ind_ideal_edge_length * ind_ideal_edge_length * ind_ideal_edge_length); - else - s = -1e10; - } - else cout <<" Error FMMMLayout:: f_attr_scalar"<& F_attr, - NodeArray& F_rep, - NodeArray& F, - int iter, - int fine_tuning_step) -{ - numexcept N; - node v; - DPoint f,force; - DPoint nullpoint (0,0); - double norm_f,scalar; - double act_spring_strength,act_rep_force_strength; - - //set cool_factor - if(coolTemperature() == false) - cool_factor = 1.0; - else if((coolTemperature() == true) && (fine_tuning_step == 0)) - { - if(iter == 1) - cool_factor = coolValue(); - else - cool_factor *= coolValue(); - } - - if(fine_tuning_step == 1) - cool_factor /= 10.0; //decrease the temperature rapidly - else if (fine_tuning_step == 2) - { - if(iter <= fineTuningIterations() -5) - cool_factor = fineTuneScalar(); //decrease the temperature rapidly - else - cool_factor = (fineTuneScalar()/10.0); - } - - //set the values for the spring strength and strength of the rep. force field - if(fine_tuning_step <= 1)//usual case - { - act_spring_strength = springStrength(); - act_rep_force_strength = repForcesStrength(); - } - else if(!adjustPostRepStrengthDynamically()) - { - act_spring_strength = postSpringStrength(); - act_rep_force_strength = postStrengthOfRepForces(); - } - else //adjustPostRepStrengthDynamically()) - { - act_spring_strength = postSpringStrength(); - act_rep_force_strength = get_post_rep_force_strength(G.numberOfNodes()); - } - - forall_nodes(v,G) - { - f.m_x = act_spring_strength * F_attr[v].m_x + act_rep_force_strength * F_rep[v].m_x; - f.m_y = act_spring_strength * F_attr[v].m_y + act_rep_force_strength * F_rep[v].m_y; - f.m_x = average_ideal_edgelength * average_ideal_edgelength * f.m_x; - f.m_y = average_ideal_edgelength * average_ideal_edgelength * f.m_y; - - norm_f = f.norm(); - if(f == nullpoint) - force = nullpoint; - else if(N.f_near_machine_precision(norm_f,force)) - restrict_force_to_comp_box(force); - else - { - scalar = min (norm_f * cool_factor * forceScalingFactor(), - max_radius(iter))/norm_f; - force.m_x = scalar * f.m_x; - force.m_y = scalar * f.m_y; - } - F[v] = force; - } -} - - -void FMMMLayout::move_nodes( - Graph& G, - NodeArray& A, - NodeArray& F) -{ - node v; - - forall_nodes(v,G) - A[v].set_position(A[v].get_position() + F[v]); -} - - -void FMMMLayout::update_boxlength_and_cornercoordinate( - Graph& G, - NodeArray&A) -{ - node v; - double xmin,xmax,ymin,ymax; - DPoint midpoint; - - - v = G.firstNode(); - midpoint = A[v].get_position(); - xmin = xmax = midpoint.m_x; - ymin = ymax = midpoint.m_y; - - forall_nodes(v,G) - { - midpoint = A[v].get_position(); - if (midpoint.m_x < xmin ) - xmin = midpoint.m_x; - if (midpoint.m_x > xmax ) - xmax = midpoint.m_x; - if (midpoint.m_y < ymin ) - ymin = midpoint.m_y; - if (midpoint.m_y > ymax ) - ymax = midpoint.m_y; - } - - //set down_left_corner and boxlength - - down_left_corner.m_x = floor(xmin - 1); - down_left_corner.m_y = floor(ymin - 1); - boxlength = ceil(max(ymax-ymin, xmax-xmin) *1.01 + 2); - - //exception handling: all nodes have same x and y coordinate - if(boxlength <= 2 ) - { - boxlength = G.numberOfNodes()* 20; - down_left_corner.m_x = floor(xmin) - (boxlength/2); - down_left_corner.m_y = floor(ymin) - (boxlength/2); - } - - //export the boxlength and down_left_corner values to the rep. calc. classes - - if(repulsiveForcesCalculation() == rfcExact || - repulsiveForcesCalculation() == rfcGridApproximation) - FR.update_boxlength_and_cornercoordinate(boxlength,down_left_corner); - else //repulsiveForcesCalculation() == rfcNMM - NM.update_boxlength_and_cornercoordinate(boxlength,down_left_corner); -} - - -void FMMMLayout::set_average_ideal_edgelength( - Graph& G, - EdgeArray& E) -{ - double averagelength = 0; - edge e; - - if(G.numberOfEdges() > 0) - { - forall_edges(e,G) - averagelength += E[e].get_length(); - average_ideal_edgelength = averagelength/G.numberOfEdges(); - } - else - average_ideal_edgelength = 50; -} - - -double FMMMLayout::get_average_forcevector_length (Graph& G, NodeArray& F) -{ - double lengthsum = 0; - node v; - forall_nodes(v,G) - lengthsum += F[v].norm(); - lengthsum /=G.numberOfNodes(); - return lengthsum; -} - - -void FMMMLayout::prevent_oscilations( - Graph& G, - NodeArray& F, - NodeArray& last_node_movement, - int iter) -{ - - const double pi_times_1_over_6 = 0.52359878; - const double pi_times_2_over_6 = 2 * pi_times_1_over_6; - const double pi_times_3_over_6 = 3 * pi_times_1_over_6; - const double pi_times_4_over_6 = 4 * pi_times_1_over_6; - const double pi_times_5_over_6 = 5 * pi_times_1_over_6; - const double pi_times_7_over_6 = 7 * pi_times_1_over_6; - const double pi_times_8_over_6 = 8 * pi_times_1_over_6; - const double pi_times_9_over_6 = 9 * pi_times_1_over_6; - const double pi_times_10_over_6 = 10 * pi_times_1_over_6; - const double pi_times_11_over_6 = 11 * pi_times_1_over_6; - - DPoint nullpoint (0,0); - double fi; //angle in [0,2pi) measured counterclockwise - double norm_old,norm_new,quot_old_new; - - if (iter > 1) //usual case - {//if1 - node v; - forall_nodes(v,G) - { - DPoint force_new (F[v].m_x,F[v].m_y); - DPoint force_old (last_node_movement[v].m_x,last_node_movement[v].m_y); - norm_new = F[v].norm(); - norm_old = last_node_movement[v].norm(); - if ((norm_new > 0) && (norm_old > 0)) - {//if2 - quot_old_new = norm_old / norm_new; - - //prevent oszilations - fi = angle(nullpoint,force_old,force_new); - if(((fi <= pi_times_1_over_6)||(fi >= pi_times_11_over_6))&& - ((norm_new > (norm_old*2.0))) ) - { - F[v].m_x = quot_old_new * 2.0 * F[v].m_x; - F[v].m_y = quot_old_new * 2.0 * F[v].m_y; - } - else if ((fi >= pi_times_1_over_6)&&(fi <= pi_times_2_over_6)&& - (norm_new > (norm_old*1.5) ) ) - { - F[v].m_x = quot_old_new * 1.5 * F[v].m_x; - F[v].m_y = quot_old_new * 1.5 * F[v].m_y; - } - else if ((fi >= pi_times_2_over_6)&&(fi <= pi_times_3_over_6)&& - (norm_new > (norm_old)) ) - { - F[v].m_x = quot_old_new * F[v].m_x; - F[v].m_y = quot_old_new * F[v].m_y; - } - else if ((fi >= pi_times_3_over_6)&&(fi <= pi_times_4_over_6)&& - (norm_new > (norm_old*0.66666666)) ) - { - F[v].m_x = quot_old_new * 0.66666666 * F[v].m_x; - F[v].m_y = quot_old_new * 0.66666666 * F[v].m_y; - } - else if ((fi >= pi_times_4_over_6)&&(fi <= pi_times_5_over_6)&& - (norm_new > (norm_old*0.5)) ) - { - F[v].m_x = quot_old_new * 0.5 * F[v].m_x; - F[v].m_y = quot_old_new * 0.5 * F[v].m_y; - } - else if ((fi >= pi_times_5_over_6)&&(fi <= pi_times_7_over_6)&& - (norm_new > (norm_old*0.33333333)) ) - { - F[v].m_x = quot_old_new * 0.33333333 * F[v].m_x; - F[v].m_y = quot_old_new * 0.33333333 * F[v].m_y; - } - else if ((fi >= pi_times_7_over_6)&&(fi <= pi_times_8_over_6)&& - (norm_new > (norm_old*0.5)) ) - { - F[v].m_x = quot_old_new * 0.5 * F[v].m_x; - F[v].m_y = quot_old_new * 0.5 * F[v].m_y; - } - else if ((fi >= pi_times_8_over_6)&&(fi <= pi_times_9_over_6)&& - (norm_new > (norm_old*0.66666666)) ) - { - F[v].m_x = quot_old_new * 0.66666666 * F[v].m_x; - F[v].m_y = quot_old_new * 0.66666666 * F[v].m_y; - } - else if ((fi >= pi_times_9_over_6)&&(fi <= pi_times_10_over_6)&& - (norm_new > (norm_old)) ) - { - F[v].m_x = quot_old_new * F[v].m_x; - F[v].m_y = quot_old_new * F[v].m_y; - } - else if ((fi >= pi_times_10_over_6)&&(fi <= pi_times_11_over_6)&& - (norm_new > (norm_old*1.5) ) ) - { - F[v].m_x = quot_old_new * 1.5 * F[v].m_x; - F[v].m_y = quot_old_new * 1.5 * F[v].m_y; - } - }//if2 - last_node_movement[v]= F[v]; - } - }//if1 - else if (iter == 1) - init_last_node_movement(G,F,last_node_movement); -} - - -double FMMMLayout::angle(DPoint& P, DPoint& Q, DPoint& R) -{ - double dx1 = Q.m_x - P.m_x; - double dy1 = Q.m_y - P.m_y; - double dx2 = R.m_x - P.m_x; - double dy2 = R.m_y - P.m_y; - double fi;//the angle - - if ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)) - cout<<"Multilevel::angle()"<= 1.0 ) fi = 0; - if (cosfi <= -1.0 ) fi = Math::pi; - else - { - fi = acos(cosfi); - if (dx1*dy2 < dy1*dx2) fi = -fi; - if (fi < 0) fi += 2*Math::pi; - } - return fi; -} - - -void FMMMLayout::init_last_node_movement( - Graph& G, - NodeArray& F, - NodeArray& last_node_movement) -{ - node v; - forall_nodes(v,G) - last_node_movement[v]= F[v]; -} - - -void FMMMLayout::adapt_drawing_to_ideal_average_edgelength( - Graph& G, - NodeArray& A, - EdgeArray& E) -{ - edge e; - node v; - double sum_real_edgelength = 0; - double sum_ideal_edgelength = 0; - double area_scaling_factor; - DPoint new_pos; - - forall_edges(e,G) - { - sum_ideal_edgelength += E[e].get_length(); - sum_real_edgelength += (A[e->source()].get_position() - A[e->target()].get_position()).norm(); - } - - if(sum_real_edgelength == 0) //very very unlike case - area_scaling_factor = 1; - else - area_scaling_factor = sum_ideal_edgelength/sum_real_edgelength; - - forall_nodes(v,G) - { - new_pos.m_x = resizingScalar() * area_scaling_factor * A[v].get_position().m_x; - new_pos.m_y = resizingScalar() * area_scaling_factor * A[v].get_position().m_y; - A[v].set_position(new_pos); - } -} - - -} //end namespace ogdf diff --git a/ext/OGDF/src/energybased/FastMultipoleEmbedder.cpp b/ext/OGDF/src/energybased/FastMultipoleEmbedder.cpp deleted file mode 100644 index 643f6bc9a..000000000 --- a/ext/OGDF/src/energybased/FastMultipoleEmbedder.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class FastMultipoleEmbedder. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include "FastUtils.h" -#include "ArrayGraph.h" -#include "LinearQuadtree.h" -#include "LinearQuadtreeExpansion.h" -#include "FMEThread.h" -#include "GalaxyMultilevel.h" -#include "FMEMultipoleKernel.h" - -namespace ogdf { - -FastMultipoleEmbedder::FastMultipoleEmbedder() -{ - m_precisionParameter = 5; - m_defaultEdgeLength = 1.0; - m_defaultNodeSize = 1.0; - m_numIterations = 100; - m_randomize = true; - m_numberOfThreads = 0; - m_maxNumberOfThreads = 1; //the only save value -} - -FastMultipoleEmbedder::~FastMultipoleEmbedder(void) -{ - // nothing -} - -void FastMultipoleEmbedder::initOptions() -{ - m_pOptions->preProcTimeStep = 0.5; // 0.5 - m_pOptions->preProcMaxNumIterations = 20; // 20 - m_pOptions->preProcEdgeForceFactor = 0.5; // 0.5 - m_pOptions->timeStep = 0.25; // 0.25 - m_pOptions->edgeForceFactor = 1.0; // 1.00; - m_pOptions->repForceFactor = 2.0; // 2.0; - m_pOptions->stopCritConstSq = 2000400; // 2000400; - m_pOptions->stopCritAvgForce = 0.1f; // - m_pOptions->minNumIterations = 4; // 4 - m_pOptions->multipolePrecision = m_precisionParameter; -} - -/* -void FastMultipoleEmbedder::call(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - call(G, MLG.getXArray(), MLG.getYArray(), MLG.getWArray(), MLG.getRArray()); -} -*/ - -void FastMultipoleEmbedder::call(const Graph& G, NodeArray& nodeXPosition, NodeArray& nodeYPosition, - const EdgeArray& edgeLength, const NodeArray& nodeSize) -{ - allocate(G.numberOfNodes(), G.numberOfEdges()); - m_pGraph->readFrom(G, nodeXPosition, nodeYPosition, edgeLength, nodeSize); - run(m_numIterations); - m_pGraph->writeTo(G, nodeXPosition, nodeYPosition); - deallocate(); -} - -void FastMultipoleEmbedder::call(GraphAttributes &GA) -{ - EdgeArray edgeLength(GA.constGraph()); - NodeArray nodeSize(GA.constGraph()); - node v; - edge e; - forall_nodes(v, GA.constGraph()) - { - nodeSize[v] = (float)sqrt(GA.width(v)*GA.width(v) + GA.height(v)*GA.height(v)) * 0.5f; - } - - forall_edges(e, GA.constGraph()) - { - edgeLength[e] = nodeSize[e->source()] + nodeSize[e->target()]; - } - call(GA, edgeLength, nodeSize); -} - -void FastMultipoleEmbedder::call(GraphAttributes &GA, const EdgeArray& edgeLength, const NodeArray& nodeSize) -{ - allocate(GA.constGraph().numberOfNodes(), GA.constGraph().numberOfEdges()); - m_pGraph->readFrom(GA, edgeLength, nodeSize); - run(m_numIterations); - m_pGraph->writeTo(GA); - deallocate(); - - edge e; - forall_edges(e, GA.constGraph()) - { - GA.bends(e).clear(); - } -} - -void FastMultipoleEmbedder::run(__uint32 numIterations) -{ - if (m_pGraph->numNodes() == 0) return; - if (m_pGraph->numNodes() == 1) - { - m_pGraph->nodeXPos()[0] = 0.0f; - m_pGraph->nodeYPos()[0] = 0.0f; - return; - } - - if (m_randomize) - { - double avgNodeSize = 0.0; - for (__uint32 i = 0; i < m_pGraph->numNodes(); i++) - { - avgNodeSize += m_pGraph->nodeSize()[i]; - } - - avgNodeSize = (avgNodeSize / (double)m_pGraph->numNodes()); - for (__uint32 i = 0; i < m_pGraph->numNodes(); i++) - { - m_pGraph->nodeXPos()[i] = (float)(randomDouble(-(double)m_pGraph->numNodes(), (double)m_pGraph->numNodes())*avgNodeSize*2); - m_pGraph->nodeYPos()[i] = (float)(randomDouble(-(double)m_pGraph->numNodes(), (double)m_pGraph->numNodes())*avgNodeSize*2); - } - } - - m_pOptions->maxNumIterations = numIterations; - m_pOptions->stopCritForce = (((float)m_pGraph->numNodes())*((float)m_pGraph->numNodes())*m_pGraph->avgNodeSize()) / m_pOptions->stopCritConstSq; - if (m_pGraph->numNodes() < 100) - runSingle(); - else - runMultipole(); -} - - -void FastMultipoleEmbedder::runMultipole() -{ - FMEGlobalContext* pGlobalContext = FMEMultipoleKernel::allocateContext(m_pGraph, m_pOptions, m_threadPool->numThreads()); - m_threadPool->runKernel(pGlobalContext); - FMEMultipoleKernel::deallocateContext(pGlobalContext); -} - - -void FastMultipoleEmbedder::runSingle() -{ - FMESingleKernel kernel; - kernel(*m_pGraph, m_pOptions->timeStep, m_pOptions->minNumIterations, m_pOptions->maxNumIterations, m_pOptions->stopCritForce); -} - - -void FastMultipoleEmbedder::allocate(__uint32 numNodes, __uint32 numEdges) -{ - m_pOptions = new FMEGlobalOptions(); - m_pGraph = new ArrayGraph(numNodes, numEdges); - initOptions(); - if (!m_maxNumberOfThreads) - { - __uint32 availableThreads = System::numberOfProcessors(); - __uint32 minNodesPerThread = 100; - m_numberOfThreads = numNodes / minNodesPerThread; - m_numberOfThreads = max<__uint32>(1, m_numberOfThreads); - m_numberOfThreads = prevPowerOfTwo(min<__uint32>(m_numberOfThreads, availableThreads)); - } else - { - __uint32 availableThreads = min<__uint32>(m_maxNumberOfThreads, System::numberOfProcessors()); - __uint32 minNodesPerThread = 100; - m_numberOfThreads = numNodes / minNodesPerThread; - m_numberOfThreads = max<__uint32>(1, m_numberOfThreads); - m_numberOfThreads = prevPowerOfTwo(min<__uint32>(m_numberOfThreads, availableThreads)); - } - m_threadPool = new FMEThreadPool(m_numberOfThreads); -} - - -void FastMultipoleEmbedder::deallocate() -{ - delete m_threadPool; - delete m_pGraph; - delete m_pOptions; -} - - - -void FastMultipoleMultilevelEmbedder::dumpCurrentLevel(const String& filename) -{ - const Graph& G = *(m_pCurrentLevel->m_pGraph); - GraphAttributes GA(G); - node v = 0; - forall_nodes(v, G) - { - GalaxyMultilevel::LevelNodeInfo& nodeInfo = (*(m_pCurrentLevel->m_pNodeInfo))[v]; - GA.x(v) = (*m_pCurrentNodeXPos)[v]; - GA.y(v) = (*m_pCurrentNodeYPos)[v]; - GA.width(v) = GA.height(v)= nodeInfo.radius / sqrt(2.0); - } - GA.writeGML(filename); -} - -void FastMultipoleMultilevelEmbedder::call(GraphAttributes &GA) -{ - EdgeArray edgeLengthAuto(GA.constGraph()); - computeAutoEdgeLength(GA, edgeLengthAuto); - m_multiLevelNumNodesBound = 10; //10 - const Graph& t = GA.constGraph(); - if (t.numberOfNodes() <= 25) - { - FastMultipoleEmbedder fme; - fme.setNumberOfThreads(this->m_iMaxNumThreads); - fme.setRandomize(true); - fme.setNumIterations(500); - fme.call(GA); - return; - } - - run(GA, edgeLengthAuto); - - edge e; - forall_edges(e, GA.constGraph()) - { - GA.bends(e).clear(); - } -} - -void FastMultipoleMultilevelEmbedder::computeAutoEdgeLength(const GraphAttributes& GA, EdgeArray& edgeLength, float factor) -{ - edge e = 0; - node v = 0; - node w = 0; - forall_edges(e, GA.constGraph()) - { - v = e->source(); - w = e->target(); - float radius_v = (float)sqrt(GA.width(v)*GA.width(v) + GA.height(v)*GA.height(v)) * 0.5f; - float radius_w = (float)sqrt(GA.width(w)*GA.width(w) + GA.height(w)*GA.height(w)) * 0.5f; - float sum = radius_v + radius_w; - if (DIsEqual(sum, 0.0)) - sum = 1.0; - edgeLength[e] = factor*(sum); - } -} - -void FastMultipoleMultilevelEmbedder::run(GraphAttributes& GA, const EdgeArray& edgeLength) -{ - // too lazy for new, delete - NodeArray nodeXPos1; - NodeArray nodeYPos1; - NodeArray nodeXPos2; - NodeArray nodeYPos2; - EdgeArray edgeLength1; - NodeArray nodeSize1; - - m_pCurrentNodeXPos = &nodeXPos1; - m_pCurrentNodeYPos = &nodeYPos1; - m_pLastNodeXPos = &nodeXPos2; - m_pLastNodeYPos = &nodeYPos2; - m_pCurrentEdgeLength= &edgeLength1; - m_pCurrentNodeSize = &nodeSize1; - Graph* pGraph = const_cast(&(GA.constGraph())); - - // create all multilevels - this->createMultiLevelGraphs(pGraph, GA, edgeLength); - // init the coarsest level - initCurrentLevel(); -#ifdef OGDF_DEBUG - String str; - str.sprintf("d:\\level%d_in.gml", m_iCurrentLevelNr); - this->dumpCurrentLevel(str); -#endif - - //------------------------- - // layout the current level - layoutCurrentLevel(); - //------------------------- - -#ifdef OGDF_DEBUG - str.sprintf("d:\\level%d_out.gml", m_iCurrentLevelNr); - this->dumpCurrentLevel(str); -#endif - - //----------------------------- - //proceed with remaining levels - while (m_iCurrentLevelNr > 0) - { - // move to finer level - nextLevel(); - // init the arrays for current level - initCurrentLevel(); - // assign positions from last to current - assignPositionsFromPrevLevel(); -#ifdef OGDF_DEBUG - str.sprintf("d:\\level%d_in.gml", m_iCurrentLevelNr); - this->dumpCurrentLevel(str); -#endif - // layout the current level - layoutCurrentLevel(); - -#ifdef OGDF_DEBUG - str.sprintf("d:\\level%d_out.gml", m_iCurrentLevelNr); - this->dumpCurrentLevel(str); -#endif - } - // the finest level is processed - // assumes m_pCurrentGraph == GA.constGraph - writeCurrentToGraphAttributes(GA); - // clean up multilevels - deleteMultiLevelGraphs(); -} - -void FastMultipoleMultilevelEmbedder::createMultiLevelGraphs(Graph* pGraph, GraphAttributes& GA, const EdgeArray& finestLevelEdgeLength) -{ - m_pCurrentLevel = new GalaxyMultilevel(pGraph); - m_pFinestLevel = m_pCurrentLevel; - initFinestLevel(GA, finestLevelEdgeLength); - m_iNumLevels = 1; - m_iCurrentLevelNr = 0; - - GalaxyMultilevelBuilder builder; - while (m_pCurrentLevel->m_pGraph->numberOfNodes() > m_multiLevelNumNodesBound) - { - GalaxyMultilevel* newLevel = builder.build(m_pCurrentLevel); - m_pCurrentLevel = newLevel; - m_iNumLevels++; - m_iCurrentLevelNr++; - } - m_pCoarsestLevel = m_pCurrentLevel; - m_pCurrentGraph = m_pCurrentLevel->m_pGraph; -} - - -void FastMultipoleMultilevelEmbedder::writeCurrentToGraphAttributes(GraphAttributes& GA) -{ - node v; - forall_nodes(v, (*m_pCurrentGraph)) - { - GA.x(v) = (*m_pCurrentNodeXPos)[v]; - GA.y(v) = (*m_pCurrentNodeYPos)[v]; - } -} - -void FastMultipoleMultilevelEmbedder::nextLevel() -{ - m_pCurrentLevel = m_pCurrentLevel->m_pFinerMultiLevel; - std::swap(m_pLastNodeXPos, m_pCurrentNodeXPos); - std::swap(m_pLastNodeYPos, m_pCurrentNodeYPos); - m_iCurrentLevelNr--; -} - -void FastMultipoleMultilevelEmbedder::initFinestLevel(GraphAttributes &GA, const EdgeArray& edgeLength) -{ - node v = 0; - node w = 0; - edge e = 0; - //NodeArray perimeter(GA.constGraph(), 0.0); - forall_nodes(v, GA.constGraph()) - { - GalaxyMultilevel::LevelNodeInfo& nodeInfo = (*(m_pFinestLevel->m_pNodeInfo))[v]; - nodeInfo.mass = 1.0; - float r = (float)sqrt(GA.width(v)*GA.width(v) + GA.height(v)*GA.height(v)) * 0.5f; - nodeInfo.radius = r; - } - - forall_edges(e, GA.constGraph()) - { - GalaxyMultilevel::LevelEdgeInfo& edgeInfo = (*(m_pFinestLevel->m_pEdgeInfo))[e]; - v = e->source(); - w = e->target(); - GalaxyMultilevel::LevelNodeInfo& vNodeInfo = (*(m_pFinestLevel->m_pNodeInfo))[v]; - GalaxyMultilevel::LevelNodeInfo& wNodeInfo = (*(m_pFinestLevel->m_pNodeInfo))[w]; - edgeInfo.length = (vNodeInfo.radius + wNodeInfo.radius) + edgeLength[e]; - } -} - -void FastMultipoleMultilevelEmbedder::initCurrentLevel() -{ - m_pCurrentGraph = m_pCurrentLevel->m_pGraph; - m_pCurrentNodeXPos->init(*m_pCurrentGraph, 0.0f); - m_pCurrentNodeYPos->init(*m_pCurrentGraph, 0.0f); - m_pCurrentEdgeLength->init(*m_pCurrentGraph, 1.0f); - m_pCurrentNodeSize->init(*m_pCurrentGraph, 1.0f); - const Graph& G = *(m_pCurrentLevel->m_pGraph); - node v = 0; - - forall_nodes(v, G) - { - GalaxyMultilevel::LevelNodeInfo& nodeInfo = (*(m_pCurrentLevel->m_pNodeInfo))[v]; - (*m_pCurrentNodeSize)[v] = ((float)nodeInfo.radius);//(((float)nodeInfo.radius)); - } - - edge e = 0; - forall_edges(e, G) - { - GalaxyMultilevel::LevelEdgeInfo& edgeInfo = (*(m_pCurrentLevel->m_pEdgeInfo))[e]; - (*m_pCurrentEdgeLength)[e] = edgeInfo.length*0.25f; - } -} - -void FastMultipoleMultilevelEmbedder::assignPositionsFromPrevLevel() -{ - float scaleFactor = 1.4f;// 1.4f;//1.4f; //1.4f - // init m_pCurrent Pos from m_pLast Pos - const Graph& G = *(m_pCurrentLevel->m_pGraph); - node v = 0; - forall_nodes(v, G) - { - GalaxyMultilevel::LevelNodeInfo& nodeInfo = (*(m_pCurrentLevel->m_pNodeInfo))[v]; - float x = (float)((*m_pLastNodeXPos)[nodeInfo.parent] + (float)randomDouble(-1.0, 1.0)); - float y = (float)((*m_pLastNodeYPos)[nodeInfo.parent] + (float)randomDouble(-1.0, 1.0)); - (*m_pCurrentNodeXPos)[v] = x*scaleFactor; - (*m_pCurrentNodeYPos)[v] = y*scaleFactor; - } -} - -void FastMultipoleMultilevelEmbedder::layoutCurrentLevel() -{ - FastMultipoleEmbedder fme; - fme.setNumberOfThreads(this->m_iMaxNumThreads); - fme.setRandomize(m_iCurrentLevelNr == (m_iNumLevels-1)); - fme.setNumIterations(numberOfIterationsByLevelNr(m_iCurrentLevelNr)); - fme.call((*m_pCurrentGraph), (*m_pCurrentNodeXPos), (*m_pCurrentNodeYPos), (*m_pCurrentEdgeLength), (*m_pCurrentNodeSize)); -} - -void FastMultipoleMultilevelEmbedder::deleteMultiLevelGraphs() -{ - GalaxyMultilevel* l = m_pCoarsestLevel; - GalaxyMultilevel* toDelete = l; - while (l) - { - toDelete = l; - l = l->m_pFinerMultiLevel; - delete (toDelete->m_pNodeInfo); - delete (toDelete->m_pEdgeInfo); - if (toDelete != m_pFinestLevel) - delete (toDelete->m_pGraph); - delete toDelete; - } -} - -__uint32 FastMultipoleMultilevelEmbedder::numberOfIterationsByLevelNr(__uint32 levelNr) -{ - return 200*(levelNr+1)*(levelNr+1); -} - - -} // end of namespace diff --git a/ext/OGDF/src/energybased/FastUtils.h b/ext/OGDF/src/energybased/FastUtils.h deleted file mode 100644 index ff188b8e6..000000000 --- a/ext/OGDF/src/energybased/FastUtils.h +++ /dev/null @@ -1,616 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definition of utility functions for FME layout. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_FAST_UTILS_H -#define OGDF_FAST_UTILS_H - -#include -#include - -namespace ogdf { - -// use SSE for Multipole computations -//#define OGDF_FME_KERNEL_USE_SSE - -// use special thread affinity (works only for unix and scatters the threads) -//#define OGDF_FME_THREAD_AFFINITY - -// simple parallel quadtree sort -//#define OGDF_FME_PARALLEL_QUADTREE_SORT - -// use SSE for direct interaction (this is slower than the normal direct computation) -//#define OGDF_FME_KERNEL_USE_SSE_DIRECT - -inline void OGDF_FME_Print_Config() -{ -#ifdef OGDF_FME_KERNEL_USE_SSE - std::cout << "OGDF_FME_KERNEL_USE_SSE" << std::endl; -#endif -#ifdef OGDF_FME_THREAD_AFFINITY - std::cout << "OGDF_FME_THREAD_AFFINITY" << std::endl; -#endif -#ifdef OGDF_FME_PARALLEL_QUADTREE_SORT - std::cout << "OGDF_FME_PARALLEL_QUADTREE_SORT" << std::endl; -#endif -#ifdef OGDF_FME_KERNEL_USE_SSE_DIRECT - std::cout << "OGDF_FME_KERNEL_USE_SSE_DIRECT" << std::endl; -#endif -}; - -#ifdef OGDF_FME_KERNEL_USE_SSE -#include -#include -#endif - -typedef __uint64 MortonNR; -typedef __uint32 CoordInt; - -template -inline bool is_align_16(T* ptr) -{ - return !(((size_t)(void*)ptr) & 0x0F); -} - -template -inline T* align_16_prev_ptr(T* t) -{ - return (T*)(((size_t)((void*)t))&~ 0x0F); -} - -template -inline T* align_16_next_ptr(T* t) -{ - return (T*)((((size_t)((void*)t)) + 15)&~ 0x0F); -} - -#ifdef OGDF_SYSTEM_UNIX -#include -inline timeval GetDiffTime(timeval _then, double& dtime) -{ - timeval then = (timeval) _then; - timeval now; - gettimeofday(&now, NULL); - timeval diff; - - diff.tv_sec = now.tv_sec - then.tv_sec; - diff.tv_usec = now.tv_usec - then.tv_usec; - while(diff.tv_usec < 0) - { - diff.tv_sec--; - diff.tv_usec = 1000000 + now.tv_usec - then.tv_usec; - } - - dtime = diff.tv_sec; - dtime += (double) diff.tv_usec / 1e6; - - return (timeval) now; -} -#endif - -inline void printProfiledTime(double t, const char* text) { std::cout << t <<"s\t" << text << std::endl; }; -inline void printProfiledTime(double t, double sum, const char* text) { std::cout << t <<"s\t" << text << "\t" << (t / sum)*100.0 <<"%"<< std::endl; }; -//! Profile Macro to measure time with OGDF -#ifdef OGDF_SYSTEM_WINDOWS -#define FME_PROFILE(STATEMENT, TEXT) if(true) { double t=0.0;t=usedTime(t);STATEMENT;t=usedTime(t);std::cout << t <<"s\t" << TEXT << std::endl;}; -#else -#define FME_PROFILE(STATEMENT, TEXT) if(true) { double t=0.0;timeval start_time,end_time;gettimeofday(&start_time,0);STATEMENT;end_time=GetDiffTime(start_time,t);if (isMainThread()) std::cout << t <<"s\t" << TEXT << std::endl;}; -#endif - -//! 16-byte aligned memory allocation macro -#define MALLOC_16(s) System::alignedMemoryAlloc16((s)) - -//! 16-byte aligned memory deallocation macro -#define FREE_16(ptr) System::alignedMemoryFree((ptr)) - -//! square root of two -#define SQRT_OF_TWO 1.4142135623730950488016887242097 - -//! common template for bit-interleaving to compute the morton number assumes sizeOf(MNR_T) = 2*sizeOf(C_T) -template -inline MNR_T mortonNumber(C_T ix, C_T iy) -{ - MNR_T x = (MNR_T)ix; - MNR_T y = (MNR_T)iy; - // bit length of the result - const unsigned int BIT_LENGTH = sizeof(MNR_T) << 3; - // set all bits - MNR_T mask = 0x0; - mask = ~mask; - - for (unsigned int i = (BIT_LENGTH >> 1);i>0; i = i >> 1) - { - // increase frequency - mask = mask ^ (mask << i); - x = (x | (x << i)) & mask; - y = (y | (y << i)) & mask; - } - return x | (y << 1); -} - - -//! common template for extracting the coordinates from a morton number assumes sizeOf(MNR_T) = 2*sizeOf(C_T) -template -inline void mortonNumberInv(MNR_T mnr, C_T& x, C_T& y) -{ - // bit length of the coordinates - unsigned int BIT_LENGTH = sizeof(C_T) << 3; - // set least significant bit - MNR_T mask = 0x1; - // set coords to zero - x = y = 0; - for (unsigned int i=0; i < BIT_LENGTH; i++) - { - x = (C_T)(x | (mnr & mask)); - mnr = mnr >> 1; - y = (C_T)(y | (mnr & mask)); - mask = mask << 1; - } -} - -//! returns the index of the most signficant bit set. 0 = most signif, bitlength-1 = least signif -template -inline __uint32 mostSignificantBit(T n) -{ - __uint32 BIT_LENGTH = sizeof(T) << 3; - T mask = 0x1; - mask = mask << (BIT_LENGTH - 1); - for (__uint32 i = 0; i < BIT_LENGTH; i++) - { - if (mask & n) - return i; - mask = mask >> 1; - } - return BIT_LENGTH; -} - -//! returns the prev power of two -inline __uint32 prevPowerOfTwo(__uint32 n) -{ - __uint32 msb = 32 - mostSignificantBit(n); - return 0x1 << (msb - 1); -} - -//! utility class to select multiple nodes randomly -class RandomNodeSet -{ -public: - //! init the random node set with the given graph. takes O(n) - RandomNodeSet(const Graph& G) : m_graph(G) { allocate(); } - - //! destructor - ~RandomNodeSet() { deallocate(); } - - //! chooses a node from the available nodes in O(1) - node chooseNode() const - { - int i = m_numNodesChoosen + ogdf::randomNumber(0,nodesLeft()-1);//(int)((double)nodesLeft()*rand()/(RAND_MAX+1.0)); - return m_array[i]; - } - - //! removes a node from available nodes (assumes v is available) in O(1) - void removeNode(node v) - { - int i = m_nodeIndex[v]; - int j = m_numNodesChoosen; - node w = m_array[j]; - swap(m_array[i], m_array[j]); - m_nodeIndex[w] = i; - m_nodeIndex[v] = j; - m_numNodesChoosen++; - } - - bool isAvailable(node v) const { return (m_nodeIndex[v]>=m_numNodesChoosen); } - - //! number of nodes available; - int nodesLeft() const { return m_numNodes - m_numNodesChoosen; } - -private: - void allocate() - { - m_array = new node[m_graph.numberOfNodes()]; - m_nodeIndex.init(m_graph); - m_numNodes = m_graph.numberOfNodes(); - m_numNodesChoosen = 0; - node v; - int i = 0; - forall_nodes(v, m_graph) - { - m_array[i] = v; - m_nodeIndex[v] = i; - i++; - } - } - - void deallocate() - { - delete[] m_array; - } - - //! the graph - const Graph& m_graph; - - //! the set of all nodes (at the end the available nodes) - node* m_array; - - //! the index in the array of the nodes - NodeArray m_nodeIndex; - - //! total num nodes - int m_numNodes; - - //! num available nodes - int m_numNodesChoosen; -}; - -inline void gridGraph(Graph& G, int n, int m) -{ - G.clear(); - node v; - node* topRow = new node[m]; - topRow[0] = G.newNode();; - for (int j=1; j -class BinCoeff -{ -public: - BinCoeff(unsigned int n) : m_max_n(n) { init_array(); } - - ~BinCoeff() { free_array(); } - - //! Init BK -matrix for values n, k in 0 to t. - void init_array() - { - typedef TYP* ptr; - unsigned int i,j; - m_binCoeffs = new ptr[m_max_n+1]; - for(i = 0;i<= m_max_n ;i++) - { - m_binCoeffs[i]= new TYP[i+1]; - } - - //Pascalsches Dreieck - for (i = 0; i <= m_max_n;i++) - { - m_binCoeffs[i][0] = m_binCoeffs[i][i] = 1; - } - - for (i = 2; i <= m_max_n; i ++) - { - for (j = 1; j < i; j++) - { - m_binCoeffs[i][j] = m_binCoeffs[i-1][j-1]+m_binCoeffs[i-1][j]; - } - } - } - - //! Free space for BK. - void free_array() - { - unsigned int i; - for(i = 0;i<= m_max_n;i++) - { - delete[] m_binCoeffs[i]; - } - delete[] m_binCoeffs; - } - - //Returns n over k. - inline TYP value(unsigned int n, unsigned int k) const - { - return m_binCoeffs[n][k]; - } - -private: - unsigned int m_max_n; - - //! holds the binominal coefficients - TYP** m_binCoeffs; -}; - - -// nothing -struct EmptyArgType {}; -// -// Function Invoker for 8 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5, ArgType6 _arg6, ArgType7 _arg7, ArgType8 _arg8) : - function(f), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5), arg6(_arg6), arg7(_arg7), arg8(_arg8) { } - - inline void operator()() { function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; - ArgType3 arg3; - ArgType4 arg4; - ArgType5 arg5; - ArgType6 arg6; - ArgType7 arg7; - ArgType8 arg8; -}; - - -// -// Function Invoker for 7 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5, ArgType6 _arg6, ArgType7 _arg7) : - function(f), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5), arg6(_arg6), arg7(_arg7) { } - - inline void operator()() { function(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; - ArgType3 arg3; - ArgType4 arg4; - ArgType5 arg5; - ArgType6 arg6; - ArgType7 arg7; -}; - -// -// Function Invoker for 6 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5, ArgType6 _arg6) : - function(f), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5), arg6(_arg6) { } - - inline void operator()() { function(arg1, arg2, arg3, arg4, arg5, arg6); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; - ArgType3 arg3; - ArgType4 arg4; - ArgType5 arg5; - ArgType6 arg6; -}; - -// -// Function Invoker for 5 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5) : - function(f), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4), arg5(_arg5) { } - - inline void operator()() { function(arg1, arg2, arg3, arg4, arg5); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; - ArgType3 arg3; - ArgType4 arg4; - ArgType5 arg5; -}; - -// -// Function Invoker for 4 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4) : - function(f), arg1(_arg1), arg2(_arg2), arg3(_arg3), arg4(_arg4) { } - - inline void operator()() { function(arg1, arg2, arg3, arg4); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; - ArgType3 arg3; - ArgType4 arg4; -}; - -// -// Function Invoker for 3 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3) : - function(f), arg1(_arg1), arg2(_arg2), arg3(_arg3) { } - - inline void operator()() { function(arg1, arg2, arg3); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; - ArgType3 arg3; -}; - -// -// Function Invoker for 2 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1, ArgType2 _arg2) : - function(f), arg1(_arg1), arg2(_arg2) { } - - inline void operator()() { function(arg1, arg2); } - - FunctionType function; - ArgType1 arg1; - ArgType2 arg2; -}; - -// -// Function Invoker for 1 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f, ArgType1 _arg1) : - function(f), arg1(_arg1) { } - - inline void operator()() { function(arg1); } - - FunctionType function; - ArgType1 arg1; -}; - -// -// Function Invoker for 0 args -// -template -struct FuncInvoker -{ - FuncInvoker(FunctionType f) : - function(f) { } - - inline void operator()() { function(); } - - FunctionType function; -}; - - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5, ArgType6 _arg6, ArgType7 _arg7, ArgType8 _arg8) -{ - return FuncInvoker(func, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5, ArgType6 _arg6, ArgType7 _arg7) -{ - return FuncInvoker(func, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5, ArgType6 _arg6) -{ - return FuncInvoker(func, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4, ArgType5 _arg5) -{ - return FuncInvoker(func, _arg1, _arg2, _arg3, _arg4, _arg5); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3, ArgType4 _arg4) -{ - return FuncInvoker(func, _arg1, _arg2, _arg3, _arg4); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2, ArgType3 _arg3) -{ - return FuncInvoker(func, _arg1, _arg2, _arg3); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1, ArgType2 _arg2) -{ - return FuncInvoker(func, _arg1, _arg2); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func, ArgType1 _arg1) -{ - return FuncInvoker(func, _arg1); -} - -template -FuncInvoker -createFuncInvoker(FunctionType func) -{ - return FuncInvoker(func); -} - -} - -#endif // fast utils h diff --git a/ext/OGDF/src/energybased/FruchtermanReingold.cpp b/ext/OGDF/src/energybased/FruchtermanReingold.cpp deleted file mode 100644 index e094e96ae..000000000 --- a/ext/OGDF/src/energybased/FruchtermanReingold.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class FruchtermanReingold (computation of forces). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -#include "numexcept.h" -#include - - -namespace ogdf { - -FruchtermanReingold::FruchtermanReingold() -{ - grid_quotient(2); -} - - -void FruchtermanReingold::calculate_exact_repulsive_forces( - const Graph &G, - NodeArray &A, - NodeArray& F_rep) -{ - //naive algorithm by Fruchterman & Reingold - numexcept N; - node v,u; - DPoint f_rep_u_on_v; - DPoint vector_v_minus_u; - DPoint pos_u,pos_v; - DPoint nullpoint (0,0); - double norm_v_minus_u; - long node_number = G.numberOfNodes(); - Array array_of_the_nodes (node_number+1); - long counter = 1; - long i,j; - double scalar; - - forall_nodes(v,G) - F_rep[v]= nullpoint; - - forall_nodes(v,G) - { - array_of_the_nodes[counter]=v; - counter++; - } - - for(i = 1; i &A, - NodeArray& F_rep) -{ - //GRID algorithm by Fruchterman & Reingold - numexcept N; - List neighbour_boxes; - List neighbour_box; - IPoint act_neighbour_box; - IPoint neighbour; - DPoint f_rep_u_on_v; - DPoint vector_v_minus_u; - DPoint nullpoint (0,0); - DPoint pos_u,pos_v; - double norm_v_minus_u; - double scalar; - - int i,j,act_i,act_j,k,l,length; - node u,v; - double x,y,gridboxlength;//length of a box in the GRID - int x_index,y_index; - - //init F_rep - forall_nodes(v,G) - F_rep[v]= nullpoint; - - //init max_gridindex and set contained_nodes; - - max_gridindex = static_cast (sqrt(double(G.numberOfNodes()))/grid_quotient())-1; - max_gridindex = ((max_gridindex > 0)? max_gridindex : 0); - Array2D > contained_nodes (0,max_gridindex, 0, max_gridindex); - - for(i=0;i<= max_gridindex;i++) - for(j=0;j<= max_gridindex;j++) - { - contained_nodes(i,j).clear(); - } - - gridboxlength = boxlength/(max_gridindex+1); - forall_nodes(v,G) - { - x = A[v].get_x()-down_left_corner.m_x;//shift comput. box to nullpoint - y = A[v].get_y()-down_left_corner.m_y; - x_index = static_cast(x/gridboxlength); - y_index = static_cast(y/gridboxlength); - contained_nodes(x_index,y_index).pushBack(v); - } - - //force calculation - - for(i=0;i<= max_gridindex;i++) - for(j=0;j<= max_gridindex;j++) - { - //step1: calculate forces inside contained_nodes(i,j) - - length = contained_nodes(i,j).size(); - Array nodearray_i_j (length+1); - k = 1; - forall_listiterators(node, v_it,contained_nodes(i,j)) - { - nodearray_i_j[k]= *v_it; - k++; - } - - for(k = 1; k=0) && (l>=0) && (k<=max_gridindex) && (l<=max_gridindex)) - { - neighbour.m_x = k; - neighbour.m_y = l; - if ((k != i) || (l != j) ) - neighbour_boxes.pushBack(neighbour); - } - - - //forget neighbour_boxes that already had access to this box - forall_listiterators(IPoint, act_neighbour_box_it,neighbour_boxes) - {//forall - act_i = (*act_neighbour_box_it).m_x; - act_j = (*act_neighbour_box_it).m_y; - if((act_j == j+1)||((act_j == j)&&(act_i == i+1))) - {//if1 - forall_listiterators(node,v_it,contained_nodes(i,j)) - forall_listiterators(node,u_it,contained_nodes(act_i,act_j)) - {//for - pos_u = A[*u_it].get_position(); - pos_v = A[*v_it].get_position(); - if (pos_u == pos_v) - {//if2 (Exception handling if two nodes have the same position) - pos_u = N.choose_distinct_random_point_in_radius_epsilon(pos_u); - }//if2 - vector_v_minus_u = pos_v - pos_u; - norm_v_minus_u = vector_v_minus_u.norm(); - - if(!N.f_rep_near_machine_precision(norm_v_minus_u,f_rep_u_on_v)) - { - scalar = f_rep_scalar(norm_v_minus_u)/norm_v_minus_u ; - f_rep_u_on_v.m_x = scalar * vector_v_minus_u.m_x; - f_rep_u_on_v.m_y = scalar * vector_v_minus_u.m_y; - } - F_rep[*v_it] = F_rep[*v_it] + f_rep_u_on_v; - F_rep[*u_it] = F_rep[*u_it] - f_rep_u_on_v; - }//for - }//if1 - }//forall - } -} - - -void FruchtermanReingold::make_initialisations(double bl, DPoint d_l_c, int grid_quot) -{ - grid_quotient(grid_quot); - down_left_corner = d_l_c; //export this two values from FMMM - boxlength = bl; -} - - -inline double FruchtermanReingold::f_rep_scalar(double d) -{ - if (d > 0) { - return 1/d; - - } else { - cout<<"Error FruchtermanReingold:: f_rep_scalar nodes at same position"< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -GEMLayout::GEMLayout() : - m_numberOfRounds(30000), - m_minimalTemperature(0.005), - m_initialTemperature(12.0), - m_gravitationalConstant(1.0/16.0), //original paper value - m_desiredLength(5.0), - m_maximalDisturbance(0), - m_rotationAngle(Math::pi/3.0), - m_oscillationAngle(Math::pi_2), - m_rotationSensitivity(0.01), - m_oscillationSensitivity(0.3), - m_attractionFormula(1), - m_minDistCC(20), - m_pageRatio(1.0) -{ } - -GEMLayout::GEMLayout(const GEMLayout &fl) : - m_numberOfRounds(fl.m_numberOfRounds), - m_minimalTemperature(fl.m_minimalTemperature), - m_initialTemperature(fl.m_initialTemperature), - m_gravitationalConstant(fl.m_gravitationalConstant), - m_desiredLength(fl.m_desiredLength), - m_maximalDisturbance(fl.m_maximalDisturbance), - m_rotationAngle(fl.m_rotationAngle), - m_oscillationAngle(fl.m_oscillationAngle), - m_rotationSensitivity(fl.m_rotationSensitivity), - m_oscillationSensitivity(fl.m_oscillationSensitivity), - m_attractionFormula(fl.m_attractionFormula), - m_minDistCC(fl.m_minDistCC), - m_pageRatio(fl.m_pageRatio) -{ } - - -GEMLayout::~GEMLayout() { } - - -GEMLayout &GEMLayout::operator=(const GEMLayout &fl) -{ - m_numberOfRounds = fl.m_numberOfRounds; - m_minimalTemperature = fl.m_minimalTemperature; - m_initialTemperature = fl.m_initialTemperature; - m_gravitationalConstant = fl.m_gravitationalConstant; - m_desiredLength = fl.m_desiredLength; - m_maximalDisturbance = fl.m_maximalDisturbance; - m_rotationAngle = fl.m_rotationAngle; - m_oscillationAngle = fl.m_oscillationAngle; - m_rotationSensitivity = fl.m_rotationSensitivity; - m_oscillationSensitivity = fl.m_oscillationSensitivity; - m_attractionFormula = fl.m_attractionFormula; - return *this; -} - - -void GEMLayout::call(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - if(G.empty()) - return; - - // all edges straight-line - AG.clearAllBends(); - - GraphCopy GC; - GC.createEmpty(G); - - // compute connected component of G - NodeArray component(G); - int numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - Array > nodesInCC(numCC); - - node v; - forall_nodes(v,G) - nodesInCC[component[v]].pushBack(v); - - EdgeArray auxCopy(G); - Array boundingBox(numCC); - - int i; - for(i = 0; i < numCC; ++i) - { - GC.initByNodes(nodesInCC[i],auxCopy); - - GraphCopyAttributes AGC(GC,AG); - node vCopy; - forall_nodes(vCopy, GC) { - node vOrig = GC.original(vCopy); - AGC.x(vCopy) = AG.x(vOrig); - AGC.y(vCopy) = AG.y(vOrig); - } - - SList permutation; - node v; - - // initialize node data - m_impulseX.init(GC,0); - m_impulseY.init(GC,0); - m_skewGauge.init(GC,0); - m_localTemperature.init(GC,m_initialTemperature); - - // initialize other data - m_globalTemperature = m_initialTemperature; - m_barycenterX = 0; - m_barycenterY = 0; - forall_nodes(v,GC) { - m_barycenterX += weight(v) * AGC.x(v); - m_barycenterY += weight(v) * AGC.y(v); - } - m_cos = cos(m_oscillationAngle / 2.0); - m_sin = sin(Math::pi / 2 + m_rotationAngle / 2.0); - - // main loop - int counter = m_numberOfRounds; - while(DIsGreater(m_globalTemperature,m_minimalTemperature) && counter--) { - - // choose nodes by random permutations - if(permutation.empty()) { - forall_nodes(v,GC) - permutation.pushBack(v); - permutation.permute(); - } - v = permutation.popFrontRet(); - - // compute the impulse of node v - computeImpulse(GC,AGC,v); - - // update node v - updateNode(GC,AGC,v); - - } - - node vFirst = GC.firstNode(); - double minX = AGC.x(vFirst), maxX = AGC.x(vFirst), - minY = AGC.y(vFirst), maxY = AGC.y(vFirst); - - forall_nodes(vCopy,GC) { - node v = GC.original(vCopy); - AG.x(v) = AGC.x(vCopy); - AG.y(v) = AGC.y(vCopy); - - if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; - if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; - if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; - if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; - } - - minX -= m_minDistCC; - minY -= m_minDistCC; - - forall_nodes(vCopy,GC) { - node v = GC.original(vCopy); - AG.x(v) -= minX; - AG.y(v) -= minY; - } - - boundingBox[i] = DPoint(maxX - minX, maxY - minY); - } - - Array offset(numCC); - TileToRowsCCPacker packer; - packer.call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node and edge by the offset - // of its connected component. - - for(i = 0; i < numCC; ++i) - { - const List &nodes = nodesInCC[i]; - - const double dx = offset[i].m_x; - const double dy = offset[i].m_y; - - // iterate over all nodes in ith CC - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - AG.x(v) += dx; - AG.y(v) += dy; - } - } - - - // free node data - m_impulseX.init(); - m_impulseY.init(); - m_skewGauge.init(); - m_localTemperature.init(); -} - -void GEMLayout::computeImpulse(GraphCopy &G, GraphCopyAttributes &AG,node v) { - //const Graph &G = AG.constGraph(); - int n = G.numberOfNodes(); - - node u; - edge e; - double deltaX,deltaY,delta,deltaSqu; - double desiredLength,desiredSqu; - - // add double node radius to desired edge length - desiredLength = m_desiredLength + length(AG.getHeight(v),AG.getWidth(v)); - desiredSqu = desiredLength * desiredLength; - - // compute attraction to center of gravity - m_newImpulseX = (m_barycenterX / n - AG.x(v)) * m_gravitationalConstant; - m_newImpulseY = (m_barycenterY / n - AG.y(v)) * m_gravitationalConstant; - - // disturb randomly - int maxIntDisturbance = (int)(m_maximalDisturbance * 10000); - m_newImpulseX += - (double)(randomNumber(-maxIntDisturbance,maxIntDisturbance) / 10000); - m_newImpulseY += - (double)(randomNumber(-maxIntDisturbance,maxIntDisturbance) / 10000); - - // compute repulsive forces - forall_nodes(u,G) - if(u != v ) { - deltaX = AG.x(v) - AG.x(u); - deltaY = AG.y(v) - AG.y(u); - delta = length(deltaX,deltaY); - if(DIsGreater(delta,0)) { - deltaSqu = delta * delta; - m_newImpulseX += deltaX * desiredSqu / deltaSqu; - m_newImpulseY += deltaY * desiredSqu / deltaSqu; - } - } - - // compute attractive forces - forall_adj_edges(e,v) { - u = e->opposite(v); - deltaX = AG.x(v) - AG.x(u); - deltaY = AG.y(v) - AG.y(u); - delta = length(deltaX,deltaY); - if(m_attractionFormula == 1) { - m_newImpulseX -= deltaX * delta / (desiredLength * weight(v)); - m_newImpulseY -= deltaY * delta / (desiredLength * weight(v)); - } - else { - deltaSqu = delta * delta; - m_newImpulseX -= deltaX * deltaSqu / (desiredSqu * weight(v)); - m_newImpulseY -= deltaY * deltaSqu / (desiredSqu * weight(v)); - } - } - -} - -void GEMLayout::updateNode(GraphCopy &G, GraphCopyAttributes &AG,node v) { - //const Graph &G = AG.constGraph(); - int n = G.numberOfNodes(); - double impulseLength; - - impulseLength = length(m_newImpulseX,m_newImpulseY); - if(DIsGreater(impulseLength,0)) { - - // scale impulse by node temperature - m_newImpulseX *= m_localTemperature[v] / impulseLength; - m_newImpulseY *= m_localTemperature[v] / impulseLength; - - // move node - AG.x(v) += m_newImpulseX; - AG.y(v) += m_newImpulseY; - - // adjust barycenter - m_barycenterX += weight(v) * m_newImpulseX; - m_barycenterY += weight(v) * m_newImpulseY; - - impulseLength = length(m_newImpulseX,m_newImpulseY) - * length(m_impulseX[v],m_impulseY[v]); - if(DIsGreater(impulseLength,0)) { - - m_globalTemperature -= m_localTemperature[v] / n; - - // compute sine and cosine of angle between old and new impulse - double sinBeta,cosBeta; - sinBeta = (m_newImpulseX * m_impulseX[v] - - m_newImpulseY * m_impulseY[v]) - / impulseLength; - cosBeta = (m_newImpulseX * m_impulseX[v] - + m_newImpulseY * m_impulseY[v]) - / impulseLength; - - // check for rotation - if(DIsGreater(sinBeta,m_sin)) - m_skewGauge[v] += m_rotationSensitivity; - - // check for oscillation - if(DIsGreater(length(cosBeta),m_cos)) - m_localTemperature[v] *= - (1 + cosBeta * m_oscillationSensitivity); - - // cool down according to skew gauge - m_localTemperature[v] *= (1.0 - length(m_skewGauge[v])); - if(DIsGreaterEqual(m_localTemperature[v],m_initialTemperature)) - m_localTemperature[v] = m_initialTemperature; - - // adjust global temperature - m_globalTemperature += m_localTemperature[v] / n; - } - - // save impulse - m_impulseX[v] = m_newImpulseX; - m_impulseY[v] = m_newImpulseY; - } -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/energybased/GalaxyMultilevel.cpp b/ext/OGDF/src/energybased/GalaxyMultilevel.cpp deleted file mode 100644 index 0b49e2837..000000000 --- a/ext/OGDF/src/energybased/GalaxyMultilevel.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class GalaxyMultilevelBuilder. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "GalaxyMultilevel.h" -#include -#include "FastUtils.h" -#include - -namespace ogdf { - - -void GalaxyMultilevelBuilder::computeSystemMass() -{ - node v = 0; - forall_nodes(v, *m_pGraph) - { - m_nodeState[v].sysMass = (*m_pNodeInfo)[v].mass; - m_nodeState[v].label = 0; - m_nodeState[v].lastVisitor = v; - } - - forall_nodes(v, *m_pGraph) - { - adjEntry adj; - forall_adj(adj, v) - { - m_nodeState[v].sysMass += (*m_pNodeInfo)[adj->twinNode()].mass; - } - - if (v->degree()==1) - m_nodeState[v].sysMass *= m_pGraph->numberOfNodes() ; - } -} - - -void swap(ogdf::GalaxyMultilevelBuilder::NodeOrderInfo& a, ogdf::GalaxyMultilevelBuilder::NodeOrderInfo& b) -{ - ogdf::GalaxyMultilevelBuilder::NodeOrderInfo t = a; - a = b; - b = t; -} - - -void GalaxyMultilevelBuilder::sortNodesBySystemMass() -{ - int i = 0; - node v = 0; - m_pRandomSet = new RandomNodeSet(*m_pGraph); - for (i=0;inumberOfNodes();i++) - { - v = m_pRandomSet->chooseNode(); - m_pRandomSet->removeNode(v); - m_nodeMassOrder[i].theNode = v; - } - - delete m_pRandomSet; - std::sort(m_nodeMassOrder, m_nodeMassOrder+(m_pGraph->numberOfNodes()), NodeMassComparer( m_nodeState )); -} - - -void GalaxyMultilevelBuilder::labelSystem(node u, node v, int d, float df) -{ - if (d>0) - { - adjEntry adj; - forall_adj(adj, v) - { - node w = adj->twinNode(); - // this node may have been labeled before but its closer to the current sun - if (m_nodeState[w].label < d) - { - float currDistFromSun = (*m_pEdgeInfo)[adj->theEdge()].length + df /*+ (*m_pNodeInfo)[w].radius*/; - // check if we relabeling by a new sun - if (m_nodeState[w].lastVisitor != u) - { - // maybe this node has never been labeled - m_nodeState[w].lastVisitor = u; - m_nodeState[w].edgeLengthFromSun = currDistFromSun; - } - // finally relabel it - m_nodeState[w].edgeLengthFromSun = min(m_nodeState[w].edgeLengthFromSun, currDistFromSun); - m_nodeState[w].label = d; - labelSystem(u, w, d-1, currDistFromSun /*+(*m_pNodeInfo)[w].radius*/); - } - } - } -} - - -void GalaxyMultilevelBuilder::labelSystem() -{ - m_sunNodeList.clear(); - node v = 0; - forall_nodes(v, *m_pGraph) - { - m_nodeState[v].sysMass = 0; - m_nodeState[v].label = 0; - m_nodeState[v].lastVisitor = v; - } - - for (int i=0; i < m_pGraph->numberOfNodes(); i++) - { - v = m_nodeMassOrder[i].theNode; - if (m_nodeState[v].label == 0) - { - m_sunNodeList.pushBack(v); - m_nodeState[v].label = (m_dist+1); - m_nodeState[v].edgeLengthFromSun = 0.0;//(*m_pNodeInfo)[v].radius; - labelSystem(v, v, m_dist, m_nodeState[v].edgeLengthFromSun); - } - } -} - - -GalaxyMultilevel* GalaxyMultilevelBuilder::build(GalaxyMultilevel* pMultiLevel) -{ - m_dist = 2; - m_pGraph = pMultiLevel->m_pGraph; - m_pNodeInfo = pMultiLevel->m_pNodeInfo; - m_pEdgeInfo = pMultiLevel->m_pEdgeInfo; - m_nodeMassOrder = (NodeOrderInfo*)MALLOC_16(sizeof(NodeOrderInfo)*m_pGraph->numberOfNodes()); - m_nodeState.init(*m_pGraph); - - this->computeSystemMass(); - this->sortNodesBySystemMass(); - this->labelSystem(); - GalaxyMultilevel* pMultiLevelResult = new GalaxyMultilevel(pMultiLevel); - this->createResult(pMultiLevelResult);; - - FREE_16(m_nodeMassOrder); - - return pMultiLevelResult; -} - - -void GalaxyMultilevelBuilder::createResult(GalaxyMultilevel* pMultiLevelResult) -{ - pMultiLevelResult->m_pGraph = new Graph(); - m_pGraphResult = pMultiLevelResult->m_pGraph; - - NodeArray toResultNode(*m_pGraph, 0); - // create all sun nodes - for(List::iterator it = m_sunNodeList.begin(); it.valid(); it++) - { - node v = *it; - node vResult = m_pGraphResult->newNode(); - toResultNode[v] = vResult; - } - - pMultiLevelResult->m_pNodeInfo = new NodeArray(*m_pGraphResult); - m_pNodeInfoResult = pMultiLevelResult->m_pNodeInfo; - - // calculate the real system mass. this may not be the same as calculated before - node u; - forall_nodes(u, *m_pGraphResult) - { - (*m_pNodeInfoResult)[u].radius = 0.0f; - (*m_pNodeInfoResult)[u].mass = 0.0f; - } - forall_nodes(u, *m_pGraph) - { - node uSun = m_nodeState[u].lastVisitor; - node uSunResult = toResultNode[uSun]; - (*m_pNodeInfo)[u].parent = uSunResult; - (*m_pNodeInfoResult)[uSunResult].mass +=((*m_pNodeInfo)[u].mass); - (*m_pNodeInfoResult)[uSunResult].radius = max( (*m_pNodeInfoResult)[uSunResult].radius, m_nodeState[u].edgeLengthFromSun);//m_nodeState[u].edgeLengthFromSun;//m_nodeState[u].edgeLengthFromSun;// max( (*m_pNodeInfoResult)[uSunResult].radius, m_nodeState[u].edgeLengthFromSun); - } - - pMultiLevelResult->m_pEdgeInfo = new EdgeArray(*m_pGraphResult); - m_pEdgeInfoResult = pMultiLevelResult->m_pEdgeInfo; - - edge e; - forall_edges(e, *m_pGraph) - { - node v = e->source(); - node w = e->target(); - node vSun = m_nodeState[v].lastVisitor; - node wSun = m_nodeState[w].lastVisitor; - if (vSun != wSun) - { - node vSunResult = toResultNode[vSun]; - node wSunResult = toResultNode[wSun]; - edge eResult = m_pGraphResult->newEdge(vSunResult, wSunResult); - (*m_pEdgeInfoResult)[eResult].length = m_nodeState[v].edgeLengthFromSun + (*m_pEdgeInfo)[e].length + m_nodeState[w].edgeLengthFromSun; - } - } - - // make fast parallel free - NodeArray lastVisit(*m_pGraphResult, 0); - node v; - forall_nodes(v, *m_pGraphResult) - { - if (v->degree()>1) - { - adjEntry adj = v->firstAdj(); - do{ - node w = adj->twinNode(); - edge e = adj->theEdge(); - adj = adj->cyclicSucc(); - if (lastVisit[w] ==v) - m_pGraphResult->delEdge(e); - else - lastVisit[w] = v; - } while (adj !=v->firstAdj()); - } - } -} - -} // end of namespace - diff --git a/ext/OGDF/src/energybased/GalaxyMultilevel.h b/ext/OGDF/src/energybased/GalaxyMultilevel.h deleted file mode 100644 index 248c40bff..000000000 --- a/ext/OGDF/src/energybased/GalaxyMultilevel.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class GalaxyMultilevelBuilder. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_GALAXY_MULTILEVEL_H -#define OGDF_GALAXY_MULTILEVEL_H - -#include -#include -#include -#include "ArrayGraph.h" -#include "FastUtils.h" -#include - -namespace ogdf { - -class GalaxyMultilevel -{ -public: - typedef List > NearSunList; - - struct LevelNodeInfo - { - float mass; - float radius; - node parent; - NearSunList nearSuns; - }; - - struct LevelEdgeInfo - { - float length; - }; - - GalaxyMultilevel(Graph* pGraph) - { - m_pFinerMultiLevel = 0; - m_pCoarserMultiLevel = 0; - m_pGraph = pGraph; - m_pNodeInfo = new NodeArray(*m_pGraph); - m_pEdgeInfo = new EdgeArray(*m_pGraph); - node v; - forall_nodes(v, *m_pGraph) - { - (*m_pNodeInfo)[v].mass = 1.0; - } - levelNumber = 0; - } - - GalaxyMultilevel(GalaxyMultilevel* prev) - { - m_pCoarserMultiLevel = 0; - m_pFinerMultiLevel = prev; - m_pFinerMultiLevel->m_pCoarserMultiLevel = this; - m_pGraph = 0; - m_pNodeInfo = 0; - levelNumber = prev->levelNumber + 1; - } - - ~GalaxyMultilevel() { } - - GalaxyMultilevel* m_pFinerMultiLevel; - GalaxyMultilevel* m_pCoarserMultiLevel; - Graph* m_pGraph; - NodeArray* m_pNodeInfo; - EdgeArray* m_pEdgeInfo; - int levelNumber; -}; - - -class GalaxyMultilevelBuilder -{ -public: - struct LevelNodeState - { - node lastVisitor; - double sysMass; - int label; - float edgeLengthFromSun; - }; - - struct NodeOrderInfo - { - node theNode; - }; - - GalaxyMultilevel* build(GalaxyMultilevel* pMultiLevel); - -private: - void computeSystemMass(); - void sortNodesBySystemMass(); - void createResult(GalaxyMultilevel* pMultiLevelResult); - void labelSystem(node u, node v, int d, float df); - void labelSystem(); - Graph* m_pGraph; - Graph* m_pGraphResult; - List m_sunNodeList; - List m_interSystemEdges; - NodeArray* m_pNodeInfo; - EdgeArray* m_pEdgeInfo; - NodeArray* m_pNodeInfoResult; - EdgeArray* m_pEdgeInfoResult; - NodeArray m_nodeState; - NodeOrderInfo* m_nodeMassOrder; - RandomNodeSet* m_pRandomSet; - int m_dist; -}; - - -class NodeMassComparer -{ -public: - NodeMassComparer(const NodeArray< GalaxyMultilevelBuilder::LevelNodeState>& nodeState) : m_nodeState(nodeState) { } - - // used for std::sort - inline bool operator()(const GalaxyMultilevelBuilder::NodeOrderInfo& a, const GalaxyMultilevelBuilder::NodeOrderInfo& b) const - { - return m_nodeState[a.theNode].sysMass < m_nodeState[b.theNode].sysMass; - } - -private: - const NodeArray< GalaxyMultilevelBuilder::LevelNodeState >& m_nodeState; -}; - -} // end of namespace ogdf - -#endif diff --git a/ext/OGDF/src/energybased/IntersectionRectangle.cpp b/ext/OGDF/src/energybased/IntersectionRectangle.cpp deleted file mode 100644 index b56189923..000000000 --- a/ext/OGDF/src/energybased/IntersectionRectangle.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class IntersectionRectangle (checks - * overlap of rectangles). - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - -namespace ogdf { - - // this constructor gets the center point, width and height and sets the corners, the - // center and the area - IntersectionRectangle::IntersectionRectangle(const DPoint &c, double width, double height) - { - m_center = c; - double halfwidth = 0.5*width; - double halfheight = 0.5*height; - m_p1.m_x = m_center.m_x - halfwidth; - m_p1.m_y = m_center.m_y - halfheight; - m_p2.m_x = m_center.m_x + halfwidth; - m_p2.m_y = m_center.m_y + halfheight; - m_area = width * height; - } - - - // two rectangles intersect if one of the center points is contained in the other rectangle - // or if one of the corners of the second rectangle is contained in the first - bool IntersectionRectangle::intersects(const IntersectionRectangle &ir) const - { - bool intersect = false; - if(inside(ir.m_center) || ir.inside(m_center)) intersect = true; - else { - DPoint p1(ir.m_p1.m_x, ir.m_p2.m_y); - DPoint p2(ir.m_p2.m_x, ir.m_p1.m_y); - intersect = inside(p1) || inside(p2) || inside(ir.m_p1) || inside(ir.m_p2); - } - return intersect; - } - - - // This makes the lower left point the first point of the rectangle, computes - // the coordinates of the center point and the area. - void IntersectionRectangle::init() { - if (width() < 0) - swap(m_p2.m_x, m_p1.m_x); - if (height() < 0) - swap(m_p2.m_y, m_p1.m_y); - m_area = (m_p2.m_x-m_p1.m_x)*(m_p2.m_y-m_p1.m_y); - m_center.m_x = m_p1.m_x + 0.5*(m_p2.m_x-m_p1.m_x); - m_center.m_y = m_p1.m_y + 0.5*(m_p2.m_y-m_p1.m_y); - } - - - // this returns the rectangle defined by the intersection of this and ir. If the intersection - // is empty, an empty rectangle is returned. - IntersectionRectangle IntersectionRectangle::intersection( - const IntersectionRectangle &ir) const - { - double top1 = m_p2.m_y; - double bottom1 = m_p1.m_y; - double left1 = m_p1.m_x; - double right1 = m_p2.m_x; - - double top2 = ir.m_p2.m_y; - double bottom2 = ir.m_p1.m_y; - double left2 = ir.m_p1.m_x; - double right2 = ir.m_p2.m_x; - - OGDF_ASSERT(top1 >= bottom1); - OGDF_ASSERT(left1 <= right1); - OGDF_ASSERT(top2 >= bottom2); - OGDF_ASSERT(left2 <= right2); - - double bottomInter = max(bottom1,bottom2); - double topInter = min(top1,top2); - double leftInter = max(left1,left2); - double rightInter = min(right1,right2); - - if(bottomInter > topInter) return IntersectionRectangle(); - if(leftInter > rightInter) return IntersectionRectangle(); - - return IntersectionRectangle(DPoint(leftInter,bottomInter),DPoint(rightInter,topInter)); - } - - - // computes distance to other rectangle - double IntersectionRectangle::distance(const IntersectionRectangle &ir) const - { - double dist = 0.0; - if(!intersects(ir)) { - dist = parallelDist(top(),ir.bottom()); - dist = min(dist, parallelDist(left(),ir.right())); - dist = min(dist, parallelDist(right(),ir.left())); - dist = min(dist, parallelDist(bottom(),ir.top())); - } - return dist; - } - - - // computes distance between two parallel lines - double IntersectionRectangle::parallelDist(const DLine& d1, const DLine& d2) const - { - OGDF_ASSERT((d1.isHorizontal() && d2.isHorizontal()) || - (d1.isVertical() && d2.isVertical())); - double d1min, d1max, d2min, d2max, paraDist, dist; - if(d1.isVertical()) { - d1min = d1.start().m_y; - d1max = d1.end().m_y; - d2min = d2.start().m_y; - d2max = d2.end().m_y; - paraDist = fabs(d1.start().m_x - d2.start().m_x); - } - else { - d1min = d1.start().m_x; - d1max = d1.end().m_x; - d2min = d2.start().m_x; - d2max = d2.end().m_x; - paraDist = fabs(d1.start().m_y - d2.start().m_y); - } - if(d1min > d1max) swap(d1min,d1max); - if(d2min > d2max) swap(d2min,d2max); - if(d1min > d2max || d2min > d1max) { // no overlap - dist = pointDist(d1.start(),d2.start()); - dist = min(dist,pointDist(d1.start(),d2.end())); - dist = min(dist,pointDist(d1.end(),d2.start())); - dist = min(dist,pointDist(d1.end(),d2.end())); - } - else - dist = paraDist; // segments overlap - return dist; - } - - - ostream& operator<<(ostream& out,const IntersectionRectangle &ir) - { - out << "\nCenter: " << ir.m_center; - out << "\nLower left corner: " << ir.m_p1; - out << "\nUpper right corner: " << ir.m_p2; - out << "\nWidth: " << ir.width(); - out << "\nHeight: " << ir.height(); - out << "\nArea: " << ir.m_area; - return out; - } - - - void IntersectionRectangle::move(const DPoint& newCenter) - { - double dX = newCenter.m_x - m_center.m_x; - double dY = newCenter.m_y - m_center.m_y; - m_center = newCenter; - m_p1.m_x += dX; - m_p1.m_y += dY; - m_p2.m_x += dX; - m_p2.m_y += dY; - } - -} // end namespace ogdf - diff --git a/ext/OGDF/src/energybased/LinearQuadtree.cpp b/ext/OGDF/src/energybased/LinearQuadtree.cpp deleted file mode 100644 index 0da1d0b17..000000000 --- a/ext/OGDF/src/energybased/LinearQuadtree.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class LinearQuadtree. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "LinearQuadtree.h" -#include "WSPD.h" - -namespace ogdf { - -void LinearQuadtree::init(float min_x, float min_y, float max_x, float max_y) -{ - m_min_x = min_x; - m_min_y = min_y; - m_max_x = max_x; - m_max_y = max_y; - m_sideLengthGrid = ((double)(0x1 << 24) - 1.0); - m_sideLengthPoints = (double)max(m_max_x - m_min_x, m_max_y - m_min_y); - m_scaleInv = (m_sideLengthGrid / m_sideLengthPoints); - m_cellSize = m_sideLengthPoints /((double)m_sideLengthGrid); - clear(); -} - - -void LinearQuadtree::clear() -{ - m_numWSP = 0; - m_numNotWSP = 0; - m_numDirectNodes = 0; - m_WSPD->clear(); -} - - -LinearQuadtree::LinearQuadtree(__uint32 n, float* origXPos, float* origYPos, float* origSize) : m_origXPos(origXPos), m_origYPos(origYPos), m_origSize(origSize) -{ - allocate(n); - m_numPoints = n; - m_maxNumNodes = 2*n; -} - - -LinearQuadtree::~LinearQuadtree(void) -{ - deallocate(); -} - - -void LinearQuadtree::allocate(__uint32 n) -{ - m_numPoints = n; - m_maxNumNodes = 2*n; - m_tree = (LQNode*)MALLOC_16(m_maxNumNodes*sizeof(LQNode)); - m_nodeXPos = (float*)MALLOC_16(m_maxNumNodes*sizeof(float)); - m_nodeYPos = (float*)MALLOC_16(m_maxNumNodes*sizeof(float)); - m_nodeSize = (float*)MALLOC_16(m_maxNumNodes*sizeof(float)); - m_points = (LQPoint*)MALLOC_16(m_numPoints*sizeof(LQPoint)); - for (__uint32 i = 0; i < m_numPoints; i++) - m_points[i].ref = i; - m_pointXPos = (float*)MALLOC_16(m_numPoints*sizeof(float)); - m_pointYPos = (float*)MALLOC_16(m_numPoints*sizeof(float)); - m_pointSize = (float*)MALLOC_16(m_numPoints*sizeof(float)); - m_notWspd = (LQWSPair*)MALLOC_16(m_maxNumNodes*sizeof(LQWSPair)*27); - m_directNodes = (NodeID*)MALLOC_16(m_maxNumNodes*sizeof(NodeID)); - m_WSPD = new WSPD(m_maxNumNodes); -} - - -void LinearQuadtree::deallocate() -{ - FREE_16(m_tree); - FREE_16(m_nodeXPos); - FREE_16(m_nodeYPos); - FREE_16(m_nodeSize); - FREE_16(m_points); - FREE_16(m_pointXPos); - FREE_16(m_pointYPos); - FREE_16(m_pointSize); - FREE_16(m_notWspd); - FREE_16(m_directNodes); - delete m_WSPD; -} - - -__uint64 LinearQuadtree::sizeInBytes() const -{ - return m_numPoints*sizeof(LQPoint) + - m_maxNumNodes*sizeof(LQNode) + - m_maxNumNodes*sizeof(LQWSPair)*27 + - m_maxNumNodes*sizeof(NodeID) + - m_WSPD->sizeInBytes(); -} - - -//! iterates back in the sequence until the first point with another morton number occures, returns that point +1 -LinearQuadtree::PointID LinearQuadtree::findFirstPointInCell(LinearQuadtree::PointID somePointInCell) const -{ - if (somePointInCell==0) return 0; - LinearQuadtree::PointID result = somePointInCell-1; - while (mortonNr(somePointInCell) == mortonNr(result)) - { - if (result==0) return 0; - result--; - } - return result+1; -} - - -void LinearQuadtree::addWSPD(NodeID s, NodeID t) -{ - m_numWSP++; - m_WSPD->addWSP(s, t); -} - - -void LinearQuadtree::addDirectPair(NodeID s, NodeID t) -{ - m_notWspd[m_numNotWSP].a = s; - m_notWspd[m_numNotWSP].b = t; - m_numNotWSP++; -} - - -void LinearQuadtree::addDirect(NodeID s) -{ - m_directNodes[m_numDirectNodes] = s; - m_numDirectNodes++; -} - -} // end of namespace ogdf diff --git a/ext/OGDF/src/energybased/LinearQuadtree.h b/ext/OGDF/src/energybased/LinearQuadtree.h deleted file mode 100644 index 76fb4bc1a..000000000 --- a/ext/OGDF/src/energybased/LinearQuadtree.h +++ /dev/null @@ -1,810 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class LinearQuadtree. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_LINEAR_QUADTREE_H -#define OGDF_LINEAR_QUADTREE_H - -#include "FastUtils.h" -#include "FMEFunctional.h" - -#define M2L_MIN_BOUND 8 -#define WSPD_BRANCH_BOUND 16 -#define WSPD_BOUND 25 - -namespace ogdf { - -class LinearQuadtreeBuilder; -class WSPD; - -class LinearQuadtree -{ - friend class LinearQuadtreeBuilder; - friend class LinearQuadtreeBuilderList; -public: - typedef unsigned int NodeID; - typedef unsigned int PointID; - - struct LQPoint // 16 byte - { - MortonNR mortonNr; // 8 byte - __uint32 node; // 4 byte - __uint32 ref; // 4 byte - }; - - struct LQNode // 27 byte - { - __uint32 level; // 4 byte - NodeID next; // 4 byte - NodeID child[4]; // 4 byte *4 = 16 byte - __uint32 numChilds; // 4 byte - PointID firstPoint; // 4 byte - __uint32 numPoints; // 4 byte - bool fence; // 1 byte - }; - - struct LQWSPair - { - LQWSPair(NodeID c, NodeID d) : a(c), b(d) {}; - NodeID a; - NodeID b; - }; - - struct is_fence_condition_functor - { - const LinearQuadtree& tree; - is_fence_condition_functor(const LinearQuadtree& t) : tree(t) { } - inline bool operator()(NodeID u) { return tree.isFence(u); } - }; - - //! creator - inline is_fence_condition_functor is_fence_condition() const { return is_fence_condition_functor(*this); } - - - struct is_leaf_condition_functor - { - const LinearQuadtree& tree; - is_leaf_condition_functor(const LinearQuadtree& t) : tree(t) { } - inline bool operator()(NodeID u) { return tree.isLeaf(u); } - }; - - //! creator - inline is_leaf_condition_functor is_leaf_condition() const { return is_leaf_condition_functor(*this); } - - - //! simple functor for iterating over all nodes - template - struct forall_tree_nodes_functor - { - const LinearQuadtree& tree; - F func; - NodeID begin; - __uint32 numNodes; - - forall_tree_nodes_functor(const LinearQuadtree& t, F f, NodeID b, __uint32 num) : tree(t), func(f), begin(b), numNodes(num) { } - - inline void operator()() - { - NodeID it = begin; - for (__uint32 i=0; i - inline forall_tree_nodes_functor forall_tree_nodes(F f, NodeID begin, __uint32 num) const - { - return forall_tree_nodes_functor(*this, f, begin, num); - } - - //! simple functor for iterating over all children of a node - template - struct forall_children_functor - { - const LinearQuadtree& tree; - F func; - - forall_children_functor(const LinearQuadtree& t, F f) : tree(t), func(f) { } - - inline void operator()(NodeID u) - { - if (tree.isLeaf(u)) return; - for (__uint32 i = 0; i < tree.numberOfChilds(u); i++) func(tree.child(u, i)); - } - }; - - //! creator - template - inline forall_children_functor forall_children(F f) const - { - return forall_children_functor(*this, f); - } - - - //! simple functor for iterating over all points of a node - template - struct forall_points_functor - { - const LinearQuadtree& tree; - Func func; - - forall_points_functor(const LinearQuadtree& t, const Func& f) : tree(t), func(f) { } - - inline void operator()(NodeID u) - { - PointID firstPoint = tree.firstPoint(u); - PointID end = firstPoint + tree.numberOfPoints(u); - for (PointID i = firstPoint; i < end; i++) - func(i); - } - }; - - //! creator - template - inline forall_points_functor forall_points(const Func& func) const - { - return forall_points_functor(*this, func); - } - - //! functor for iterating over all ordered pairs of children of a node - template - struct forall_ordered_pairs_of_children_functor - { - const LinearQuadtree& tree; - F func; - - forall_ordered_pairs_of_children_functor(const LinearQuadtree& t, F f) : tree(t), func(f) { } - - inline void operator()(NodeID u) - { - if (tree.isLeaf(u)) return; - for (__uint32 i = 0; i < tree.numberOfChilds(u); i++) - for (__uint32 j = i+1; j < tree.numberOfChilds(u); j++) - func(tree.child(u, i), tree.child(u, j)); - } - }; - - //! creator - template - inline forall_ordered_pairs_of_children_functor forall_ordered_pairs_of_children(F f) const - { - return forall_ordered_pairs_of_children_functor(*this, f); - } - - //! top down traversal of the subtree of a given node - template - struct top_down_traversal_functor - { - const LinearQuadtree& tree; - F func; - CondType cond; - - top_down_traversal_functor(const LinearQuadtree& t, F f) : tree(t), func(f) { } - top_down_traversal_functor(const LinearQuadtree& t, F f, CondType c) : tree(t), func(f), cond(c) { } - - inline void operator()(NodeID u) - { - if (cond(u)) { func(u); tree.forall_children(*this)(u); }; - } - }; - - //! creator - template - inline top_down_traversal_functor top_down_traversal(F f) const - { - return top_down_traversal_functor(*this, f); - } - - //! creator - template - inline top_down_traversal_functor top_down_traversal(F f, Cond cond) const - { - return top_down_traversal_functor(*this, f, cond); - } - - - //! bottom up traversal of the subtree of a given node - template - struct bottom_up_traversal_functor - { - const LinearQuadtree& tree; - F func; - CondType cond; - - bottom_up_traversal_functor(const LinearQuadtree& t, F f) : tree(t), func(f) { } - bottom_up_traversal_functor(const LinearQuadtree& t, F f, CondType c) : tree(t), func(f), cond(c) { } - - inline void operator()(NodeID u) - { - if (cond(u)) { tree.forall_children(*this)(u); func(u); }; - } - }; - - //! creator - template - inline bottom_up_traversal_functor bottom_up_traversal(F f) const - { - return bottom_up_traversal_functor(*this, f); - } - - //! creator - template - inline bottom_up_traversal_functor bottom_up_traversal(F f, Cond cond) const - { - return bottom_up_traversal_functor(*this, f, cond); - } - - - template - struct wspd_functor - { - const LinearQuadtree& tree; - WSPairFuncType WSFunction; - DPairFuncType DPairFunction; - DNodeFuncType DNodeFunction; - BranchCondType BranchCondFunction; - - wspd_functor(const LinearQuadtree& t, WSPairFuncType& wsf, DPairFuncType& dpf, DNodeFuncType& dnf) : tree(t), WSFunction(wsf), DPairFunction(dpf), DNodeFunction(dnf) { } - - wspd_functor(const LinearQuadtree& t, WSPairFuncType& wsf, DPairFuncType& dpf, DNodeFuncType& dnf, BranchCondType& bc) : tree(t), WSFunction(wsf), DPairFunction(dpf), DNodeFunction(dnf), BranchCondFunction(bc) { } - - inline void operator()(NodeID u) - { - if (BranchCondFunction(u)) - { - if (tree.isLeaf(u) || (tree.numberOfPoints(u) <= WSPD_BOUND)) - { - if (tree.numberOfPoints(u) > 1) - DNodeFunction(u); - } else - { - tree.forall_children(*this)(u); - tree.forall_ordered_pairs_of_children(*this)(u); - } - } - } - - - inline void operator()(NodeID u, NodeID v) - { - if (tree.isWS(u, v)) - { - if ((tree.numberOfPoints(u) < M2L_MIN_BOUND) && (tree.numberOfPoints(v) < M2L_MIN_BOUND)) - DPairFunction(u, v); - else - WSFunction(u, v); - } - else - { - if (((tree.numberOfPoints(u) <= WSPD_BRANCH_BOUND) && (tree.numberOfPoints(v) <= WSPD_BRANCH_BOUND)) || - (tree.isLeaf(u) || tree.isLeaf(v))) - { - DPairFunction(u, v); - } - else - { - if (tree.level(u) >= tree.level(v)) - tree.forall_children(pair_call(*this, v))(u); - else - tree.forall_children(pair_call(*this, u))(v); - } - } - } - }; - - template - inline wspd_functor forall_well_separated_pairs(A a, B b, C c, ConditionType cond) - { - return wspd_functor(*this, a, b, c, cond); - } - - template - inline wspd_functor forall_well_separated_pairs(A a, B b, C c) - { - return wspd_functor(*this, a, b, c); - } - - struct StoreWSPairFunctor - { - LinearQuadtree& tree; - StoreWSPairFunctor(LinearQuadtree& t) : tree(t) { } - inline void operator()(NodeID a, NodeID b) { tree.addWSPD(a, b); } - }; - - StoreWSPairFunctor inline StoreWSPairFunction() { return StoreWSPairFunctor(*this); } - - - struct StoreDirectPairFunctor - { - LinearQuadtree& tree; - StoreDirectPairFunctor(LinearQuadtree& t) : tree(t) { } - inline void operator()(NodeID a, NodeID b) { tree.addDirectPair(a, b); } - }; - - StoreDirectPairFunctor inline StoreDirectPairFunction() { return StoreDirectPairFunctor(*this); } - - - struct StoreDirectNodeFunctor - { - LinearQuadtree& tree; - StoreDirectNodeFunctor(LinearQuadtree& t) : tree(t) { } - inline void operator()(NodeID a) { tree.addDirect(a); } - }; - - StoreDirectNodeFunctor inline StoreDirectNodeFunction() { return StoreDirectNodeFunctor(*this); } - - inline NodeID level(NodeID node) const - { - return m_tree[node].level; - } - - inline NodeID nextNode(NodeID node) const - { - return m_tree[node].next; - } - - inline void setNextNode(NodeID node, NodeID next) - { - m_tree[node].next = next; - } - - inline void setLevel(NodeID node, __uint32 level) - { - m_tree[node].level = level; - } - - inline PointID firstPoint(NodeID node) const - { - return m_tree[node].firstPoint; - } - - inline void setFirstPoint(NodeID node, PointID firstPoint) - { - m_tree[node].firstPoint = firstPoint; - } - - inline LQPoint& point(PointID pointID) - { - return m_points[pointID]; - } - - inline const LQPoint& point(PointID pointID) const - { - return m_points[pointID]; - } - - inline MortonNR mortonNr(PointID point) const - { - return m_points[point].mortonNr; - } - - //! returns the number of children of node node. for an inner node this is 1..4 and - //! can be accessed by child(i). For a leaf the number of points in this leaf is returned - //! starting with point child(0) - inline __uint32 numberOfChilds(NodeID node) const - { - return m_tree[node].numChilds; - } - - //! sets the number of children of a node - inline void setNumberOfChilds(NodeID node, __uint32 numChilds) - { - m_tree[node].numChilds = numChilds; - } - - //! returns the i th child index of node node - inline NodeID child(NodeID node, __uint32 i) const - { - return m_tree[node].child[i]; - } - - //! sets the i-th child index of node node - inline void setChild(NodeID node, __uint32 i, NodeID c) - { - m_tree[node].child[i] = c; - } - - //! returns true if the given node index is a leaf - inline bool isLeaf(NodeID node) const - { - return !m_tree[node].numChilds; - } - - //! sets the fence flag for node - inline bool isFence(NodeID node) const - { - return m_tree[node].fence; - } - - //! returns the number of points contained in the subtree of node - inline __uint32 numberOfPoints(NodeID node) const - { - return m_tree[node].numPoints; - } - - //! sets the number of nodes containted in node - inline void setNumberOfPoints(NodeID node, __uint32 numPoints) - { - m_tree[node].numPoints = numPoints; - } - - //! returns the index of the root - inline NodeID root() const - { - return m_root; - } - - //! returns the number of points in this tree - inline __uint32 numberOfPoints() const - { - return m_numPoints; - } - - //! returns the number of nodes in this tree - inline __uint32 numberOfNodes() const - { - return m_numInnerNodes + m_numLeaves; - } - - //! the upper bound for a compressed quadtree (2*numPoints) - inline __uint32 maxNumberOfNodes() const - { - return m_maxNumNodes; - } - - //! resets the tree - void clear(); - - //! constructor. required tree mem will be allocated - LinearQuadtree(__uint32 n, float* origXPos, float* origYPos, float* origSize); - - //! destructor. tree mem will be released - ~LinearQuadtree(void); - - __uint64 sizeInBytes() const; - - inline NodeID pointLeaf(PointID point) const - { - return m_points[point].node; - } - - inline void setPointLeaf(PointID point, NodeID leaf) - { - m_points[point].node = leaf; - } - - inline float pointX(PointID point) const { return m_pointXPos[point]; } - - inline float pointY(PointID point) const { return m_pointYPos[point]; } - - inline float pointSize(PointID point) const { return m_pointSize[point]; } - - inline float* pointX() const { return m_pointXPos; } - - inline float* pointY() const { return m_pointYPos; } - - inline float* pointSize() const { return m_pointSize; } - - inline float nodeX(NodeID node) const { return m_nodeXPos[node]; } - - inline void setNodeX(NodeID node, float x) { m_nodeXPos[node] = x; } - - inline float nodeY(NodeID node) const { return m_nodeYPos[node]; } - - inline void setNodeY(NodeID node, float y) { m_nodeYPos[node] = y; } - - inline float nodeSize(NodeID node) const { return m_nodeSize[node]; } - - inline void setNodeSize(NodeID node, float size) { m_nodeSize[node] = size; } - - void setPoint(PointID id, float x, float y, __uint32 ref) - { - m_pointXPos[id] = x; - m_pointYPos[id] = y; - m_points[id].ref = ref; - } - - void updatePointPositionSize(PointID id) - { - __uint32 ref = m_points[id].ref; - m_pointXPos[id] = m_origXPos[ref]; - m_pointYPos[id] = m_origYPos[ref]; - m_pointSize[id] = m_origSize[ref]; - } - - void setPoint(PointID id, float x, float y, float r, __uint32 ref) - { - m_pointXPos[id] = x; - m_pointYPos[id] = y; - m_pointSize[id] = r; - m_points[id].ref = ref; - } - - void setPoint(PointID id, float x, float y, float r) - { - m_pointXPos[id] = x; - m_pointYPos[id] = y; - m_pointSize[id] = r; - } - - inline __uint32 refOfPoint(PointID id) const - { - return m_points[id].ref; - } - - inline NodeID nodeOfPoint(PointID id) const - { - return m_points[id].node; - } - - inline void nodeFence(NodeID node) - { - m_tree[node].fence = true; - } - - inline bool isWS(NodeID a, NodeID b) const - { - float s = 0.00000001f; - float dx = nodeX(a) - nodeX(b); - float dy = nodeY(a) - nodeY(b); - float d_sq = dx*dx+dy*dy; - float l = max(nodeSize(a), nodeSize(b)); - return (d_sq >(s*0.5 + 1)*(s*0.5 + 1)* 2 * l * l); - } - - void computeWSPD(); - - void computeWSPD(NodeID n); - - inline NodeID firstInnerNode() const { return m_firstInner; } - - inline __uint32 numberOfInnerNodes() const { return m_numInnerNodes; } - - inline NodeID firstLeaf() const { return m_firstLeaf; } - - inline __uint32 numberOfLeaves() const { return m_numLeaves; } - - - __uint32 numberOfWSP() const { return m_numWSP; } - - __uint32 numberOfDirectPairs() const { return m_numNotWSP; } - - __uint32 numberOfDirectNodes() const { return m_numDirectNodes; } - - inline NodeID directNode(__uint32 i) const { return m_directNodes[i]; } - - inline NodeID directNodeA(__uint32 i) const { return m_notWspd[i].a; } - - inline NodeID directNodeB(__uint32 i) const { return m_notWspd[i].b; } - - - WSPD* wspd() const{ return m_WSPD; }; - - void init(float min_x, float min_y, float max_x, float max_y); - inline float minX() const { return m_min_x; } - inline float minY() const { return m_min_y; } - inline float maxX() const { return m_max_x; } - inline float maxY() const { return m_max_y; } - inline double scaleInv() const { return m_scaleInv; } - - - inline void computeCoords(NodeID nodeIndex) - { - __uint32 ix, iy; - __uint32 level = this->level(nodeIndex); - float s = (float)(m_cellSize * (1 << level)); - this->setNodeSize(nodeIndex, s); - MortonNR mnr = this->mortonNr(this->firstPoint(nodeIndex)); - mnr = mnr >> (level * 2); - mnr = mnr << (level * 2); - mortonNumberInv<__uint64, __uint32>(mnr, ix, iy); - this->setNodeX(nodeIndex, (float)((m_sideLengthPoints*((float)ix)-0.5)/m_sideLengthGrid + (float)m_min_x + (float)s*0.5f)); - this->setNodeY(nodeIndex, (float)((m_sideLengthPoints*((float)iy)-0.5)/m_sideLengthGrid + (float)m_min_y + (float)s*0.5f)); - } - - LQPoint* pointArray() { return m_points; } - - PointID findFirstPointInCell(PointID somePointInCell) const; - -private: - //! helper function for allocating the array's - void allocate(__uint32 n); - - //! helper function for releasing memory - void deallocate(); - - inline void initLeaf(NodeID leaf, PointID firstPoint, __uint32 numPoints, NodeID next) - { - m_tree[leaf].numChilds = 0; - m_tree[leaf].next = next; - m_tree[leaf].fence = 0; - m_tree[leaf].level = 0; - m_tree[leaf].firstPoint = firstPoint; - m_tree[leaf].numPoints = numPoints; - } - - inline void initInnerNode(NodeID node, NodeID leftChild, NodeID rightChild, __uint32 level, NodeID next) - { - m_tree[node].numChilds = 2; - m_tree[node].child[0] = leftChild; - m_tree[node].child[1] = rightChild; - m_tree[node].next = next; - m_tree[node].fence = 0; - m_tree[node].level = level; - m_tree[node].firstPoint = leftChild; - m_tree[node].numPoints = rightChild - leftChild; - } - - //! appends one child index. Assumes childCount < 4 and not leaf - inline void nodeAppendChild(NodeID node, NodeID child) - { - m_tree[node].child[m_tree[node].numChilds++] = child; - m_tree[node].numPoints += m_tree[child].numPoints; - } - - //! appends an successing point by simply increasing childcount of a leaf. Assumes isLeaf - inline void leafAppendPoint(NodeID leaf, PointID point) - { - m_points[point].node = leaf; - m_tree[leaf].numPoints++; - } - - //! adds a well-separated pair to the wspd - void addWSPD(NodeID s, NodeID t); - - //! add a direct pair to the array list of direct pairs - void addDirectPair(NodeID s, NodeID t); - - //! add a direct node to the array list of direct nodes - void addDirect(NodeID s); - - //! the x coordinate of the left most point - float m_min_x; - - //! the y coordinate of the bottom most point - float m_min_y; - - //! the x coordinate of the right most point - float m_max_x; - - //! the y coordinate of the top most point - float m_max_y; - - //! the height and width of a grid cell - double m_cellSize; - - //! the inverse scale to transform - double m_scaleInv; - - //! the maximum of height and width - double m_sideLengthPoints; - - //! the resulting side length of the grid (constant) - double m_sideLengthGrid; - - //! point x coord in graph order - float* m_origXPos; - - //! point y coord in graph order - float* m_origYPos; - - //! point size in graph order - float* m_origSize; - - //! point x coord in tree order - float* m_pointXPos; - - //! point y coord in tree order - float* m_pointYPos; - - //! point size in tree order - float* m_pointSize; - - //! node x coord - float* m_nodeXPos; - - - //! node y coord - float* m_nodeYPos; - - //! node size - float* m_nodeSize; - - //! the main tree array containing all nodes (including leaves) - LQNode* m_tree; - - //! the maximum number of nodes (2*n here instead of 2*n-1) - __uint32 m_maxNumNodes; - - //! the point order in tree order - LQPoint* m_points; - - //! number of points this quadtree is based on - __uint32 m_numPoints; - - __uint32 m_numWSP; - - LQWSPair* m_notWspd; - __uint32 m_numNotWSP; - - NodeID* m_directNodes; - __uint32 m_numDirectNodes; - - //! the wspd of this quadtree - WSPD* m_WSPD; - - //! the root of the tree - NodeID m_root; - - //! first leaf in the leaf chain - NodeID m_firstLeaf; - - //! number of leaves in the chain - __uint32 m_numLeaves; - - //! first inner node in the inner node chain - NodeID m_firstInner; - - //! number of inner nodes in the chain - __uint32 m_numInnerNodes; - -}; - -inline void swap(ogdf::LinearQuadtree::LQPoint& b, ogdf::LinearQuadtree::LQPoint& a) -{ - ogdf::LinearQuadtree::LQPoint t = a; - a = b; - b = t; -} - -inline bool LQPointComparer(const LinearQuadtree::LQPoint& a, const LinearQuadtree::LQPoint& b) -{ - return a.mortonNr < b.mortonNr; -} - -} // end of namespace ogdf - -#endif - diff --git a/ext/OGDF/src/energybased/LinearQuadtreeBuilder.cpp b/ext/OGDF/src/energybased/LinearQuadtreeBuilder.cpp deleted file mode 100644 index 071af17ac..000000000 --- a/ext/OGDF/src/energybased/LinearQuadtreeBuilder.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class LinearQuadtreeBuilder. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "LinearQuadtree.h" -#include "LinearQuadtreeBuilder.h" - -namespace ogdf { - -void LinearQuadtreeBuilder::prepareNodeAndLeaf(LinearQuadtree::PointID leafPos, LinearQuadtree::PointID nextLeafPos) -{ - numLeaves++; - // first init the leaf on its layer - tree.initLeaf(leafPos, leafPos, nextLeafPos-leafPos, nextLeafPos); - // second the node on the inner node layer - tree.initInnerNode(leafPos + n, leafPos, nextLeafPos, CAL(leafPos, nextLeafPos), nextLeafPos + n); - - lastInner = leafPos + n; - lastLeaf = leafPos; -} - - -void LinearQuadtreeBuilder::prepareTree(LinearQuadtree::PointID begin, LinearQuadtree::PointID end) -{ - LinearQuadtree::PointID i = begin; - firstLeaf = begin; - firstInner = firstLeaf+n; - numLeaves = 0; - numInnerNodes = 0; - while (i tree.level(curr_next) - { - LinearQuadtree::NodeID right_node = buildHierarchy(curr_next, tree.level(curr)); - tree.setChild(curr, tree.numberOfChilds(curr)-1, right_node); - tree.setNextNode(curr, tree.nextNode(right_node)); - } - } - //pushBackChain(curr); - return curr; -} - - -void LinearQuadtreeBuilder::buildHierarchy() -{ - tree.clear(); - restoreChainLastNode = 0; - tree.m_root = buildHierarchy(n, 128); -} - - -void LinearQuadtreeBuilder::build() -{ - numInnerNodes = 0; - buildHierarchy(); - restoreChain();; - - tree.m_firstInner = firstInner; - tree.m_numInnerNodes = numInnerNodes; - tree.m_firstLeaf = firstLeaf; - tree.m_numLeaves = numLeaves; -} - -} // end of namespace diff --git a/ext/OGDF/src/energybased/LinearQuadtreeBuilder.h b/ext/OGDF/src/energybased/LinearQuadtreeBuilder.h deleted file mode 100644 index e88526c02..000000000 --- a/ext/OGDF/src/energybased/LinearQuadtreeBuilder.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class LinearQuadtreeBuilder. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_LINEAR_QUADTREE__BUILDER_H -#define OGDF_LINEAR_QUADTREE__BUILDER_H - -#include "FastUtils.h" -#include "LinearQuadtree.h" - -namespace ogdf { - -//! the builder for the LinearQuadtree -class LinearQuadtreeBuilder -{ -public: - //! constructor - LinearQuadtreeBuilder(LinearQuadtree& treeRef) : tree(treeRef) { n = tree.numberOfPoints(); } - - //! the main build call - void build(); - - //! prepares the node and leaf layer at position l where r is the next position - void prepareNodeAndLeaf(LinearQuadtree::PointID l, LinearQuadtree::PointID r); - - //! prepares the node and leaf layer from position begin until end (excluding end) - void prepareTree(LinearQuadtree::PointID begin, LinearQuadtree::PointID end); - - //! prepares the node and leaf layer for the complete tree from 0 to n (excluding n) - void prepareTree(); - - //! merges the node curr with curr's next node by appending the next nodes children to curr except the first one. - void mergeWithNext(LinearQuadtree::NodeID curr); - - //! the new link-only recursive builder - LinearQuadtree::NodeID buildHierarchy(LinearQuadtree::NodeID curr, __uint32 maxLevel); - - //! the main function for the new link-only recursive builder - void buildHierarchy(); - - //! used by restore chain - inline void restorePushBackChain(LinearQuadtree::NodeID curr) - { - if (restoreChainLastNode) tree.setNextNode(restoreChainLastNode, curr); else firstInner = curr; - restoreChainLastNode = curr; - numInnerNodes++; - } - - inline void restoreChain(LinearQuadtree::NodeID curr) - { - if (tree.isLeaf(curr)) - return; - else - { - restoreChain(tree.child(curr,0)); - tree.setFirstPoint(curr, tree.firstPoint(tree.child(curr, 0))); - restorePushBackChain(curr); - for (__uint32 i = 1; i < tree.numberOfChilds(curr); i++) - restoreChain(tree.child(curr, i)); - - __uint32 lastPoint = tree.firstPoint(tree.child(curr, tree.numberOfChilds(curr)-1)) + tree.numberOfPoints(tree.child(curr, tree.numberOfChilds(curr)-1)); - tree.setNumberOfPoints(curr, lastPoint - tree.firstPoint(curr)); - } - } - - inline void restoreChain() - { - restoreChainLastNode = 0; - numInnerNodes = 0; - if (!tree.isLeaf(tree.root())) - restoreChain(tree.root()); - if (restoreChainLastNode) - tree.setNextNode(restoreChainLastNode, 0); - } - - //! returns the level of the first common ancestor of a and b - inline __uint32 CAL(LinearQuadtree::PointID a, LinearQuadtree::PointID b) - { - // 64 bit version - //if (a<0) return 64; // FIXME: a < 0 is always true (PointID is unsigned int) - if (b>=tree.numberOfPoints()) return 64; - __uint32 res = (32-((mostSignificantBit(tree.mortonNr(a) ^ tree.mortonNr(b)))/2)); - return res; - } - - LinearQuadtree::NodeID firstInner; - LinearQuadtree::NodeID firstLeaf; - - LinearQuadtree::NodeID lastInner; - LinearQuadtree::NodeID lastLeaf; - __uint32 numInnerNodes; - __uint32 numLeaves; - - LinearQuadtree& tree; - LinearQuadtree::NodeID restoreChainLastNode; - LinearQuadtree::PointID n; -}; - -} // end of namespace ogdf - -#endif - - diff --git a/ext/OGDF/src/energybased/LinearQuadtreeExpansion.cpp b/ext/OGDF/src/energybased/LinearQuadtreeExpansion.cpp deleted file mode 100644 index 84f894f20..000000000 --- a/ext/OGDF/src/energybased/LinearQuadtreeExpansion.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class LinearQuadtreeExpansion. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "LinearQuadtreeExpansion.h" -#include "ComplexDouble.h" -#include "WSPD.h" -#include - -using namespace ogdf::sse; - -namespace ogdf { - -LinearQuadtreeExpansion::LinearQuadtreeExpansion(__uint32 precision, const LinearQuadtree& tree) : m_tree(tree), m_numCoeff(precision), binCoef(2*m_numCoeff) -{ - m_numExp = m_tree.maxNumberOfNodes(); - allocate(); -} - - -LinearQuadtreeExpansion::~LinearQuadtreeExpansion(void) -{ - deallocate(); -} - - -void LinearQuadtreeExpansion::allocate() -{ - m_multiExp = (double*)MALLOC_16(m_numCoeff*sizeof(double)*2*m_numExp); - m_localExp = (double*)MALLOC_16(m_numCoeff*sizeof(double)*2*m_numExp); -} - - -void LinearQuadtreeExpansion::deallocate() -{ - FREE_16(m_multiExp); - FREE_16(m_localExp); -} - - -void LinearQuadtreeExpansion::P2M(__uint32 point, __uint32 receiver) -{ - double* receiv_coeff = m_multiExp + receiver*(m_numCoeff<<1); - const double q = (double)m_tree.pointSize(point); - const double x = (double)m_tree.pointX(point); - const double y = (double)m_tree.pointY(point); - const double centerX = (double)m_tree.nodeX(receiver); - const double centerY = (double)m_tree.nodeY(receiver); - // a0 += q_i - receiv_coeff[0] += q; - // a_1..m - ComplexDouble ak; - // p - z0 - ComplexDouble delta(ComplexDouble(x, y) - ComplexDouble(centerX, centerY)); - // (p - z0)^k - ComplexDouble delta_k(delta); - for (__uint32 k=1; k sdelta(m_center[(receiver<<1)] - m_center[(source<<1)], m_center[(receiver<<1)+1] - m_center[(source<<1) +1]);//, m_x[receiver] - m_x[source], m_y[receiver] - m_y[source]); - /*std::complex sdelta(center_x_receiver - center_x_source, - center_y_receiver - center_y_source);//, m_x[receiver] - m_x[source], m_y[receiver] - m_y[source]); - - if ((sdelta.real() <=0) && (sdelta.imag() == 0)) //no cont. compl. log fct exists !!! - sdelta = log(sdelta + 0.00000001); - else - sdelta = log(sdelta); - - */ - double r = delta1.length();//= sqrt(sdelta.real()*sdelta.real()+sdelta.imag()*sdelta.imag()); - double phi = atan((center_x_receiver - center_x_source)/(center_y_receiver - center_y_source)); - // sum = a0*log(z1 - z0) - b += a0*ComplexDouble(log(r), phi); - // (z1 - z0)^1 - //b += a0*ComplexDouble(sdelta.real(), sdelta.imag()); - delta1_l = delta1; - for (__uint32 k=1;k - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_LINEAR_QUADTREE_EXPANSION_H -#define OGDF_LINEAR_QUADTREE_EXPANSION_H - -#include "LinearQuadtree.h" - -namespace ogdf { - -class LinearQuadtreeExpansion -{ -public: - //! constructor - LinearQuadtreeExpansion(__uint32 precision, const LinearQuadtree& tree); - - //! destructor - ~LinearQuadtreeExpansion(void); - - //! adds a point with the given charge to the receiver expansion - void P2M(__uint32 point, __uint32 receiver); - - //! shifts the source multipole coefficient to the center of the receiver and adds them - void M2M(__uint32 source, __uint32 receiver); - - //! converts the source multipole coefficient in to a local coefficients at the center of the receiver and adds them - void M2L(__uint32 source, __uint32 receiver); - - //! shifts the source local coefficient to the center of the receiver and adds them - void L2L(__uint32 source, __uint32 receiver); - - //! evaluates the derivate of the local expansion at the point and adds the forces to fx fy - void L2P(__uint32 source, __uint32 point, float& fx, float& fy); - - //! returns the size in bytes - __uint32 sizeInBytes() const { return m_numExp*m_numCoeff*sizeof(double)*4; } - - //! returns the array with multipole coefficients - inline double* multiExp() const { return m_multiExp; } - - //! returns the array with local coefficients - inline double* localExp() const { return m_localExp; } - - //! number of coefficients per expansions - inline __uint32 numCoeff() const { return m_numCoeff; } - - //! the quadtree - const LinearQuadtree& tree() { return m_tree; } -private: - - //! allocates the space for the coeffs - void allocate(); - - //! releases the memory for the coeffs - void deallocate(); - - //! the Quadtree reference - const LinearQuadtree& m_tree; -public: - //! the big multipole expansione coeff array - double* m_multiExp; - - //! the big local expansion coeff array - double* m_localExp; - -public: - //! the number of multipole (locale) expansions - __uint32 m_numExp; - - //! the number of coeff per expansions - __uint32 m_numCoeff; - - BinCoeff binCoef; -}; - - -} // end of namespace ogdf - -#endif diff --git a/ext/OGDF/src/energybased/MAARPacking.cpp b/ext/OGDF/src/energybased/MAARPacking.cpp deleted file mode 100644 index 5e36c712d..000000000 --- a/ext/OGDF/src/energybased/MAARPacking.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class MAARPacking (used by FMMMLayout). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "MAARPacking.h" -#include "numexcept.h" -#include - -namespace ogdf { - -MAARPacking::MAARPacking() -{ - area_width = 0; - area_height = 0; -} - - -MAARPacking::~MAARPacking() { } - - -void MAARPacking::pack_rectangles_using_Best_Fit_strategy( - List& R, - double aspect_ratio, - int presort, - int allow_tipping_over, - double& aspect_ratio_area, - double& bounding_rectangles_area) -{ - Rectangle r; - double area; - ListIterator B_F_item; - ListIterator rect_item; - List P; //represents the packing of the rectangles - List > row_of_rectangle; //stores for each rectangle - //r at pos. i in R the ListIterator of the row in P - //where r is placed (at pos i in row_of_rectangle) - List > rectangle_order;//holds the order in which the - //rectangles are touched - PQueue total_width_of_row; //stores for each row the ListIterator of the corresp. list - //in R and its total width - - if(presort == FMMMLayout::psDecreasingHeight) - presort_rectangles_by_height(R); - else if (presort == FMMMLayout::psDecreasingWidth) - presort_rectangles_by_width(R); - - //init rectangle_order - for(rect_item = R.begin(); rect_item.valid(); ++rect_item) - rectangle_order.pushBack(rect_item); - - for(rect_item = R.begin(); rect_item.valid(); ++rect_item) - { - if (P.empty()) - { - r = *rect_item; - if(better_tipp_rectangle_in_new_row(r,aspect_ratio,allow_tipping_over,area)) - r = tipp_over(rect_item); - B_F_insert_rectangle_in_new_row(r,P,row_of_rectangle,total_width_of_row); - aspect_ratio_area = calculate_aspect_ratio_area(r.get_width(),r.get_height(), - aspect_ratio); - } - else - { - B_F_item = find_Best_Fit_insert_position(rect_item,allow_tipping_over, - aspect_ratio,aspect_ratio_area, - total_width_of_row); - - r = *rect_item; - B_F_insert_rectangle(r,P,row_of_rectangle,B_F_item,total_width_of_row); - } - } - export_new_rectangle_positions(P,row_of_rectangle,rectangle_order); - bounding_rectangles_area = calculate_bounding_rectangles_area(R); -} - - -inline void MAARPacking::presort_rectangles_by_height(List& R) -{ - RectangleComparerHeight comp_height; - R.quicksort(comp_height); -} - - -inline void MAARPacking::presort_rectangles_by_width(List& R) -{ - RectangleComparerWidth comp_width; - R.quicksort(comp_width); -} - - -void MAARPacking::B_F_insert_rectangle_in_new_row( - Rectangle r, - List& P, - List >&row_of_rectangle, - PQueue& total_width_of_row) -{ - PackingRowInfo p; - - //create new empty row and insert r into this row of P - p.set_max_height(r.get_height()); - p.set_total_width(r.get_width()); - p.set_row_index(P.size()); - P.pushBack(p); - - //remember in which row of P r is placed by updating row_of_rectangle - row_of_rectangle.pushBack(P.rbegin()); - - //update area_height,area_width - area_width = max(r.get_width(),area_width); - area_height += r.get_height(); - - - //update total_width_of_row - total_width_of_row.insert(r.get_width(),P.rbegin()); -} - - -ListIterator MAARPacking::find_Best_Fit_insert_position( - ListIterator rect_item, - int allow_tipping_over, - double aspect_ratio, - double& aspect_ratio_area, - PQueue& total_width_of_row) -{ - numexcept N; - double area_2; - int best_try_index,index_2; - Rectangle r = *rect_item; - - if(better_tipp_rectangle_in_new_row(r,aspect_ratio,allow_tipping_over, - aspect_ratio_area)) - best_try_index = 2; - else - best_try_index = 1; - - ListIterator B_F_item = total_width_of_row.find_min(); - PackingRowInfo B_F_row = *B_F_item; - if(better_tipp_rectangle_in_this_row(r,aspect_ratio,allow_tipping_over,B_F_row,area_2)) - index_2 = 4; - else - index_2 = 3; - - if((area_2 <= aspect_ratio_area) || N.nearly_equal(aspect_ratio_area,area_2)) - { - aspect_ratio_area = area_2; - best_try_index = index_2; - } - - //return the row and eventually tipp the rectangle with ListIterator rect_item - if(best_try_index == 1) - return NULL; - else if(best_try_index == 2) - { - tipp_over(rect_item); - return NULL; - } - else if(best_try_index == 3) - return B_F_item; - else //best_try_index == 4 - { - tipp_over(rect_item); - return B_F_item; - } -} - - -void MAARPacking::B_F_insert_rectangle( - Rectangle r, - List& P, - List >&row_of_rectangle, - ListIterator B_F_item, - PQueue& total_width_of_row) -{ - ListIterator null = NULL; - if (B_F_item == null) //insert into a new row - B_F_insert_rectangle_in_new_row(r,P,row_of_rectangle,total_width_of_row); - else //insert into an existing row - { - double old_max_height; - - //update P[B_F_item] - PackingRowInfo p = *B_F_item; - old_max_height = p.get_max_height(); - p.set_max_height(max(old_max_height,r.get_height())); - p.set_total_width(p.get_total_width()+r.get_width()); - *B_F_item = p; - - //updating row_of_rectangle - row_of_rectangle.pushBack(B_F_item); - - //update area_height,area_width - area_width = max(area_width,p.get_total_width()); - area_height = max(area_height,area_height-old_max_height+r.get_height()); - - //update total_width_of_row - - total_width_of_row.del_min(); - total_width_of_row.insert(p.get_total_width(),B_F_item); - - } -} - - - -void MAARPacking::export_new_rectangle_positions( - List& P, - List >& row_of_rectangle, - List >& rectangle_order) -{ - int i; - Rectangle r; - PackingRowInfo p,p_pred; - DPoint new_dlc_pos; - double new_x,new_y; - Array row_y_min (P.size()); //stores the min. y-coordinates for each row in P - Array act_row_x_max (P.size()); //stores the actual rightmost x-coordinate - //for each row in P - //ListIterator< ListIterator > row_item; - ListIterator row_item; - ListIterator R_item; - ListIterator > RR_item; - ListIterator > Rrow_item; - - //init act_row_x_max; - for(i = 0; i& R) -{ - double area = 0; - Rectangle r; - - forall_listiterators(Rectangle,r_it,R) - area += (*r_it).get_width() * (*r_it).get_height(); - - return area; -} - - -inline double MAARPacking::calculate_aspect_ratio_area( - double width, - double height, - double aspect_ratio) -{ - double ratio = width/height; - - if(ratio < aspect_ratio) //scale width - return ( width * height * (aspect_ratio/ratio)); - else //scale height - return ( width * height * (ratio/aspect_ratio)); -} - - -bool MAARPacking::better_tipp_rectangle_in_new_row( - Rectangle r, - double aspect_ratio, - int allow_tipping_over, - double& best_area) -{ - double height,width,act_area; - bool rotate = false; - - //first try: new row insert position - width = max(area_width,r.get_width()); - height = area_height + r.get_height(); - best_area = calculate_aspect_ratio_area(width,height,aspect_ratio); - - - //second try: new row insert position with tipping r over - if(allow_tipping_over == FMMMLayout::toNoGrowingRow || - allow_tipping_over == FMMMLayout::toAlways) - { - width = max(area_width,r.get_height()); - height = area_height + r.get_width(); - act_area = calculate_aspect_ratio_area(width,height,aspect_ratio); - if(act_area < 0.99999 * best_area) - { - best_area = act_area; - rotate = true; - } - } - return rotate; -} - - -bool MAARPacking::better_tipp_rectangle_in_this_row( - Rectangle r, - double aspect_ratio, - int allow_tipping_over, - PackingRowInfo B_F_row, - double& best_area) -{ - double height,width,act_area; - bool rotate = false; - - //first try: BEST_FIT insert position - width = max(area_width,B_F_row.get_total_width()+r.get_width()); - height = max(area_height, area_height-B_F_row.get_max_height()+r.get_height()); - best_area = calculate_aspect_ratio_area(width,height,aspect_ratio); - - //second try: BEST_FIT insert position with skipping r over - if((allow_tipping_over == FMMMLayout::toNoGrowingRow && r.get_width() - <= B_F_row.get_max_height()) || allow_tipping_over == FMMMLayout::toAlways) - { - width = max(area_width,B_F_row.get_total_width()+r.get_height()); - height = max(area_height, area_height-B_F_row.get_max_height()+r.get_width()); - act_area = calculate_aspect_ratio_area(width,height,aspect_ratio); - if(act_area < 0.99999 * best_area) - { - best_area = act_area; - rotate = true; - } - } - return rotate; -} - - -inline Rectangle MAARPacking::tipp_over(ListIterator rect_item) -{ - Rectangle r = *rect_item; - Rectangle r_tipped_over = r; - DPoint tipped_dlc; - - if(r.is_tipped_over() == false) - {//tipp old_dlc over - tipped_dlc.m_x = r.get_old_dlc_position().m_y*(-1)-r.get_height(); - tipped_dlc.m_y = r.get_old_dlc_position().m_x; - } - else - {//tipp old_dlc back; - tipped_dlc.m_x = r.get_old_dlc_position().m_y; - tipped_dlc.m_y = r.get_old_dlc_position().m_x*(-1)-r.get_width(); - } - r_tipped_over.set_old_dlc_position(tipped_dlc); - r_tipped_over.set_width(r.get_height()); - r_tipped_over.set_height(r.get_width()); - r_tipped_over.tipp_over(); - *rect_item = r_tipped_over; - - return r_tipped_over; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/MAARPacking.h b/ext/OGDF/src/energybased/MAARPacking.h deleted file mode 100644 index d3eea6ee4..000000000 --- a/ext/OGDF/src/energybased/MAARPacking.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class MAARPacking (used by FMMMLayout). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MAAR_PACKING_H -#define OGDF_MAAR_PACKING_H - -#include "PackingRowInfo.h" -#include "Rectangle.h" -#include "Set.h" -#include -#include "PQueue.h" - -namespace ogdf { - - class MAARPacking - { - //data structure for packing rectangles within an area of a desired aspect ratio - //without overlappings; optimization goal: to minimize the used aspect ratio area - - public: - - MAARPacking(); //constructor - ~MAARPacking(); //destructor - - //The rectangles in R are packed using the First Fit tiling stratey (precisely the - //new down left corner coordinate of each rectangle is calculated and stored in R). - //The aspect ratio area and the area of the bounding rectangles are calculated, - //too. - void pack_rectangles_using_Best_Fit_strategy(List& R,double - aspect_ratio, int presort, int - allow_tipping_over,double& - aspect_ratio_area,double& - bounding_rectangles_area); - - private: - - - double area_height; //total height of the packing area - double area_width; //total width of the packing area - - - //Sorts elemets of R with momotonously dedreasing height. - void presort_rectangles_by_height(List& R); - - //Sorts elemets of R with momotonously decreasing width. - void presort_rectangles_by_width(List& R); - - //Creates a new empty row in P and inserts r into this row (by updating P, - //row_of_rectangle and total_width_of_row). - void B_F_insert_rectangle_in_new_row(Rectangle r,List& P, List - >& - row_of_rectangle, PQueue& - total_width_of_row); - - - //Finds the Best Fit insert positions of *rect_item and returns the - //corresp. ListIterator in P or NULL (indicating that a new row has - //to be created in P); aspect_ratio_area stores the used aspect ratio area of - //the drawing. - ListIterator find_Best_Fit_insert_position( - ListIterator rect_item, - int allow_tipping_over, - double aspect_ratio, - double& aspect_ratio_area, - PQueue& total_width_of_row); - - - //Inserts r into the row with corresponding ListIterator B_F_item and updates - //total_width_of_row. - void B_F_insert_rectangle(Rectangle r,List& P,List - >& row_of_rectangle,ListIterator - B_F_item, PQueue& total_width_of_row); - - - //The information in P and row_of_rectangle are used to generate the new down left - //coordinates of the rectangles in R (rectangle_order holds the order in which - //the rectangles of R have to be processed. - void export_new_rectangle_positions(List& P,List >& - row_of_rectangle,List >& rectangle_order); - - //Returns the area of the bounding rectangles in R. - double calculate_bounding_rectangles_area(List&R); - - //Calculate the aspect ratio area of a rectangle with width w and height h and the - //given aspect ratio r. - double calculate_aspect_ratio_area(double w,double h,double r); - - //Returns true if the aspect_ratio_area of the acual packing becomes better, when - //tipping r over bevore inserting it into the new row. best_area holds the aspect - //ratio area of the best of the two insertion alternatives. - bool better_tipp_rectangle_in_new_row(Rectangle r,double aspect_ratio, int - allow_tipping_over,double& best_area); - - //Returns true if the aspect_ratio_area of the acual packing becomes better, when - //tipping r over bevore inserting it into the existing row B_F_row. best_area holds - //the aspect ratio area of the best of the two insertion alternatives. - bool better_tipp_rectangle_in_this_row(Rectangle r,double aspect_ratio,int - allow_tipping_over,PackingRowInfo B_F_row, - double& best_area); - - //Tipps *rect_item over, by newly calculatting its width, height, and old_dlc - //values (Coordinates of the underlying connected subgraph are not recaculated - //here!!!). The new values are saved in R[rect_item] and are returned. - Rectangle tipp_over(ListIterator rect_item); - - }; - -}//namespace ogdf -#endif - - diff --git a/ext/OGDF/src/energybased/Multilevel.cpp b/ext/OGDF/src/energybased/Multilevel.cpp deleted file mode 100644 index d02424ead..000000000 --- a/ext/OGDF/src/energybased/Multilevel.cpp +++ /dev/null @@ -1,885 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class Multlevel (used by FMMMLayout). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "Multilevel.h" -#include "Set.h" -#include "Node.h" -#include -#include -#include -#include - - -namespace ogdf { - -void Multilevel::create_multilevel_representations( - Graph& G, - NodeArray& A, - EdgeArray& E, - int rand_seed, - int galaxy_choice, - int min_Graph_size, - int random_tries, - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int & max_level) -{ - //make initialisations; - srand(rand_seed); - G_mult_ptr[0] = &G; //init graph at level 0 to the original undirected simple - A_mult_ptr[0] = &A; //and loopfree connected graph G/A/E - E_mult_ptr[0] = &E; - - int bad_edgenr_counter = 0; - int act_level = 0; - Graph* act_Graph_ptr = G_mult_ptr[0]; - - while( (act_Graph_ptr->numberOfNodes() > min_Graph_size) && - edgenumbersum_of_all_levels_is_linear(G_mult_ptr,act_level,bad_edgenr_counter) ) - { - Graph* G_new = new (Graph); - NodeArray* A_new = OGDF_NEW NodeArray; - EdgeArray* E_new = OGDF_NEW EdgeArray; - G_mult_ptr[act_level+1] = G_new; - A_mult_ptr[act_level+1] = A_new; - E_mult_ptr[act_level+1] = E_new; - - init_multilevel_values(G_mult_ptr,A_mult_ptr,E_mult_ptr,act_level); - partition_galaxy_into_solar_systems(G_mult_ptr,A_mult_ptr,E_mult_ptr,rand_seed, - galaxy_choice,random_tries,act_level); - collaps_solar_systems(G_mult_ptr,A_mult_ptr,E_mult_ptr,act_level); - - act_level++; - act_Graph_ptr = G_mult_ptr[act_level]; - } - max_level = act_level; -} - - -bool Multilevel::edgenumbersum_of_all_levels_is_linear( - Array &G_mult_ptr, - int act_level, - int& bad_edgenr_counter) -{ - if(act_level == 0) - return true; - else - { - if(G_mult_ptr[act_level]->numberOfEdges()<= - 0.8 * double (G_mult_ptr[act_level-1]->numberOfEdges())) - return true; - else if(bad_edgenr_counter < 5) - { - bad_edgenr_counter++; - return true; - } - else - return false; - } -} - - -inline void Multilevel::init_multilevel_values( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int level) -{ - node v; - forall_nodes(v,*G_mult_ptr[level]) - (*A_mult_ptr[level])[v].init_mult_values(); - - edge e; - forall_edges(e,*G_mult_ptr[level]) - (*E_mult_ptr[level])[e].init_mult_values(); -} - - -inline void Multilevel::partition_galaxy_into_solar_systems( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int rand_seed, - int galaxy_choice, - int random_tries, - int act_level) -{ - create_suns_and_planets(G_mult_ptr, A_mult_ptr, E_mult_ptr, rand_seed, galaxy_choice, - random_tries, act_level); - create_moon_nodes_and_pm_nodes(G_mult_ptr, A_mult_ptr, E_mult_ptr, act_level); -} - - -void Multilevel::create_suns_and_planets( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int rand_seed, - int galaxy_choice, - int random_tries, - int act_level) -{ - Set Node_Set; - node v, sun_node, planet_node, newNode, pos_moon_node; - edge sun_edge, e; - double dist_to_sun; - List planet_nodes; - List sun_nodes; - - //make initialisations - sun_nodes.clear(); - Node_Set.set_seed(rand_seed); //set seed for random number generator - forall_nodes(v,*G_mult_ptr[act_level]) - if(act_level == 0) (*A_mult_ptr[act_level])[v].set_mass(1); - if(galaxy_choice == FMMMLayout::gcUniformProb) - Node_Set.init_node_set(*G_mult_ptr[act_level]); - else //galaxy_choice != gcUniformProb in FMMMLayout - Node_Set.init_node_set(*G_mult_ptr[act_level],*A_mult_ptr[act_level]); - - - while (!Node_Set.empty_node_set()) - {//while - //randomly select a sun node - planet_nodes.clear(); - if(galaxy_choice == FMMMLayout::gcUniformProb) - sun_node = Node_Set.get_random_node(); - else if (galaxy_choice == FMMMLayout::gcNonUniformProbLowerMass) - sun_node = Node_Set.get_random_node_with_lowest_star_mass(random_tries); - else //galaxy_choice == FMMMLayout::gcNonUniformProbHigherMass - sun_node = Node_Set.get_random_node_with_highest_star_mass(random_tries); - sun_nodes.pushBack(sun_node); - - //create new node at higher level that represents the collapsed solar_system - newNode = G_mult_ptr[act_level+1]->newNode(); - - //update information for sun_node - (*A_mult_ptr[act_level])[sun_node].set_higher_level_node(newNode); - (*A_mult_ptr[act_level])[sun_node].set_type(1); - (*A_mult_ptr[act_level])[sun_node].set_dedicated_sun_node(sun_node); - (*A_mult_ptr[act_level])[sun_node].set_dedicated_sun_distance(0); - - //update information for planet_nodes - forall_adj_edges(sun_edge,sun_node) - { - dist_to_sun = (*E_mult_ptr[act_level])[sun_edge].get_length(); - if (sun_edge->source() != sun_node) - planet_node = sun_edge->source(); - else - planet_node = sun_edge->target(); - (*A_mult_ptr[act_level])[planet_node].set_type(2); - (*A_mult_ptr[act_level])[planet_node].set_dedicated_sun_node(sun_node); - (*A_mult_ptr[act_level])[planet_node].set_dedicated_sun_distance(dist_to_sun); - planet_nodes.pushBack(planet_node); - } - - //delete all planet_nodes and possible_moon_nodes from Node_Set - - ListConstIterator planet_node_ptr; - //forall_listiterators(node,planet_node_ptr,planet_nodes) - for(planet_node_ptr = planet_nodes.begin(); planet_node_ptr.valid(); ++planet_node_ptr) - if(!Node_Set.is_deleted(*planet_node_ptr)) - Node_Set.delete_node(*planet_node_ptr); - - for(planet_node_ptr = planet_nodes.begin(); planet_node_ptr.valid(); ++planet_node_ptr) - //forall_listiterators(node,planet_node_ptr,planet_nodes) - { - forall_adj_edges(e,*planet_node_ptr) - { - if(e->source() == *planet_node_ptr) - pos_moon_node = e->target(); - else - pos_moon_node = e->source(); - if(!Node_Set.is_deleted(pos_moon_node)) - Node_Set.delete_node(pos_moon_node); - } - } - }//while - - //init *A_mult_ptr[act_level+1] and set NodeAttributes information for new nodes - A_mult_ptr[act_level+1]->init(*G_mult_ptr[act_level+1]); - forall_listiterators(node, sun_node_ptr, sun_nodes) - { - newNode = (*A_mult_ptr[act_level])[*sun_node_ptr].get_higher_level_node(); - (*A_mult_ptr[act_level+1])[newNode].set_NodeAttributes((*A_mult_ptr[act_level]) - [*sun_node_ptr].get_width(), - (*A_mult_ptr[act_level]) - [*sun_node_ptr].get_height(), - (*A_mult_ptr[act_level]) - [*sun_node_ptr].get_position(), - *sun_node_ptr,NULL); - (*A_mult_ptr[act_level+1])[newNode].set_mass(0); - } -} - - -void Multilevel::create_moon_nodes_and_pm_nodes( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int act_level) -{ - edge e; - node v, nearest_neighbour_node, neighbour_node, dedicated_sun_node; - double dist_to_nearest_neighbour, dedicated_sun_distance; - bool first_adj_edge; - int neighbour_type; - edge moon_edge; - - forall_nodes(v,*G_mult_ptr[act_level]) - if((*A_mult_ptr[act_level])[v].get_type() == 0) //a moon node - {//forall - //find nearest neighbour node - first_adj_edge = true; - forall_adj_edges(e,v) - {//forall2 - if(v == e->source()) - neighbour_node = e->target(); - else - neighbour_node = e->source(); - neighbour_type = (*A_mult_ptr[act_level])[neighbour_node].get_type(); - if( (neighbour_type == 2) || (neighbour_type == 3) ) - {//if_1 - if(first_adj_edge) - {//if - first_adj_edge = false; - moon_edge = e; - dist_to_nearest_neighbour = (*E_mult_ptr[act_level])[e].get_length(); - nearest_neighbour_node = neighbour_node; - }//if - else if(dist_to_nearest_neighbour >(*E_mult_ptr[act_level])[e].get_length()) - {//else - moon_edge = e; - dist_to_nearest_neighbour = (*E_mult_ptr[act_level])[e].get_length(); - nearest_neighbour_node = neighbour_node; - }//else - }//if_1 - }//forall2 - //find dedic. solar system for v and update information in *A_mult_ptr[act_level] - //and *E_mult_ptr[act_level] - - (*E_mult_ptr[act_level])[moon_edge].make_moon_edge(); //mark this edge - dedicated_sun_node = (*A_mult_ptr[act_level])[nearest_neighbour_node]. - get_dedicated_sun_node(); - dedicated_sun_distance = dist_to_nearest_neighbour + (*A_mult_ptr[act_level]) - [nearest_neighbour_node].get_dedicated_sun_distance(); - (*A_mult_ptr[act_level])[v].set_type(4); - (*A_mult_ptr[act_level])[v].set_dedicated_sun_node(dedicated_sun_node); - (*A_mult_ptr[act_level])[v].set_dedicated_sun_distance(dedicated_sun_distance); - (*A_mult_ptr[act_level])[v].set_dedicated_pm_node(nearest_neighbour_node); - - //identify nearest_neighbour_node as a pm_node and update its information - - (*A_mult_ptr[act_level])[nearest_neighbour_node].set_type(3); - (*A_mult_ptr[act_level])[nearest_neighbour_node]. - get_dedicated_moon_node_List_ptr()->pushBack(v); - }//forall -} - - -inline void Multilevel::collaps_solar_systems( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int act_level) -{ - EdgeArray new_edgelength; - calculate_mass_of_collapsed_nodes(G_mult_ptr, A_mult_ptr, act_level); - create_edges_edgedistances_and_lambda_Lists(G_mult_ptr, A_mult_ptr, E_mult_ptr, - new_edgelength, act_level); - delete_parallel_edges_and_update_edgelength(G_mult_ptr, E_mult_ptr, new_edgelength, - act_level); -} - - -inline void Multilevel::calculate_mass_of_collapsed_nodes( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - int act_level) -{ - node v; - node dedicated_sun,high_level_node; - - forall_nodes(v,*G_mult_ptr[act_level]) - { - dedicated_sun = (*A_mult_ptr[act_level])[v].get_dedicated_sun_node(); - high_level_node = (*A_mult_ptr[act_level])[dedicated_sun].get_higher_level_node(); - (*A_mult_ptr[act_level+1])[high_level_node].set_mass((*A_mult_ptr[act_level+1]) - [high_level_node].get_mass()+1); - } -} - - -void Multilevel::create_edges_edgedistances_and_lambda_Lists( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - EdgeArray& new_edgelength,int - act_level) -{ - edge e, e_new; - node s_node, t_node; - node s_sun_node, t_sun_node; - node high_level_sun_s, high_level_sun_t; - double length_e, length_s_edge, length_t_edge, newlength; - double lambda_s, lambda_t; - List inter_solar_system_edges; - - //create new edges at act_level+1 and create for each inter solar system edge at - //act_level a link to its corresponding edge - - forall_edges(e,*G_mult_ptr[act_level]) - {//forall - s_node = e->source(); - t_node = e->target(); - s_sun_node = (*A_mult_ptr[act_level])[s_node].get_dedicated_sun_node(); - t_sun_node = (*A_mult_ptr[act_level])[t_node].get_dedicated_sun_node(); - if( s_sun_node != t_sun_node) //a inter solar system edge - {//if - high_level_sun_s = (*A_mult_ptr[act_level])[s_sun_node].get_higher_level_node(); - high_level_sun_t = (*A_mult_ptr[act_level])[t_sun_node].get_higher_level_node(); - - //create new edge in *G_mult_ptr[act_level+1] - e_new = G_mult_ptr[act_level+1]->newEdge(high_level_sun_s,high_level_sun_t); - (*E_mult_ptr[act_level])[e].set_higher_level_edge(e_new); - inter_solar_system_edges.pushBack(e); - }//if - }//forall - - //init new_edgelength calculate the values of new_edgelength and the lambda Lists - - new_edgelength.init(*G_mult_ptr[act_level+1]); - forall_listiterators(edge, e_ptr, inter_solar_system_edges) - {//forall - s_node = (*e_ptr)->source(); - t_node = (*e_ptr)->target(); - s_sun_node = (*A_mult_ptr[act_level])[s_node].get_dedicated_sun_node(); - t_sun_node = (*A_mult_ptr[act_level])[t_node].get_dedicated_sun_node(); - length_e = (*E_mult_ptr[act_level])[*e_ptr].get_length(); - length_s_edge =(*A_mult_ptr[act_level])[s_node].get_dedicated_sun_distance(); - length_t_edge =(*A_mult_ptr[act_level])[t_node].get_dedicated_sun_distance(); - newlength = length_s_edge + length_e + length_t_edge; - - //set new edge_length in *G_mult_ptr[act_level+1] - e_new = (*E_mult_ptr[act_level])[*e_ptr].get_higher_level_edge(); - new_edgelength[e_new] = newlength; - - //create entries in lambda Lists - lambda_s = length_s_edge/newlength; - lambda_t = length_t_edge/newlength; - (*A_mult_ptr[act_level])[s_node].get_lambda_List_ptr()->pushBack(lambda_s); - (*A_mult_ptr[act_level])[t_node].get_lambda_List_ptr()->pushBack(lambda_t); - (*A_mult_ptr[act_level])[s_node].get_neighbour_sun_node_List_ptr()->pushBack( - t_sun_node); - (*A_mult_ptr[act_level])[t_node].get_neighbour_sun_node_List_ptr()->pushBack( - s_sun_node); - }//forall -} - - -void Multilevel::delete_parallel_edges_and_update_edgelength( - Array &G_mult_ptr, - Array*> &E_mult_ptr, - EdgeArray& new_edgelength,int - act_level) -{ - EdgeMaxBucketFunc get_max_index; - EdgeMinBucketFunc get_min_index; - edge e_act, e_save; - Edge f_act; - List sorted_edges; - Graph* Graph_ptr = G_mult_ptr[act_level+1]; - int save_s_index,save_t_index,act_s_index,act_t_index; - int counter = 1; - - //make *G_mult_ptr[act_level+1] undirected - makeSimpleUndirected(*G_mult_ptr[act_level+1]); - - //sort the List sorted_edges - forall_edges(e_act,*Graph_ptr) - { - f_act.set_Edge(e_act,Graph_ptr); - sorted_edges.pushBack(f_act); - } - - sorted_edges.bucketSort(0,Graph_ptr->numberOfNodes()-1,get_max_index); - sorted_edges.bucketSort(0,Graph_ptr->numberOfNodes()-1,get_min_index); - - //now parallel edges are consecutive in sorted_edges - forall_listiterators(Edge, EdgeIterator,sorted_edges) - {//for - e_act = (*EdgeIterator).get_edge(); - act_s_index = e_act->source()->index(); - act_t_index = e_act->target()->index(); - - if(EdgeIterator != sorted_edges.begin()) - {//if - if( (act_s_index == save_s_index && act_t_index == save_t_index) || - (act_s_index == save_t_index && act_t_index == save_s_index) ) - { - new_edgelength[e_save] += new_edgelength[e_act]; - Graph_ptr->delEdge(e_act); - counter++; - } - else - { - if (counter > 1) - { - new_edgelength[e_save] /= counter; - counter = 1; - } - save_s_index = act_s_index; - save_t_index = act_t_index; - e_save = e_act; - } - }//if - else //first edge - { - save_s_index = act_s_index; - save_t_index = act_t_index; - e_save = e_act; - } - }//for - - //treat special case (last edges were multiple edges) - if(counter >1) - new_edgelength[e_save] /= counter; - - //init *E_mult_ptr[act_level+1] and import EdgeAttributes - E_mult_ptr[act_level+1]->init(*G_mult_ptr[act_level+1]); - forall_edges(e_act,*Graph_ptr) - (*E_mult_ptr[act_level+1])[e_act].set_length(new_edgelength[e_act]); -} - - -void Multilevel::find_initial_placement_for_level( - int level, - int init_placement_way, - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr) -{ - List pm_nodes; - set_initial_positions_of_sun_nodes(level, G_mult_ptr, A_mult_ptr); - set_initial_positions_of_planet_and_moon_nodes(level, init_placement_way, G_mult_ptr, - A_mult_ptr, E_mult_ptr, pm_nodes); - set_initial_positions_of_pm_nodes(level, init_placement_way, A_mult_ptr, - E_mult_ptr, pm_nodes); -} - - -void Multilevel::set_initial_positions_of_sun_nodes( - int level, - Array &G_mult_ptr, - Array*> &A_mult_ptr) -{ - node v_high, v_act; - DPoint new_pos; - forall_nodes(v_high,*G_mult_ptr[level+1]) - { - v_act = (*A_mult_ptr[level+1])[v_high].get_lower_level_node(); - new_pos = (*A_mult_ptr[level+1])[v_high].get_position(); - (*A_mult_ptr[level])[v_act].set_position(new_pos); - (*A_mult_ptr[level])[v_act].place(); - } -} - - -void Multilevel::set_initial_positions_of_planet_and_moon_nodes( - int level, - int init_placement_way, - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - List& pm_nodes) -{ - double lambda, dedicated_sun_distance; - int node_type; - node v, v_adj, dedicated_sun; - edge e; - DPoint new_pos,dedicated_sun_pos, adj_sun_pos; - List L; - ListIterator lambdaIterator; - - create_all_placement_sectors(G_mult_ptr,A_mult_ptr,E_mult_ptr,level); - forall_nodes(v,*G_mult_ptr[level]) - {//for - node_type = (*A_mult_ptr[level])[v].get_type(); - if(node_type == 3) - pm_nodes.pushBack(v); - else if(node_type == 2 || node_type == 4) //a planet_node or moon_node - {//else - L.clear(); - dedicated_sun = (*A_mult_ptr[level])[v].get_dedicated_sun_node(); - dedicated_sun_pos = (*A_mult_ptr[level])[dedicated_sun].get_position(); - dedicated_sun_distance = (*A_mult_ptr[level])[v].get_dedicated_sun_distance(); - - if(init_placement_way == FMMMLayout::ipmAdvanced) - { - forall_adj_edges(e,v) - { - if(e->source() != v) - v_adj = e->source(); - else - v_adj = e->target(); - if( ( (*A_mult_ptr[level])[v].get_dedicated_sun_node() == - (*A_mult_ptr[level])[v_adj].get_dedicated_sun_node() ) && - ( (*A_mult_ptr[level])[v_adj].get_type() != 1 ) && - ( (*A_mult_ptr[level])[v_adj].is_placed() ) ) - { - new_pos = calculate_position(dedicated_sun_pos,(*A_mult_ptr[level]) - [v_adj].get_position(),dedicated_sun_distance, - (*E_mult_ptr[level])[e].get_length()); - L.pushBack(new_pos); - } - } - } - if ((*A_mult_ptr[level])[v].get_lambda_List_ptr()->empty()) - {//special case - if(L.empty()) - { - new_pos = create_random_pos(dedicated_sun_pos,(*A_mult_ptr[level]) - [v].get_dedicated_sun_distance(), - (*A_mult_ptr[level])[v].get_angle_1(), - (*A_mult_ptr[level])[v].get_angle_2()); - L.pushBack(new_pos); - } - }//special case - else - {//usual case - lambdaIterator = (*A_mult_ptr[level])[v].get_lambda_List_ptr()->begin(); - - forall_listiterators(node, adj_sun_ptr,*(*A_mult_ptr[level])[v]. - get_neighbour_sun_node_List_ptr()) - { - lambda = *lambdaIterator; - adj_sun_pos = (*A_mult_ptr[level])[*adj_sun_ptr].get_position(); - new_pos = get_waggled_inbetween_position(dedicated_sun_pos,adj_sun_pos, - lambda); - L.pushBack(new_pos); - if(lambdaIterator != (*A_mult_ptr[level])[v].get_lambda_List_ptr() - ->rbegin()) - lambdaIterator = (*A_mult_ptr[level])[v].get_lambda_List_ptr() - ->cyclicSucc(lambdaIterator); - } - }//usual case - - (*A_mult_ptr[level])[v].set_position(get_barycenter_position(L)); - (*A_mult_ptr[level])[v].place(); - }//else - }//for -} - - -void Multilevel::create_all_placement_sectors( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int level) -{ - node v_high, w_high, sun_node, v, ded_sun; - edge e_high; - List adj_pos; - double angle_1, angle_2, act_angle_1, act_angle_2, next_angle, min_next_angle; - DPoint start_pos, end_pos; - int MAX = 10; //the biggest of at most MAX random selected sectors is choosen - int steps; - ListIterator it, next_pos_ptr; - bool first_angle; - - - forall_nodes(v_high,(*G_mult_ptr[level+1])) - {//forall - //find pos of adjacent nodes - adj_pos.clear(); - DPoint v_high_pos ((*A_mult_ptr[level+1])[v_high].get_x(), - (*A_mult_ptr[level+1])[v_high].get_y()); - forall_adj_edges(e_high,v_high) - if(!(*E_mult_ptr[level+1])[e_high].is_extra_edge()) - { - if(v_high == e_high->source()) - w_high = e_high->target(); - else - w_high = e_high->source(); - - DPoint w_high_pos ((*A_mult_ptr[level+1])[w_high].get_x(), - (*A_mult_ptr[level+1])[w_high].get_y()); - adj_pos.pushBack(w_high_pos); - } - if(adj_pos.empty()) //easy case - { - angle_1 = 0; - angle_2 = 6.2831853; - } - else if(adj_pos.size() == 1) //special case - { - //create angle_1 - start_pos = *adj_pos.begin(); - DPoint x_parallel_pos (v_high_pos.m_x + 1, v_high_pos.m_y); - angle_1 = angle(v_high_pos,x_parallel_pos,start_pos); - //create angle_2 - angle_2 = angle_1 + Math::pi; - } - else //usual case - {//else - steps = 1; - it = adj_pos.begin(); - do - { - //create act_angle_1 - start_pos = *it; - DPoint x_parallel_pos (v_high_pos.m_x + 1, v_high_pos.m_y); - act_angle_1 = angle(v_high_pos,x_parallel_pos,start_pos); - //create act_angle_2 - first_angle = true; - - for(next_pos_ptr = adj_pos.begin();next_pos_ptr.valid();++next_pos_ptr) - { - next_angle = angle(v_high_pos,start_pos,*next_pos_ptr); - - if(start_pos != *next_pos_ptr && (first_angle || next_angle < - min_next_angle)) - { - min_next_angle = next_angle; - first_angle = false; - } - } - act_angle_2 = act_angle_1 + min_next_angle; - if((it == adj_pos.begin())||((act_angle_2-act_angle_1)>(angle_2-angle_1))) - { - angle_1 = act_angle_1; - angle_2 = act_angle_2; - } - if(it != adj_pos.rbegin()) - it = adj_pos.cyclicSucc(it); - steps++; - } - while((steps <= MAX) && (it != adj_pos.rbegin())); - - if(angle_1 == angle_2) - angle_2 = angle_1 + Math::pi; - }//else - - //import angle_1 and angle_2 to the dedicated suns at level level - sun_node = (*A_mult_ptr[level+1])[v_high].get_lower_level_node(); - (*A_mult_ptr[level])[sun_node].set_angle_1(angle_1); - (*A_mult_ptr[level])[sun_node].set_angle_2(angle_2); - }//forall - - //import the angle values from the values of the dedicated sun nodes - forall_nodes(v,*G_mult_ptr[level]) - { - ded_sun = (*A_mult_ptr[level])[v].get_dedicated_sun_node(); - (*A_mult_ptr[level])[v].set_angle_1((*A_mult_ptr[level])[ded_sun].get_angle_1()); - (*A_mult_ptr[level])[v].set_angle_2((*A_mult_ptr[level])[ded_sun].get_angle_2()); - } -} - - -void Multilevel::set_initial_positions_of_pm_nodes( - int level, - int init_placement_way, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - List& pm_nodes) -{ - double moon_dist, sun_dist, lambda; - node v_adj, sun_node; - edge e; - DPoint sun_pos, moon_pos, new_pos, adj_sun_pos; - List L; - ListIterator lambdaIterator; - - forall_listiterators(node,v_ptr,pm_nodes) - {//forall - L.clear(); - sun_node = (*A_mult_ptr[level])[*v_ptr].get_dedicated_sun_node(); - sun_pos = (*A_mult_ptr[level])[sun_node].get_position(); - sun_dist = (*A_mult_ptr[level])[*v_ptr].get_dedicated_sun_distance(); - - if(init_placement_way == FMMMLayout::ipmAdvanced) - {//if - forall_adj_edges(e,*v_ptr) - { - if(e->source() != *v_ptr) - v_adj = e->source(); - else - v_adj = e->target(); - if( (!(*E_mult_ptr[level])[e].is_moon_edge()) && - ( (*A_mult_ptr[level])[*v_ptr].get_dedicated_sun_node() == - (*A_mult_ptr[level])[v_adj].get_dedicated_sun_node() ) && - ( (*A_mult_ptr[level])[v_adj].get_type() != 1 ) && - ( (*A_mult_ptr[level])[v_adj].is_placed() ) ) - { - new_pos = calculate_position(sun_pos,(*A_mult_ptr[level])[v_adj]. - get_position(),sun_dist,(*E_mult_ptr[level]) - [e].get_length()); - L.pushBack(new_pos); - } - } - }//if - forall_listiterators(node, moon_node_ptr,*(*A_mult_ptr[level])[*v_ptr]. - get_dedicated_moon_node_List_ptr()) - { - moon_pos = (*A_mult_ptr[level])[*moon_node_ptr].get_position(); - moon_dist = (*A_mult_ptr[level])[*moon_node_ptr].get_dedicated_sun_distance(); - lambda = sun_dist/moon_dist; - new_pos = get_waggled_inbetween_position(sun_pos,moon_pos,lambda); - L.pushBack(new_pos); - } - - if (!(*A_mult_ptr[level])[*v_ptr].get_lambda_List_ptr()->empty()) - { - lambdaIterator = (*A_mult_ptr[level])[*v_ptr].get_lambda_List_ptr()->begin(); - - forall_listiterators(node,adj_sun_ptr,*(*A_mult_ptr[level])[*v_ptr]. - get_neighbour_sun_node_List_ptr()) - { - lambda = *lambdaIterator; - adj_sun_pos = (*A_mult_ptr[level])[*adj_sun_ptr].get_position(); - new_pos = get_waggled_inbetween_position(sun_pos,adj_sun_pos,lambda); - L.pushBack(new_pos); - if(lambdaIterator != (*A_mult_ptr[level])[*v_ptr].get_lambda_List_ptr() - ->rbegin()) - lambdaIterator = (*A_mult_ptr[level])[*v_ptr].get_lambda_List_ptr() - ->cyclicSucc(lambdaIterator); - } - } - - (*A_mult_ptr[level])[*v_ptr].set_position(get_barycenter_position(L)); - (*A_mult_ptr[level])[*v_ptr].place(); - }//forall -} - - -inline DPoint Multilevel::create_random_pos(DPoint center,double radius,double angle_1, - double angle_2) -{ - const int BILLION = 1000000000; - DPoint new_point; - double rnd = double(randomNumber(1,BILLION)+1)/(BILLION+2);//rand number in (0,1) - double rnd_angle = angle_1 +(angle_2-angle_1)*rnd; - double dx = cos(rnd_angle) * radius; - double dy = sin(rnd_angle) * radius; - new_point.m_x = center.m_x + dx ; - new_point.m_y = center.m_y + dy; - return new_point; -} - - -inline DPoint Multilevel::get_waggled_inbetween_position(DPoint s, DPoint t, double lambda) -{ - const double WAGGLEFACTOR = 0.05; - const int BILLION = 1000000000; - DPoint inbetween_point; - inbetween_point.m_x = s.m_x + lambda*(t.m_x - s.m_x); - inbetween_point.m_y = s.m_y + lambda*(t.m_y - s.m_y); - double radius = WAGGLEFACTOR * (t-s).norm(); - double rnd = double(randomNumber(1,BILLION)+1)/(BILLION+2);//rand number in (0,1) - double rand_radius = radius * rnd; - return create_random_pos(inbetween_point,rand_radius,0,6.2831853); -} - - -inline DPoint Multilevel::get_barycenter_position(List& L) -{ - DPoint sum (0,0); - DPoint barycenter; - - forall_listiterators(DPoint, act_point_ptr,L) - sum = sum + (*act_point_ptr); - barycenter.m_x = sum.m_x/L.size(); - barycenter.m_y = sum.m_y/L.size(); - return barycenter; -} - - -inline DPoint Multilevel::calculate_position(DPoint P, DPoint Q, double dist_P, double dist_Q) -{ - double dist_PQ = (P-Q).norm(); - double lambda = (dist_P + (dist_PQ - dist_P - dist_Q)/2)/dist_PQ; - return get_waggled_inbetween_position(P,Q,lambda); -} - - -void Multilevel::delete_multilevel_representations( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int max_level) -{ - for(int i=1; i<= max_level; i++) - { - delete G_mult_ptr[i]; - delete A_mult_ptr[i]; - delete E_mult_ptr[i]; - } -} - - -double Multilevel::angle(DPoint& P, DPoint& Q, DPoint& R) -{ - double dx1 = Q.m_x - P.m_x; - double dy1 = Q.m_y - P.m_y; - double dx2 = R.m_x - P.m_x; - double dy2 = R.m_y - P.m_y; - double fi;//the angle - - if ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)) - cout<<"Multilevel::angle()"<= 1.0 ) fi = 0; - if (cosfi <= -1.0 ) fi = Math::pi; - else - { - fi = acos(cosfi); - if (dx1*dy2 < dy1*dx2) fi = -fi; - if (fi < 0) fi += 2*Math::pi; - } - return fi; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/Multilevel.h b/ext/OGDF/src/energybased/Multilevel.h deleted file mode 100644 index 3160a051e..000000000 --- a/ext/OGDF/src/energybased/Multilevel.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Multlevel (used by FMMMLayout). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MULTILEVEL_H -#define OGDF_MULTILEVEL_H - -#include -#include -#include -#include -#include "Edge.h" -#include -#include - - -namespace ogdf { - -class Multilevel -{ -public: - - Multilevel() { } //constructor - ~Multilevel() { } //destructor - - //The multilevel representations *G_mult_ptr/*A_mult_ptr/*E_mult_ptr for - //G/A/E are created. The maximum multilevel is calculated, too. - void create_multilevel_representations(Graph& G,NodeArray& A, - EdgeArray & E, - int rand_seed, - int galaxy_choice, - int min_Graph_size, - int rand_tries, - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int & max_level); - - //The initial placement of the nodes at multilevel level are created by the - //placements of the nodes of the graphs at the lower level (if init_placement_way - //is 0) or additionally using information of the actual level ( if - //init_placement_way == 1). Precondition: level < max_level - void find_initial_placement_for_level( - int level, - int init_placement_way, - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr); - - //Free dynamically allocated memory. - void delete_multilevel_representations( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int max_level); - -private: - - //This function returns true if act_level = 0 or if act_level >0 and the - //number of edges at the actual level is <= 80% of the number of edges of the - //previous level or if the actual edgenumber is >80% of the number of edges of the - //previous level, but bad_edgecounter is <= 5. In this case edgecounter is - //incremented. In all other cases false is returned. - bool edgenumbersum_of_all_levels_is_linear( - Array &G_mult_ptr, - int act_level, - int&bad_edgenr_counter); - - //The multilevel values of *A_mult_ptr[level][v] are set to the default values - //for all nodes v in *G_mult_ptr[level] - void init_multilevel_values( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int level); - - //The nodeset(galaxy) of *G_mult_ptr[act_level] is partitioned in s,p,pm,m nodes. - //The dedicated s,p,pm,m nodes define a subgraph (called solar system). - //For each solar system a new node is created in *G_mult_ptr[act_level+1] and - //it is linked with the corresponding sun node at act_level; the mass of this node - //is set to the mass of the solar system. Additionally for each node in *G_mult_ptr - //[act_level] the dedicated sun node and the distance to its dedicates sun node is - //calculated - void partition_galaxy_into_solar_systems( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int rand_seed, - int galaxy_choice, - int random_tries, - int act_level); - - //The sun and planet nodes are created by choosing the sun nodes randomly with - //uniform or weighted probability (depending on galaxy_choice) - void create_suns_and_planets( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int rand_seed, - int galaxy_choice, - int random_tries, - int act_level); - - //Partitions the nodes of *G_mult_ptr[act_level] that have not been assigned yet, - //to moon nodes of a nearest planet or pm node and identify this planet as a - //pm-node if this has not been done before. - void create_moon_nodes_and_pm_nodes( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int act_level); - - //Using information generated in partition_galaxy_into_solar_systems we - //create the edge set of *G_mult_ptr[act_level+1] and for each node at act_level+1 - //the list of sun nodes of neighbouring sun systems and the corresponding lambda - //values. - void collaps_solar_systems( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int act_level); - - //The mass of all nodes at level act_level+1 is set to the mass of its dedicated - //solar_system at level act_level. - void calculate_mass_of_collapsed_nodes( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - int act_level); - - //The edges , new_edgelength and the lambda lists at level act_level+1 are created - //(the graph may contain parallel edges afterwards). - void create_edges_edgedistances_and_lambda_Lists( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - EdgeArray& new_edgelength, - int act_level); - - //Parallel edges at level act_level+1 are deleted and the edgelength of the - //remaining edge is set to the average edgelength of all its parallel edges. - void delete_parallel_edges_and_update_edgelength( - Array &G_mult_ptr, - Array*> &E_mult_ptr, - EdgeArray& new_edgelength, - int act_level); - - //The initial positions of all sun_nodes at level level are set. - void set_initial_positions_of_sun_nodes( - int level, - Array &G_mult_ptr, - Array*> &A_mult_ptr); - - //The initial positions of the planet/moon_nodes at level level are calculated here - //and a list of all pm_nodes is returned. - void set_initial_positions_of_planet_and_moon_nodes( - int level, - int init_placement_way, - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - List &pm_nodes); - - //The values of angle_1 and angle_2 that restrict the area of the placement for - //all nodes that are not adjacent to other solar systems are created for all nodes - //at multilevel level. - void create_all_placement_sectors( - Array &G_mult_ptr, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - int level); - - //The initial positions of the pm nodes are calculated by the position of the - //dedicated sun and moon_nodes. - void set_initial_positions_of_pm_nodes( - int level, - int init_placement_way, - Array*> &A_mult_ptr, - Array*> &E_mult_ptr, - List& pm_nodes); - - //Returns a random point with radius radius between angle_1 and angle_2. - DPoint create_random_pos(DPoint center, double radius, double angle_1, double angle_2); - - //Returns roughtly the position s +lambda*(t-s) + some random waggling. - DPoint get_waggled_inbetween_position(DPoint s, DPoint t, double lambda); - - //Returns the barycenter position of all points in L (the mass of all point is - //regarded as equal). - DPoint get_barycenter_position(List& L); - - //Creates a waggled position on the line PQ, depending on dist_P and dist_Q - //needed in case init_placement_way() == 1. - DPoint calculate_position(DPoint P,DPoint Q, double dist_P, double dist_Q); - - //Calculates the angle between PQ and PS in [0,2pi) - double angle(DPoint& P, DPoint& Q, DPoint& R); -}; - -}//namespace ogdf -#endif - diff --git a/ext/OGDF/src/energybased/MultilevelGraph.cpp b/ext/OGDF/src/energybased/MultilevelGraph.cpp deleted file mode 100644 index e3391ac94..000000000 --- a/ext/OGDF/src/energybased/MultilevelGraph.cpp +++ /dev/null @@ -1,834 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief MLG is the main data structure for ModularMultilevelMixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - - -namespace ogdf { - - -MultilevelGraph::~MultilevelGraph() -{ - // delete all Nodemerges! - while(!m_changes.empty()) { - delete m_changes.back(); - m_changes.pop_back(); - } - - // only delete the Graph if it was created! - if (m_createdGraph) { - delete m_G; - } - delete m_GA; -} - -//initialize internal structures such as the GraphAttributes that store the layout -void MultilevelGraph::initInternal() -{ - OGDF_ASSERT(m_G != 0); - m_GA = new GraphAttributes(*m_G); -} - -MultilevelGraph::MultilevelGraph() -:m_createdGraph(true) -{ - m_G = new Graph(); - if(m_G == 0) { - OGDF_THROW(InsufficientMemoryException); - } - - //replaces layout info stuff below - initInternal(); - - m_nodeAssociations.init(*m_G, 0); - m_edgeAssociations.init(*m_G, 0); - m_radius.init(*m_G, 1.0); - m_weight.init(*m_G, 1.0); - - initReverseIndizes(); -} - - -MultilevelGraph::MultilevelGraph(GraphAttributes &GA) -:m_createdGraph(true) -{ - m_G = new Graph(); - if(m_G == 0) { - OGDF_THROW(InsufficientMemoryException); - } - - //replaces layout info stuff below - initInternal(); - - m_nodeAssociations.init(*m_G); - m_edgeAssociations.init(*m_G); - m_radius.init(*m_G); - m_weight.init(*m_G); - copyFromGraph(GA.constGraph(), m_nodeAssociations, m_edgeAssociations); - prepareGraphAttributes(GA); - importAttributes(GA); - - initReverseIndizes(); -} - - -MultilevelGraph::MultilevelGraph(Graph &G) -:m_createdGraph(false), m_G(0) -{ - m_G = &G; - - //replaces layout info stuff below - initInternal(); - - m_nodeAssociations.init(*m_G, 0); - m_edgeAssociations.init(*m_G, 0); - m_radius.init(*m_G, 1.0); - m_weight.init(*m_G, 1.0); - - initReverseIndizes(); -} - - -MultilevelGraph::MultilevelGraph(GraphAttributes &GA, Graph &G) -:m_createdGraph(false), m_G(0) -{ - m_G = &G; - m_nodeAssociations.init(*m_G, 0); - m_edgeAssociations.init(*m_G, 0); - m_radius.init(*m_G); - m_weight.init(*m_G); - - initInternal(); - - prepareGraphAttributes(GA); - importAttributes(GA); - - initReverseIndizes(); -} - - -MultilevelGraph::MultilevelGraph(istream &is) -:m_createdGraph(true) -{ - m_G = new Graph(); - if(m_G == 0) { - OGDF_THROW(InsufficientMemoryException); - } - m_nodeAssociations.init(*m_G); - m_edgeAssociations.init(*m_G); - m_radius.init(*m_G); - m_weight.init(*m_G); - - initInternal(); - //GraphAttributes tempGA(*m_G); - m_GA->readGML(*m_G, is); - prepareGraphAttributes(*m_GA); - importAttributesSimple(*m_GA); - - initReverseIndizes(); -} - - -MultilevelGraph::MultilevelGraph(const String &filename) -:m_createdGraph(true) -{ - m_G = new Graph(); - if(m_G == 0) { - OGDF_THROW(InsufficientMemoryException); - } - m_nodeAssociations.init(*m_G); - m_edgeAssociations.init(*m_G); - m_radius.init(*m_G); - m_weight.init(*m_G); - - initInternal(); - //GraphAttributes tempGA(*m_G); - m_GA->readGML(*m_G, filename); - prepareGraphAttributes(*m_GA); - importAttributesSimple(*m_GA); - - initReverseIndizes(); -} - - -void MultilevelGraph::prepareGraphAttributes(GraphAttributes &GA) const -{ - long additionalAttributes = 0; - if (!(GA.attributes() & GraphAttributes::edgeDoubleWeight)) { - additionalAttributes |= GraphAttributes::edgeDoubleWeight; - } - if (!(GA.attributes() & GraphAttributes::nodeWeight)) { - additionalAttributes |= GraphAttributes::nodeWeight; - } - GA.initAttributes(additionalAttributes); -} - - -void MultilevelGraph::copyFromGraph(const Graph &G, NodeArray & /*nodeAssociations*/, EdgeArray & /* edgeAssociations */) -{ - NodeArray tempAssociations(G); - - node v; - forall_nodes(v, G) { - node v_new = m_G->newNode(); - m_nodeAssociations[v_new] = v->index(); - tempAssociations[v] = v_new; - } - - edge e; - forall_edges(e, G) { - edge e_new = m_G->newEdge(tempAssociations[e->source()], tempAssociations[e->target()]); - m_edgeAssociations[e_new] = e->index(); - } - - initReverseIndizes(); -} - - -int MultilevelGraph::getLevel() -{ - if (m_changes.size() == 0) - { - return 0; - } - else - { - return m_changes.back()->m_level; - } -} - - -// assumes, that the Graphs of MultilevelGraph and GA are the same, not copies! -void MultilevelGraph::exportAttributesSimple(GraphAttributes &GA) const -{ - OGDF_ASSERT(&(GA.constGraph()) == m_G); - - prepareGraphAttributes(GA); - - node v; - forall_nodes(v, *m_G) { - GA.x(v) = m_GA->x(v); - GA.y(v) = m_GA->y(v); - //TODO: Check what this w,h computation does - double w = GA.width(v); - double h = GA.height(v); - if(w > 0 || h > 0) { - double factor = m_radius[v] / sqrt(w*w + h*h) * 2.0f; - w *= factor; - h *= factor; - } else { - w = h = m_radius[v] * sqrt(2.0f); - } - GA.width(v) = w; - GA.height(v) = h; - GA.weight(v) = m_reverseNodeMergeWeight[v->index()]; - } - - edge e; - forall_edges(e, *m_G) { - GA.doubleWeight(e) = m_weight[e]; - } -} - - -void MultilevelGraph::exportAttributes(GraphAttributes &GA) const -{ - OGDF_ASSERT(GA.constGraph().numberOfNodes() == m_G->numberOfNodes()); - OGDF_ASSERT(GA.constGraph().numberOfEdges() == m_G->numberOfEdges()); - - prepareGraphAttributes(GA); - - std::vector tempNodeAssociations; - node v; - const Graph &cG = GA.constGraph(); - tempNodeAssociations.resize(cG.maxNodeIndex()+1, 0); - forall_nodes(v, cG) { - tempNodeAssociations[v->index()] = v; - } - - forall_nodes(v, *m_G) { - GA.x(tempNodeAssociations[m_nodeAssociations[v]]) = m_GA->x(v); - GA.y(tempNodeAssociations[m_nodeAssociations[v]]) = m_GA->y(v); - double w = GA.width(tempNodeAssociations[m_nodeAssociations[v]]); - double h = GA.height(tempNodeAssociations[m_nodeAssociations[v]]); - if(w > 0 || h > 0) { - double factor = m_radius[v] / sqrt(w*w + h*h) * 2.0f; - w *= factor; - h *= factor; - } else { - w = h = m_radius[v] * sqrt(2.0f); - } - GA.width(tempNodeAssociations[m_nodeAssociations[v]]) = w; - GA.height(tempNodeAssociations[m_nodeAssociations[v]]) = h; - GA.weight(tempNodeAssociations[m_nodeAssociations[v]]) = m_reverseNodeMergeWeight[v->index()]; - } - - std::vector tempEdgeAssociations; - edge e; - tempEdgeAssociations.resize(cG.maxEdgeIndex()+1, 0); - forall_edges(e, cG) { - tempEdgeAssociations[e->index()] = e; - } - - forall_edges(e, *m_G) { - GA.doubleWeight(tempEdgeAssociations[m_edgeAssociations[e]]) = m_weight[e]; - } -} - - -void MultilevelGraph::importAttributesSimple(const GraphAttributes &GA) -{ - OGDF_ASSERT(&(GA.constGraph()) == m_G); - - m_avgRadius = 0.0; - - node v; - forall_nodes(v, *m_G) { - double w = GA.width(v); - double h = GA.height(v); - if(w > 0 || h > 0) { - m_radius[v] = sqrt(w*w + h*h) / 2.0f; - } else { - m_radius[v] = 1.0f; - } - m_avgRadius += m_radius[v]; - m_GA->x(v) = GA.x(v); - m_GA->y(v) = GA.y(v); - m_GA->width(v) = GA.width(v); - m_GA->height(v) = GA.height(v); - } - m_avgRadius /= m_G->numberOfNodes(); - - edge e; - forall_edges(e, *m_G) { - m_weight[e] = GA.doubleWeight(e); - } -} - - -void MultilevelGraph::importAttributes(const GraphAttributes &GA) -{ - OGDF_ASSERT(GA.constGraph().numberOfNodes() == m_G->numberOfNodes()); - OGDF_ASSERT(GA.constGraph().numberOfEdges() == m_G->numberOfEdges()); - - m_avgRadius = 0.0; - - std::vector tempNodeAssociations; - node v; - const Graph &cG = GA.constGraph(); - tempNodeAssociations.resize(cG.maxNodeIndex()+1, 0); - forall_nodes(v, cG) { - tempNodeAssociations[v->index()] = v; - } - - forall_nodes(v, *m_G) { - - double w = GA.width(tempNodeAssociations[m_nodeAssociations[v]]); - double h = GA.height(tempNodeAssociations[m_nodeAssociations[v]]); - if(w > 0 || h > 0) { - m_radius[v] = sqrt(w*w + h*h) / 2.0f; - } else { - m_radius[v] = 1.0f; - } - - m_avgRadius += m_radius[v]; - - m_GA->x(v) = GA.x(tempNodeAssociations[m_nodeAssociations[v]]); - m_GA->y(v) = GA.y(tempNodeAssociations[m_nodeAssociations[v]]); - m_GA->width(v) = GA.width(tempNodeAssociations[m_nodeAssociations[v]]); - m_GA->height(v) = GA.height(tempNodeAssociations[m_nodeAssociations[v]]); - } - - m_avgRadius /= m_G->numberOfNodes(); - - std::vector tempEdgeAssociations; - edge e; - tempEdgeAssociations.resize(cG.maxEdgeIndex()+1, 0); - forall_edges(e, cG) { - tempEdgeAssociations[e->index()] = e; - } - - forall_edges(e, *m_G) { - m_weight[e] = GA.doubleWeight(tempEdgeAssociations[m_edgeAssociations[e]]); - } -} - - -void MultilevelGraph::reInsertGraph(MultilevelGraph &MLG) -{ - std::map tempNodeAssociations; - - node v; - forall_nodes(v, *(MLG.m_G)) { - MLG.copyNodeTo(v, *this, tempNodeAssociations, false, MLG.m_nodeAssociations[v]); - } - - edge e; - forall_edges(e, *(MLG.m_G)) { - MLG.copyEdgeTo(e, *this, tempNodeAssociations, false, MLG.m_edgeAssociations[e]); - } - - initReverseIndizes(); -} - - -void MultilevelGraph::reInsertAll(std::vector components) -{ - for(std::vector::iterator i = components.begin(); - i != components.end(); i++) - { - reInsertGraph(**i); - } -} - - -// keeps Changes -// keeps Node and Edge Associations -// deletes Nodes and Eges from Graph -// deletes Attributes -// deprecated, use componentsplitterlayout instead -std::vector MultilevelGraph::splitIntoComponents() -{ - std::vector components; - - NodeArray componentNumbers(*m_G); - int numComponents = connectedComponents(*m_G, componentNumbers); - if (numComponents == 0) { - return components; - } - - std::vector< std::vector > componentArray; - componentArray.resize(numComponents); - node v; - forall_nodes(v, *m_G) { - componentArray[componentNumbers[v]].push_back(v); - } - - for (unsigned int componentNumber = 0; componentNumber < componentArray.size(); componentNumber++) { - std::vector componentSubArray = componentArray[componentNumber]; - MultilevelGraph * component = removeOneCC(componentSubArray); - components.push_back(component); - } - - OGDF_ASSERT(m_G->numberOfNodes() == 0); - OGDF_ASSERT(m_G->numberOfEdges() == 0); - - m_radius.init(*m_G); - m_weight.init(*m_G); - - return components; -} - - -void MultilevelGraph::copyNodeTo(node v, MultilevelGraph &MLG, std::map &tempNodeAssociations, bool associate, int index) -{ - node v_new; - if (index == -1) { - v_new = MLG.m_G->newNode(); - } else { - v_new = MLG.m_G->newNode(index); - } - - tempNodeAssociations[v] = v_new; - if(associate) { - MLG.m_nodeAssociations[v_new] = v->index(); - } - MLG.m_radius[v_new] = m_radius[v]; - MLG.x(v_new, x(v)); - MLG.y(v_new, y(v)); -} - - -void MultilevelGraph::copyEdgeTo(edge e, MultilevelGraph &MLG, std::map &tempNodeAssociations, bool associate, int index) -{ - node source = e->source(); - node target = e->target(); - edge e_new; - if (index == -1) { - e_new = MLG.m_G->newEdge(tempNodeAssociations[source], tempNodeAssociations[target]); - } else { - e_new = MLG.m_G->newEdge(tempNodeAssociations[source], tempNodeAssociations[target], index); - } - - if(associate) { - MLG.m_edgeAssociations[e_new] = e->index(); - } - MLG.m_weight[e_new] = m_weight[e]; -} - - -MultilevelGraph * MultilevelGraph::removeOneCC(std::vector &componentSubArray) -{ - MultilevelGraph * MLGcomponent = new MultilevelGraph(); - std::map tempNodeAssociations; - - // copy nodes - for (std::vector::iterator i = componentSubArray.begin(); i != componentSubArray.end(); i++) { - node v = *i; - copyNodeTo(v, *MLGcomponent, tempNodeAssociations, true); - } - - // move edges - for (std::vector::iterator i = componentSubArray.begin(); i != componentSubArray.end(); i++) { - node v = *i; - edge e; -// std::vector toDelete; - forall_adj_edges(e, v) { - if (e != 0 && e->source() == v) { - copyEdgeTo(e, *MLGcomponent, tempNodeAssociations, true); -// toDelete.push_back(e); - } - } -/* // Test if this is good for Performace. - // makes Assert Edges == 0 fail! - // Because of self loops! - for(std::vector::iterator j = toDelete.begin(); j != toDelete.end(); j++) { - m_G->delEdge(*j); - } -*/ - } - - tempNodeAssociations.clear(); - - // delete nodes - for (std::vector::iterator i = componentSubArray.begin(); i != componentSubArray.end(); i++) { - node v = *i; - m_G->delNode(v); - } - - MLGcomponent->initReverseIndizes(); - return MLGcomponent; -} - - -bool MultilevelGraph::postMerge(NodeMerge * NM, node merged) -{ - // merged has no more edges! - int index = merged->index(); - if (merged->degree() == 0 && NM->m_changedNodes.size() > 0) { - NM->m_mergedNode = index; - NM->m_radius[index] = m_radius[index]; - m_changes.push_back(NM); - m_G->delNode(merged); - m_reverseNodeIndex[index] = 0; - return true; - } else { - return false; - } -} - - -bool MultilevelGraph::changeNode(NodeMerge * NM, node theNode, double newRadius, node merged) -{ - int index = theNode->index(); - //we assume that changeNode is called exactly onces when a node is merged - //with its parent with parameter theNode being the parent and add 1 to - //the parents merge weight - m_reverseNodeMergeWeight[index] += m_reverseNodeMergeWeight[merged->index()]; - std::vector::iterator pos = find(NM->m_changedNodes.begin(), NM->m_changedNodes.end(), index); - - if (pos == NM->m_changedNodes.end()) { - NM->m_changedNodes.push_back(index); - NM->m_radius[index] = m_radius[index]; - } - m_radius[index] = newRadius; - - return true; -} - - -bool MultilevelGraph::changeEdge(NodeMerge * NM, edge theEdge, double newWeight, node newSource, node newTarget) -{ - int index = theEdge->index(); - std::vector::iterator pos = find(NM->m_changedEdges.begin(), NM->m_changedEdges.end(), index); - - if (pos == NM->m_changedEdges.end()) { - NM->m_changedEdges.push_back(index); - NM->m_doubleWeight[index] = m_weight[index]; - NM->m_source[index] = theEdge->source()->index(); - NM->m_target[index] = theEdge->target()->index(); - } - m_G->delEdge(theEdge); - m_reverseEdgeIndex[index] = m_G->newEdge(newSource, newTarget, index); - m_weight[index] = newWeight; - - return true; -} - - -bool MultilevelGraph::deleteEdge(NodeMerge * NM, edge theEdge) -{ - int index = theEdge->index(); - - NM->m_deletedEdges.push_back(index); - NM->m_doubleWeight[index] = m_weight[index]; - NM->m_source[index] = theEdge->source()->index(); - NM->m_target[index] = theEdge->target()->index(); - - m_G->delEdge(theEdge); - m_reverseEdgeIndex[index] = 0; - - return true; -} - - -std::vector MultilevelGraph::moveEdgesToParent(NodeMerge * NM, node theNode, node parent, bool deleteDoubleEdges, int adjustEdgeLengths) -{ - OGDF_ASSERT(theNode != parent); - - std::vector doubleEdges; - std::vector adjEdges; - edge e; - forall_adj_edges(e, theNode) { - adjEdges.push_back(e); - } - - double nodeToParentLen = 0.0; - for (std::vector::iterator i = adjEdges.begin(); i != adjEdges.end(); i++) - { - e = *i; - node newSource = e->source(); - node newTarget = e->target(); - if ((newSource == theNode && newTarget == parent) - || (newSource == parent && newTarget == theNode)){ - nodeToParentLen = m_weight[e->index()]; - break; - } - } - - for (std::vector::iterator i = adjEdges.begin(); i != adjEdges.end(); i++) - { - e = *i; - node newSource = e->source(); - node newTarget = e->target(); - - if (newSource == theNode) { - newSource = parent; - } - if (newTarget == theNode) { - newTarget = parent; - } - - bool exists = false; - edge twinEdge = 0; - adjEntry adj; - forall_adj(adj, parent) { - if (adj->twinNode() != parent && (adj->twinNode() == newSource || adj->twinNode() == newTarget)) { - exists = true; - twinEdge = adj->theEdge(); - double extraLength = 0.0; - if(adjustEdgeLengths != 0) { - extraLength = m_weight[twinEdge->index()] + adjustEdgeLengths * nodeToParentLen; - } - changeEdge(NM, twinEdge, (m_weight[twinEdge->index()] + m_weight[e->index()] + extraLength) * 0.5f, twinEdge->source(), twinEdge->target()); - break; - } - } - - // has this edge already - if (exists || newSource == newTarget) { - doubleEdges.push_back(e); - } else { - changeEdge(NM, e, m_weight[e->index()], newSource, newTarget); - } - } - - if (deleteDoubleEdges) { - while (!doubleEdges.empty()) { - deleteEdge(NM, doubleEdges.back()); - doubleEdges.pop_back(); - } - } - - OGDF_ASSERT(theNode->degree() == doubleEdges.size()); - - // not deleted edges that are adjacent to theNode are returned. - return doubleEdges; -} - - -NodeMerge * MultilevelGraph::getLastMerge() -{ - return m_changes.back(); -} - - -node MultilevelGraph::undoLastMerge() -{ - if (m_changes.empty()) { - return 0; - } - NodeMerge * merge = m_changes.back(); - m_changes.pop_back(); - - // reinsert merged node - int index = merge->m_mergedNode; - node merged = m_G->newNode(index); - m_reverseNodeIndex[index] = merged; - m_radius[index] = merge->m_radius[index]; - - std::vector::iterator it; - // add deleted edges - for (it = merge->m_deletedEdges.begin(); it != merge->m_deletedEdges.end(); it++) { - index = *it; - m_reverseEdgeIndex[index] = m_G->newEdge(m_reverseNodeIndex[merge->m_source[index]], m_reverseNodeIndex[merge->m_target[index]], index); - m_weight[index] = merge->m_doubleWeight[index]; - } - - // undo edge changes - for (it = merge->m_changedEdges.begin(); it != merge->m_changedEdges.end(); it++) { - index = *it; - m_G->delEdge(m_reverseEdgeIndex[index]); - m_reverseEdgeIndex[index] = m_G->newEdge(m_reverseNodeIndex[merge->m_source[index]], m_reverseNodeIndex[merge->m_target[index]], index); - m_weight[index] = merge->m_doubleWeight[index]; - } - - // undo node changes - for (it = merge->m_changedNodes.begin(); it != merge->m_changedNodes.end(); it++) { - index = *it; - m_radius[index] = merge->m_radius[index]; - m_reverseNodeMergeWeight[index] -= m_reverseNodeMergeWeight[merged->index()]; - } - - delete merge; - return merged; -} - - -edge MultilevelGraph::getEdge(unsigned int index) -{ - if (index >= m_reverseEdgeIndex.size()) { - return 0; - } - return m_reverseEdgeIndex[index]; -} - - -node MultilevelGraph::getNode(unsigned int index) -{ - if (index >= m_reverseNodeIndex.size()) { - return 0; - } - return m_reverseNodeIndex[index]; -} - - -void MultilevelGraph::initReverseIndizes() -{ - if (m_G->numberOfNodes() > 0) { - m_reverseNodeIndex.resize(m_G->maxNodeIndex()+1, 0); - } - if (m_G->numberOfNodes() > 0) { - m_reverseNodeMergeWeight.resize(m_G->maxNodeIndex()+1, 1); - } - if (m_G->numberOfEdges() > 0) { - m_reverseEdgeIndex.resize(m_G->maxEdgeIndex()+1, 0); - } -} - - -void MultilevelGraph::updateMergeWeights() -{ - node v; - forall_nodes(v, *m_G) { - m_reverseNodeMergeWeight[v->index()] = 1; - } - -} - - -void MultilevelGraph::updateReverseIndizes() -{ - if ((unsigned int)m_G->maxNodeIndex() >= m_reverseNodeIndex.size() || (unsigned int)m_G->maxEdgeIndex() >= m_reverseEdgeIndex.size()) { - initReverseIndizes(); - } - - node v; - forall_nodes(v, *m_G) { - m_reverseNodeIndex[v->index()] = v; - } - - edge e; - forall_edges(e, *m_G) { - m_reverseEdgeIndex[e->index()] = e; - } -} - - -void MultilevelGraph::writeGML(ostream &os) -{ - GraphAttributes GA(*m_G); - exportAttributesSimple(GA); - - GA.writeGML(os); -} - - -void MultilevelGraph::writeGML(const String &fileName) -{ - ofstream os(fileName.cstr()); - writeGML(os); -} - - -void MultilevelGraph::moveToZero() -{ - // move Graph to zero - node v; - double avg_x = 0.0; - double avg_y = 0.0; - forall_nodes(v, getGraph()) { - avg_x += x(v); - avg_y += y(v); - } - avg_x /= getGraph().numberOfNodes(); - avg_y /= getGraph().numberOfNodes(); - forall_nodes(v, getGraph()) { - x(v, x(v) - avg_x); - y(v, y(v) - avg_y); - } -} - - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/MultilevelLayout.cpp b/ext/OGDF/src/energybased/MultilevelLayout.cpp deleted file mode 100644 index 058a0ccad..000000000 --- a/ext/OGDF/src/energybased/MultilevelLayout.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * $Revision: 2620 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 16:28:52 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class MultilevelLayout - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "ogdf/energybased/MultilevelLayout.h" -#include "ogdf/energybased/SpringEmbedderFR.h" - -namespace ogdf { - -//! Sets the single level layout -void MultilevelLayout::setLayout(LayoutModule* L) -{ - m_mmm->setLevelLayoutModule(L); -} - - -//! Sets the method used for coarsening -void MultilevelLayout::setMultilevelBuilder(MultilevelBuilder* B) -{ - m_mmm->setMultilevelBuilder(B); -} - - -//! Sets the placement method used when refining the levels again. -void MultilevelLayout::setPlacer(InitialPlacer* P) -{ - m_mmm->setInitialPlacer(P); -} - - -MultilevelLayout::MultilevelLayout() -{ - m_mmm = new ModularMultilevelMixer(); - m_sc = new ScalingLayout(); - m_cs = new ComponentSplitterLayout(); - m_pp = new PreprocessorLayout(); - //initial placer, coarsener are the default - //modules of m_mmm. - //For the layout, we set a scaling layout with - //standard level layout FR. This scales the layout - //on each level (with a constant factor) and then applies the FR. - m_sc->setSecondaryLayout(new SpringEmbedderFR); - m_sc->setScalingType(ScalingLayout::st_relativeToDrawing); - m_sc->setLayoutRepeats(1); - - m_sc->setScaling(1.0, 1.5); - m_sc->setExtraScalingSteps(2); - m_mmm->setLevelLayoutModule(m_sc); - - // m_mmm->setLayoutRepeats(1); - // m_mmm->setAllEdgeLenghts(5.0); - // m_mmm->setAllNodeSizes(1.0); - - m_cs->setLayoutModule(m_mmm); - m_pp->setLayoutModule(m_cs); - m_pp->setRandomizePositions(true); - -}//constructor - - -void MultilevelLayout::call(GraphAttributes &GA, GraphConstraints &GC) -{ - //we assume that both structures work on the same graph - - OGDF_THROW(AlgorithmFailureException); -} - - -void MultilevelLayout::call(GraphAttributes &GA) -{ - MultilevelGraph MLG(GA); - - // Call the nested call, including preprocessing, - // component splitting, scaling, level layout. - m_pp->call(MLG); - - MLG.exportAttributes(GA); -} - -} //end namespace ogdf diff --git a/ext/OGDF/src/energybased/NMM.cpp b/ext/OGDF/src/energybased/NMM.cpp deleted file mode 100644 index 3c6692c2e..000000000 --- a/ext/OGDF/src/energybased/NMM.cpp +++ /dev/null @@ -1,2867 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class NMM (New Multipole Method). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include "numexcept.h" -#include - - -#define MIN_BOX_LENGTH 1e-300 - -#ifdef __BORLANDC__ - using _STL::log; -#else - using std::log; -#endif - - -namespace ogdf { - -NMM::NMM() -{ - //set MIN_NODE_NUMBER and using_NMM - MIN_NODE_NUMBER = 175; using_NMM = true; - - //setting predefined parameters - precision(4); particles_in_leaves(25); - tree_construction_way(FMMMLayout::rtcSubtreeBySubtree); - find_sm_cell(FMMMLayout::scfIteratively); -} - - -void NMM::calculate_repulsive_forces( - const Graph &G, - NodeArray & A, - NodeArray& F_rep) -{ - if(using_NMM) //use NewMultipoleMethod - calculate_repulsive_forces_by_NMM(G,A,F_rep); - else //used the exact naive way - calculate_repulsive_forces_by_exact_method(G,A,F_rep); -} - - -void NMM::calculate_repulsive_forces_by_NMM( - const Graph &G, - NodeArray& A, - NodeArray& F_rep) -{ - QuadTreeNM T; - node v; - DPoint nullpoint (0,0); - NodeArray F_direct(G); - NodeArray F_local_exp(G); - NodeArray F_multipole_exp(G); - List quad_tree_leaves; - - //initializations - - forall_nodes(v,G) - F_direct[v]=F_local_exp[v]=F_multipole_exp[v]=nullpoint; - - quad_tree_leaves.clear(); - if(tree_construction_way() == FMMMLayout::rtcPathByPath) - build_up_red_quad_tree_path_by_path(G,A,T); - else //tree_construction_way == FMMMLayout::rtcSubtreeBySubtree - build_up_red_quad_tree_subtree_by_subtree(G,A,T); - - form_multipole_expansions(A,T,quad_tree_leaves); - calculate_local_expansions_and_WSPRLS(A,T.get_root_ptr()); - transform_local_exp_to_forces(A,quad_tree_leaves,F_local_exp); - transform_multipole_exp_to_forces(A,quad_tree_leaves,F_multipole_exp); - calculate_neighbourcell_forces(A,quad_tree_leaves,F_direct); - add_rep_forces(G,F_direct,F_multipole_exp,F_local_exp,F_rep); - - delete_red_quad_tree_and_count_treenodes(T); -} - - -inline void NMM::calculate_repulsive_forces_by_exact_method( - const Graph &G, - NodeArray& A, - NodeArray& F_rep) -{ - ExactMethod.calculate_exact_repulsive_forces(G,A,F_rep); -} - - -void NMM::make_initialisations( - const Graph &G, - double bl, - DPoint d_l_c, - int p_i_l, - int p, - int t_c_w, - int f_s_c) -{ - if(G.numberOfNodes() >= MIN_NODE_NUMBER) //using_NMM - { - using_NMM = true; //indicate that NMM is used for force calculation - - particles_in_leaves(p_i_l); - precision(p); - tree_construction_way(t_c_w); - find_sm_cell(f_s_c); - down_left_corner = d_l_c; //Export this two values from FMMM - boxlength = bl; - init_binko(2* precision()); - init_power_of_2_array(); - } - else //use exact method - { - using_NMM = false; //indicate that exact method is used for force calculation - ExactMethod.make_initialisations(bl,d_l_c,0); - } -} - - -void NMM::deallocate_memory() -{ - if(using_NMM) { - free_binko(); - free_power_of_2_array(); - } -} - - -void NMM::update_boxlength_and_cornercoordinate(double b_l, DPoint d_l_c) -{ - if(using_NMM) { - boxlength = b_l; - down_left_corner = d_l_c; - } - else - ExactMethod.update_boxlength_and_cornercoordinate(b_l,d_l_c); -} - - -inline void NMM::init_power_of_2_array() -{ - int p = 1; - max_power_of_2_index = 30; - power_of_2 = new int[max_power_of_2_index+1]; - for(int i = 0; i<= max_power_of_2_index; i++) { - power_of_2[i] = p; - p*=2; - } -} - - -inline void NMM::free_power_of_2_array() -{ - delete [] power_of_2; -} - - -inline int NMM::power_of_two(int i) -{ - if(i <= max_power_of_2_index) - return power_of_2[i]; - else - return static_cast(pow(2.0,i)); -} - - -inline int NMM::maxboxindex (int level) -{ - if ((level < 0 )) { - cout <<"Failure NMM::maxboxindex :wrong level "<& A, - QuadTreeNM& T) -{ - List act_leaf_List,new_leaf_List; - List *act_leaf_List_ptr,*new_leaf_List_ptr,*help_ptr; - List act_x_List_copy,act_y_List_copy; - QuadTreeNodeNM *act_node_ptr; - - build_up_root_node(G,A,T); - - act_leaf_List.clear(); - new_leaf_List.clear(); - act_leaf_List.pushFront(T.get_root_ptr()); - act_leaf_List_ptr = &act_leaf_List; - new_leaf_List_ptr = &new_leaf_List; - - while(!act_leaf_List_ptr->empty()) - { - while(!act_leaf_List_ptr->empty()) - { - act_node_ptr = act_leaf_List_ptr->popFrontRet(); - make_copy_and_init_Lists(*(act_node_ptr->get_x_List_ptr()),act_x_List_copy, - *(act_node_ptr->get_y_List_ptr()),act_y_List_copy); - T.set_act_ptr(act_node_ptr); - decompose_subtreenode(T,act_x_List_copy,act_y_List_copy,*new_leaf_List_ptr); - } - help_ptr = act_leaf_List_ptr; - act_leaf_List_ptr = new_leaf_List_ptr; - new_leaf_List_ptr = help_ptr; - } -} - - -void NMM::make_copy_and_init_Lists( - List& L_x_orig, - List& L_x_copy, - List& L_y_orig, - List& L_y_copy) -{ - ListIterator origin_x_item,copy_x_item,origin_y_item,copy_y_item, - new_cross_ref_item; - ParticleInfo P_x_orig,P_y_orig,P_x_copy,P_y_copy; - bool L_x_orig_traversed = false; - bool L_y_orig_traversed = false; - - L_x_copy.clear(); - L_y_copy.clear(); - - origin_x_item = L_x_orig.begin(); - while(!L_x_orig_traversed) - { - //reset values - P_x_orig = *origin_x_item; - P_x_orig.set_subList_ptr(NULL); //clear subList_ptr - P_x_orig.set_copy_item(NULL); //clear copy_item - P_x_orig.unmark(); //unmark this element - P_x_orig.set_tmp_cross_ref_item(NULL);//clear tmp_cross_ref_item - - //update L_x_copy - P_x_copy = P_x_orig; - L_x_copy.pushBack(P_x_copy); - - //update L_x_orig - P_x_orig.set_copy_item(L_x_copy.rbegin()); - *origin_x_item = P_x_orig; - - if(origin_x_item != L_x_orig.rbegin()) - origin_x_item = L_x_orig.cyclicSucc(origin_x_item); - else - L_x_orig_traversed = true; - } - - origin_y_item = L_y_orig.begin(); - while(!L_y_orig_traversed) - { - //reset values - P_y_orig = *origin_y_item; - P_y_orig.set_subList_ptr(NULL); //clear subList_ptr - P_y_orig.set_copy_item(NULL); //clear copy_item - P_y_orig.set_tmp_cross_ref_item(NULL);//clear tmp_cross_ref_item - P_y_orig.unmark(); //unmark this element - - //update L_x(y)_copy - P_y_copy = P_y_orig; - new_cross_ref_item = (*P_y_orig.get_cross_ref_item()).get_copy_item(); - P_y_copy.set_cross_ref_item(new_cross_ref_item); - L_y_copy.pushBack(P_y_copy); - P_x_copy = *new_cross_ref_item; - P_x_copy.set_cross_ref_item(L_y_copy.rbegin()); - *new_cross_ref_item = P_x_copy; - - //update L_y_orig - P_y_orig.set_copy_item(L_y_copy.rbegin()); - *origin_y_item = P_y_orig; - - if(origin_y_item != L_y_orig.rbegin()) - origin_y_item = L_y_orig.cyclicSucc(origin_y_item); - else - L_y_orig_traversed = true; - } -} - - -void NMM::build_up_root_node( - const Graph& G, - NodeArray& A, - QuadTreeNM& T) -{ - T.init_tree(); - T.get_root_ptr()->set_Sm_level(0); - T.get_root_ptr()->set_Sm_downleftcorner(down_left_corner); - T.get_root_ptr()->set_Sm_boxlength(boxlength); - //allocate space for L_x and L_y List of the root node - T.get_root_ptr()->set_x_List_ptr(OGDF_NEW List); - T.get_root_ptr()->set_y_List_ptr(OGDF_NEW List); - create_sorted_coordinate_Lists(G, A, *(T.get_root_ptr()->get_x_List_ptr()), *(T.get_root_ptr()->get_y_List_ptr())); -} - - -void NMM::create_sorted_coordinate_Lists( - const Graph& G, - NodeArray & A, - List& L_x, - List& L_y) -{ - ParticleInfo P_x,P_y; - ListIterator x_item,y_item; - node v; - - //build up L_x,L_y and link the Lists - forall_nodes(v,G) - { - P_x.set_x_y_coord(A[v].get_x()); - P_y.set_x_y_coord(A[v].get_y()); - P_x.set_vertex(v); - P_y.set_vertex(v); - L_x.pushBack(P_x); - L_y.pushBack(P_y); - P_x.set_cross_ref_item(L_y.rbegin()); - P_y.set_cross_ref_item(L_x.rbegin()); - *L_x.rbegin() = P_x; - *L_y.rbegin() = P_y; - } - - - //sort L_x and update the links of L_y - ParticleInfoComparer comp; - L_x.quicksort(comp);//Quicksort L_x - - for(x_item = L_x.begin(); x_item.valid();++x_item) - { - y_item = (*x_item).get_cross_ref_item(); - P_y = *y_item; - P_y.set_cross_ref_item(x_item); - *y_item = P_y; - } - - //sort L_y and update the links of L_x - L_y.quicksort(comp);//Quicksort L_x - - for(y_item = L_y.begin(); y_item.valid();++y_item) - { - x_item = (*y_item).get_cross_ref_item(); - P_x = *x_item; - P_x.set_cross_ref_item(y_item); - *x_item = P_x; - } -} - - -void NMM::decompose_subtreenode( - QuadTreeNM& T, - List& act_x_List_copy, - List& act_y_List_copy, - List& new_leaf_List) -{ - QuadTreeNodeNM* act_ptr = T.get_act_ptr(); - int act_particle_number = act_ptr->get_x_List_ptr()->size(); - double x_min,x_max,y_min,y_max; - List *L_x_l_ptr,*L_x_r_ptr,*L_x_lb_ptr,*L_x_rb_ptr,*L_x_lt_ptr, - *L_x_rt_ptr; - List *L_y_l_ptr,*L_y_r_ptr,*L_y_lb_ptr,*L_y_rb_ptr,*L_y_lt_ptr, - *L_y_rt_ptr; - - L_x_l_ptr = L_x_r_ptr = L_x_lb_ptr = L_x_lt_ptr = L_x_rb_ptr = L_x_rt_ptr = NULL; - L_y_l_ptr = L_y_r_ptr = L_y_lb_ptr = L_y_lt_ptr = L_y_rb_ptr = L_y_rt_ptr = NULL; - - calculate_boundaries_of_act_node(T.get_act_ptr(),x_min,x_max,y_min,y_max); - if(find_sm_cell() == FMMMLayout::scfIteratively) - find_small_cell_iteratively(T.get_act_ptr(),x_min,x_max,y_min,y_max); - else //find_small_cell == FMMMLayout::scfAluru - find_small_cell_iteratively(T.get_act_ptr(),x_min,x_max,y_min,y_max); - - if( (act_particle_number > particles_in_leaves()) && - ((x_max-x_min >=MIN_BOX_LENGTH) || (y_max-y_min >= MIN_BOX_LENGTH ))) - {//if0 - - //recursive calls for the half of the quad that contains the most particles - - split_in_x_direction(act_ptr,L_x_l_ptr,L_y_l_ptr, - L_x_r_ptr,L_y_r_ptr); - if((L_x_r_ptr == NULL) || - (L_x_l_ptr != NULL && L_x_l_ptr->size() > L_x_r_ptr->size())) - {//if1 left half contains more particles - split_in_y_direction(act_ptr,L_x_lb_ptr, - L_y_lb_ptr,L_x_lt_ptr,L_y_lt_ptr); - if((L_x_lt_ptr == NULL)|| - (L_x_lb_ptr != NULL && L_x_lb_ptr->size() > L_x_lt_ptr->size())) - {//if2 - T.create_new_lb_child(L_x_lb_ptr,L_y_lb_ptr); - T.go_to_lb_child(); - decompose_subtreenode(T,act_x_List_copy,act_y_List_copy,new_leaf_List); - T.go_to_father(); - }//if2 - else //L_x_lt_ptr != NULL && L_x_lb_ptr->size() <= L_x_lt_ptr->size() - {//else1 - T.create_new_lt_child(L_x_lt_ptr,L_y_lt_ptr); - T.go_to_lt_child(); - decompose_subtreenode(T,act_x_List_copy,act_y_List_copy,new_leaf_List); - T.go_to_father(); - }//else1 - }//if1 - else //L_x_r_ptr != NULL && (L_x_l_ptr->size() <= L_x_r_ptr->size()) - {//else2 right half contains more particles - split_in_y_direction(act_ptr,L_x_rb_ptr, - L_y_rb_ptr,L_x_rt_ptr,L_y_rt_ptr); - if ((L_x_rt_ptr == NULL) || - (L_x_rb_ptr != NULL && L_x_rb_ptr->size() > L_x_rt_ptr->size())) - {//if3 - T.create_new_rb_child(L_x_rb_ptr,L_y_rb_ptr); - T.go_to_rb_child(); - decompose_subtreenode(T,act_x_List_copy,act_y_List_copy,new_leaf_List); - T.go_to_father(); - }//if3 - else// L_x_rt_ptr != NULL && L_x_rb_ptr->size() <= L_x_rt_ptr->size() - {//else3 - T.create_new_rt_child(L_x_rt_ptr,L_y_rt_ptr); - T.go_to_rt_child(); - decompose_subtreenode(T,act_x_List_copy,act_y_List_copy,new_leaf_List); - T.go_to_father(); - }//else3 - }//else2 - - //build up the rest of the quad-subLists - - if( L_x_l_ptr != NULL && L_x_lb_ptr == NULL && L_x_lt_ptr == NULL && - !act_ptr->child_lb_exists() && !act_ptr->child_lt_exists() ) - split_in_y_direction(act_ptr,L_x_l_ptr,L_x_lb_ptr,L_x_lt_ptr,L_y_l_ptr, - L_y_lb_ptr,L_y_lt_ptr); - else if( L_x_r_ptr != NULL && L_x_rb_ptr == NULL && L_x_rt_ptr == NULL && - !act_ptr->child_rb_exists() && !act_ptr->child_rt_exists() ) - split_in_y_direction(act_ptr,L_x_r_ptr,L_x_rb_ptr,L_x_rt_ptr,L_y_r_ptr, - L_y_rb_ptr,L_y_rt_ptr); - - //create rest of the childnodes - if((!act_ptr->child_lb_exists()) && (L_x_lb_ptr != NULL)) - { - T.create_new_lb_child(L_x_lb_ptr,L_y_lb_ptr); - T.go_to_lb_child(); - new_leaf_List.pushBack(T.get_act_ptr()); - T.go_to_father(); - } - if((!act_ptr->child_lt_exists()) && (L_x_lt_ptr != NULL)) - { - T.create_new_lt_child(L_x_lt_ptr,L_y_lt_ptr); - T.go_to_lt_child(); - new_leaf_List.pushBack(T.get_act_ptr()); - T.go_to_father(); - } - if((!act_ptr->child_rb_exists()) && (L_x_rb_ptr != NULL)) - { - T.create_new_rb_child(L_x_rb_ptr,L_y_rb_ptr); - T.go_to_rb_child(); - new_leaf_List.pushBack(T.get_act_ptr()); - T.go_to_father(); - } - if((!act_ptr->child_rt_exists()) && (L_x_rt_ptr != NULL)) - { - T.create_new_rt_child(L_x_rt_ptr,L_y_rt_ptr); - T.go_to_rt_child(); - new_leaf_List.pushBack(T.get_act_ptr()); - T.go_to_father(); - } - //reset act_ptr->set_x(y)_List_ptr to avoid multiple deleting of dynamic memory; - //(only if *act_ptr is a leaf of T the reserved space is freed (and this is - //sufficient !!!)) - act_ptr->set_x_List_ptr(NULL); - act_ptr->set_y_List_ptr(NULL); - }//if0 - else - { //else a leaf or machineprecision is reached: - //The List contained_nodes is set for *act_ptr and the information of - //act_x_List_copy and act_y_List_copy is used to insert particles into the - //shorter Lists of previous touched treenodes;additionaly the dynamical allocated - //space for *act_ptr->get_x(y)_List_ptr() is freed. - - List L; - ListIterator it; - - //set List contained nodes - - L.clear(); - for(it = act_ptr->get_x_List_ptr()->begin();it.valid();++it) - L.pushBack((*it).get_vertex()); - T.get_act_ptr()->set_contained_nodes(L); - - //insert particles into previous touched Lists - - build_up_sorted_subLists(act_x_List_copy,act_y_List_copy); - - //free allocated space for *act_ptr->get_x(y)_List_ptr() - act_ptr->get_x_List_ptr()->clear();//free used space for old L_x,L_y Lists - act_ptr->get_y_List_ptr()->clear(); - }//else -} - - -inline void NMM::calculate_boundaries_of_act_node( - QuadTreeNodeNM* act_ptr, - double& x_min, - double& x_max, - double& y_min, - double& y_max) -{ - List* L_x_ptr = act_ptr->get_x_List_ptr(); - List* L_y_ptr = act_ptr->get_y_List_ptr(); - - x_min = (*L_x_ptr->begin()).get_x_y_coord(); - x_max = (*L_x_ptr->rbegin()).get_x_y_coord(); - y_min = (*L_y_ptr->begin()).get_x_y_coord(); - y_max = (*L_y_ptr->rbegin()).get_x_y_coord(); -} - - -bool NMM::in_lt_quad( - QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max) -{ - double l = act_ptr->get_Sm_downleftcorner().m_x; - double r = act_ptr->get_Sm_downleftcorner().m_x+act_ptr->get_Sm_boxlength()/2; - double b = act_ptr->get_Sm_downleftcorner().m_y+act_ptr->get_Sm_boxlength()/2; - double t = act_ptr->get_Sm_downleftcorner().m_y+act_ptr->get_Sm_boxlength(); - - if(l <= x_min && x_max < r && b <= y_min && y_max < t ) - return true; - else if(x_min == x_max && y_min == y_max && l==r && t == b && x_min ==r && y_min ==b) - return true; - else - return false; -} - - -bool NMM::in_rt_quad( - QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max) -{ - double l = act_ptr->get_Sm_downleftcorner().m_x+act_ptr->get_Sm_boxlength()/2; - double r = act_ptr->get_Sm_downleftcorner().m_x+act_ptr->get_Sm_boxlength(); - double b = act_ptr->get_Sm_downleftcorner().m_y+act_ptr->get_Sm_boxlength()/2; - double t = act_ptr->get_Sm_downleftcorner().m_y+act_ptr->get_Sm_boxlength(); - - if(l <= x_min && x_max < r && b <= y_min && y_max < t ) - return true; - else if(x_min == x_max && y_min == y_max && l==r && t == b && x_min ==r && y_min ==b) - return true; - else - return false; -} - - -bool NMM::in_lb_quad( - QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max) -{ - double l = act_ptr->get_Sm_downleftcorner().m_x; - double r = act_ptr->get_Sm_downleftcorner().m_x+act_ptr->get_Sm_boxlength()/2; - double b = act_ptr->get_Sm_downleftcorner().m_y; - double t = act_ptr->get_Sm_downleftcorner().m_y+act_ptr->get_Sm_boxlength()/2; - - if(l <= x_min && x_max < r && b <= y_min && y_max < t ) - return true; - else if(x_min == x_max && y_min == y_max && l==r && t == b && x_min ==r && y_min ==b) - return true; - else - return false; -} - - -bool NMM::in_rb_quad( - QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max) -{ - double l = act_ptr->get_Sm_downleftcorner().m_x+act_ptr->get_Sm_boxlength()/2; - double r = act_ptr->get_Sm_downleftcorner().m_x+act_ptr->get_Sm_boxlength(); - double b = act_ptr->get_Sm_downleftcorner().m_y; - double t = act_ptr->get_Sm_downleftcorner().m_y+act_ptr->get_Sm_boxlength()/2; - - if(l <= x_min && x_max < r && b <= y_min && y_max < t ) - return true; - else if(x_min == x_max && y_min == y_max && l==r && t == b && x_min ==r && y_min ==b) - return true; - else - return false; -} - - -void NMM::split_in_x_direction( - QuadTreeNodeNM* act_ptr, - List *& L_x_left_ptr, - List*& L_y_left_ptr, - List *& L_x_right_ptr, - List*& L_y_right_ptr) -{ - ListIterator l_item = act_ptr->get_x_List_ptr()->begin(); - ListIterator r_item = act_ptr->get_x_List_ptr()->rbegin(); - ListIterator last_left_item; - double act_Sm_boxlength_half = act_ptr->get_Sm_boxlength()/2; - double x_mid_coord = act_ptr->get_Sm_downleftcorner().m_x+ act_Sm_boxlength_half; - double l_xcoord,r_xcoord; - bool last_left_item_found = false; - bool left_particleList_empty = false; - bool right_particleList_empty = false; - bool left_particleList_larger = true; - - //traverse *act_ptr->get_x_List_ptr() from left and right - - while(!last_left_item_found) - {//while - l_xcoord = (*l_item).get_x_y_coord(); - r_xcoord = (*r_item).get_x_y_coord(); - if(l_xcoord >= x_mid_coord) - { - left_particleList_larger = false; - last_left_item_found = true; - if(l_item != act_ptr->get_x_List_ptr()->begin()) - last_left_item = act_ptr->get_x_List_ptr()->cyclicPred(l_item); - else - left_particleList_empty = true; - } - else if(r_xcoord < x_mid_coord) - { - last_left_item_found = true; - if(r_item != act_ptr->get_x_List_ptr()->rbegin()) - last_left_item = r_item; - else - right_particleList_empty = true; - } - if(!last_left_item_found) - { - l_item = act_ptr->get_x_List_ptr()->cyclicSucc(l_item); - r_item = act_ptr->get_x_List_ptr()->cyclicPred(r_item); - } - }//while - - //get the L_x(y) Lists of the bigger half (from *act_ptr->get_x(y)_List_ptr)) - //and make entries in L_x_copy,L_y_copy for the smaller halfs - - if(left_particleList_empty) - { - L_x_left_ptr = NULL; - L_y_left_ptr = NULL; - L_x_right_ptr = act_ptr->get_x_List_ptr(); - L_y_right_ptr = act_ptr->get_y_List_ptr(); - } - else if(right_particleList_empty) - { - L_x_left_ptr = act_ptr->get_x_List_ptr(); - L_y_left_ptr = act_ptr->get_y_List_ptr(); - L_x_right_ptr = NULL; - L_y_right_ptr = NULL; - } - else if(left_particleList_larger) - x_delete_right_subLists(act_ptr,L_x_left_ptr,L_y_left_ptr, - L_x_right_ptr,L_y_right_ptr,last_left_item); - else //left particleList is smaller or equal to right particleList - x_delete_left_subLists(act_ptr,L_x_left_ptr,L_y_left_ptr, - L_x_right_ptr,L_y_right_ptr,last_left_item); -} - - -void NMM::split_in_y_direction( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List*& L_y_left_ptr, - List*& L_x_right_ptr, - List*& L_y_right_ptr) -{ - ListIterator l_item = act_ptr->get_y_List_ptr()->begin(); - ListIterator r_item = act_ptr->get_y_List_ptr()->rbegin(); - ListIterator last_left_item; - double act_Sm_boxlength_half = act_ptr->get_Sm_boxlength()/2; - double y_mid_coord = act_ptr->get_Sm_downleftcorner().m_y+ act_Sm_boxlength_half; - double l_ycoord,r_ycoord; - bool last_left_item_found = false; - bool left_particleList_empty = false; - bool right_particleList_empty = false; - bool left_particleList_larger = true; - //traverse *act_ptr->get_y_List_ptr() from left and right - - while(!last_left_item_found) - {//while - l_ycoord = (*l_item).get_x_y_coord(); - r_ycoord = (*r_item).get_x_y_coord(); - if(l_ycoord >= y_mid_coord) - { - left_particleList_larger = false; - last_left_item_found = true; - if(l_item != act_ptr->get_y_List_ptr()->begin()) - last_left_item = act_ptr->get_y_List_ptr()->cyclicPred(l_item); - else - left_particleList_empty = true; - } - else if(r_ycoord < y_mid_coord) - { - last_left_item_found = true; - if(r_item != act_ptr->get_y_List_ptr()->rbegin()) - last_left_item = r_item; - else - right_particleList_empty = true; - } - if(!last_left_item_found) - { - l_item = act_ptr->get_y_List_ptr()->cyclicSucc(l_item); - r_item = act_ptr->get_y_List_ptr()->cyclicPred(r_item); - } - }//while - - //get the L_x(y) Lists of the bigger half (from *act_ptr->get_x(y)_List_ptr)) - //and make entries in L_x_copy,L_y_copy for the smaller halfs - - if(left_particleList_empty) - { - L_x_left_ptr = NULL; - L_y_left_ptr = NULL; - L_x_right_ptr = act_ptr->get_x_List_ptr(); - L_y_right_ptr = act_ptr->get_y_List_ptr(); - } - else if(right_particleList_empty) - { - L_x_left_ptr = act_ptr->get_x_List_ptr(); - L_y_left_ptr = act_ptr->get_y_List_ptr(); - L_x_right_ptr = NULL; - L_y_right_ptr = NULL; - } - else if(left_particleList_larger) - y_delete_right_subLists(act_ptr,L_x_left_ptr,L_y_left_ptr, - L_x_right_ptr,L_y_right_ptr,last_left_item); - else //left particleList is smaller or equal to right particleList - y_delete_left_subLists(act_ptr,L_x_left_ptr,L_y_left_ptr, - L_x_right_ptr,L_y_right_ptr,last_left_item); -} - - -void NMM::x_delete_right_subLists( - QuadTreeNodeNM* act_ptr, - List *& L_x_left_ptr, - List*& L_y_left_ptr, - List *& L_x_right_ptr, - List*& L_y_right_ptr, - ListIterator last_left_item) -{ - ParticleInfo act_p_info,p_in_L_x_info,p_in_L_y_info,del_p_info; - ListIterator act_item,p_in_L_x_item,p_in_L_y_item,del_item; - bool last_item_reached =false; - - L_x_left_ptr = act_ptr->get_x_List_ptr(); - L_y_left_ptr = act_ptr->get_y_List_ptr(); - L_x_right_ptr = OGDF_NEW List; - L_y_right_ptr = OGDF_NEW List; - - act_item = L_x_left_ptr->cyclicSucc(last_left_item); - - while(!last_item_reached) - {//while - act_p_info = *act_item; - del_item = act_item; - del_p_info = act_p_info; - - //save references for *L_x(y)_right_ptr in L_x(y)_copy - p_in_L_x_item = act_p_info.get_copy_item(); - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.set_subList_ptr(L_x_right_ptr); - *p_in_L_x_item = p_in_L_x_info; - - p_in_L_y_item = (*act_p_info.get_cross_ref_item()).get_copy_item(); - p_in_L_y_info = *p_in_L_y_item; - p_in_L_y_info.set_subList_ptr(L_y_right_ptr); - *p_in_L_y_item = p_in_L_y_info; - - if(act_item != L_x_left_ptr->rbegin()) - act_item = L_x_left_ptr->cyclicSucc(act_item); - else - last_item_reached = true; - - //create *L_x(y)_left_ptr - L_y_left_ptr->del(del_p_info.get_cross_ref_item()); - L_x_left_ptr->del(del_item); - }//while -} - - -void NMM::x_delete_left_subLists( - QuadTreeNodeNM* act_ptr, - List *& L_x_left_ptr, - List*& L_y_left_ptr, - List *& L_x_right_ptr, - List*& L_y_right_ptr, - ListIterator last_left_item) -{ - ParticleInfo act_p_info,p_in_L_x_info,p_in_L_y_info,del_p_info; - ListIterator act_item,p_in_L_x_item,p_in_L_y_item,del_item; - bool last_item_reached =false; - - L_x_right_ptr = act_ptr->get_x_List_ptr(); - L_y_right_ptr = act_ptr->get_y_List_ptr(); - L_x_left_ptr = OGDF_NEW List; - L_y_left_ptr = OGDF_NEW List; - - act_item = L_x_right_ptr->begin(); - - while(!last_item_reached) - {//while - act_p_info = *act_item; - del_item = act_item; - del_p_info = act_p_info; - - //save references for *L_x(y)_right_ptr in L_x(y)_copy - p_in_L_x_item = act_p_info.get_copy_item(); - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.set_subList_ptr(L_x_left_ptr); - *p_in_L_x_item = p_in_L_x_info; - - p_in_L_y_item =(*act_p_info.get_cross_ref_item()).get_copy_item(); - p_in_L_y_info = *p_in_L_y_item; - p_in_L_y_info.set_subList_ptr(L_y_left_ptr); - *p_in_L_y_item = p_in_L_y_info; - - if(act_item != last_left_item) - act_item = L_x_right_ptr->cyclicSucc(act_item); - else - last_item_reached = true; - - //create *L_x(y)_right_ptr - L_y_right_ptr->del(del_p_info.get_cross_ref_item()); - L_x_right_ptr->del(del_item); - }//while -} - - -void NMM::y_delete_right_subLists( - QuadTreeNodeNM* act_ptr, - List *& L_x_left_ptr, - List*& L_y_left_ptr, - List *& L_x_right_ptr, - List*& L_y_right_ptr, - ListIterator last_left_item) -{ - ParticleInfo act_p_info,p_in_L_x_info,p_in_L_y_info,del_p_info; - ListIterator act_item,p_in_L_x_item,p_in_L_y_item,del_item; - bool last_item_reached =false; - - L_x_left_ptr = act_ptr->get_x_List_ptr(); - L_y_left_ptr = act_ptr->get_y_List_ptr(); - L_x_right_ptr = OGDF_NEW List; - L_y_right_ptr = OGDF_NEW List; - - act_item = L_y_left_ptr->cyclicSucc(last_left_item); - - while(!last_item_reached) - {//while - act_p_info = *act_item; - del_item = act_item; - del_p_info = act_p_info; - - //save references for *L_x(y)_right_ptr in L_x(y)_copy - p_in_L_y_item = act_p_info.get_copy_item(); - p_in_L_y_info = *p_in_L_y_item; - p_in_L_y_info.set_subList_ptr(L_y_right_ptr); - *p_in_L_y_item = p_in_L_y_info; - - p_in_L_x_item = (*act_p_info.get_cross_ref_item()).get_copy_item(); - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.set_subList_ptr(L_x_right_ptr); - *p_in_L_x_item = p_in_L_x_info; - - if(act_item != L_y_left_ptr->rbegin()) - act_item = L_y_left_ptr->cyclicSucc(act_item); - else - last_item_reached = true; - - //create *L_x(y)_left_ptr - L_x_left_ptr->del(del_p_info.get_cross_ref_item()); - L_y_left_ptr->del(del_item); - }//while -} - - -void NMM::y_delete_left_subLists( - QuadTreeNodeNM* act_ptr, - List*& L_x_left_ptr, - List*& L_y_left_ptr, - List *& L_x_right_ptr, - List*& L_y_right_ptr, - ListIterator last_left_item) -{ - ParticleInfo act_p_info,p_in_L_x_info,p_in_L_y_info,del_p_info; - ListIterator act_item,p_in_L_x_item,p_in_L_y_item,del_item; - bool last_item_reached =false; - - L_x_right_ptr = act_ptr->get_x_List_ptr(); - L_y_right_ptr = act_ptr->get_y_List_ptr(); - L_x_left_ptr = OGDF_NEW List; - L_y_left_ptr = OGDF_NEW List; - - act_item = L_y_right_ptr->begin(); - - while(!last_item_reached) - {//while - act_p_info = *act_item; - del_item = act_item; - del_p_info = act_p_info; - - //save references for *L_x(y)_right_ptr in L_x(y)_copy - p_in_L_y_item = act_p_info.get_copy_item(); - p_in_L_y_info = *p_in_L_y_item; - p_in_L_y_info.set_subList_ptr(L_y_left_ptr); - *p_in_L_y_item = p_in_L_y_info; - - p_in_L_x_item = (*act_p_info.get_cross_ref_item()).get_copy_item(); - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.set_subList_ptr(L_x_left_ptr); - *p_in_L_x_item = p_in_L_x_info; - - if(act_item != last_left_item) - act_item = L_y_right_ptr->cyclicSucc(act_item); - else - last_item_reached = true; - - //create *L_x(y)_right_ptr - L_x_right_ptr->del(del_p_info.get_cross_ref_item()); - L_y_right_ptr->del(del_item); - }//while -} - - -void NMM::split_in_y_direction( - QuadTreeNodeNM* act_ptr, - List*& L_x_ptr, - List*& L_x_b_ptr, - List*& L_x_t_ptr, - List*& L_y_ptr, - List*& L_y_b_ptr, - List*& L_y_t_ptr) -{ - ListIterator l_item = L_y_ptr->begin(); - ListIterator r_item = L_y_ptr->rbegin(); - ListIterator last_left_item; - double act_Sm_boxlength_half = act_ptr->get_Sm_boxlength()/2; - double y_mid_coord = act_ptr->get_Sm_downleftcorner().m_y+ act_Sm_boxlength_half; - double l_ycoord,r_ycoord; - bool last_left_item_found = false; - bool left_particleList_empty = false; - bool right_particleList_empty = false; - bool left_particleList_larger = true; - - //traverse *L_y_ptr from left and right - - while(!last_left_item_found) - {//while - l_ycoord = (*l_item).get_x_y_coord(); - r_ycoord = (*r_item).get_x_y_coord(); - if(l_ycoord >= y_mid_coord) - { - left_particleList_larger = false; - last_left_item_found = true; - if(l_item != L_y_ptr->begin()) - last_left_item = L_y_ptr->cyclicPred(l_item); - else - left_particleList_empty = true; - } - else if(r_ycoord < y_mid_coord) - { - last_left_item_found = true; - if(r_item != L_y_ptr->rbegin()) - last_left_item = r_item; - else - right_particleList_empty = true; - } - if(!last_left_item_found) - { - l_item = L_y_ptr->cyclicSucc(l_item); - r_item = L_y_ptr->cyclicPred(r_item); - } - }//while - - //create *L_x_l(b)_ptr - - if(left_particleList_empty) - { - L_x_b_ptr = NULL; - L_y_b_ptr = NULL; - L_x_t_ptr = L_x_ptr; - L_y_t_ptr = L_y_ptr; - } - else if(right_particleList_empty) - { - L_x_b_ptr = L_x_ptr; - L_y_b_ptr = L_y_ptr; - L_x_t_ptr = NULL; - L_y_t_ptr = NULL; - } - else if(left_particleList_larger) - y_move_right_subLists(L_x_ptr,L_x_b_ptr,L_x_t_ptr,L_y_ptr,L_y_b_ptr,L_y_t_ptr, - last_left_item); - else //left particleList is smaller or equal to right particleList - y_move_left_subLists(L_x_ptr,L_x_b_ptr,L_x_t_ptr,L_y_ptr,L_y_b_ptr,L_y_t_ptr, - last_left_item); -} - - -void NMM::y_move_left_subLists( - List*& L_x_ptr, - List *& L_x_l_ptr, - List*& L_x_r_ptr, - List*& L_y_ptr, - List *& L_y_l_ptr, - List*& L_y_r_ptr, - ListIterator last_left_item) -{ - ParticleInfo p_in_L_x_info,p_in_L_y_info; - ListIterator p_in_L_x_item,p_in_L_y_item,del_item; - bool last_item_reached =false; - - L_x_r_ptr = L_x_ptr; - L_y_r_ptr = L_y_ptr; - L_x_l_ptr = OGDF_NEW List; - L_y_l_ptr = OGDF_NEW List; - - p_in_L_y_item = L_y_r_ptr->begin(); - - //build up the L_y_Lists and update crossreferences in *L_x_l_ptr - while(!last_item_reached) - {//while - p_in_L_y_info = *p_in_L_y_item; - del_item = p_in_L_y_item; - - //create *L_x(y)_l_ptr - L_y_l_ptr->pushBack(p_in_L_y_info); - p_in_L_x_item = p_in_L_y_info.get_cross_ref_item(); - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.set_cross_ref_item(L_y_l_ptr->rbegin()); - p_in_L_x_info.mark(); //mark this element of the List - *p_in_L_x_item = p_in_L_x_info; - - if(p_in_L_y_item != last_left_item) - p_in_L_y_item = L_y_r_ptr->cyclicSucc(p_in_L_y_item); - else - last_item_reached = true; - - //create *L_y_r_ptr - L_y_r_ptr->del(del_item); - }//while - - //build up the L_x Lists and update crossreferences in *L_y_l_ptr - - last_item_reached = false; - p_in_L_x_item = L_x_r_ptr->begin(); - - while(!last_item_reached) - {//while - del_item = p_in_L_x_item; - - if((*del_item).is_marked()) - { - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.unmark(); - L_x_l_ptr->pushBack(p_in_L_x_info); - p_in_L_y_item = p_in_L_x_info.get_cross_ref_item(); - p_in_L_y_info = *p_in_L_y_item; - p_in_L_y_info.set_cross_ref_item(L_x_l_ptr->rbegin()); - *p_in_L_y_item = p_in_L_y_info; - } - - if(p_in_L_x_item != L_x_r_ptr->rbegin()) - p_in_L_x_item = L_x_r_ptr->cyclicSucc(p_in_L_x_item); - else - last_item_reached = true; - - //create *L_x_r_ptr - if((*del_item).is_marked()) - L_x_r_ptr->del(del_item); - }//while -} - - -void NMM::y_move_right_subLists( - List*& L_x_ptr, - List *& L_x_l_ptr, - List*& L_x_r_ptr, - List*& L_y_ptr, - List *& L_y_l_ptr, - List*& L_y_r_ptr, - ListIterator last_left_item) -{ - ParticleInfo p_in_L_x_info,p_in_L_y_info; - ListIterator p_in_L_x_item,p_in_L_y_item,del_item; - bool last_item_reached =false; - - L_x_l_ptr = L_x_ptr; - L_y_l_ptr = L_y_ptr; - L_x_r_ptr = OGDF_NEW List; - L_y_r_ptr = OGDF_NEW List; - - p_in_L_y_item = L_y_l_ptr->cyclicSucc(last_left_item); - - //build up the L_y_Lists and update crossreferences in *L_x_r_ptr - while(!last_item_reached) - {//while - p_in_L_y_info = *p_in_L_y_item; - del_item = p_in_L_y_item; - - //create *L_x(y)_r_ptr - L_y_r_ptr->pushBack(p_in_L_y_info); - p_in_L_x_item = p_in_L_y_info.get_cross_ref_item(); - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.set_cross_ref_item(L_y_r_ptr->rbegin()); - p_in_L_x_info.mark(); //mark this element of the List - *p_in_L_x_item = p_in_L_x_info; - - if(p_in_L_y_item != L_y_l_ptr->rbegin()) - p_in_L_y_item = L_y_l_ptr->cyclicSucc(p_in_L_y_item); - else - last_item_reached = true; - - //create *L_y_l_ptr - L_y_l_ptr->del(del_item); - }//while - - //build up the L_x Lists and update crossreferences in *L_y_r_ptr - - last_item_reached = false; - p_in_L_x_item = L_x_l_ptr->begin(); - - while(!last_item_reached) - {//while - del_item = p_in_L_x_item; - - if((*del_item).is_marked()) - { - p_in_L_x_info = *p_in_L_x_item; - p_in_L_x_info.unmark(); - L_x_r_ptr->pushBack(p_in_L_x_info); - p_in_L_y_item = p_in_L_x_info.get_cross_ref_item(); - p_in_L_y_info = *p_in_L_y_item; - p_in_L_y_info.set_cross_ref_item(L_x_r_ptr->rbegin()); - *p_in_L_y_item = p_in_L_y_info; - } - - if(p_in_L_x_item != L_x_l_ptr->rbegin()) - p_in_L_x_item = L_x_l_ptr->cyclicSucc(p_in_L_x_item); - else - last_item_reached = true; - - //create *L_x_r_ptr - if((*del_item).is_marked()) - L_x_l_ptr->del(del_item); - }//while -} - - -void NMM::build_up_sorted_subLists( - List& L_x_copy, - List& L_y_copy) -{ - ParticleInfo P_x,P_y; - List *L_x_ptr,*L_y_ptr; - ListIterator it,new_cross_ref_item; - - for(it = L_x_copy.begin();it.valid();++it) - if((*it).get_subList_ptr() != NULL) - { - //reset values - P_x = *it; - L_x_ptr = P_x.get_subList_ptr(); - P_x.set_subList_ptr(NULL); //clear subList_ptr - P_x.set_copy_item(NULL); //clear copy_item - P_x.unmark(); //unmark this element - P_x.set_tmp_cross_ref_item(NULL);//clear tmp_cross_ref_item - - //update *L_x_ptr - L_x_ptr->pushBack(P_x); - - //update L_x_copy - P_x.set_tmp_cross_ref_item(L_x_ptr->rbegin()); - *it = P_x; - } - - for(it = L_y_copy.begin();it.valid();++it) - if((*it).get_subList_ptr() != NULL) - { - //reset values - P_y = *it; - L_y_ptr = P_y.get_subList_ptr(); - P_y.set_subList_ptr(NULL); //clear subList_ptr - P_y.set_copy_item(NULL); //clear copy_item - P_y.unmark(); //unmark this element - P_y.set_tmp_cross_ref_item(NULL);//clear tmp_cross_ref_item - - //update *L_x(y)_ptr - - new_cross_ref_item = (*P_y.get_cross_ref_item()).get_tmp_cross_ref_item(); - P_y.set_cross_ref_item(new_cross_ref_item); - L_y_ptr->pushBack(P_y); - P_x = *new_cross_ref_item; - P_x.set_cross_ref_item(L_y_ptr->rbegin()); - *new_cross_ref_item = P_x; - } -} - - -// **********Functions needed for subtree by subtree tree construction(Begin)********* - -void NMM::build_up_red_quad_tree_subtree_by_subtree( - const Graph& G, - NodeArray& A, - QuadTreeNM& T) -{ - List act_subtree_root_List,new_subtree_root_List; - List *act_subtree_root_List_ptr,*new_subtree_root_List_ptr,*help_ptr; - QuadTreeNodeNM *subtree_root_ptr; - - build_up_root_vertex(G,T); - - act_subtree_root_List.clear(); - new_subtree_root_List.clear(); - act_subtree_root_List.pushFront(T.get_root_ptr()); - act_subtree_root_List_ptr = &act_subtree_root_List; - new_subtree_root_List_ptr = &new_subtree_root_List; - - while(!act_subtree_root_List_ptr->empty()) - { - while(!act_subtree_root_List_ptr->empty()) - { - subtree_root_ptr = act_subtree_root_List_ptr->popFrontRet(); - construct_subtree(A,T,subtree_root_ptr,*new_subtree_root_List_ptr); - } - help_ptr = act_subtree_root_List_ptr; - act_subtree_root_List_ptr = new_subtree_root_List_ptr; - new_subtree_root_List_ptr = help_ptr; - } -} - - -void NMM::build_up_root_vertex(const Graph&G, QuadTreeNM& T) -{ - node v; - - T.init_tree(); - T.get_root_ptr()->set_Sm_level(0); - T.get_root_ptr()->set_Sm_downleftcorner(down_left_corner); - T.get_root_ptr()->set_Sm_boxlength(boxlength); - T.get_root_ptr()->set_particlenumber_in_subtree(G.numberOfNodes()); - forall_nodes(v,G) - T.get_root_ptr()->pushBack_contained_nodes(v); -} - - -void NMM::construct_subtree( - NodeArray& A, - QuadTreeNM& T, - QuadTreeNodeNM *subtree_root_ptr, - List& new_subtree_root_List) -{ - int n = subtree_root_ptr->get_particlenumber_in_subtree(); - int subtree_depth = static_cast(max(1.0,floor(Math::log4(n))-2.0)); - int maxindex=1; - - for(int i=1; i<=subtree_depth; i++) - maxindex *= 2; - double subtree_min_boxlength = subtree_root_ptr->get_Sm_boxlength()/maxindex; - - if(subtree_min_boxlength >= MIN_BOX_LENGTH) - { - Array2D leaf_ptr(0,maxindex-1,0,maxindex-1); - T.set_act_ptr(subtree_root_ptr); - if (find_smallest_quad(A,T)) //not all nodes have the same position - { - construct_complete_subtree(T,subtree_depth,leaf_ptr,0,0,0); - set_contained_nodes_for_leaves(A,subtree_root_ptr,leaf_ptr,maxindex); - T.set_act_ptr(subtree_root_ptr); - set_particlenumber_in_subtree_entries(T); - T.set_act_ptr(subtree_root_ptr); - construct_reduced_subtree(A,T,new_subtree_root_List); - } - } -} - - -void NMM::construct_complete_subtree( - QuadTreeNM& T, - int subtree_depth, - Array2D& leaf_ptr, - int act_depth, - int act_x_index, - int act_y_index) -{ - if(act_depth < subtree_depth) - { - T.create_new_lt_child(); - T.create_new_rt_child(); - T.create_new_lb_child(); - T.create_new_rb_child(); - - T.go_to_lt_child(); - construct_complete_subtree(T,subtree_depth,leaf_ptr,act_depth+1,2*act_x_index, - 2*act_y_index+1); - T.go_to_father(); - - T.go_to_rt_child(); - construct_complete_subtree(T,subtree_depth,leaf_ptr,act_depth+1,2*act_x_index+1, - 2*act_y_index+1); - T.go_to_father(); - - T.go_to_lb_child(); - construct_complete_subtree(T,subtree_depth,leaf_ptr,act_depth+1,2*act_x_index, - 2*act_y_index); - T.go_to_father(); - - T.go_to_rb_child(); - construct_complete_subtree(T,subtree_depth,leaf_ptr,act_depth+1,2*act_x_index+1, - 2*act_y_index); - T.go_to_father(); - } - else if (act_depth == subtree_depth) - { - leaf_ptr(act_x_index,act_y_index) = T.get_act_ptr(); - } - else - cout<<"Error NMM::construct_complete_subtree()"< &A, - QuadTreeNodeNM* subtree_root_ptr, - Array2D &leaf_ptr, - int maxindex) -{ - node v; - QuadTreeNodeNM* act_ptr; - double xcoord,ycoord; - int x_index,y_index; - double minboxlength = subtree_root_ptr->get_Sm_boxlength()/maxindex; - - while(!subtree_root_ptr->contained_nodes_empty()) - { - v = subtree_root_ptr->pop_contained_nodes(); - xcoord = A[v].get_x()-subtree_root_ptr->get_Sm_downleftcorner().m_x; - ycoord = A[v].get_y()-subtree_root_ptr->get_Sm_downleftcorner().m_y;; - x_index = int(xcoord/minboxlength); - y_index = int(ycoord/minboxlength); - act_ptr = leaf_ptr(x_index,y_index); - act_ptr->pushBack_contained_nodes(v); - act_ptr->set_particlenumber_in_subtree(act_ptr->get_particlenumber_in_subtree()+1); - } -} - - -void NMM::set_particlenumber_in_subtree_entries(QuadTreeNM& T) -{ - int child_nr; - - if(!T.get_act_ptr()->is_leaf()) - {//if - T.get_act_ptr()->set_particlenumber_in_subtree(0); - - if (T.get_act_ptr()->child_lt_exists()) - { - T.go_to_lt_child(); - set_particlenumber_in_subtree_entries(T); - T.go_to_father(); - child_nr = T.get_act_ptr()->get_child_lt_ptr()->get_particlenumber_in_subtree(); - T.get_act_ptr()->set_particlenumber_in_subtree(child_nr + T.get_act_ptr()-> - get_particlenumber_in_subtree()); - } - if (T.get_act_ptr()->child_rt_exists()) - { - T.go_to_rt_child(); - set_particlenumber_in_subtree_entries(T); - T.go_to_father(); - child_nr = T.get_act_ptr()->get_child_rt_ptr()->get_particlenumber_in_subtree(); - T.get_act_ptr()->set_particlenumber_in_subtree(child_nr + T.get_act_ptr()-> - get_particlenumber_in_subtree()); - } - if (T.get_act_ptr()->child_lb_exists()) - { - T.go_to_lb_child(); - set_particlenumber_in_subtree_entries(T); - T.go_to_father(); - child_nr = T.get_act_ptr()->get_child_lb_ptr()->get_particlenumber_in_subtree(); - T.get_act_ptr()->set_particlenumber_in_subtree(child_nr + T.get_act_ptr()-> - get_particlenumber_in_subtree()); - } - if (T.get_act_ptr()->child_rb_exists()) - { - T.go_to_rb_child(); - set_particlenumber_in_subtree_entries(T); - T.go_to_father(); - child_nr = T.get_act_ptr()->get_child_rb_ptr()->get_particlenumber_in_subtree(); - T.get_act_ptr()->set_particlenumber_in_subtree(child_nr + T.get_act_ptr()-> - get_particlenumber_in_subtree()); - } - }//if -} - - -void NMM::construct_reduced_subtree( - NodeArray& A, - QuadTreeNM& T, - List& new_subtree_root_List) -{ - do - { - QuadTreeNodeNM* act_ptr = T.get_act_ptr(); - delete_empty_subtrees(T); - T.set_act_ptr(act_ptr); - } - while(check_and_delete_degenerated_node(T)== true) ; - - if(!T.get_act_ptr()->is_leaf() && T.get_act_ptr()->get_particlenumber_in_subtree() - <= particles_in_leaves()) - { - delete_sparse_subtree(T,T.get_act_ptr()); - } - - //push leaves that contain many particles - if(T.get_act_ptr()->is_leaf() && T.get_act_ptr()-> - get_particlenumber_in_subtree() > particles_in_leaves()) - new_subtree_root_List.pushBack(T.get_act_ptr()); - - //find smallest quad for leaves of T - else if(T.get_act_ptr()->is_leaf() && T.get_act_ptr()-> - get_particlenumber_in_subtree() <= particles_in_leaves()) - find_smallest_quad(A,T); - - //recursive calls - else if(!T.get_act_ptr()->is_leaf()) - {//else - if(T.get_act_ptr()->child_lt_exists()) - { - T.go_to_lt_child(); - construct_reduced_subtree(A,T,new_subtree_root_List); - T.go_to_father(); - } - if(T.get_act_ptr()->child_rt_exists()) - { - T.go_to_rt_child(); - construct_reduced_subtree(A,T,new_subtree_root_List); - T.go_to_father(); - } - if(T.get_act_ptr()->child_lb_exists()) - { - T.go_to_lb_child(); - construct_reduced_subtree(A,T,new_subtree_root_List); - T.go_to_father(); - } - if(T.get_act_ptr()->child_rb_exists()) - { - T.go_to_rb_child(); - construct_reduced_subtree(A,T,new_subtree_root_List); - T.go_to_father(); - } - }//else -} - - -void NMM::delete_empty_subtrees(QuadTreeNM& T) -{ - int child_part_nr; - QuadTreeNodeNM* act_ptr = T.get_act_ptr(); - - if(act_ptr->child_lt_exists()) - { - child_part_nr = act_ptr->get_child_lt_ptr()->get_particlenumber_in_subtree(); - if(child_part_nr == 0) - { - T.delete_tree(act_ptr->get_child_lt_ptr()); - act_ptr->set_child_lt_ptr(NULL); - } - } - - if(act_ptr->child_rt_exists()) - { - child_part_nr = act_ptr->get_child_rt_ptr()->get_particlenumber_in_subtree(); - if(child_part_nr == 0) - { - T.delete_tree(act_ptr->get_child_rt_ptr()); - act_ptr->set_child_rt_ptr(NULL); - } - } - - if(act_ptr->child_lb_exists()) - { - child_part_nr = act_ptr->get_child_lb_ptr()->get_particlenumber_in_subtree(); - if(child_part_nr == 0) - { - T.delete_tree(act_ptr->get_child_lb_ptr()); - act_ptr->set_child_lb_ptr(NULL); - } - } - - if(act_ptr->child_rb_exists()) - { - child_part_nr = act_ptr->get_child_rb_ptr()->get_particlenumber_in_subtree(); - if(child_part_nr == 0) - { - T.delete_tree(act_ptr->get_child_rb_ptr()); - act_ptr->set_child_rb_ptr(NULL); - } - } -} - - -bool NMM::check_and_delete_degenerated_node(QuadTreeNM& T) -{ - QuadTreeNodeNM* delete_ptr; - QuadTreeNodeNM* father_ptr; - QuadTreeNodeNM* child_ptr; - - bool lt_child = T.get_act_ptr()->child_lt_exists(); - bool rt_child = T.get_act_ptr()->child_rt_exists(); - bool lb_child = T.get_act_ptr()->child_lb_exists(); - bool rb_child = T.get_act_ptr()->child_rb_exists(); - bool is_degenerated = false; - - if(lt_child && !rt_child && !lb_child && !rb_child) - {//if1 - is_degenerated = true; - delete_ptr = T.get_act_ptr(); - child_ptr = T.get_act_ptr()->get_child_lt_ptr(); - if(T.get_act_ptr() == T.get_root_ptr())//special case - { - T.set_root_ptr(child_ptr); - T.set_act_ptr(T.get_root_ptr()); - } - else//usual case - { - father_ptr = T.get_act_ptr()->get_father_ptr(); - child_ptr->set_father_ptr(father_ptr); - if(father_ptr->get_child_lt_ptr() == T.get_act_ptr()) - father_ptr->set_child_lt_ptr(child_ptr); - else if(father_ptr->get_child_rt_ptr() == T.get_act_ptr()) - father_ptr->set_child_rt_ptr(child_ptr); - else if(father_ptr->get_child_lb_ptr() == T.get_act_ptr()) - father_ptr->set_child_lb_ptr(child_ptr); - else if(father_ptr->get_child_rb_ptr() == T.get_act_ptr()) - father_ptr->set_child_rb_ptr(child_ptr); - else - cout<<"Error NMM::delete_degenerated_node"<get_child_rt_ptr(); - if(T.get_act_ptr() == T.get_root_ptr())//special case - { - T.set_root_ptr(child_ptr); - T.set_act_ptr(T.get_root_ptr()); - } - else//usual case - { - father_ptr = T.get_act_ptr()->get_father_ptr(); - child_ptr->set_father_ptr(father_ptr); - if(father_ptr->get_child_lt_ptr() == T.get_act_ptr()) - father_ptr->set_child_lt_ptr(child_ptr); - else if(father_ptr->get_child_rt_ptr() == T.get_act_ptr()) - father_ptr->set_child_rt_ptr(child_ptr); - else if(father_ptr->get_child_lb_ptr() == T.get_act_ptr()) - father_ptr->set_child_lb_ptr(child_ptr); - else if(father_ptr->get_child_rb_ptr() == T.get_act_ptr()) - father_ptr->set_child_rb_ptr(child_ptr); - else - cout<<"Error NMM::delete_degenerated_node"<get_child_lb_ptr(); - if(T.get_act_ptr() == T.get_root_ptr())//special case - { - T.set_root_ptr(child_ptr); - T.set_act_ptr(T.get_root_ptr()); - } - else//usual case - { - father_ptr = T.get_act_ptr()->get_father_ptr(); - child_ptr->set_father_ptr(father_ptr); - if(father_ptr->get_child_lt_ptr() == T.get_act_ptr()) - father_ptr->set_child_lt_ptr(child_ptr); - else if(father_ptr->get_child_rt_ptr() == T.get_act_ptr()) - father_ptr->set_child_rt_ptr(child_ptr); - else if(father_ptr->get_child_lb_ptr() == T.get_act_ptr()) - father_ptr->set_child_lb_ptr(child_ptr); - else if(father_ptr->get_child_rb_ptr() == T.get_act_ptr()) - father_ptr->set_child_rb_ptr(child_ptr); - else - cout<<"Error NMM::delete_degenerated_node"<get_child_rb_ptr(); - if(T.get_act_ptr() == T.get_root_ptr())//special case - { - T.set_root_ptr(child_ptr); - T.set_act_ptr(T.get_root_ptr()); - } - else//usual case - { - father_ptr = T.get_act_ptr()->get_father_ptr(); - child_ptr->set_father_ptr(father_ptr); - if(father_ptr->get_child_lt_ptr() == T.get_act_ptr()) - father_ptr->set_child_lt_ptr(child_ptr); - else if(father_ptr->get_child_rt_ptr() == T.get_act_ptr()) - father_ptr->set_child_rt_ptr(child_ptr); - else if(father_ptr->get_child_lb_ptr() == T.get_act_ptr()) - father_ptr->set_child_lb_ptr(child_ptr); - else if(father_ptr->get_child_rb_ptr() == T.get_act_ptr()) - father_ptr->set_child_rb_ptr(child_ptr); - else - cout<<"Error NMM::delete_degenerated_node"<child_lt_exists()) - { - T.delete_tree(new_leaf_ptr->get_child_lt_ptr()); - new_leaf_ptr->set_child_lt_ptr(NULL); - } - if(new_leaf_ptr->child_rt_exists()) - { - T.delete_tree(new_leaf_ptr->get_child_rt_ptr()); - new_leaf_ptr->set_child_rt_ptr(NULL); - } - if(new_leaf_ptr->child_lb_exists()) - { - T.delete_tree(new_leaf_ptr->get_child_lb_ptr()); - new_leaf_ptr->set_child_lb_ptr(NULL); - } - if(new_leaf_ptr->child_rb_exists()) - { - T.delete_tree(new_leaf_ptr->get_child_rb_ptr()); - new_leaf_ptr->set_child_rb_ptr(NULL); - } -} - - -void NMM::collect_contained_nodes(QuadTreeNM& T, QuadTreeNodeNM* new_leaf_ptr) -{ - if(T.get_act_ptr()->is_leaf()) - while(!T.get_act_ptr()->contained_nodes_empty()) - new_leaf_ptr->pushBack_contained_nodes(T.get_act_ptr()->pop_contained_nodes()); - else if(T.get_act_ptr()->child_lt_exists()) - { - T.go_to_lt_child(); - collect_contained_nodes(T,new_leaf_ptr); - T.go_to_father(); - } - if(T.get_act_ptr()->child_rt_exists()) - { - T.go_to_rt_child(); - collect_contained_nodes(T,new_leaf_ptr); - T.go_to_father(); - } - if(T.get_act_ptr()->child_lb_exists()) - { - T.go_to_lb_child(); - collect_contained_nodes(T,new_leaf_ptr); - T.go_to_father(); - } - if(T.get_act_ptr()->child_rb_exists()) - { - T.go_to_rb_child(); - collect_contained_nodes(T,new_leaf_ptr); - T.go_to_father(); - } -} - - -bool NMM::find_smallest_quad(NodeArray& A, QuadTreeNM& T) -{ - OGDF_ASSERT(!T.get_act_ptr()->contained_nodes_empty()); - //if(T.get_act_ptr()->contained_nodes_empty()) - // cout<<"Error NMM :: find_smallest_quad()"<L; - T.get_act_ptr()->get_contained_nodes(L); - node v = L.popFrontRet(); - double x_min = A[v].get_x(); - double x_max = x_min; - double y_min = A[v].get_y(); - double y_max = y_min; - - while(! L.empty()) - { - v = L.popFrontRet(); - if(A[v].get_x() < x_min) - x_min = A[v].get_x(); - if(A[v].get_x() > x_max) - x_max = A[v].get_x(); - if(A[v].get_y() < y_min) - y_min = A[v].get_y(); - if(A[v].get_y() > y_max) - y_max = A[v].get_y(); - } - if(x_min != x_max || y_min != y_max) //nodes are not all at the same position - { - if(find_sm_cell() == FMMMLayout::scfIteratively) - find_small_cell_iteratively(T.get_act_ptr(),x_min,x_max,y_min,y_max); - else //find_sm_cell == FMMMLayout::scfAluru - find_small_cell_iteratively(T.get_act_ptr(),x_min,x_max,y_min,y_max); - return true; - } - else - return false; - //}//else -} - - -// ********Functions needed for subtree by subtree tree construction(END)************ - -void NMM::find_small_cell_iteratively( - QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max) -{ - int new_level; - double new_boxlength; - DPoint new_dlc; - bool Sm_cell_found = false; - - while ( !Sm_cell_found && ((x_max-x_min >=MIN_BOX_LENGTH) || - (y_max-y_min >=MIN_BOX_LENGTH)) ) - { - if(in_lt_quad(act_ptr,x_min,x_max,y_min,y_max)) - { - new_level = act_ptr->get_Sm_level()+1; - new_boxlength = act_ptr->get_Sm_boxlength()/2; - new_dlc.m_x = act_ptr->get_Sm_downleftcorner().m_x; - new_dlc.m_y = act_ptr->get_Sm_downleftcorner().m_y+new_boxlength; - act_ptr->set_Sm_level(new_level); - act_ptr->set_Sm_boxlength(new_boxlength); - act_ptr->set_Sm_downleftcorner(new_dlc); - } - else if(in_rt_quad(act_ptr,x_min,x_max,y_min,y_max)) - { - new_level = act_ptr->get_Sm_level()+1; - new_boxlength = act_ptr->get_Sm_boxlength()/2; - new_dlc.m_x = act_ptr->get_Sm_downleftcorner().m_x+new_boxlength; - new_dlc.m_y = act_ptr->get_Sm_downleftcorner().m_y+new_boxlength; - act_ptr->set_Sm_level(new_level); - act_ptr->set_Sm_boxlength(new_boxlength); - act_ptr->set_Sm_downleftcorner(new_dlc); - } - else if(in_lb_quad(act_ptr,x_min,x_max,y_min,y_max)) - { - new_level = act_ptr->get_Sm_level()+1; - new_boxlength = act_ptr->get_Sm_boxlength()/2; - act_ptr->set_Sm_level(new_level); - act_ptr->set_Sm_boxlength(new_boxlength); - } - else if(in_rb_quad(act_ptr,x_min,x_max,y_min,y_max)) - { - new_level = act_ptr->get_Sm_level()+1; - new_boxlength = act_ptr->get_Sm_boxlength()/2; - new_dlc.m_x = act_ptr->get_Sm_downleftcorner().m_x+new_boxlength; - new_dlc.m_y = act_ptr->get_Sm_downleftcorner().m_y; - act_ptr->set_Sm_level(new_level); - act_ptr->set_Sm_boxlength(new_boxlength); - act_ptr->set_Sm_downleftcorner(new_dlc); - } - else Sm_cell_found = true; - } -} - - -void NMM::find_small_cell_by_formula( - QuadTreeNodeNM* act_ptr, - double x_min, - double x_max, - double y_min, - double y_max) -{ - numexcept N; - int level_offset = act_ptr->get_Sm_level(); - max_power_of_2_index = 30;//up to this level standard integer arithmetic is used - DPoint nullpoint (0,0); - IPoint Sm_position; - double Sm_dlc_x_coord,Sm_dlc_y_coord; - double Sm_boxlength; - int Sm_level; - DPoint Sm_downleftcorner; - int j_x = max_power_of_2_index+1; - int j_y = max_power_of_2_index+1; - bool rectangle_is_horizontal_line = false; - bool rectangle_is_vertical_line = false; - bool rectangle_is_point = false; - - //shift boundaries to the origin for easy calculations - double x_min_old = x_min; - double x_max_old = x_max; - double y_min_old = y_min; - double y_max_old = y_max; - - Sm_boxlength = act_ptr->get_Sm_boxlength(); - Sm_dlc_x_coord = act_ptr->get_Sm_downleftcorner().m_x; - Sm_dlc_y_coord = act_ptr->get_Sm_downleftcorner().m_y; - - x_min -= Sm_dlc_x_coord; - x_max -= Sm_dlc_x_coord; - y_min -= Sm_dlc_y_coord; - y_max -= Sm_dlc_y_coord; - - //check if iterative way has to be used - if (x_min == x_max && y_min == y_max) - rectangle_is_point = true; - else if(x_min == x_max && y_min != y_max) - rectangle_is_vertical_line = true; - else //x_min != x_max - j_x = static_cast(ceil(Math::log2(Sm_boxlength/(x_max-x_min)))); - - if(x_min != x_max && y_min == y_max) - rectangle_is_horizontal_line = true; - else //y_min != y_max - j_y = static_cast(ceil(Math::log2(Sm_boxlength/(y_max-y_min)))); - - if(rectangle_is_point) - { - ;//keep the old values - } - else if ( !N.nearly_equal((x_min_old - x_max_old),(x_min-x_max)) || - !N.nearly_equal((y_min_old - y_max_old),(y_min-y_max)) || - x_min/Sm_boxlength < MIN_BOX_LENGTH || x_max/Sm_boxlength < MIN_BOX_LENGTH || - y_min/Sm_boxlength < MIN_BOX_LENGTH || y_max/Sm_boxlength < MIN_BOX_LENGTH ) - find_small_cell_iteratively(act_ptr,x_min_old,x_max_old,y_min_old,y_max_old); - else if ( ((j_x > max_power_of_2_index) && (j_y > max_power_of_2_index)) || - ((j_x > max_power_of_2_index) && !rectangle_is_vertical_line) || - ((j_y > max_power_of_2_index) && !rectangle_is_horizontal_line) ) - find_small_cell_iteratively(act_ptr,x_min_old,x_max_old,y_min_old,y_max_old); - else //idea of Aluru et al. - {//else - int k,a1,a2,A,j_minus_k; - double h1,h2; - int Sm_x_level,Sm_y_level; - int Sm_x_position,Sm_y_position; - - if(x_min != x_max) - {//if1 - //calculate Sm_x_level and Sm_x_position - a1 = static_cast(ceil((x_min/Sm_boxlength)*power_of_two(j_x))); - a2 = static_cast(floor((x_max/Sm_boxlength)*power_of_two(j_x))); - h1 = (Sm_boxlength/power_of_two(j_x))* a1; - h2 = (Sm_boxlength/power_of_two(j_x))* a2; - - //special cases: two tangents or left tangent and righ cutline - if(((h1 == x_min)&&(h2 == x_max)) || ((h1 == x_min) && (h2 != x_max)) ) - A = a2; - else if (a1 == a2) //only one cutline - A = a1; - else //two cutlines or a right tangent and a left cutline (usual case) - { - if((a1 % 2) == 0) - A = a1; - else - A = a2; - } - - j_minus_k = static_cast(Math::log2(1+(A ^ (A-1)))-1); - k = j_x - j_minus_k; - Sm_x_level = k-1; - Sm_x_position = a1/ power_of_two(j_x - Sm_x_level); - }//if1 - - if(y_min != y_max) - {//if2 - //calculate Sm_y_level and Sm_y_position - a1 = static_cast(ceil((y_min/Sm_boxlength)*power_of_two(j_y))); - a2 = static_cast(floor((y_max/Sm_boxlength)*power_of_two(j_y))); - h1 = (Sm_boxlength/power_of_two(j_y))* a1; - h2 = (Sm_boxlength/power_of_two(j_y))* a2; - - //special cases: two tangents or bottom tangent and top cutline - if(((h1 == y_min)&&(h2 == y_max)) || ((h1 == y_min) && (h2 != y_max)) ) - A = a2; - else if (a1 == a2) //only one cutline - A = a1; - else //two cutlines or a top tangent and a bottom cutline (usual case) - { - if((a1 % 2) == 0) - A = a1; - else - A = a2; - } - - j_minus_k = static_cast(Math::log2(1+(A ^ (A-1)))-1); - k = j_y - j_minus_k; - Sm_y_level = k-1; - Sm_y_position = a1/ power_of_two(j_y - Sm_y_level); - }//if2 - - if((x_min != x_max) &&(y_min != y_max))//a box with area > 0 - {//if3 - if (Sm_x_level == Sm_y_level) - { - Sm_level = Sm_x_level; - Sm_position.m_x = Sm_x_position; - Sm_position.m_y = Sm_y_position; - } - else if (Sm_x_level < Sm_y_level) - { - Sm_level = Sm_x_level; - Sm_position.m_x = Sm_x_position; - Sm_position.m_y = Sm_y_position/power_of_two(Sm_y_level-Sm_x_level); - } - else //Sm_x_level > Sm_y_level - { - Sm_level = Sm_y_level; - Sm_position.m_x = Sm_x_position/power_of_two(Sm_x_level-Sm_y_level); - Sm_position.m_y = Sm_y_position; - } - }//if3 - else if(x_min == x_max) //a vertical line - {//if4 - Sm_level = Sm_y_level; - Sm_position.m_x = static_cast (floor((x_min*power_of_two(Sm_level))/ - Sm_boxlength)); - Sm_position.m_y = Sm_y_position; - }//if4 - else //y_min == y_max (a horizontal line) - {//if5 - Sm_level = Sm_x_level; - Sm_position.m_x = Sm_x_position; - Sm_position.m_y = static_cast (floor((y_min*power_of_two(Sm_level))/ - Sm_boxlength)); - }//if5 - - Sm_boxlength = Sm_boxlength/power_of_two(Sm_level); - Sm_downleftcorner.m_x = Sm_dlc_x_coord + Sm_boxlength * Sm_position.m_x; - Sm_downleftcorner.m_y = Sm_dlc_y_coord + Sm_boxlength * Sm_position.m_y; - act_ptr->set_Sm_level(Sm_level+level_offset); - act_ptr->set_Sm_boxlength(Sm_boxlength); - act_ptr->set_Sm_downleftcorner(Sm_downleftcorner); - }//else -} - - -inline void NMM::delete_red_quad_tree_and_count_treenodes(QuadTreeNM& T) -{ - T.delete_tree(T.get_root_ptr()); -} - - -inline void NMM::form_multipole_expansions( - NodeArray& A, - QuadTreeNM& T, - List& quad_tree_leaves) -{ - T.set_act_ptr(T.get_root_ptr()); - form_multipole_expansion_of_subtree(A,T,quad_tree_leaves); -} - - -void NMM::form_multipole_expansion_of_subtree( - NodeArray& A, - QuadTreeNM& T, - List& quad_tree_leaves) -{ - init_expansion_Lists(T.get_act_ptr()); - set_center(T.get_act_ptr()); - - if(T.get_act_ptr()->is_leaf()) //form expansions for leaf nodes - {//if - quad_tree_leaves.pushBack(T.get_act_ptr()); - form_multipole_expansion_of_leaf_node(A,T.get_act_ptr()); - }//if - else //rekursive calls and add shifted expansions - {//else - if(T.get_act_ptr()->child_lt_exists()) - { - T.go_to_lt_child(); - form_multipole_expansion_of_subtree(A,T,quad_tree_leaves); - add_shifted_expansion_to_father_expansion(T.get_act_ptr()); - T.go_to_father(); - } - if(T.get_act_ptr()->child_rt_exists()) - { - T.go_to_rt_child(); - form_multipole_expansion_of_subtree(A,T,quad_tree_leaves); - add_shifted_expansion_to_father_expansion(T.get_act_ptr()); - T.go_to_father(); - } - if(T.get_act_ptr()->child_lb_exists()) - { - T.go_to_lb_child(); - form_multipole_expansion_of_subtree(A,T,quad_tree_leaves); - add_shifted_expansion_to_father_expansion(T.get_act_ptr()); - T.go_to_father(); - } - if(T.get_act_ptr()->child_rb_exists()) - { - T.go_to_rb_child(); - form_multipole_expansion_of_subtree(A,T,quad_tree_leaves); - add_shifted_expansion_to_father_expansion(T.get_act_ptr()); - T.go_to_father(); - } - }//else -} - - -inline void NMM::init_expansion_Lists(QuadTreeNodeNM* act_ptr) -{ - int i; - Array > nulList (precision()+1); - - for (i = 0;i<=precision();i++) - nulList[i] = 0; - - act_ptr->set_multipole_exp(nulList,precision()); - act_ptr->set_locale_exp(nulList,precision()); -} - - -void NMM::set_center(QuadTreeNodeNM* act_ptr) -{ - - const int BILLION = 1000000000; - DPoint Sm_downleftcorner = act_ptr->get_Sm_downleftcorner(); - double Sm_boxlength = act_ptr->get_Sm_boxlength(); - double boxcenter_x_coord,boxcenter_y_coord; - DPoint Sm_dlc; - double rand_y; - - boxcenter_x_coord = Sm_downleftcorner.m_x + Sm_boxlength * 0.5; - boxcenter_y_coord = Sm_downleftcorner.m_y + Sm_boxlength * 0.5; - - //for use of complex logarithm: waggle the y-coordinates a little bit - //such that the new center is really inside the actual box and near the exact center - rand_y = double(randomNumber(1,BILLION)+1)/(BILLION+2);//rand number in (0,1) - boxcenter_y_coord = boxcenter_y_coord + 0.001 * Sm_boxlength * rand_y; - - complex boxcenter(boxcenter_x_coord,boxcenter_y_coord); - act_ptr->set_Sm_center(boxcenter); -} - - -void NMM::form_multipole_expansion_of_leaf_node( - NodeArray& A, - QuadTreeNodeNM* act_ptr) -{ - int k; - complex Q (0,0); - complex z_0 = act_ptr->get_Sm_center();//center of actual box - complex nullpoint (0,0); - Array > coef (precision()+1); - complex z_v_minus_z_0_over_k; - List nodes_in_box; - int i; - ListIterator v_it; - - act_ptr->get_contained_nodes(nodes_in_box); - - for(v_it = nodes_in_box.begin();v_it.valid();++v_it) - Q += 1; - coef[0] = Q; - - for(i = 1; i<=precision();i++) - coef[i] = nullpoint; - - for(v_it = nodes_in_box.begin();v_it.valid();++v_it) - { - complex z_v (A[*v_it].get_x(),A[*v_it].get_y()); - z_v_minus_z_0_over_k = z_v - z_0; - for(k=1;k<=precision();k++) - { - coef[k] += ((double(-1))*z_v_minus_z_0_over_k)/double(k); - z_v_minus_z_0_over_k *= z_v - z_0; - } - } - act_ptr->replace_multipole_exp(coef,precision()); -} - - -void NMM::add_shifted_expansion_to_father_expansion(QuadTreeNodeNM* act_ptr) -{ - QuadTreeNodeNM* father_ptr = act_ptr->get_father_ptr(); - complex sum; - complex z_0,z_1; - Array > z_0_minus_z_1_over (precision()+1); - - z_1 = father_ptr->get_Sm_center(); - z_0 = act_ptr->get_Sm_center(); - father_ptr->get_multipole_exp()[0] += act_ptr->get_multipole_exp()[0]; - - //init z_0_minus_z_1_over - z_0_minus_z_1_over[0] = 1; - for(int i = 1; i<= precision(); i++) - z_0_minus_z_1_over[i] = z_0_minus_z_1_over[i-1] * (z_0 - z_1); - - for(int k=1; k<=precision(); k++) - { - sum = (act_ptr->get_multipole_exp()[0]*(double(-1))*z_0_minus_z_1_over[k])/ - double(k) ; - for(int s=1; s<=k; s++) - sum += act_ptr->get_multipole_exp()[s]*z_0_minus_z_1_over[k-s]* binko(k-1,s-1); - father_ptr->get_multipole_exp()[k] += sum; - } -} - - -void NMM::calculate_local_expansions_and_WSPRLS( - NodeArray&A, - QuadTreeNodeNM* act_node_ptr) -{ - List I,L,L2,E,D1,D2,M; - QuadTreeNodeNM *father_ptr,*selected_node_ptr; - ListIterator ptr_it; - - //Step 0: Initializations - if(! act_node_ptr->is_root()) - father_ptr = act_node_ptr->get_father_ptr(); - I.clear();L.clear();L2.clear();D1.clear();D2.clear();M.clear(); - - //Step 1: calculate Lists I (min. ill sep. set), L (interaction List of well sep. - //nodes , they are used to form the Local Expansions from the multipole expansions), - //L2 (non bordering leaves that have a larger or equal Sm-cell and are ill separated; - //empty if the actual node is a leaf) - //calculate List D1(bordering leaves that have a larger or equal Sm-cell and are - //ill separated) and D2 (non bordering leaves that have a larger or equal Sm-cell and - //are ill separated;empty if the actual node is an interior node) - - //special case: act_node is the root of T - if (act_node_ptr->is_root()) - {//if - E.clear(); - if(act_node_ptr->child_lt_exists()) - E.pushBack(act_node_ptr->get_child_lt_ptr()); - if(act_node_ptr->child_rt_exists()) - E.pushBack(act_node_ptr->get_child_rt_ptr()); - if(act_node_ptr->child_lb_exists()) - E.pushBack(act_node_ptr->get_child_lb_ptr()); - if(act_node_ptr->child_rb_exists()) - E.pushBack(act_node_ptr->get_child_rb_ptr()); - }//if - - //usual case: act_node is an interior node of T - else - { - father_ptr->get_D1(E); //bordering leaves of father - father_ptr->get_I(I); //min ill sep. nodes of father - - - for(ptr_it = I.begin();ptr_it.valid();++ptr_it) - E.pushBack(*ptr_it); - I.clear(); - } - - - while (!E.empty()) - {//while - selected_node_ptr = E.popFrontRet(); - if (well_separated(act_node_ptr,selected_node_ptr)) - L.pushBack(selected_node_ptr); - else if (act_node_ptr->get_Sm_level() < selected_node_ptr->get_Sm_level()) - I.pushBack(selected_node_ptr); - else if(!selected_node_ptr->is_leaf()) - { - if(selected_node_ptr->child_lt_exists()) - E.pushBack(selected_node_ptr->get_child_lt_ptr()); - if(selected_node_ptr->child_rt_exists()) - E.pushBack(selected_node_ptr->get_child_rt_ptr()); - if(selected_node_ptr->child_lb_exists()) - E.pushBack(selected_node_ptr->get_child_lb_ptr()); - if(selected_node_ptr->child_rb_exists()) - E.pushBack(selected_node_ptr->get_child_rb_ptr()); - } - else if(bordering(act_node_ptr,selected_node_ptr)) - D1.pushBack(selected_node_ptr); - else if( (selected_node_ptr != act_node_ptr)&&(act_node_ptr->is_leaf())) - D2.pushBack(selected_node_ptr); //direct calculation (no errors produced) - else if((selected_node_ptr != act_node_ptr)&&!(act_node_ptr->is_leaf())) - L2.pushBack(selected_node_ptr); - }//while - - act_node_ptr->set_I(I); - act_node_ptr->set_D1(D1); - act_node_ptr->set_D2(D2); - - //Step 2: add local expansions from father(act_node_ptr) and calculate locale - //expansions for all nodes in L - if(!act_node_ptr->is_root()) - add_shifted_local_exp_of_parent(act_node_ptr); - - for(ptr_it = L.begin();ptr_it.valid();++ptr_it) - add_local_expansion(*ptr_it,act_node_ptr); - - //Step 3: calculate locale expansions for all nodes in D2 (simpler than in Step 2) - - for(ptr_it = L2.begin();ptr_it.valid();++ptr_it) - add_local_expansion_of_leaf(A,*ptr_it,act_node_ptr); - - //Step 4: recursive calls if act_node is not a leaf - if(!act_node_ptr->is_leaf()) - { - if(act_node_ptr->child_lt_exists()) - calculate_local_expansions_and_WSPRLS(A,act_node_ptr->get_child_lt_ptr()); - if(act_node_ptr->child_rt_exists()) - calculate_local_expansions_and_WSPRLS(A,act_node_ptr->get_child_rt_ptr()); - if(act_node_ptr->child_lb_exists()) - calculate_local_expansions_and_WSPRLS(A,act_node_ptr->get_child_lb_ptr()); - if(act_node_ptr->child_rb_exists()) - calculate_local_expansions_and_WSPRLS(A,act_node_ptr->get_child_rb_ptr()); - } - - //Step 5: WSPRLS(Well Separateness Preserving Refinement of leaf surroundings) - //if act_node is a leaf than calculate the list D1,D2 and M from I and D1 - else // *act_node_ptr is a leaf - {//else - act_node_ptr->get_D1(D1); - act_node_ptr->get_D2(D2); - - while(!I.empty()) - {//while - selected_node_ptr = I.popFrontRet(); - if(selected_node_ptr->is_leaf()) - { - //here D1 contains larger AND smaller bordering leaves! - if(bordering(act_node_ptr,selected_node_ptr)) - D1.pushBack(selected_node_ptr); - else - D2.pushBack(selected_node_ptr); - } - else //!selected_node_ptr->is_leaf() - { - if(bordering(act_node_ptr,selected_node_ptr)) - { - if(selected_node_ptr->child_lt_exists()) - I.pushBack(selected_node_ptr->get_child_lt_ptr()); - if(selected_node_ptr->child_rt_exists()) - I.pushBack(selected_node_ptr->get_child_rt_ptr()); - if(selected_node_ptr->child_lb_exists()) - I.pushBack(selected_node_ptr->get_child_lb_ptr()); - if(selected_node_ptr->child_rb_exists()) - I.pushBack(selected_node_ptr->get_child_rb_ptr()); - } - else - M.pushBack(selected_node_ptr); - } - }//while - act_node_ptr->set_D1(D1); - act_node_ptr->set_D2(D2); - act_node_ptr->set_M(M); - }//else -} - - -bool NMM::well_separated(QuadTreeNodeNM* node_1_ptr, QuadTreeNodeNM* node_2_ptr) -{ - numexcept N; - double boxlength_1 = node_1_ptr->get_Sm_boxlength(); - double boxlength_2 = node_2_ptr->get_Sm_boxlength(); - double x1_min,x1_max,y1_min,y1_max,x2_min,x2_max,y2_min,y2_max; - bool x_overlap,y_overlap; - - if(boxlength_1 <= boxlength_2) - { - x1_min = node_1_ptr->get_Sm_downleftcorner().m_x; - x1_max = node_1_ptr->get_Sm_downleftcorner().m_x+boxlength_1; - y1_min = node_1_ptr->get_Sm_downleftcorner().m_y; - y1_max = node_1_ptr->get_Sm_downleftcorner().m_y+boxlength_1; - - //blow the box up - x2_min = node_2_ptr->get_Sm_downleftcorner().m_x-boxlength_2; - x2_max = node_2_ptr->get_Sm_downleftcorner().m_x+2*boxlength_2; - y2_min = node_2_ptr->get_Sm_downleftcorner().m_y-boxlength_2; - y2_max = node_2_ptr->get_Sm_downleftcorner().m_y+2*boxlength_2; - } - else //boxlength_1 > boxlength_2 - { - //blow the box up - x1_min = node_1_ptr->get_Sm_downleftcorner().m_x-boxlength_1; - x1_max = node_1_ptr->get_Sm_downleftcorner().m_x+2*boxlength_1; - y1_min = node_1_ptr->get_Sm_downleftcorner().m_y-boxlength_1; - y1_max = node_1_ptr->get_Sm_downleftcorner().m_y+2*boxlength_1; - - x2_min = node_2_ptr->get_Sm_downleftcorner().m_x; - x2_max = node_2_ptr->get_Sm_downleftcorner().m_x+boxlength_2; - y2_min = node_2_ptr->get_Sm_downleftcorner().m_y; - y2_max = node_2_ptr->get_Sm_downleftcorner().m_y+boxlength_2; - } - - //test if boxes overlap - if((x1_max <= x2_min)|| N.nearly_equal(x1_max,x2_min)|| - (x2_max <= x1_min)|| N.nearly_equal(x2_max,x1_min)) - x_overlap = false; - else - x_overlap = true; - if((y1_max <= y2_min)|| N.nearly_equal(y1_max,y2_min)|| - (y2_max <= y1_min)|| N.nearly_equal(y2_max,y1_min)) - y_overlap = false; - else - y_overlap = true; - - if (x_overlap && y_overlap) - return false; - else - return true; -} - - -bool NMM::bordering(QuadTreeNodeNM* node_1_ptr,QuadTreeNodeNM* node_2_ptr) -{ - numexcept N; - double boxlength_1 = node_1_ptr->get_Sm_boxlength(); - double boxlength_2 = node_2_ptr->get_Sm_boxlength(); - double x1_min = node_1_ptr->get_Sm_downleftcorner().m_x; - double x1_max = node_1_ptr->get_Sm_downleftcorner().m_x+boxlength_1; - double y1_min = node_1_ptr->get_Sm_downleftcorner().m_y; - double y1_max = node_1_ptr->get_Sm_downleftcorner().m_y+boxlength_1; - double x2_min = node_2_ptr->get_Sm_downleftcorner().m_x; - double x2_max = node_2_ptr->get_Sm_downleftcorner().m_x+boxlength_2; - double y2_min = node_2_ptr->get_Sm_downleftcorner().m_y; - double y2_max = node_2_ptr->get_Sm_downleftcorner().m_y+boxlength_2; - - if( ( (x2_min <= x1_min || N.nearly_equal(x2_min,x1_min)) && - (x1_max <= x2_max || N.nearly_equal(x1_max,x2_max)) && - (y2_min <= y1_min || N.nearly_equal(y2_min,y1_min)) && - (y1_max <= y2_max || N.nearly_equal(y1_max,y2_max)) ) || - ( (x1_min <= x2_min || N.nearly_equal(x1_min,x2_min)) && - (x2_max <= x1_max || N.nearly_equal(x2_max,x1_max)) && - (y1_min <= y2_min || N.nearly_equal(y1_min,y2_min)) && - (y2_max <= y1_max || N.nearly_equal(y2_max,y1_max)) ) ) - return false; //one box contains the other box(inclusive neighbours) - else - {//else - if (boxlength_1 <= boxlength_2) - { //shift box1 - if (x1_min < x2_min) - { x1_min +=boxlength_1;x1_max +=boxlength_1; } - else if (x1_max > x2_max) - { x1_min -=boxlength_1;x1_max -=boxlength_1; } - if (y1_min < y2_min) - { y1_min +=boxlength_1;y1_max +=boxlength_1; } - else if (y1_max > y2_max) - { y1_min -=boxlength_1;y1_max -=boxlength_1; } - } - else //boxlength_1 > boxlength_2 - {//shift box2 - if (x2_min < x1_min) - { x2_min +=boxlength_2;x2_max +=boxlength_2; } - else if (x2_max > x1_max) - { x2_min -=boxlength_2;x2_max -=boxlength_2; } - if (y2_min < y1_min) - { y2_min +=boxlength_2;y2_max +=boxlength_2; } - else if (y2_max > y1_max) - { y2_min -=boxlength_2;y2_max -=boxlength_2; } - } - if( ( (x2_min <= x1_min || N.nearly_equal(x2_min,x1_min)) && - (x1_max <= x2_max || N.nearly_equal(x1_max,x2_max)) && - (y2_min <= y1_min || N.nearly_equal(y2_min,y1_min)) && - (y1_max <= y2_max || N.nearly_equal(y1_max,y2_max)) ) || - ( (x1_min <= x2_min || N.nearly_equal(x1_min,x2_min)) && - (x2_max <= x1_max || N.nearly_equal(x2_max,x1_max)) && - (y1_min <= y2_min || N.nearly_equal(y1_min,y2_min)) && - (y2_max <= y1_max || N.nearly_equal(y2_max,y1_max)) ) ) - return true; - else - return false; - }//else -} - - -void NMM::add_shifted_local_exp_of_parent(QuadTreeNodeNM* node_ptr) -{ - QuadTreeNodeNM* father_ptr = node_ptr->get_father_ptr(); - - complex z_0 = father_ptr->get_Sm_center(); - complex z_1 = node_ptr->get_Sm_center(); - Array > z_1_minus_z_0_over (precision()+1); - - //init z_1_minus_z_0_over - z_1_minus_z_0_over[0] = 1; - for(int i = 1; i<= precision(); i++) - z_1_minus_z_0_over[i] = z_1_minus_z_0_over[i-1] * (z_1 - z_0); - - - for(int l = 0; l <= precision();l++) - { - complex sum (0,0); - for(int k = l;k<=precision();k++) - sum += binko(k,l)*father_ptr->get_local_exp()[k]*z_1_minus_z_0_over[k-l]; - node_ptr->get_local_exp()[l] += sum; - } -} - - -void NMM::add_local_expansion(QuadTreeNodeNM* ptr_0, QuadTreeNodeNM* ptr_1) -{ - complex z_0 = ptr_0->get_Sm_center(); - complex z_1 = ptr_1->get_Sm_center(); - complex sum, z_error; - complex factor; - complex z_1_minus_z_0_over_k; - complex z_1_minus_z_0_over_s; - complex pow_minus_1_s_plus_1; - complex pow_minus_1_s; - - //Error-Handling for complex logarithm - if ((std::real(z_1-z_0) <=0) && (std::imag(z_1-z_0) == 0)) //no cont. compl. log fct exists !!! - { - z_error = log(z_1 -z_0 + 0.0000001); - sum = ptr_0->get_multipole_exp()[0] * z_error; - } - else - sum = ptr_0->get_multipole_exp()[0]* log(z_1-z_0); - - - z_1_minus_z_0_over_k = z_1 - z_0; - for(int k = 1; k<=precision(); k++) - { - sum += ptr_0->get_multipole_exp()[k]/z_1_minus_z_0_over_k; - z_1_minus_z_0_over_k *= z_1-z_0; - } - ptr_1->get_local_exp()[0] += sum; - - z_1_minus_z_0_over_s = z_1 - z_0; - for (int s = 1; s <= precision(); s++) - { - pow_minus_1_s_plus_1 = (((s+1)% 2 == 0) ? 1 : -1); - pow_minus_1_s = ((pow_minus_1_s_plus_1 == double(1))? -1 : 1); - sum = pow_minus_1_s_plus_1*ptr_0->get_multipole_exp()[0]/(z_1_minus_z_0_over_s * - double(s)); - factor = pow_minus_1_s/z_1_minus_z_0_over_s; - z_1_minus_z_0_over_s *= z_1-z_0; - complex sum_2 (0,0); - - z_1_minus_z_0_over_k = z_1 - z_0; - for(int k=1; k<=precision(); k++) - { - sum_2 += binko(s+k-1,k-1)*ptr_0->get_multipole_exp()[k]/z_1_minus_z_0_over_k; - z_1_minus_z_0_over_k *= z_1-z_0; - } - ptr_1->get_local_exp()[s] += sum + factor* sum_2; - } -} - - -void NMM::add_local_expansion_of_leaf( - NodeArray&A, - QuadTreeNodeNM* ptr_0, - QuadTreeNodeNM* ptr_1) -{ - List contained_nodes; - double multipole_0_of_v = 1;//only the first coefficient is not zero - complex z_1 = ptr_1->get_Sm_center(); - complex z_error; - complex z_1_minus_z_0_over_s; - complex pow_minus_1_s_plus_1; - - ptr_0->get_contained_nodes(contained_nodes); - - forall_listiterators(node, v_it, contained_nodes) - {//forall - //set position of v as center ( (1,0,....,0) are the multipole coefficients at v) - complex z_0 (A[*v_it].get_x(),A[*v_it].get_y()); - - //now transform multipole_0_of_v to the locale expansion around z_1 - - //Error-Handling for complex logarithm - if ((std::real(z_1-z_0) <=0) && (std::imag(z_1-z_0) == 0)) //no cont. compl. log fct exists! - { - z_error = log(z_1 -z_0 + 0.0000001); - ptr_1->get_local_exp()[0] += multipole_0_of_v * z_error; - } - else - ptr_1->get_local_exp()[0] += multipole_0_of_v * log(z_1-z_0); - - z_1_minus_z_0_over_s = z_1 - z_0; - for (int s = 1;s <= precision();s++) - { - pow_minus_1_s_plus_1 = (((s+1)% 2 == 0) ? 1 : -1); - ptr_1->get_local_exp()[s] += pow_minus_1_s_plus_1*multipole_0_of_v/ - (z_1_minus_z_0_over_s * double(s)); - z_1_minus_z_0_over_s *= z_1-z_0; - } - }//forall -} - - -void NMM::transform_local_exp_to_forces( - NodeArray &A, - List& quad_tree_leaves, - NodeArray& F_local_exp) -{ - List contained_nodes; - complex sum; - complex complex_null (0,0); - complex z_0; - complex z_v_minus_z_0_over_k_minus_1; - DPoint force_vector; - - //calculate derivative of the potential polynom (= local expansion at leaf nodes) - //and evaluate it for each node in contained_nodes() - //and transform the complex number back to the real-world, to obtain the force - - forall_listiterators( QuadTreeNodeNM*, leaf_ptr_ptr,quad_tree_leaves) - { - (*leaf_ptr_ptr)->get_contained_nodes(contained_nodes); - z_0 = (*leaf_ptr_ptr)->get_Sm_center(); - - forall_listiterators(node, v_ptr,contained_nodes) - { - complex z_v (A[*v_ptr].get_x(),A[*v_ptr].get_y()); - sum = complex_null; - z_v_minus_z_0_over_k_minus_1 = 1; - for(int k=1; k<=precision(); k++) - { - sum += double(k) * (*leaf_ptr_ptr)->get_local_exp()[k] * - z_v_minus_z_0_over_k_minus_1; - z_v_minus_z_0_over_k_minus_1 *= z_v - z_0; - } - force_vector.m_x = sum.real(); - force_vector.m_y = (-1) * sum.imag(); - F_local_exp[*v_ptr] = force_vector; - } - } -} - - -void NMM::transform_multipole_exp_to_forces( - NodeArray& A, - List& quad_tree_leaves, - NodeArray& F_multipole_exp) -{ - List M; - List act_contained_nodes; - ListIterator v_ptr; - complex sum; - complex z_0; - complex z_v_minus_z_0_over_minus_k_minus_1; - DPoint force_vector; - - //for each leaf u in the M-List of an actual leaf v do: - //calculate derivative of the multipole expansion function at u - //and evaluate it for each node in v.get_contained_nodes() - //and transform the complex number back to the real-world, to obtain the force - - forall_listiterators(QuadTreeNodeNM*, act_leaf_ptr_ptr,quad_tree_leaves) - { - (*act_leaf_ptr_ptr)->get_contained_nodes(act_contained_nodes); - (*act_leaf_ptr_ptr)->get_M(M); - forall_listiterators(QuadTreeNodeNM*, M_node_ptr_ptr,M) - { - z_0 = (*M_node_ptr_ptr)->get_Sm_center(); - forall_listiterators(node, v_ptr,act_contained_nodes) - { - complex z_v (A[*v_ptr].get_x(),A[*v_ptr].get_y()); - z_v_minus_z_0_over_minus_k_minus_1 = 1.0/(z_v-z_0); - sum = (*M_node_ptr_ptr)->get_multipole_exp()[0]* - z_v_minus_z_0_over_minus_k_minus_1; - - for(int k=1; k<=precision(); k++) - { - z_v_minus_z_0_over_minus_k_minus_1 /= z_v - z_0; - sum -= double(k) * (*M_node_ptr_ptr)->get_multipole_exp()[k] * - z_v_minus_z_0_over_minus_k_minus_1; - } - force_vector.m_x = sum.real(); - force_vector.m_y = (-1) * sum.imag(); - F_multipole_exp[*v_ptr] = F_multipole_exp[*v_ptr] + force_vector; - - } - } - } -} - - -void NMM::calculate_neighbourcell_forces( - NodeArray& A, - List & quad_tree_leaves, - NodeArray& F_direct) -{ - numexcept N; - List act_contained_nodes,neighbour_contained_nodes,non_neighbour_contained_nodes; - List neighboured_leaves; - List non_neighboured_leaves; - double act_leaf_boxlength,neighbour_leaf_boxlength; - DPoint act_leaf_dlc,neighbour_leaf_dlc; - DPoint f_rep_u_on_v; - DPoint vector_v_minus_u; - DPoint nullpoint(0,0); - DPoint pos_u,pos_v; - double norm_v_minus_u,scalar; - int length; - node u,v; - - forall_listiterators(QuadTreeNodeNM*, act_leaf_ptr,quad_tree_leaves) - {//forall - (*act_leaf_ptr)->get_contained_nodes(act_contained_nodes); - - if(act_contained_nodes.size() <= particles_in_leaves()) - {//if (usual case) - - //Step1:calculate forces inside act_contained_nodes - - length = act_contained_nodes.size(); - Array numbered_nodes (length+1); - int k = 1; - forall_listiterators(node, v_ptr,act_contained_nodes) - { - numbered_nodes[k]= *v_ptr; - k++; - } - - for(k = 1; kget_D1() - - (*act_leaf_ptr)->get_D1(neighboured_leaves); - act_leaf_boxlength = (*act_leaf_ptr)->get_Sm_boxlength(); - act_leaf_dlc = (*act_leaf_ptr)->get_Sm_downleftcorner(); - - forall_listiterators(QuadTreeNodeNM*, neighbour_leaf_ptr,neighboured_leaves) - {//forall2 - //forget boxes that have already been looked at - - neighbour_leaf_boxlength = (*neighbour_leaf_ptr)->get_Sm_boxlength(); - neighbour_leaf_dlc = (*neighbour_leaf_ptr)->get_Sm_downleftcorner(); - - if( (act_leaf_boxlength > neighbour_leaf_boxlength) || - (act_leaf_boxlength == neighbour_leaf_boxlength && - act_leaf_dlc.m_x < neighbour_leaf_dlc.m_x) - || (act_leaf_boxlength == neighbour_leaf_boxlength && - act_leaf_dlc.m_x == neighbour_leaf_dlc.m_x && - act_leaf_dlc.m_y < neighbour_leaf_dlc.m_y) ) - {//if - (*neighbour_leaf_ptr)->get_contained_nodes(neighbour_contained_nodes); - forall_listiterators(node, v_ptr,act_contained_nodes) - forall_listiterators(node, u_ptr, neighbour_contained_nodes) - {//for - pos_u = A[*u_ptr].get_position(); - pos_v = A[*v_ptr].get_position(); - if (pos_u == pos_v) - {//if2 (Exception handling if two nodes have the same position) - pos_u = N.choose_distinct_random_point_in_radius_epsilon(pos_u); - }//if2 - vector_v_minus_u = pos_v - pos_u; - norm_v_minus_u = vector_v_minus_u.norm(); - if(!N.f_rep_near_machine_precision(norm_v_minus_u,f_rep_u_on_v)) - { - scalar = f_rep_scalar(norm_v_minus_u)/norm_v_minus_u ; - f_rep_u_on_v.m_x = scalar * vector_v_minus_u.m_x; - f_rep_u_on_v.m_y = scalar * vector_v_minus_u.m_y; - } - F_direct[*v_ptr] = F_direct[*v_ptr] + f_rep_u_on_v; - F_direct[*u_ptr] = F_direct[*u_ptr] - f_rep_u_on_v; - }//for - }//if - }//forall2 - - //Step 3: calculated forces to nodes in act_contained_nodes() of - //leaf_ptr->get_D2() - - (*act_leaf_ptr)->get_D2(non_neighboured_leaves); - forall_listiterators(QuadTreeNodeNM*, non_neighbour_leaf_ptr, - non_neighboured_leaves) - {//forall3 - (*non_neighbour_leaf_ptr)->get_contained_nodes( - non_neighbour_contained_nodes); - forall_listiterators(node,v_ptr,act_contained_nodes) - forall_listiterators(node, u_ptr,non_neighbour_contained_nodes) - {//for - pos_u = A[*u_ptr].get_position(); - pos_v = A[*v_ptr].get_position(); - if (pos_u == pos_v) - {//if2 (Exception handling if two nodes have the same position) - pos_u = N.choose_distinct_random_point_in_radius_epsilon(pos_u); - }//if2 - vector_v_minus_u = pos_v - pos_u; - norm_v_minus_u = vector_v_minus_u.norm(); - if(!N.f_rep_near_machine_precision(norm_v_minus_u,f_rep_u_on_v)) - { - scalar = f_rep_scalar(norm_v_minus_u)/norm_v_minus_u ; - f_rep_u_on_v.m_x = scalar * vector_v_minus_u.m_x; - f_rep_u_on_v.m_y = scalar * vector_v_minus_u.m_y; - } - F_direct[*v_ptr] = F_direct[*v_ptr] + f_rep_u_on_v; - }//for - }//forall3 - }//if(usual case) - else //special case (more then particles_in_leaves() particles in this leaf) - {//else - forall_listiterators(node, v_ptr, act_contained_nodes) - { - pos_v = A[*v_ptr].get_position(); - pos_u = N.choose_distinct_random_point_in_radius_epsilon(pos_v); - vector_v_minus_u = pos_v - pos_u; - norm_v_minus_u = vector_v_minus_u.norm(); - if(!N.f_rep_near_machine_precision(norm_v_minus_u,f_rep_u_on_v)) - { - scalar = f_rep_scalar(norm_v_minus_u)/norm_v_minus_u ; - f_rep_u_on_v.m_x = scalar * vector_v_minus_u.m_x; - f_rep_u_on_v.m_y = scalar * vector_v_minus_u.m_y; - } - F_direct[*v_ptr] = F_direct[*v_ptr] + f_rep_u_on_v; - } - }//else - }//forall -} - - -inline void NMM::add_rep_forces( - const Graph& G, - NodeArray& F_direct, - NodeArray& F_multipole_exp, - NodeArray& F_local_exp, - NodeArray& F_rep) -{ - node v; - forall_nodes(v,G) - { - F_rep[v] = F_direct[v]+F_local_exp[v]+F_multipole_exp[v]; - } -} - - -inline double NMM::f_rep_scalar(double d) -{ - if (d > 0) - { - return 1/d; - } - else - { - cout<<"Error NMM:: f_rep_scalar nodes at same position"< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//Data structure for representing nodes and an int value (needed for class ogdf/list) -//to perform bucket sort. - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NODE_H -#define OGDF_NODE_H - -#include -#include -#include - -namespace ogdf { - - class Node - { - friend int value(const Node& A) { return A.value; } - - friend ostream &operator<< (ostream & output,const Node & A) - { - output <<"node index "; - if(A.vertex == NULL) - output<<"nil"; - else - output<index(); - output<<" value "<< A.value; - return output; - } - - friend istream &operator>> (istream & input,Node & A) { - input >> A.value; - return input; - } - - public: - Node() { vertex = NULL; value = 0; } //constructor - ~Node() { } //destructor - - - void set_Node(node v,int a) { vertex = v; value = a; } - int get_value() const { return value; } - node get_node() const { return vertex; } - - private: - node vertex; - int value ; - }; - -}//namespace ogdf -#endif - - diff --git a/ext/OGDF/src/energybased/NodeAttributes.cpp b/ext/OGDF/src/energybased/NodeAttributes.cpp deleted file mode 100644 index 8fbcbdcd7..000000000 --- a/ext/OGDF/src/energybased/NodeAttributes.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class NodeAttributes. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf{ - -ostream &operator<< (ostream & output, const NodeAttributes & A) -{ - output <<"width: "<< A.width<<" height: "<index(); - output<<" index of higher level node "; - if (A.v_higher_level == NULL) - output <<"NULL"; - else output<index(); - output<<" mass "<index()<<" "; - } - if(A.type == 4) - output<<" dedic_pm_node "<index(); - output<<" distance to dedicated sun "<index()<<" "; - if(A.placed == true) - output<<" is placed"; - else - output<<" is not placed"; - cout<<" angle_1 "<> (istream & input, NodeAttributes & /* A */) -{ - //input >> A.l; - return input; -} - - -void NodeAttributes::init_mult_values() -{ - type = 0; - dedicated_sun_node = NULL; - dedicated_sun_distance = 0; - dedicated_pm_node = NULL; - lambda.clear(); - neighbour_s_node.clear(); - lambda_List_ptr = λ - neighbour_s_node_List_ptr = &neighbour_s_node; - moon_List.clear(); - moon_List_ptr = &moon_List; - placed = false; - angle_1 = 0; - angle_2 = 6.2831853; -} - - -NodeAttributes::NodeAttributes() -{ - position.m_x = 0; - position.m_y = 0; - width = 0; - height = 0; - v_lower_level = NULL; - v_higher_level = NULL; - - //for multilevel step - mass = 0; - type = 0; - dedicated_sun_node = NULL; - dedicated_sun_distance = 0; - dedicated_pm_node = NULL; - lambda.clear(); - neighbour_s_node.clear(); - lambda_List_ptr = λ - neighbour_s_node_List_ptr = &neighbour_s_node; - moon_List.clear(); - moon_List_ptr = &moon_List; - placed = false; - angle_1 = 0; - angle_2 = 6.2831853; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/NodePairEnergy.cpp b/ext/OGDF/src/energybased/NodePairEnergy.cpp deleted file mode 100644 index badefd561..000000000 --- a/ext/OGDF/src/energybased/NodePairEnergy.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class NodePairEnergy - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -#ifdef OGDF_SYSTEM_UNIX -#include -#endif - -#ifdef OGDF_SYSTEM_WINDOWS -#include -#endif - -using namespace std; - -namespace ogdf { - - -NodePairEnergy::NodePairEnergy(const String energyname, GraphAttributes &AG) : - EnergyFunction(energyname,AG), - m_candPairEnergy(m_G), - m_shape(m_G), - m_adjacentOracle(m_G) -{ - node v; - double lengthSum = 0; - forall_nodes(v,m_G) { //saving the shapes of the nodes in m_shape - DPoint center(AG.x(v),AG.y(v)); - lengthSum += AG.width(v); - lengthSum += AG.height(v); - m_shape[v] = IntersectionRectangle(center,AG.width(v),AG.height(v)); - } - m_G.allNodes(m_nonIsolated); - ListIterator it, itSucc; - for(it = m_nonIsolated.begin(); it.valid(); it = itSucc) { - itSucc = it.succ(); - if((*it)->degree() == 0) m_nonIsolated.del(it); - } - m_nodeNums = OGDF_NEW NodeArray(m_G,0); - int n_num = 1; - for(it = m_nonIsolated.begin(); it.valid(); ++it) { - (*m_nodeNums)[*it] = n_num; - n_num++; - } - n_num--; - m_pairEnergy = new Array2D (1,n_num,1,n_num); -} - - -void NodePairEnergy::computeEnergy() -{ - int n_num = m_nonIsolated.size(); - double energySum = 0.0; - Array numNodes(1,n_num); - - ListIterator it; - for(it = m_nonIsolated.begin(); it.valid(); ++it) { - numNodes[(*m_nodeNums)[*it]] = *it; - } - for(int i = 1; i <= n_num-1 ; i++) { - for(int j = i+1; j <= n_num; j++) { - double E = computePairEnergy(numNodes[i],numNodes[j]); - (*m_pairEnergy)(i,j) = E; - energySum += E; - } - } - m_energy = energySum; -} - - -double NodePairEnergy::computePairEnergy(const node v, const node w) const { - return computeCoordEnergy(v,w,currentPos(v),currentPos(w)); -} - - -void NodePairEnergy::internalCandidateTaken() { - node v = testNode(); - int candNum = (*m_nodeNums)[v]; - ListIterator it; - for(it = m_nonIsolated.begin(); it.valid(); ++ it) { - if((*it) != v) { - int numit = (*m_nodeNums)[*it]; - (*m_pairEnergy)(min(numit,candNum),max(numit,candNum)) = m_candPairEnergy[*it]; - m_candPairEnergy[*it] = 0.0; - } - } -} - - -void NodePairEnergy::compCandEnergy() -{ - node v = testNode(); - int numv = (*m_nodeNums)[v]; - m_candidateEnergy = energy(); - ListIterator it; - for(it = m_nonIsolated.begin(); it.valid(); ++ it) { - if(*it != v) { - int j = (*m_nodeNums)[*it]; - m_candidateEnergy -= (*m_pairEnergy)(min(j,numv),max(j,numv)); - m_candPairEnergy[*it] = computeCoordEnergy(v,*it,testPos(),currentPos(*it)); - m_candidateEnergy += m_candPairEnergy[*it]; - if(m_candidateEnergy < 0.0) { - OGDF_ASSERT(m_candidateEnergy > -0.00001); - m_candidateEnergy = 0.0; - } - } - else m_candPairEnergy[*it] = 0.0; - } - OGDF_ASSERT(m_candidateEnergy >= -0.0001); -} - - -#ifdef OGDF_DEBUG -void NodePairEnergy::printInternalData() const { - ListConstIterator it; - for(it = m_nonIsolated.begin(); it.valid(); ++it) { - cout << "\nNode: " << (*m_nodeNums)[*it]; - cout << " CandidatePairEnergy: " << m_candPairEnergy[*it]; - } - cout << "\nPair energies:"; - for(int i=1; i< m_nonIsolated.size(); i++) - for(int j=i+1; j <= m_nonIsolated.size(); j++) - if((*m_pairEnergy)(i,j) != 0.0) - cout << "\nEnergy(" << i << ',' << j << ") = " << (*m_pairEnergy)(i,j); -} -#endif - -} //namespace ogdf diff --git a/ext/OGDF/src/energybased/Overlap.cpp b/ext/OGDF/src/energybased/Overlap.cpp deleted file mode 100644 index 5dd606cb7..000000000 --- a/ext/OGDF/src/energybased/Overlap.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class Overlap - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - - Overlap::Overlap(GraphAttributes &AG) : NodePairEnergy("Overlap",AG){} - - double Overlap::computeCoordEnergy(node v1, node v2, const DPoint &p1, const DPoint &p2) - const - { - IntersectionRectangle i1(shape(v1)), i2(shape(v2)); - i1.move(p1); - i2.move(p2); - IntersectionRectangle intersection = i1.intersection(i2); - double area = intersection.area(); - if(area < 0.0) { - OGDF_ASSERT(area > -0.00001); - area = 0.0; - } - double minArea = min(i1.area(),i2.area()); - double energy = area / minArea; - return energy; - } - -}// namespace ogdf - diff --git a/ext/OGDF/src/energybased/PQueue.h b/ext/OGDF/src/energybased/PQueue.h deleted file mode 100644 index 59e028d88..000000000 --- a/ext/OGDF/src/energybased/PQueue.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PQueue (priority queue). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PQUEUE_H -#define OGDF_PQUEUE_H - -#include - -namespace ogdf { - -//Needed for storing entries of the heap. -class HelpRecord -{ -public: - HelpRecord() { } //constructor - ~HelpRecord(){ } //destructor - - void set_ListIterator(ListIterator& it) { iterator = it; } - void set_value (double v) { value = v; } - ListIterator get_ListIterator() const { return iterator; } - double get_value() const { return value; } - -private: - double value; - ListIterator iterator; -}; - -class PQueue -{ - //Helping data structure that is a priority queue (heap) and holds double values - //(as comparison values) and iterators of type ListIterator - //as contents. It is needed in class MAARPacking for the Best_Fit insert strategy. - -public: - - PQueue() { P.clear(); } //constructor - ~PQueue(){ } //destructor - - //Inserts content with value value into the priority queue and restores the heap. - void insert(double value, ListIterator iterator) - { - HelpRecord h; - h.set_value(value); - h.set_ListIterator(iterator); - P.pushBack(h); - //reheap bottom up - reheap_bottom_up(P.size()-1); - } - - //Deletes the element with the minimum value from the queue and restores - //the heap. - void del_min() - { - if(P.size() < 1) - cout<<"Error PQueue:: del_min() ; Heap is empty"< find_min() - { - OGDF_ASSERT(P.size() >= 1); - //if(P.size() < 1) - // cout<<"Error PQueue:: find_min() ; Heap is empty"< P;//the priority queue; - - //Restores the heap property in P starting from position i bottom up. - void reheap_bottom_up(int i) - { - int parent = (i-1)/2; - - if((i != 0) && ((*P.get(parent)).get_value() > (*P.get(i)).get_value())) - { - exchange(i,parent); - reheap_bottom_up(parent); - } - } - - //Restores the heap property in P starting from position i top down. - void reheap_top_down(int i) - { - int smallest = i; - int l = 2*i+1; - int r = 2*i+2; - - if((l <= P.size()-1) && ((*P.get(l)).get_value() < (*P.get(i)).get_value())) - smallest = l; - else - smallest = i; - if((r <= P.size()-1) && ((*P.get(r)).get_value() < (*P.get(smallest)).get_value())) - smallest = r; - if(smallest != i)//exchange and recursion - { - exchange(i,smallest); - reheap_top_down(smallest); - } - } - - //Exchanges heap entries at positions i and j. - void exchange(int i, int j) - { - HelpRecord h = *P.get(i); - *P.get(i) = *P.get(j); - *P.get(j) = h; - } -}; - -}//namespace ogdf -#endif - - - - diff --git a/ext/OGDF/src/energybased/PackingRowInfo.h b/ext/OGDF/src/energybased/PackingRowInfo.h deleted file mode 100644 index 3019dc8ac..000000000 --- a/ext/OGDF/src/energybased/PackingRowInfo.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class PackingRowInfo. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_PACKING_ROW_INFO_H -#define OGDF_PACKING_ROW_INFO_H - -#include - -namespace ogdf { - - class PackingRowInfo - { - //Helping data structure for MAARPacking. - - //Outputstream for PackingRowInfo - friend ostream &operator<< (ostream & output, const PackingRowInfo & A) - { - output <<" max_height "<> (istream & input, PackingRowInfo & A) - { - input >>A.max_height>>A.total_width>>A.row_index; - return input; - } - - public: - - PackingRowInfo() //constructor - { - total_width = 0; - max_height = 0; - row_index = 0; - } - - ~PackingRowInfo() { } //destructor - - void set_max_height(double h) { max_height = h; } - void set_total_width(double w) { total_width = w; } - void set_row_index(int i) { row_index = i; } - - double get_max_height() { return max_height; } - double get_total_width() { return total_width; } - int get_row_index() { return row_index; } - - private: - double max_height; //the maximum height of a rectangle placed in this row - double total_width; //the sum of the width of all rectsngles in this row - int row_index; //the index of the row (first row in packing has index 0) - - }; - -}//namespace ogdf -#endif - - diff --git a/ext/OGDF/src/energybased/Planarity.cpp b/ext/OGDF/src/energybased/Planarity.cpp deleted file mode 100644 index f301d922d..000000000 --- a/ext/OGDF/src/energybased/Planarity.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class Planarity - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - - Planarity::~Planarity() - { - delete m_edgeNums; - delete m_crossingMatrix; - } - - - // intializes number of edges and allocates memory for crossingMatrix - Planarity::Planarity(GraphAttributes &AG): - EnergyFunction("Planarity",AG) - { - m_edgeNums = OGDF_NEW EdgeArray(m_G,0); - m_G.allEdges(m_nonSelfLoops); - ListIterator it, itSucc; - for(it = m_nonSelfLoops.begin(); it.valid(); it = itSucc) { - itSucc = it.succ(); - if((*it)->isSelfLoop()) m_nonSelfLoops.del(it); - } - int e_num = 1; - for(it = m_nonSelfLoops.begin(); it.valid(); ++it) (*m_edgeNums)[*it] = e_num ++; - e_num --; - m_crossingMatrix = new Array2D (1,e_num,1,e_num); - } - - - // computes energy of layout, stores it and sets the crossingMatrix - void Planarity::computeEnergy() - { - int e_num = m_nonSelfLoops.size(); - int energySum = 0; - Array numEdge(1,e_num); - edge e; - ListIterator it; - - for(it = m_nonSelfLoops.begin(); it.valid(); ++it) - numEdge[(*m_edgeNums)[*it]] = *it; - for(int i = 1; i < e_num; i++) { - e = numEdge[i]; - for(int j = i+1; j <= e_num ; j++) { - bool cross = intersect(e,numEdge[j]); - (*m_crossingMatrix)(i,j) = cross; - if(cross) energySum += 1; - } - } - m_energy = energySum; - } - - - // tests if two edges cross - bool Planarity::intersect(const edge e1, const edge e2) const - { - node v1s = e1->source(); - node v1t = e1->target(); - node v2s = e2->source(); - node v2t = e2->target(); - - bool cross = false; - if(v1s != v2s && v1s != v2t && v1t != v2s && v1t != v2t) - cross = lowLevelIntersect(currentPos(v1s),currentPos(v1t), currentPos(v2s),currentPos(v2t)); - return cross; - } - - - // tests if two lines given by four points cross - bool Planarity::lowLevelIntersect( - const DPoint &e1s, - const DPoint &e1t, - const DPoint &e2s, - const DPoint &e2t) const - { - DPoint s1(e1s),t1(e1t),s2(e2s),t2(e2t); - DLine l1(s1,t1), l2(s2,t2); - DPoint dummy; - return l1.intersection(l2,dummy); - } - - - // computes the energy if the node returned by testNode() is moved - // to position testPos(). - void Planarity::compCandEnergy() - { - node v = testNode(); - m_candidateEnergy = energy(); - edge e; - m_crossingChanges.clear(); - - forall_adj_edges(e,v) if(!e->isSelfLoop()) { - // first we compute the two endpoints of e if v is on its new position - node s = e->source(); - node t = e->target(); - DPoint p1 = testPos(); - DPoint p2 = (s==v)? currentPos(t) : currentPos(s); - int e_num = (*m_edgeNums)[e]; - edge f; - // now we compute the crossings of all other edges with e - ListIterator it; - for(it = m_nonSelfLoops.begin(); it.valid(); ++it) if(*it != e) { - f = *it; - node s2 = f->source(); - node t2 = f->target(); - if(s2 != s && s2 != t && t2 != s && t2 != t) { - bool cross = lowLevelIntersect(p1,p2,currentPos(s2),currentPos(t2)); - int f_num = (*m_edgeNums)[f]; - bool priorIntersect = (*m_crossingMatrix)(min(e_num,f_num),max(e_num,f_num)); - if(priorIntersect != cross) { - if(priorIntersect) m_candidateEnergy --; // this intersection was saved - else m_candidateEnergy ++; // produced a new intersection - ChangedCrossing cc; - cc.edgeNum1 = min(e_num,f_num); - cc.edgeNum2 = max(e_num,f_num); - cc.cross = cross; - m_crossingChanges.pushBack(cc); - } - } - } - } - } - - - // this functions sets the crossingMatrix according to candidateCrossings - void Planarity::internalCandidateTaken() { - ListIterator it; - for(it = m_crossingChanges.begin(); it.valid(); ++ it) { - ChangedCrossing cc = *(it); - (*m_crossingMatrix)(cc.edgeNum1,cc.edgeNum2) = cc.cross; - } - } - - -#ifdef OGDF_DEBUG -void Planarity::printInternalData() const { - cout << "\nCrossing Matrix:"; - int e_num = m_nonSelfLoops.size(); - for(int i = 1; i < e_num; i++) { - cout << "\n Edge " << i << " crosses: "; - for(int j = i+1; j <= e_num; j++) - if((*m_crossingMatrix)(i,j)) cout << j << " "; - } - cout << "\nChanged crossings:"; - if(testNode() == NULL) cout << " None."; - else { - ListConstIterator it; - for(it = m_crossingChanges.begin(); it.valid(); ++it) { - ChangedCrossing cc = *(it); - cout << " (" << cc.edgeNum1 << "," << cc.edgeNum2 << ")" << cc.cross; - } - } -} -#endif - -} diff --git a/ext/OGDF/src/energybased/PlanarityGrid.cpp b/ext/OGDF/src/energybased/PlanarityGrid.cpp deleted file mode 100644 index 7cd2b93cb..000000000 --- a/ext/OGDF/src/energybased/PlanarityGrid.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class PlanarityGrid - * - * The PlanarityGrid energy function counts the number of - * crossings. It contains two UniformGrids: One for the - * current layout and one for the candidate layout. - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - - PlanarityGrid::~PlanarityGrid() - { - delete m_currentGrid; - if(m_candidateGrid != NULL) - delete m_candidateGrid; - } - - - // intialize m_currentLayout and m_candidateLayout - PlanarityGrid::PlanarityGrid(GraphAttributes &AG): - EnergyFunction("PlanarityGrid",AG), m_layout(AG) - { - m_currentGrid = new UniformGrid(AG); - m_candidateGrid = NULL; - } - - - // computes energy of layout, stores it and sets the crossingMatrix - void PlanarityGrid::computeEnergy() - { - m_energy = m_currentGrid->numberOfCrossings(); - } - - - // computes the energy if the node returned by testNode() is moved - // to position testPos(). - void PlanarityGrid::compCandEnergy() - { - if(m_candidateGrid != NULL) - delete m_candidateGrid; - node v = testNode(); - const DPoint& newPos = testPos(); - if(m_currentGrid->newGridNecessary(v,newPos)) - m_candidateGrid = new UniformGrid(m_layout,v,newPos); - else - m_candidateGrid = new UniformGrid(*m_currentGrid,v,newPos); - m_candidateEnergy = m_candidateGrid->numberOfCrossings(); - } - - - // this functions sets the currentGrid to the candidateGrid - void PlanarityGrid::internalCandidateTaken() { - delete m_currentGrid; - m_currentGrid = m_candidateGrid; - m_candidateGrid = NULL; - } - - -#ifdef OGDF_DEBUG -void PlanarityGrid::printInternalData() const { - cout << "\nCurrent grid: " << *m_currentGrid; - cout << "\nCandidate grid: "; - if(m_candidateGrid != NULL) - cout << *m_candidateGrid; - else cout << "empty."; -} -#endif - -} diff --git a/ext/OGDF/src/energybased/QuadTreeNM.cpp b/ext/OGDF/src/energybased/QuadTreeNM.cpp deleted file mode 100644 index ce684bd94..000000000 --- a/ext/OGDF/src/energybased/QuadTreeNM.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class QuadTreeNM. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - -QuadTreeNM::QuadTreeNM() -{ - root_ptr = act_ptr =NULL; -} - - -void QuadTreeNM::create_new_lt_child( - List* L_x_ptr, - List* L_y_ptr) -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x; - new_Sm_dlc.m_y = old_Sm_dlc.m_y+act_ptr->get_Sm_boxlength()/2; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_x_List_ptr(L_x_ptr); - new_ptr->set_y_List_ptr(L_y_ptr); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_lt_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_lt_child() -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x; - new_Sm_dlc.m_y = old_Sm_dlc.m_y+act_ptr->get_Sm_boxlength()/2; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_lt_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_rt_child( - List* L_x_ptr, - List* L_y_ptr) -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x+act_ptr->get_Sm_boxlength()/2; - new_Sm_dlc.m_y = old_Sm_dlc.m_y+act_ptr->get_Sm_boxlength()/2; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_x_List_ptr(L_x_ptr); - new_ptr->set_y_List_ptr(L_y_ptr); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_rt_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_rt_child() -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x+act_ptr->get_Sm_boxlength()/2; - new_Sm_dlc.m_y = old_Sm_dlc.m_y+act_ptr->get_Sm_boxlength()/2; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_rt_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_lb_child( - List* L_x_ptr, - List* L_y_ptr) -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x; - new_Sm_dlc.m_y = old_Sm_dlc.m_y; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_x_List_ptr(L_x_ptr); - new_ptr->set_y_List_ptr(L_y_ptr); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_lb_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_lb_child() -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x; - new_Sm_dlc.m_y = old_Sm_dlc.m_y; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_lb_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_rb_child( - List* L_x_ptr, - List* L_y_ptr) -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x+act_ptr->get_Sm_boxlength()/2; - new_Sm_dlc.m_y = old_Sm_dlc.m_y; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_x_List_ptr(L_x_ptr); - new_ptr->set_y_List_ptr(L_y_ptr); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_rb_ptr(new_ptr); -} - - -void QuadTreeNM::create_new_rb_child() -{ - QuadTreeNodeNM* new_ptr = new QuadTreeNodeNM(); - - DPoint old_Sm_dlc = act_ptr->get_Sm_downleftcorner(); - DPoint new_Sm_dlc; - new_Sm_dlc.m_x = old_Sm_dlc.m_x+act_ptr->get_Sm_boxlength()/2; - new_Sm_dlc.m_y = old_Sm_dlc.m_y; - - new_ptr->set_Sm_level(act_ptr->get_Sm_level()+1); - new_ptr->set_Sm_downleftcorner(new_Sm_dlc); - new_ptr->set_Sm_boxlength((act_ptr->get_Sm_boxlength())/2); - new_ptr->set_father_ptr(act_ptr); - act_ptr->set_child_rb_ptr(new_ptr); -} - - -void QuadTreeNM::delete_tree(QuadTreeNodeNM* node_ptr) -{ - if(node_ptr != NULL) - { - if(node_ptr->get_child_lt_ptr() != NULL) - delete_tree(node_ptr->get_child_lt_ptr()); - if(node_ptr->get_child_rt_ptr() != NULL) - delete_tree(node_ptr->get_child_rt_ptr()); - if(node_ptr->get_child_lb_ptr() != NULL) - delete_tree(node_ptr->get_child_lb_ptr()); - if(node_ptr->get_child_rb_ptr() != NULL) - delete_tree(node_ptr->get_child_rb_ptr()); - delete node_ptr; - if (node_ptr == root_ptr) - root_ptr = NULL; - } -} - - -void QuadTreeNM::delete_tree_and_count_nodes(QuadTreeNodeNM* node_ptr, int& nodecounter) -{ - if(node_ptr != NULL) - { - nodecounter++; - if(node_ptr->get_child_lt_ptr() != NULL) - delete_tree_and_count_nodes(node_ptr->get_child_lt_ptr(),nodecounter); - if(node_ptr->get_child_rt_ptr() != NULL) - delete_tree_and_count_nodes(node_ptr->get_child_rt_ptr(),nodecounter); - if(node_ptr->get_child_lb_ptr() != NULL) - delete_tree_and_count_nodes(node_ptr->get_child_lb_ptr(),nodecounter); - if(node_ptr->get_child_rb_ptr() != NULL) - delete_tree_and_count_nodes(node_ptr->get_child_rb_ptr(),nodecounter); - delete node_ptr; - if (node_ptr == root_ptr) - root_ptr = NULL; - } -} - - -void QuadTreeNM::cout_preorder(QuadTreeNodeNM* node_ptr) -{ - if(node_ptr != NULL) - { - cout<< *node_ptr <get_child_lt_ptr() != NULL) - cout_preorder(node_ptr->get_child_lt_ptr()); - if(node_ptr->get_child_rt_ptr() != NULL) - cout_preorder(node_ptr->get_child_rt_ptr()); - if(node_ptr->get_child_lb_ptr() != NULL) - cout_preorder(node_ptr->get_child_lb_ptr()); - if(node_ptr->get_child_rb_ptr() != NULL) - cout_preorder(node_ptr->get_child_rb_ptr()); - } -} - - -void QuadTreeNM::cout_preorder(QuadTreeNodeNM* node_ptr, int precision) -{ - int i; - if(node_ptr != NULL) - { - complex* L =node_ptr->get_local_exp(); - complex* M =node_ptr->get_multipole_exp(); - cout<< *node_ptr <get_child_lt_ptr() != NULL) - cout_preorder(node_ptr->get_child_lt_ptr(),precision); - if(node_ptr->get_child_rt_ptr() != NULL) - cout_preorder(node_ptr->get_child_rt_ptr(),precision); - if(node_ptr->get_child_lb_ptr() != NULL) - cout_preorder(node_ptr->get_child_lb_ptr(),precision); - if(node_ptr->get_child_rb_ptr() != NULL) - cout_preorder(node_ptr->get_child_rb_ptr(),precision); - } -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/QuadTreeNodeNM.cpp b/ext/OGDF/src/energybased/QuadTreeNodeNM.cpp deleted file mode 100644 index 95488b9fc..000000000 --- a/ext/OGDF/src/energybased/QuadTreeNodeNM.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * $Revision: 2555 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 12:12:10 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class QuadTreeNodeNM. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - -ostream &operator<< (ostream & output, const QuadTreeNodeNM & A) -{ - output <<" Sm_level: "<empty()) - output <<"is empty"; - else - { - forall_listiterators(ParticleInfo, it,*A.L_x_ptr) - output<<" "<<*it; - } - - output<<" L_y: "; - if(A.L_y_ptr == NULL) - output<<"no list specified"; - else if(A.L_y_ptr->empty()) - output <<"is empty"; - else - { - forall_listiterators(ParticleInfo, it,*A.L_y_ptr) - output<<" "<<*it; - } - - output<<" I: "; - if(A.I.empty()) - output <<"is empty"; - else - { - forall_listiterators(QuadTreeNodeNM*, v_ptr,A.I) - output<<" ["<<(*v_ptr)->get_Sm_level()<<" , " - <<(*v_ptr)->get_Sm_downleftcorner()<<"," - <<(*v_ptr)->get_Sm_boxlength()<<"]"; - } - - output<<" D1: "; - if(A.D1.empty()) - output <<"is empty"; - else - { - forall_listiterators(QuadTreeNodeNM*, v_ptr,A.D1) - output<<" ["<<(*v_ptr)->get_Sm_level()<<" , " - <<(*v_ptr)->get_Sm_downleftcorner()<<"," - <<(*v_ptr)->get_Sm_boxlength()<<"]"; - } - - output<<" D2: "; - if(A.D2.empty()) - output <<"is empty"; - else - { - forall_listiterators(QuadTreeNodeNM*, v_ptr,A.D2) - output<<" ["<<(*v_ptr)->get_Sm_level()<<" , " - <<(*v_ptr)->get_Sm_downleftcorner()<<"," - <<(*v_ptr)->get_Sm_boxlength()<<"]"; - } - - output<<" M: "; - if(A.M.empty()) - output <<"is empty"; - else - { - forall_listiterators(QuadTreeNodeNM*, v_ptr,A.M) - output<<" ["<<(*v_ptr)->get_Sm_level()<<" , " - <<(*v_ptr)->get_Sm_downleftcorner()<<"," - <<(*v_ptr)->get_Sm_boxlength()<<"]"; - } - output<<" contained_nodes "; - if(A.contained_nodes.empty()) - output <<"is empty"; - else - { - forall_listiterators(node,v_it,A.contained_nodes) - output<<(*v_it)->index()<<" "; - } - return output; -} - - -istream &operator>> (istream & input, QuadTreeNodeNM & A) -{ - input >> A.Sm_level; - return input; -} - - -QuadTreeNodeNM::QuadTreeNodeNM() -{ - DPoint double_null(0,0); - complex comp_null(0,0); - - L_x_ptr = NULL; ;L_y_ptr = NULL; - subtreeparticlenumber = 0; - Sm_level = 0; - Sm_downleftcorner = double_null; - Sm_boxlength = 0; - Sm_center = comp_null; - ME = NULL; - LE = NULL; - contained_nodes.clear(); - I.clear();D1.clear();D2.clear();M.clear(); - father_ptr = NULL; - child_lt_ptr = child_rt_ptr = child_lb_ptr = child_rb_ptr = NULL; -} - - -QuadTreeNodeNM::~QuadTreeNodeNM() -{ - if(L_x_ptr != NULL) - { - delete L_x_ptr; - L_x_ptr = NULL; - } - if(L_y_ptr != NULL) - { - delete L_y_ptr; - L_y_ptr = NULL; - } - contained_nodes.clear(); - I.clear();D1.clear();D2.clear();M.clear(); - delete [] ME; - delete [] LE; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/Rectangle.h b/ext/OGDF/src/energybased/Rectangle.h deleted file mode 100644 index b0a310b88..000000000 --- a/ext/OGDF/src/energybased/Rectangle.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Rectangle. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_RECTANGLE_H -#define OGDF_RECTANGLE_H - -#include -#include - -namespace ogdf { - - class Rectangle - { - //Helping data structure for packing rectangles; The width, height and the position - //of the down left corner of the tight surroundig rectangle is represented for each - //connected component of the graph. - - //Outputstream for Rectangle. - friend ostream &operator<< (ostream & output, const Rectangle & A) - { - output <<"width: "<< A.width<<" height: "<> (istream & input, Rectangle & A) - { - input >>A.width; - return input; - } - - public: - - Rectangle() //constructor - { - old_down_left_corner_position.m_x = 0; - old_down_left_corner_position.m_y = 0; - new_down_left_corner_position.m_x = 0; - new_down_left_corner_position.m_y = 0; - width = 0; - height = 0; - component_index = -1; - tipped_over = false; - } - - ~Rectangle() { } //destructor - - void set_rectangle (double w, double h, double old_dlc_x_pos,double - old_dlc_y_pos,int comp_index) - { - width = w; - height = h; - old_down_left_corner_position.m_x = old_dlc_x_pos; - old_down_left_corner_position.m_y = old_dlc_y_pos; - component_index = comp_index; - tipped_over = false; - } - - void set_old_dlc_position(DPoint dlc_pos){old_down_left_corner_position = dlc_pos;} - void set_new_dlc_position(DPoint dlc_pos){new_down_left_corner_position = dlc_pos;} - void set_width(double w) {width = w;} - void set_height(double h) {height = h;} - void set_component_index (int comp_index) {component_index = comp_index;} - void tipp_over() - { - if(tipped_over == false) - tipped_over = true; - else - tipped_over = false; - } - - DPoint get_old_dlc_position() const { return old_down_left_corner_position; } - DPoint get_new_dlc_position() const { return new_down_left_corner_position; } - double get_width() const {return width;} - double get_height() const {return height;} - int get_component_index() const {return component_index;} - bool is_tipped_over() const {return tipped_over;} - - private: - DPoint old_down_left_corner_position;//down left corner of the tight surround. rect. - DPoint new_down_left_corner_position;//new calculated down left corner of ... - double width; //width of the surround. rect. - double height; //height of the surround. rect. - int component_index; //the index of the related connected component - bool tipped_over; //indicates if this rectangle has been tipped over in the - //packing step - - }; - - - //Needed for sorting algorithms in ogdf/List and ogdf/Array. - class RectangleComparerHeight - { - public: - RectangleComparerHeight() { } - ~RectangleComparerHeight() { } - - bool less(const Rectangle& A,const Rectangle & B) const - { - if(A.get_height() > B.get_height() ) - return true; - else - return false; - } - - bool leq(const Rectangle& A,const Rectangle & B) const - { - if(A.get_height() >= B.get_height() ) - return true; - else - return false; - } - - bool equal(const Rectangle& A,const Rectangle & B) const - { - if(A.get_height() == B.get_height() ) - return true; - else - return false; - } - }; - - - class RectangleComparerWidth - { - public: - RectangleComparerWidth() { } - ~RectangleComparerWidth() { } - - bool less(const Rectangle& A,const Rectangle & B) const - { - if(A.get_width() > B.get_width() ) - return true; - else - return false; - } - - bool leq(const Rectangle& A,const Rectangle & B) const - { - if(A.get_width() >= B.get_width() ) - return true; - else - return false; - } - - bool equal(const Rectangle& A,const Rectangle & B) const - { - if(A.get_width() == B.get_width() ) - return true; - else - return false; - } - }; - -}//namespace ogdf -#endif - - diff --git a/ext/OGDF/src/energybased/Repulsion.cpp b/ext/OGDF/src/energybased/Repulsion.cpp deleted file mode 100644 index 07dc02db2..000000000 --- a/ext/OGDF/src/energybased/Repulsion.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class Repulsion - * - * \author Rene Weiskircher - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -#ifdef OGDF_SYSTEM_UNIX -#include -#endif - -#ifdef OGDF_SYSTEM_WINDOWS -#include -#endif - -using namespace std; - -namespace ogdf { - - Repulsion::Repulsion(GraphAttributes &AG) : NodePairEnergy("Repulsion",AG) { } - - - double Repulsion::computeCoordEnergy( - node v1, - node v2, - const DPoint &p1, - const DPoint &p2) - const - { - double energy = 0; - if(!adjacent(v1,v2)) { - IntersectionRectangle i1 = shape(v1); - IntersectionRectangle i2 = shape(v2); - i1.move(p1); - i2.move(p2); - double dist = i1.distance(i2); - OGDF_ASSERT(dist >= 0.0); - double div = (dist+1.0)*(dist+1.0); - energy = 1.0/div; - } - return energy; - } - -} //namespace ogdf diff --git a/ext/OGDF/src/energybased/Set.cpp b/ext/OGDF/src/energybased/Set.cpp deleted file mode 100644 index af32a92c4..000000000 --- a/ext/OGDF/src/energybased/Set.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class Set. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "Set.h" - -namespace ogdf { - -Set::Set() -{ - last_selectable_index_of_S_node = -1; - S_node = NULL; - using_S_node = false; -} - - -Set::~Set() -{ - if (using_S_node) delete [] S_node; -} - - -void Set::set_seed(int rand_seed) -{ - srand(rand_seed); -} - - -void Set::init_node_set(Graph& G) -{ - using_S_node = true; - node v; - - S_node = new node[G.numberOfNodes()]; - position_in_node_set.init(G); - - forall_nodes(v,G) - { - S_node[v->index()] = v; - position_in_node_set[v] = v->index(); - } - last_selectable_index_of_S_node = G.numberOfNodes()-1; -} - - -bool Set::empty_node_set() -{ - if(last_selectable_index_of_S_node < 0) - return true; - else - return false; -} - - -bool Set::is_deleted(node v) -{ - if (position_in_node_set[v] > last_selectable_index_of_S_node ) - return true; - else - return false; -} - - -void Set::delete_node(node del_node) -{ - int del_node_index = position_in_node_set[del_node]; - node last_selectable_node = S_node[last_selectable_index_of_S_node]; - - S_node[last_selectable_index_of_S_node] = del_node; - S_node[del_node_index] = last_selectable_node; - position_in_node_set[del_node] = last_selectable_index_of_S_node; - position_in_node_set[last_selectable_node] = del_node_index; - last_selectable_index_of_S_node -=1; -} - - -//---------------- for set of nodes with uniform probability ------------------- - -node Set::get_random_node() -{ - int rand_index = randomNumber(0,last_selectable_index_of_S_node); - node random_node = S_node[rand_index]; - node last_selectable_node = S_node[last_selectable_index_of_S_node]; - - S_node[last_selectable_index_of_S_node] = random_node; - S_node[rand_index] = last_selectable_node; - position_in_node_set[random_node] = last_selectable_index_of_S_node; - position_in_node_set[last_selectable_node] = rand_index; - last_selectable_index_of_S_node -=1; - return random_node; -} - - -//---------------- for set of nodes with weighted probability ------------------ - -void Set::init_node_set(Graph& G,NodeArray& A) -{ - node v,v_adj; - edge e_adj; - - init_node_set(G); - mass_of_star.init(G); - forall_nodes(v,G) - { - mass_of_star[v] = A[v].get_mass(); - forall_adj_edges(e_adj, v) - { - if(e_adj->source() != v) - v_adj = e_adj->source(); - else - v_adj = e_adj->target(); - mass_of_star[v] += A[v_adj].get_mass(); - } - } -} - -//---------------- for set of nodes with ``lower mass'' probability -------------- - -node Set::get_random_node_with_lowest_star_mass(int rand_tries) -{ - int rand_index,new_rand_index,min_mass; - int i = 1; - node random_node,new_rand_node,last_trie_node,last_selectable_node; - - //randomly select rand_tries distinct!!! nodes from S_node and select the one - //with the lowest mass - - int last_trie_index = last_selectable_index_of_S_node; - while( (i<= rand_tries) && (last_trie_index >= 0) ) - {//while - last_trie_node = S_node[last_trie_index]; - new_rand_index = randomNumber(0,last_trie_index); - new_rand_node = S_node[new_rand_index]; - S_node[last_trie_index] = new_rand_node; - S_node[new_rand_index] = last_trie_node; - position_in_node_set[new_rand_node] = last_trie_index; - position_in_node_set[last_trie_node] = new_rand_index; - - if( (i == 1) || (min_mass > mass_of_star[S_node[last_trie_index]]) ) - { - rand_index = last_trie_index; - random_node = S_node[last_trie_index]; - min_mass = mass_of_star[random_node]; - } - i++; - last_trie_index -=1; - }//while - - //now rand_index and random_node have been fixed - last_selectable_node = S_node[last_selectable_index_of_S_node]; - S_node[last_selectable_index_of_S_node] = random_node; - S_node[rand_index] = last_selectable_node; - position_in_node_set[random_node] = last_selectable_index_of_S_node; - position_in_node_set[last_selectable_node] = rand_index; - last_selectable_index_of_S_node -=1; - return random_node; -} - - -//---------------- for set of nodes with ``higher mass'' probability -------------- - -node Set::get_random_node_with_highest_star_mass(int rand_tries) -{ - int rand_index,new_rand_index,min_mass; - int i = 1; - node random_node,new_rand_node,last_trie_node,last_selectable_node; - - //randomly select rand_tries distinct!!! nodes from S_node and select the one - //with the lowest mass - - int last_trie_index = last_selectable_index_of_S_node; - while( (i<= rand_tries) && (last_trie_index >= 0) ) - {//while - last_trie_node = S_node[last_trie_index]; - new_rand_index = randomNumber(0,last_trie_index); - new_rand_node = S_node[new_rand_index]; - S_node[last_trie_index] = new_rand_node; - S_node[new_rand_index] = last_trie_node; - position_in_node_set[new_rand_node] = last_trie_index; - position_in_node_set[last_trie_node] = new_rand_index; - - if( (i == 1) || (min_mass < mass_of_star[S_node[last_trie_index]]) ) - { - rand_index = last_trie_index; - random_node = S_node[last_trie_index]; - min_mass = mass_of_star[random_node]; - } - i++; - last_trie_index -=1; - }//while - - //now rand_index and random_node have been fixed - last_selectable_node = S_node[last_selectable_index_of_S_node]; - S_node[last_selectable_index_of_S_node] = random_node; - S_node[rand_index] = last_selectable_node; - position_in_node_set[random_node] = last_selectable_index_of_S_node; - position_in_node_set[last_selectable_node] = rand_index; - last_selectable_index_of_S_node -=1; - return random_node; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/Set.h b/ext/OGDF/src/energybased/Set.h deleted file mode 100644 index dc3f0ca75..000000000 --- a/ext/OGDF/src/energybased/Set.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class Set. - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_SET_H -#define OGDF_SET_H - -#include -#include -#include -#include - -namespace ogdf { - - class Set - { - //Helping data structure that holds set S_node of nodes in the range [0, - //G.number_of_nodes()-1] (needed for class Multilevel) for randomly choosing nodes - //(with uniform or weighted probability!) - - public: - - Set(); //constructor - ~Set(); //destructor - - void set_seed(int rand_seed); //the the random seed to rand_seed - - - //---------------------- for set of nodes--------------------------------------- - - //Inits S_node[0,...,G.number_of_nodes()-1] and stores the i-th node of P - //at position S_node[i] and in position_in_node_set for each node its index in - //S_node. - void init_node_set(Graph& G); - - //Returns whether S_node is empty or not. - bool empty_node_set(); - - //Returns true if and only if v is deleted from S_node. - bool is_deleted(node v); - - //Deletes the node v from S_node. - void delete_node(node v); - - //---------------- for set of nodes with uniform probability ------------------- - - - //Selects a random element from S_node with uniform probability and updates S_node - //and position_in_node_set. - node get_random_node(); - - //---------------- for set of nodes with weighted probability ------------------- - - //Same as init_node_set(G), but additionally the array mass_of_star is caculated. - void init_node_set(Graph& G,NodeArray& A); - - //---------------- for set of nodes with ``lower mass'' probability -------------- - - //Gets rand_tries random elements from S_node and selects the one with the lowest - //mass_of_star and updates S_node and position_in_node_set. - node get_random_node_with_lowest_star_mass(int rand_tries); - - //---------------- for set of nodes with ``higher mass'' probability -------------- - - //Gets rand_tries random elements from S_node and selects the one with the highest - //mass_of_star and updates S_node and position_in_node_set. - node get_random_node_with_highest_star_mass(int rand_tries); - - private: - - bool using_S_node; //indicates weather S_item, or S_node is used - - node* S_node; //representation of the node set S_node[0,G.number_of_nodes()-1] - int last_selectable_index_of_S_node;//index of the last randomly choosable element - //in S_node (this value is decreased after each - //select operation) - NodeArray position_in_node_set;//holds for each node of G the index of its - //position in S_node - NodeArray mass_of_star; //the sum of the masses of a node and its neighbours - - }; - -}//namespace ogdf -#endif - - diff --git a/ext/OGDF/src/energybased/SpringEmbedderFR.cpp b/ext/OGDF/src/energybased/SpringEmbedderFR.cpp deleted file mode 100644 index f677062c2..000000000 --- a/ext/OGDF/src/energybased/SpringEmbedderFR.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Spring-Embedder algorithm - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -SpringEmbedderFR::SpringEmbedderFR() -{ - m_A = 0; - // default parameters - m_iterations = 400; - m_fineness = 0.51; - - m_xleft = m_ysmall = 0.0; - m_xright = m_ybig = 250.0; - m_noise = true; - - m_scaling = scScaleFunction; - m_scaleFactor = 8.0; - m_bbXmin = 0.0; - m_bbXmax = 100.0; - m_bbYmin = 0.0; - m_bbYmax = 100.0; - - m_minDistCC = 20; - m_pageRatio = 1.0; -} - - -void SpringEmbedderFR::call(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - if(G.empty()) - return; - - // all edges straight-line - AG.clearAllBends(); - - GraphCopy GC; - GC.createEmpty(G); - - // compute connected component of G - NodeArray component(G); - int numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - Array > nodesInCC(numCC); - - node v; - forall_nodes(v,G) - nodesInCC[component[v]].pushBack(v); - - EdgeArray auxCopy(G); - Array boundingBox(numCC); - - int i; - for(i = 0; i < numCC; ++i) - { - GC.initByNodes(nodesInCC[i],auxCopy); - - GraphCopyAttributes AGC(GC,AG); - node vCopy; - forall_nodes(vCopy, GC) { - node vOrig = GC.original(vCopy); - AGC.x(vCopy) = AG.x(vOrig); - AGC.y(vCopy) = AG.y(vOrig); - } - - // original - if (initialize(GC, AGC) == true) - { - for(int i = 1; i <= m_iterations; i++) - mainStep(GC, AGC); - - } - cleanup(); - // end original - - node vFirst = GC.firstNode(); - double minX = AGC.x(vFirst), maxX = AGC.x(vFirst), - minY = AGC.y(vFirst), maxY = AGC.y(vFirst); - - forall_nodes(vCopy,GC) { - node v = GC.original(vCopy); - AG.x(v) = AGC.x(vCopy); - AG.y(v) = AGC.y(vCopy); - - if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; - if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; - if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; - if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; - } - - minX -= m_minDistCC; - minY -= m_minDistCC; - - forall_nodes(vCopy,GC) { - node v = GC.original(vCopy); - AG.x(v) -= minX; - AG.y(v) -= minY; - } - - boundingBox[i] = DPoint(maxX - minX, maxY - minY); - } - - Array offset(numCC); - TileToRowsCCPacker packer; - packer.call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node and edge by the offset - // of its connected component. - - for(i = 0; i < numCC; ++i) - { - const List &nodes = nodesInCC[i]; - - const double dx = offset[i].m_x; - const double dy = offset[i].m_y; - - // iterate over all nodes in ith CC - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - AG.x(v) += dx; - AG.y(v) += dy; - } - } - - m_lit.init(); -} - - -bool SpringEmbedderFR::initialize(GraphCopy &G, GraphCopyAttributes &AG) -{ - if(G.numberOfNodes() <= 1) - return false; // nothing to do - - m_A = 0; - - // compute a suitable area (xleft,ysmall), (xright,ybig) - // zoom the current layout into that area - - double w_sum = 0.0, h_sum = 0.0; - double xmin, xmax, ymin, ymax; - - node v = G.firstNode(); - xmin = xmax = AG.x(v); - ymin = ymax = AG.y(v); - - forall_nodes(v,G) { - if(AG.x(v) < xmin) xmin = AG.x(v); - if(AG.x(v) > xmax) xmax = AG.x(v); - if(AG.y(v) < ymin) ymin = AG.y(v); - if(AG.y(v) > ymax) ymax = AG.y(v); - w_sum += AG.getWidth (v); - h_sum += AG.getHeight(v); - } - - switch(m_scaling) { - case scInput: - m_xleft = xmin; - m_xright = xmax; - m_ysmall = ymin; - m_ybig = ymax; - break; - - case scUserBoundingBox: - case scScaleFunction: - - if (m_scaling == scUserBoundingBox) { - m_xleft = m_bbXmin; - m_xright = m_bbXmax; - m_ysmall = m_bbYmin; - m_ybig = m_bbYmax; - - } else { - double sqrt_n = sqrt((double)G.numberOfNodes()); - m_xleft = 0; - m_ysmall = 0; - m_xright = (w_sum > 0) ? m_scaleFactor * w_sum / sqrt_n : 1; - m_ybig = (h_sum > 0) ? m_scaleFactor * h_sum / sqrt_n : 1; - } - // Compute scaling such that layout coordinates fit into used bounding box - double fx = (xmax == xmin) ? 1.0 : m_xright / (xmax - xmin); - double fy = (ymax == ymin) ? 1.0 : m_ybig / (ymax - ymin); - // Adjust coordinates accordingly - forall_nodes(v,G) { - AG.x(v) = m_xleft + (AG.x(v) - xmin) * fx; - AG.y(v) = m_ysmall + (AG.y(v) - ymin) * fy; - } - } - - - m_lit.init(G); - - - m_width = m_xright - m_xleft; - m_height = m_ybig - m_ysmall; - - OGDF_ASSERT((m_width >= 0) && (m_height >= 0)) - - m_txNull = m_width/50; - m_tyNull = m_height/50; - m_tx = m_txNull; - m_ty = m_tyNull; - - //m_k = sqrt(m_width*m_height / G.numberOfNodes()) / 2; - m_k = m_fineness * sqrt(m_width*m_height / G.numberOfNodes()); - m_k2 = 2*m_k; - m_kk = m_k*m_k; - - m_ki = int(m_k); - - if (m_ki == 0) m_ki = 1; - - m_cF = 1; - - // build matrix of node lists - m_xA = int(m_width / m_ki + 1); - m_yA = int(m_height / m_ki + 1); - m_A = new Array2D >(-1,m_xA,-1,m_yA); - - forall_nodes(v,G) - { - double xv = AG.x(v); - double yv = AG.y(v); - - int i = int((xv - m_xleft) / m_ki); - int j = int((yv - m_ysmall) / m_ki); - - OGDF_ASSERT( (i < m_xA) && (i > -1) ) - OGDF_ASSERT( (j < m_yA) && (j > -1) ) - - m_lit[v] = (*m_A)(i,j).pushFront(v); - } - - return true; -} - - -#define FREPULSE(d) ((m_k2 > (d)) ? m_kk/(d) : 0) - - -void SpringEmbedderFR::mainStep(GraphCopy &G, GraphCopyAttributes &AG) -{ - //const Graph &G = AG.constGraph(); - - node u,v; - edge e; - - NodeArray xdisp(G,0); - NodeArray ydisp(G,0); - - // repulsive forces - forall_nodes(v,G) - { - double xv = AG.x(v); - double yv = AG.y(v); - - int i = int((xv - m_xleft) / m_ki); - int j = int((yv - m_ysmall) / m_ki); - - for(int m = -1; m <= 1; m++) - { - for(int n = -1; n <= 1; n++) - { - ListIterator it; - for(it = (*m_A)(i+m,j+n).begin(); it.valid(); ++it) - { - u = *it; - - if(u == v) continue; - double xdist = xv - AG.x(u); - double ydist = yv - AG.y(u); - double dist = sqrt(xdist*xdist + ydist*ydist); - if(dist < 1e-3) - dist = 1e-3; - xdisp[v] += FREPULSE(dist) * xdist / dist; - ydisp[v] += FREPULSE(dist) * ydist / dist; - } - } - } - } - - // attractive forces - forall_edges(e,G) - { - node u = e->source(); - node v = e->target(); - double xdist = AG.x(v) - AG.x(u); - double ydist = AG.y(v) - AG.y(u); - double dist = sqrt(xdist*xdist + ydist*ydist); - - double f = (u->degree()+v->degree())/6.0; - - dist /= f; - - double fac = dist / m_k; - - xdisp[v] -= xdist*fac; - ydisp[v] -= ydist*fac; - xdisp[u] += xdist*fac; - ydisp[u] += ydist*fac; - } - - // noise - if(m_noise) - { - forall_nodes(v,G) - { - xdisp[v] *= (double(randomNumber(750,1250))/1000.0); - ydisp[v] *= (double(randomNumber(750,1250))/1000.0); - } - } - - - // preventions - - forall_nodes(v,G) - { - double xv = AG.x(v); - double yv = AG.y(v); - - int i0 = int((xv - m_xleft) / m_ki); - int j0 = int((yv - m_ysmall) / m_ki); - - double xd = xdisp[v]; - double yd = ydisp[v]; - double dist = sqrt(xd*xd+yd*yd); - - if (dist < 1) - dist = 1; - - xd = m_tx*xd/dist; - yd = m_ty*yd/dist; - - double xp = xv + xd; - double yp = yv + yd; - - int i,j; - - if( (xp > m_xleft) && (xp < m_xright) ) - { - AG.x(v) = xp; - i = int((xp - m_xleft) / m_ki); - } else - i = i0; - - if( (yp > m_ysmall) && (yp < m_ybig) ) - { - AG.y(v) = yp; - j = int((yp - m_ysmall) / m_ki); - } else - j = j0; - - if( (i != i0) || (j != j0) ) - { - OGDF_ASSERT(m_lit[v].valid()); - - (*m_A)(i0,j0).moveToFront(m_lit[v], (*m_A)(i,j)); - } - } - - m_tx = m_txNull / mylog2(m_cF); - m_ty = m_tyNull / mylog2(m_cF); - - m_cF++; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/energybased/SpringEmbedderFRExact.cpp b/ext/OGDF/src/energybased/SpringEmbedderFRExact.cpp deleted file mode 100644 index 59cb689f6..000000000 --- a/ext/OGDF/src/energybased/SpringEmbedderFRExact.cpp +++ /dev/null @@ -1,599 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Spring-Embedder (Fruchterman,Reingold) - * algorithm with exact force computations. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - -#ifdef _OPENMP -#include -#endif - -#ifdef OGDF_SSE3_EXTENSIONS -#include -#endif - - -namespace ogdf { - -SpringEmbedderFRExact::ArrayGraph::ArrayGraph(GraphAttributes &ga) : m_ga(&ga), m_mapNode(ga.constGraph()) -{ - const Graph &G = ga.constGraph(); - m_numNodes = m_numEdges = 0; - - m_orig = 0; - m_src = m_tgt = 0; - m_x = m_y = 0; - m_nodeWeight = 0; - m_useNodeWeight = false; - - // compute connected components of G - NodeArray component(G); - m_numCC = connectedComponents(G,component); - - m_nodesInCC.init(m_numCC); - - node v; - forall_nodes(v,G) - m_nodesInCC[component[v]].pushBack(v); -} - - -SpringEmbedderFRExact::ArrayGraph::~ArrayGraph() -{ - System::alignedMemoryFree(m_orig); - System::alignedMemoryFree(m_src); - System::alignedMemoryFree(m_tgt); - System::alignedMemoryFree(m_x); - System::alignedMemoryFree(m_y); - System::alignedMemoryFree(m_nodeWeight); -} - - -void SpringEmbedderFRExact::ArrayGraph::initCC(int i) -{ - System::alignedMemoryFree(m_orig); - System::alignedMemoryFree(m_src); - System::alignedMemoryFree(m_tgt); - System::alignedMemoryFree(m_x); - System::alignedMemoryFree(m_y); - System::alignedMemoryFree(m_nodeWeight); - - m_numNodes = m_nodesInCC[i].size(); - m_numEdges = 0; - - m_orig = (node *) System::alignedMemoryAlloc16(m_numNodes*sizeof(node)); - m_x = (double *) System::alignedMemoryAlloc16(m_numNodes*sizeof(double)); - m_y = (double *) System::alignedMemoryAlloc16(m_numNodes*sizeof(double)); - m_nodeWeight = (double *) System::alignedMemoryAlloc16(m_numNodes*sizeof(double)); - - int j = 0; - SListConstIterator it; - for(it = m_nodesInCC[i].begin(); it.valid(); ++it, ++j) { - node v = *it; - - m_orig[j] = v; - m_mapNode[v] = j; - - m_x[j] = m_ga->x(v); - m_y[j] = m_ga->y(v); - - if (m_useNodeWeight) - m_nodeWeight[j] = (m_ga->attributes() & GraphAttributes::nodeWeight) ? m_ga->weight(v) : 1.0; - else - m_nodeWeight[j] = 1.0; - adjEntry adj; - forall_adj(adj,v) - if(v->index() < adj->twinNode()->index()) - ++m_numEdges; - } - - m_src = (int *) System::alignedMemoryAlloc16(m_numEdges*sizeof(int)); - m_tgt = (int *) System::alignedMemoryAlloc16(m_numEdges*sizeof(int)); - - j = 0; - int srcId; - for(it = m_nodesInCC[i].begin(), srcId = 0; it.valid(); ++it, ++srcId) { - node v = *it; - - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(v->index() < w->index()) { - m_src[j] = srcId; - m_tgt[j] = m_mapNode[w]; - ++j; - } - } - } -} - - -SpringEmbedderFRExact::SpringEmbedderFRExact() -{ - // default parameters - m_iterations = 1000; - m_noise = true; - m_coolingFunction = cfFactor; - - m_coolFactor_x = 0.9; - m_coolFactor_y = 0.9; - - m_idealEdgeLength = 10; - m_minDistCC = 20; - m_pageRatio = 1.0; - m_useNodeWeight = false; - m_checkConvergence = true; - m_convTolerance = 0.01; //fraction of ideal edge length below which convergence is achieved -} - - -void SpringEmbedderFRExact::call(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - if(G.empty()) - return; - - // all edges straight-line - AG.clearAllBends(); - - ArrayGraph component(AG); - component.m_useNodeWeight = m_useNodeWeight; - - EdgeArray auxCopy(G); - Array boundingBox(component.numberOfCCs()); - - int i; - for(i = 0; i < component.numberOfCCs(); ++i) - { - component.initCC(i); - - if (component.numberOfNodes() >= 2) - { - initialize(component); - -#ifdef OGDF_SSE3_EXTENSIONS - if(System::cpuSupports(cpufSSE3)) - mainStep_sse3(component); - else -#endif - mainStep(component); - } - - double minX, maxX, minY, maxY; - minX = maxX = component.m_x[0]; - minY = maxY = component.m_y[0]; - - for(int vCopy = 0; vCopy < component.numberOfNodes(); ++vCopy) { - node v = component.original(vCopy); - AG.x(v) = component.m_x[vCopy]; - AG.y(v) = component.m_y[vCopy]; - - if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; - if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; - if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; - if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; - } - - minX -= m_minDistCC; - minY -= m_minDistCC; - - for(int vCopy = 0; vCopy < component.numberOfNodes(); ++vCopy) { - node v = component.original(vCopy); - AG.x(v) -= minX; - AG.y(v) -= minY; - } - - boundingBox[i] = DPoint(maxX - minX, maxY - minY); - } - - Array offset(component.numberOfCCs()); - TileToRowsCCPacker packer; - packer.call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node and edge by the offset - // of its connected component. - - for(i = 0; i < component.numberOfCCs(); ++i) - { - const SList &nodes = component.nodesInCC(i); - - const double dx = offset[i].m_x; - const double dy = offset[i].m_y; - - // iterate over all nodes in ith CC - SListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - AG.x(v) += dx; - AG.y(v) += dy; - } - } -} - - -void SpringEmbedderFRExact::initialize(ArrayGraph &component) -{ - // compute bounding box of current layout - double xmin, xmax, ymin, ymax; - xmin = xmax = component.m_x[0]; - ymin = ymax = component.m_y[0]; - - for(int v = 0; v < component.numberOfNodes(); ++v) - { - xmin = min(xmin, component.m_x[v]); - xmax = max(xmax, component.m_x[v]); - ymin = min(ymin, component.m_y[v]); - ymax = max(ymax, component.m_y[v]); - } - - double w = xmax-xmin+m_idealEdgeLength; - double h = ymax-ymin+m_idealEdgeLength; - - // scale such that the area is about n*k^2 (k = ideal edge length) - double ratio = h/w; - double W = sqrt(component.numberOfNodes() / ratio) * m_idealEdgeLength; - double H = ratio * W; - - double fx = W / w; - double fy = H / h; - - // check: was outcommented in paper version - for(int v = 0; v < component.numberOfNodes(); ++v) - { - component.m_x[v] = (component.m_x[v] - xmin) * fx; - component.m_y[v] = (component.m_y[v] - ymin) * fy; - } - - // 1/20 of all nodes in row - //m_txNull = m_tyNull = m_tx = m_ty = 0.05 * G.numberOfNodes() * m_idealEdgeLength; - //m_txNull = 3*m_idealEdgeLength; - //m_tyNull = 3*m_idealEdgeLength; - m_txNull = W / 8.0; - m_tyNull = H / 8.0; -} - - -void SpringEmbedderFRExact::cool(double &tx, double &ty, int &cF) -{ - switch(m_coolingFunction) { - case cfFactor: - tx *= m_coolFactor_x; - ty *= m_coolFactor_y; - break; - - case cfLogarithmic: - tx = m_txNull / mylog2(cF); - ty = m_tyNull / mylog2(cF); - cF++; - break; - } -} - - -void SpringEmbedderFRExact::mainStep(ArrayGraph &C) -{ - const int n = C.numberOfNodes(); - const double k = m_idealEdgeLength; - const double kSquare = k*k; - const double c_rep = 0.052 * kSquare; // factor for repulsive forces as suggested by Walshaw = 0.2 - - const double minDist = 10e-6;//100*DBL_EPSILON; - const double minDistSquare = minDist*minDist; - - double *disp_x = (double*) System::alignedMemoryAlloc16(n*sizeof(double)); //new double[n]; - double *disp_y = (double*) System::alignedMemoryAlloc16(n*sizeof(double)); //new double[n]; - - double tx = m_txNull; - double ty = m_tyNull; - int cF = 1; - - bool converged = (m_iterations == 0); - int itCount = 1; - - // Loop until either maximum number of iterations reached or - // movement falls under convergence threshold - while (!converged) - { - if (m_checkConvergence) converged = true; - // repulsive forces - - #pragma omp parallel for - for(int v = 0; v < n; ++v) - { - disp_x[v] = disp_y[v] = 0; - - for(int u = 0; u < n; ++u) - { - if(u == v) continue; - - double delta_x = C.m_x[v] - C.m_x[u]; - double delta_y = C.m_y[v] - C.m_y[u]; - - double distSquare = max(minDistSquare, delta_x*delta_x + delta_y*delta_y); - - double t = C.m_nodeWeight[u] / distSquare; - disp_x[v] += delta_x * t; - disp_y[v] += delta_y * t; - } - - disp_x[v] *= c_rep; - disp_y[v] *= c_rep; - } - - // attractive forces - - for(int e = 0; e < C.numberOfEdges(); ++e) - { - int v = C.m_src[e]; - int u = C.m_tgt[e]; - - double delta_x = C.m_x[v] - C.m_x[u]; - double delta_y = C.m_y[v] - C.m_y[u]; - - double dist = max(minDist, sqrt(delta_x*delta_x + delta_y*delta_y)); - - disp_x[v] -= delta_x * dist / k; - disp_y[v] -= delta_y * dist / k; - - disp_x[u] += delta_x * dist / k; - disp_y[u] += delta_y * dist / k; - } - - // limit the maximum displacement to the temperature (m_tx,m_ty) - - #pragma omp parallel for - for(int v = 0; v < n; ++v) - { - double dist = max(minDist, sqrt(disp_x[v]*disp_x[v] + disp_y[v]*disp_y[v])); - double xdisplace = disp_x[v] / dist * min(dist,tx); - double ydisplace = disp_y[v] / dist * min(dist,ty); - double eucdistsq = xdisplace*xdisplace+ydisplace*ydisplace; - double threshold = m_convTolerance*m_idealEdgeLength; - if (eucdistsq > threshold*threshold) - converged = false; - C.m_x[v] += xdisplace; - C.m_y[v] += ydisplace; - } - - cool(tx,ty,cF); - //}//if - itCount++; - converged = (itCount > m_iterations || converged); - }//while not converged - - System::alignedMemoryFree(disp_x); - System::alignedMemoryFree(disp_y); -}//mainstep - - -void SpringEmbedderFRExact::mainStep_sse3(ArrayGraph &C) -{ -//#if (defined(OGDF_ARCH_X86) || defined(OGDF_ARCH_X64)) && !(defined(__GNUC__) && !defined(__SSE3__)) -#ifdef OGDF_SSE3_EXTENSIONS - - const int n = C.numberOfNodes(); - -#ifdef _OPENMP - const int work = 256; - const int nThreadsRep = min(omp_get_max_threads(), 1 + n*n/work); - const int nThreadsPrev = min(omp_get_max_threads(), 1 + n /work); -#endif - - const double k = m_idealEdgeLength; - const double kSquare = k*k; - const double c_rep = 0.052 * kSquare; // 0.2 = factor for repulsive forces as suggested by Warshal - - const double minDist = 10e-6;//100*DBL_EPSILON; - const double minDistSquare = minDist*minDist; - - double *disp_x = (double*) System::alignedMemoryAlloc16(n*sizeof(double)); - double *disp_y = (double*) System::alignedMemoryAlloc16(n*sizeof(double)); - - __m128d mm_kSquare = _mm_set1_pd(kSquare); - __m128d mm_minDist = _mm_set1_pd(minDist); - __m128d mm_minDistSquare = _mm_set1_pd(minDistSquare); - __m128d mm_c_rep = _mm_set1_pd(c_rep); - - #pragma omp parallel num_threads(nThreadsRep) - { - double tx = m_txNull; - double ty = m_tyNull; - int cF = 1; - - for(int i = 1; i <= m_iterations; i++) - { - // repulsive forces - - #pragma omp for - for(int v = 0; v < n; ++v) - { - __m128d mm_disp_xv = _mm_setzero_pd(); - __m128d mm_disp_yv = _mm_setzero_pd(); - - __m128d mm_xv = _mm_set1_pd(C.m_x[v]); - __m128d mm_yv = _mm_set1_pd(C.m_y[v]); - - int u; - for(u = 0; u+1 < v; u += 2) - { - __m128d mm_delta_x = _mm_sub_pd(mm_xv, _mm_load_pd(&C.m_x[u])); - __m128d mm_delta_y = _mm_sub_pd(mm_yv, _mm_load_pd(&C.m_y[u])); - - __m128d mm_distSquare = _mm_max_pd(mm_minDistSquare, - _mm_add_pd(_mm_mul_pd(mm_delta_x,mm_delta_x),_mm_mul_pd(mm_delta_y,mm_delta_y)) - ); - - __m128d mm_t = _mm_div_pd(_mm_load_pd(&C.m_nodeWeight[u]), mm_distSquare); - mm_disp_xv = _mm_add_pd(mm_disp_xv, _mm_mul_pd(mm_delta_x, mm_t)); - mm_disp_yv = _mm_add_pd(mm_disp_yv, _mm_mul_pd(mm_delta_y, mm_t)); - //mm_disp_xv = _mm_add_pd(mm_disp_xv, _mm_mul_pd(mm_delta_x, _mm_div_pd(mm_kSquare,mm_distSquare))); - //mm_disp_yv = _mm_add_pd(mm_disp_yv, _mm_mul_pd(mm_delta_y, _mm_div_pd(mm_kSquare,mm_distSquare))); - } - int uStart = u+2; - if(u == v) ++u; - if(u < n) { - __m128d mm_delta_x = _mm_sub_sd(mm_xv, _mm_load_sd(&C.m_x[u])); - __m128d mm_delta_y = _mm_sub_sd(mm_yv, _mm_load_sd(&C.m_y[u])); - - __m128d mm_distSquare = _mm_max_sd(mm_minDistSquare, - _mm_add_sd(_mm_mul_sd(mm_delta_x,mm_delta_x),_mm_mul_sd(mm_delta_y,mm_delta_y)) - ); - - __m128d mm_t = _mm_div_sd(_mm_load_sd(&C.m_nodeWeight[u]), mm_distSquare); - mm_disp_xv = _mm_add_sd(mm_disp_xv, _mm_mul_sd(mm_delta_x, mm_t)); - mm_disp_yv = _mm_add_sd(mm_disp_yv, _mm_mul_sd(mm_delta_y, mm_t)); - //mm_disp_xv = _mm_add_sd(mm_disp_xv, _mm_mul_sd(mm_delta_x, _mm_div_sd(mm_kSquare,mm_distSquare))); - //mm_disp_yv = _mm_add_sd(mm_disp_yv, _mm_mul_sd(mm_delta_y, _mm_div_sd(mm_kSquare,mm_distSquare))); - } - - for(u = uStart; u < n; u += 2) - { - __m128d mm_delta_x = _mm_sub_pd(mm_xv, _mm_load_pd(&C.m_x[u])); - __m128d mm_delta_y = _mm_sub_pd(mm_yv, _mm_load_pd(&C.m_y[u])); - - __m128d mm_distSquare = _mm_max_pd(mm_minDistSquare, - _mm_add_pd(_mm_mul_pd(mm_delta_x,mm_delta_x),_mm_mul_pd(mm_delta_y,mm_delta_y)) - ); - - __m128d mm_t = _mm_div_pd(_mm_load_pd(&C.m_nodeWeight[u]), mm_distSquare); - mm_disp_xv = _mm_add_pd(mm_disp_xv, _mm_mul_pd(mm_delta_x, mm_t)); - mm_disp_yv = _mm_add_pd(mm_disp_yv, _mm_mul_pd(mm_delta_y, mm_t)); - //mm_disp_xv = _mm_add_pd(mm_disp_xv, _mm_mul_pd(mm_delta_x, _mm_div_pd(mm_kSquare,mm_distSquare))); - //mm_disp_yv = _mm_add_pd(mm_disp_yv, _mm_mul_pd(mm_delta_y, _mm_div_pd(mm_kSquare,mm_distSquare))); - } - if(u < n) { - __m128d mm_delta_x = _mm_sub_sd(mm_xv, _mm_load_sd(&C.m_x[u])); - __m128d mm_delta_y = _mm_sub_sd(mm_yv, _mm_load_sd(&C.m_y[u])); - - __m128d mm_distSquare = _mm_max_sd(mm_minDistSquare, - _mm_add_sd(_mm_mul_sd(mm_delta_x,mm_delta_x),_mm_mul_sd(mm_delta_y,mm_delta_y)) - ); - - __m128d mm_t = _mm_div_sd(_mm_load_sd(&C.m_nodeWeight[u]), mm_distSquare); - mm_disp_xv = _mm_add_sd(mm_disp_xv, _mm_mul_sd(mm_delta_x, mm_t)); - mm_disp_yv = _mm_add_sd(mm_disp_yv, _mm_mul_sd(mm_delta_y, mm_t)); - //mm_disp_xv = _mm_add_sd(mm_disp_xv, _mm_mul_sd(mm_delta_x, _mm_div_sd(mm_kSquare,mm_distSquare))); - //mm_disp_yv = _mm_add_sd(mm_disp_yv, _mm_mul_sd(mm_delta_y, _mm_div_sd(mm_kSquare,mm_distSquare))); - } - - mm_disp_xv = _mm_hadd_pd(mm_disp_xv,mm_disp_xv); - mm_disp_yv = _mm_hadd_pd(mm_disp_yv,mm_disp_yv); - - _mm_store_sd(&disp_x[v], _mm_mul_sd(mm_disp_xv, mm_c_rep)); - _mm_store_sd(&disp_y[v], _mm_mul_sd(mm_disp_yv, mm_c_rep)); - } - - // attractive forces - - #pragma omp single - for(int e = 0; e < C.numberOfEdges(); ++e) - { - int v = C.m_src[e]; - int u = C.m_tgt[e]; - - double delta_x = C.m_x[v] - C.m_x[u]; - double delta_y = C.m_y[v] - C.m_y[u]; - - double dist = max(minDist, sqrt(delta_x*delta_x + delta_y*delta_y)); - - disp_x[v] -= delta_x * dist / k; - disp_y[v] -= delta_y * dist / k; - - disp_x[u] += delta_x * dist / k; - disp_y[u] += delta_y * dist / k; - } - - // limit the maximum displacement to the temperature (m_tx,m_ty) - - __m128d mm_tx = _mm_set1_pd(tx); - __m128d mm_ty = _mm_set1_pd(ty); - - #pragma omp for nowait - for(int v = 0; v < n-1; v += 2) - { - __m128d mm_disp_xv = _mm_load_pd(&disp_x[v]); - __m128d mm_disp_yv = _mm_load_pd(&disp_y[v]); - - __m128d mm_dist = _mm_max_pd(mm_minDist, _mm_sqrt_pd( - _mm_add_pd(_mm_mul_pd(mm_disp_xv,mm_disp_xv),_mm_mul_pd(mm_disp_yv,mm_disp_yv)) - )); - - _mm_store_pd(&C.m_x[v], _mm_add_pd(_mm_load_pd(&C.m_x[v]), - _mm_mul_pd(_mm_div_pd(mm_disp_xv, mm_dist), _mm_min_pd(mm_dist,mm_tx)) - )); - _mm_store_pd(&C.m_y[v], _mm_add_pd(_mm_load_pd(&C.m_y[v]), - _mm_mul_pd(_mm_div_pd(mm_disp_yv, mm_dist), _mm_min_pd(mm_dist,mm_ty)) - )); - } - #pragma omp single nowait - { - if(n % 2) { - int v = n-1; - double dist = max(minDist, sqrt(disp_x[v]*disp_x[v] + disp_y[v]*disp_y[v])); - - C.m_x[v] += disp_x[v] / dist * min(dist,tx); - C.m_y[v] += disp_y[v] / dist * min(dist,ty); - } - } - - cool(tx,ty,cF); - - #pragma omp barrier - } - } - - System::alignedMemoryFree(disp_x); - System::alignedMemoryFree(disp_y); - -#else - mainStep(C); -#endif -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/energybased/SpringEmbedderKK.cpp b/ext/OGDF/src/energybased/SpringEmbedderKK.cpp deleted file mode 100644 index 4db04d837..000000000 --- a/ext/OGDF/src/energybased/SpringEmbedderKK.cpp +++ /dev/null @@ -1,644 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Kamada-Kaway layout algorithm. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -//only debugging -#include - -namespace ogdf { -const double SpringEmbedderKK::startVal = DBL_MAX - 1.0; -const double SpringEmbedderKK::minVal = DBL_MIN; -const double SpringEmbedderKK::desMinLength = 0.0001; - -void SpringEmbedderKK::initialize( - GraphAttributes& GA, - NodeArray& partialDer, - const EdgeArray& eLength, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& sstrength, - double & maxDist, - bool simpleBFS) -{ - node v; - const Graph &G = GA.constGraph(); - //hier if m_spread vorlayout oder muss der Nutzer das extern erledigen? - m_prevEnergy = startVal; - m_prevLEnergy = startVal; - - // all edges straight-line - GA.clearAllBends(); - if (!m_useLayout) - shufflePositions(GA); - - //the shortest path lengths - forall_nodes (v, G) oLength[v].init(G, DBL_MAX); - - //------------------------------------- - //computes shortest path distances d_ij - //------------------------------------- - if (simpleBFS) - { - //we use simply BFS n times - //TODO experimentally compare speed, also with bintree dijkstra -//#ifdef OGDF_DEBUG -// double timeUsed; -// usedTime(timeUsed); -//#endif - maxDist = allpairsspBFS(G, oLength); -//#ifdef OGDF_DEBUG -// timeUsed = usedTime(timeUsed); -// cout << "\n******APSP BFS runtime: \n"; -//#endif - } - else - { - EdgeArray adaptedLength(G); - adaptLengths(G, GA, eLength, adaptedLength); - //we use simply the BFM n times or Floyd instead, leading to cubic runtime - //TODO experimentally compare speed, also with bintree dijkstra - maxDist = allpairssp(G, adaptedLength, oLength, DBL_MAX); - } - //------------------------------------ - //computes original spring length l_ij - //------------------------------------ - - //first we determine desirable edge length L - //nodes sizes may be non-uniform, we approximate the display size (grid) - //this part relies on the fact that node sizes are set != zero - //TODO check later if this is a good choice - double L = m_desLength; //desirable length - double Lzero; //Todo check with m_zeroLength - if (L < desMinLength) - { - double swidth = 0.0f, sheight = 0.0f; - - // Do all nodes lie on the same point? Check by computing BB of centers - // Then, perform simple shifting in layout - node vFirst = G.firstNode(); - double minX = GA.x(vFirst), maxX = GA.x(vFirst), - minY = GA.y(vFirst), maxY = GA.y(vFirst); - // Two goals: - // add node sizes to estimate desirable length - // compute BB to check degeneracy - forall_nodes(v, G) - { - swidth += GA.width(v); - sheight += GA.height(v); - - if(GA.x(v) < minX) minX = GA.x(v); - if(GA.x(v) > maxX) maxX = GA.x(v); - if(GA.y(v) < minY) minY = GA.y(v); - if(GA.y(v) > maxY) maxY = GA.y(v); - } - - double sroot = maxDist;//sqrt(G.numberOfNodes()); - swidth = swidth / sroot; - sheight = sheight / sroot; - Lzero = max(2.0*sroot, 2.0*(swidth + sheight)); - //test for multilevel - Lzero = max(max(maxX-minX, maxY-minY), 2.0*Lzero); - //cout << "Lzero: "<& partialDer, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& sstrength, - const double maxDist) -{ - const Graph &G = GA.constGraph(); - node v; - -#ifdef OGDF_DEBUG - NodeArray nodeCounts(G, 0); - int nodeCount = 0; //number of moved nodes -#endif - // Now we compute delta_m, we search for the node with max value - double delta_m = 0.0f; - double delta_v; - node best_m = G.firstNode(); - - // Compute the partial derivatives first - forall_nodes (v, G) - { - dpair parder = computeParDers(v, GA, sstrength, oLength); - partialDer[v] = parder; - //delta_m is sqrt of squares of partial derivatives - delta_v = sqrt(parder.x1()*parder.x1() + parder.x2()*parder.x2()); - - if (delta_v > delta_m) - { - best_m = v; - delta_m = delta_v; - } - } - - int globalItCount, localItCount; - if (m_computeMaxIt) - { - globalItCount = m_gItBaseVal+m_gItFactor*G.numberOfNodes(); - localItCount = 2*G.numberOfNodes(); - } - else - { - globalItCount = m_maxGlobalIt; - localItCount = m_maxLocalIt; - } - - - while (globalItCount-- > 0 && !finished(delta_m)) - { -#ifdef OGDF_DEBUG -// cout <<"G: "<index()<<"\n"; - nodeCount++; - nodeCounts[best_m]++; -#endif - // The contribution best_m makes to the partial derivatives of - // each vertex. - NodeArray p_partials(G); - forall_nodes(v, G) - { - p_partials[v] = computeParDer(v, best_m, GA, sstrength, oLength); - } - - localItCount = 0; - do { -#ifdef OGDF_DEBUG -// cout <<" New local iteration\n"; -// cout <<" L: "< 0 && !finishedNode(delta_m)); - - // Select new best_m by updating each partial derivative and delta - node old_p = best_m; - forall_nodes(v, G) - { - dpair old_deriv_p = p_partials[v]; - dpair old_p_partial = - computeParDer(v, old_p, GA, sstrength, oLength); - dpair deriv = partialDer[v]; - - deriv.x1() += old_p_partial.x1() - old_deriv_p.x1(); - deriv.x2() += old_p_partial.x2() - old_deriv_p.x2(); - - partialDer[v] = deriv; - double delta = sqrt(deriv.x1()*deriv.x1() + deriv.x2()*deriv.x2()); - - if (delta > delta_m) { - best_m = v; - delta_m = delta; - } - } - }//while -#ifdef OGDF_DEBUG -// cout << "NodeCount: "<index()<<": "<& eLength, bool simpleBFS) -{ - const Graph& G = GA.constGraph(); - NodeArray partialDer(G); //stores the partial derivative per node - double maxDist; //maximum distance between nodes - NodeArray< NodeArray > oLength(G);//first distance, then original length - NodeArray< NodeArray > sstrength(G);//the spring strength - - //only for debugging - OGDF_ASSERT(isConnected(G)); - - //compute relevant values - initialize(GA, partialDer, eLength, oLength, sstrength, maxDist, simpleBFS); - - //main loop with node movement - mainStep(GA, partialDer, oLength, sstrength, maxDist); - - if (simpleBFS) scale(GA); -} - - -void SpringEmbedderKK::call(GraphAttributes& GA) -{ - const Graph &G = GA.constGraph(); - if(G.numberOfEdges() < 1) - return; - - EdgeArray eLength(G);//, 1.0);is not used - doCall(GA, eLength, true); -}//call - -void SpringEmbedderKK::call(GraphAttributes& GA, const EdgeArray& eLength) -{ - const Graph &G = GA.constGraph(); - if(G.numberOfEdges() < 1) - return; - - doCall(GA, eLength, false); -}//call with edge lengths - - -//changes given edge lengths (interpreted as weight factors) -//according to additional parameters like node size etc. -void SpringEmbedderKK::adaptLengths( - const Graph& G, - const GraphAttributes& GA, - const EdgeArray& eLengths, - EdgeArray& adaptedLengths) -{ - //we use the edge lengths as factor and try to respect - //the node sizes such that each node has enough distance - edge e; - //adapt to node sizes - forall_edges(e, G) - { - double smax = max(GA.width(e->source()), GA.height(e->source())); - double tmax = max(GA.width(e->target()), GA.height(e->target())); - if (smax+tmax > 0.0) - adaptedLengths[e] = (1+eLengths[e])*((smax+tmax));///2.0); - else adaptedLengths[e] = 5.0*eLengths[e]; - } -}//adaptLengths - -void SpringEmbedderKK::shufflePositions(GraphAttributes& GA) -{ -//first check if degenerated or -//just position all on a circle or random layout? -}//shufflePositions - - - -// Compute contribution of vertex u to the first partial -// derivatives (dE/dx_m, dE/dy_m) (for vertex m) (eq. 7 and 8 in paper) -SpringEmbedderKK::dpair SpringEmbedderKK::computeParDer( - node m, - node u, - GraphAttributes& GA, - NodeArray< NodeArray >& ss, - NodeArray< NodeArray >& dist) -{ - dpair result(0.0, 0.0); - if (m != u) - { - double x_diff = GA.x(m) - GA.x(u); - double y_diff = GA.y(m) - GA.y(u); - double distance = sqrt(x_diff * x_diff + y_diff * y_diff); - result.x1() = (ss[m][u]) * (x_diff - (dist[m][u])*x_diff/distance); - result.x2() = (ss[m][u]) * (y_diff - (dist[m][u])*y_diff/distance); - } - - return result; -} - - -//compute partial derivative for v -SpringEmbedderKK::dpair SpringEmbedderKK::computeParDers(node v, - GraphAttributes& GA, - NodeArray< NodeArray >& ss, - NodeArray< NodeArray >& dist) -{ - node u; - dpair result(0.0, 0.0); - forall_nodes(u, GA.constGraph()) - { - dpair deriv = computeParDer(v, u, GA, ss, dist); - result.x1() += deriv.x1(); - result.x2() += deriv.x2(); - } - - return result; -} - - -/** - * Initialise the original estimates from nodes and edges. - */ - -//we could speed this up by not using nested NodeArrays and -//by not doing the fully symmetrical computation on undirected graphs -//All Pairs Shortest Path Floyd, initializes the whole matrix -//returns maximum distance. Does not detect negative cycles (lead to neg. values on diagonal) -//threshold is the value for the distance of non-adjacent nodes, distance has to be -//initialized with -double SpringEmbedderKK::allpairssp(const Graph& G, const EdgeArray& eLengths, NodeArray< NodeArray >& distance, - const double threshold) -{ - node v; - edge e; - double maxDist = -threshold; - - forall_nodes(v, G) - { - distance[v][v] = 0.0f; - } - - //TODO: Experimentally compare this against - // all nodes and incident edges (memory access) on huge graphs - forall_edges(e, G) - { - distance[e->source()][e->target()] = eLengths[e]; - distance[e->target()][e->source()] = eLengths[e]; - } - -///** -// * And run the main loop of the algorithm. -// */ - node u, w; - forall_nodes(v, G) - { - forall_nodes(u, G) - { - forall_nodes(w, G) - { - if ((distance[u][v] < threshold) && (distance[v][w] < threshold)) - { - distance[u][w] = min( distance[u][w], distance[u][v] + distance[v][w] ); - //distance[w][u] = distance[u][w]; //is done anyway afterwards - } - if (distance[u][w] < threshold) - maxDist = max(maxDist,distance[u][w]); - } - } - } - //debug output -//#ifdef OGDF_DEBUG -// forall_nodes(v, G) -// { -// if (distance[v][v] < 0.0) cerr << "\n###Error in shortest path computation###\n\n"; -// } -// cout << "Maxdist: "<index() << " -> "<index()<<" "< >& distance) -{ - node v; - double maxDist = 0; - - forall_nodes(v, G) - { - distance[v][v] = 0.0f; - } - - v = G.firstNode(); - - //start in each node once - while (v != 0) - { - //do a bfs - NodeArray mark(G, true); - SListPure bfs; - bfs.pushBack(v); - mark[v] = false; - - while (!bfs.empty()) - { - node w = bfs.popFrontRet(); - edge e; - double d = distance[v][w]+1.0f; - forall_adj_edges(e,w) - { - node u = e->opposite(w); - if (mark[u]) - { - mark[u] = false; - bfs.pushBack(u); - distance[v][u] = d; - maxDist = max(maxDist,d); - } - } - }//while - - v = v->succ(); - }//while - //check for negative cycles - forall_nodes(v, G) - { - if (distance[v][v] < 0.0) cerr << "\n###Error in shortest path computation###\n\n"; - } - -//debug output -//#ifdef OGDF_DEBUG -// node u, w; -// cout << "Maxdist: "<index() << " -> "<index()<<" "<source())*GA.width(e->source())+ - GA.height(e->source())*GA.height(e->source())); - double w2 = sqrt(GA.width(e->target())*GA.width(e->target())+ - GA.height(e->target())*GA.height(e->target())); - w2 = (w1+w2)/2.0; //half length of both diagonals - double xs = GA.x(e->source()); - double xt = GA.x(e->target()); - double ys = GA.y(e->source()); - double yt = GA.y(e->target()); - double xdist = xs-xt; - double ydist = ys-yt; - if ((fabs(xs) > (DBL_MAX / 2.0)-1) || (fabs(xt)> (DBL_MAX/2.0)-1) || - (fabs(ys)> (DBL_MAX/2.0)-1) || (fabs(yt)> (DBL_MAX/2.0)-1)) - scale = false; //never scale with huge numbers - //(even though the drawing may be small and could be shifted to origin) - double elength = sqrt(xdist*xdist+ydist*ydist); - - //Avoid a max factor of inf!! - if (DIsGreater(elength, 0.0001)) - { - w2 = m_distFactor * w2 / elength;//relative to edge length - - if (w2 > maxFac) - maxFac = w2; - } - } - - - if (maxFac > 1.0 && (maxFac < (DBL_MAX/2.0)-1) && scale) //only scale to increase distance - { - //if maxFac is large, we scale in steps until we reach a threshold - if (maxFac > 2048) - { - double scaleF = maxFac+0.00001; - double base = 2.0; - maxFac = base; - - while (scale && maxFac (DBL_MAX / base)-1 || GA.y(v) > (DBL_MAX / base) - 1) - scale = false; - } - maxFac *= base; - } - } - else - { - forall_nodes(v, GA.constGraph()) - { - GA.x(v) = GA.x(v)*maxFac; - GA.y(v) = GA.y(v)*maxFac; - } - } -//#ifdef OGDF_DEBUG -// cout << "Scaled by factor "< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -//For initial layouts -#include - -#include - -//only debugging -#include - -namespace ogdf { -const double StressMajorization::startVal = DBL_MAX - 1.0; -const double StressMajorization::minVal = DBL_MIN; -const double StressMajorization::desMinLength = 0.0001; - -void StressMajorization::initialize( - GraphAttributes& GA, - const EdgeArray& eLength, - NodeArray< NodeArray >& oLength, - NodeArray< NodeArray >& weights, - double & maxDist, - bool simpleBFS) -{ - node v; - const Graph &G = GA.constGraph(); - - m_prevEnergy = startVal; - m_prevLEnergy = startVal; - - // all edges straight-line - GA.clearAllBends(); - if (!m_useLayout) - shufflePositions(GA); - - //the shortest path lengths - forall_nodes (v, G) oLength[v].init(G, DBL_MAX); - forall_nodes (v, G) weights[v].init(G, 0.0); - - //------------------------------------- - //computes shortest path distances d_ij - //------------------------------------- - if (simpleBFS) - { - //we use simply BFS n times - //TODO experimentally compare speed, also with bintree dijkstra -#ifdef OGDF_DEBUG - double timeUsed; - usedTime(timeUsed); -#endif - maxDist = allpairsspBFS(G, oLength, weights); -#ifdef OGDF_DEBUG - timeUsed = usedTime(timeUsed); - cout << "\n******APSP BFS runtime: \n"; -#endif - } - else - { - EdgeArray adaptedLength(G); - adaptLengths(G, GA, eLength, adaptedLength); - //we use simply the BFM n times or Floyd instead, leading to cubic runtime - //TODO experimentally compare speed, also with bintree dijkstra - maxDist = allpairssp(G, adaptedLength, oLength, weights, DBL_MAX); - } - - if (m_radial) - { - //TODO: Also allow different ways to compute centrality (closeness,...) - // and incorporate node sizes - //if centrality - computeRadii(G, oLength, maxDist); - } -//Todo: Here we could add distance values depending on given node sizes -}//initialize - - -//uses closeness to compute the radii -void StressMajorization::computeRadii(const Graph& G, const NodeArray< NodeArray >& distances, - double diameter) -{ - m_radii.init(G, 1.0); - //compute a center (simple version) - node v, w; - double minMax = DBL_MAX; - node center = 0; - int numCentralNodes = 0; - double maxCloseness = 0.0; - double minCloseness = DBL_MAX; - - // inverse of sum of shortest path distances - NodeArray closeness(G, 0.0); - - //Compute closeness values and min/max - forall_nodes(v, G) - { - double maxDist = 0.0; - forall_nodes(w, G) - { - if (v != w) closeness[v] += distances[v][w]; - if (distances[v][w] > maxDist) maxDist = distances[v][w]; - } - if (maxDist < minMax) - { - minMax = maxDist; - center = v; - } - closeness[v] = (G.numberOfNodes()-1)/closeness[v]; //was 1/ - - //Check for min/max closeness - if (DIsGreater(closeness[v], maxCloseness)) - { - maxCloseness = closeness[v]; - numCentralNodes = 1; - } - else if (DIsEqual(closeness[v], maxCloseness)) numCentralNodes++; - if (DIsGreater(minCloseness, closeness[v])) - minCloseness = closeness[v]; - } - - //see paper by Brandes, Kenis, Wagner - double coincideOfs = min(0.5, double(numCentralNodes)/double((G.numberOfNodes()-1))); - - OGDF_ASSERT(center != 0); - forall_nodes(v, G) - { - //cout << "Diameter: "< >& oLength, - NodeArray< NodeArray >& weights, - const double maxDist) -{ - const Graph &G = GA.constGraph(); - node v; - - //preparation for upward constraints - edge e; - NodeArray< NodeArray > upWeight(G); - forall_nodes(v, G) upWeight[v].init(G, 0.0); - //try to add upward constraints by looking at the adjacent edges - forall_edges(e, G) - { - upWeight[e->source()][e->target()] = 1.0; - upWeight[e->target()][e->source()] = -1.0; - } - -#ifdef OGDF_DEBUG - NodeArray nodeCounts(G, 0); -#endif - NodeArray invPosNorm(G); - NodeArray< NodeArray > invDistb(G); //bij in paper Pich Brandes - - //this value is needed quite often - NodeArray wijSum(G, 0.0); //sum of w_ij for each i over j!= i - - forall_nodes(v, G) - { - invDistb[v].init(G); - node w; - forall_nodes(w, G) - { - if (v != w) wijSum[v]+= weights[v][w]; - } - } - - //-------------------------------------------------- - // Iterations can either be done until a predefined - // number m_numSteps+m_itFac*|G| is reached or a break condition - // is fullfilled - //-------------------------------------------------- - //for iteration checking - double weightsum = 1.0; - if (m_upward) weightsum = 0.93; - - OGDF_ASSERT(DIsGreater(m_numSteps+m_itFac*G.numberOfNodes(), 0.0)); - double kinv = weightsum/double(m_numSteps+m_itFac*G.numberOfNodes()); - - NodeArray newX(G); - NodeArray newY(G); - //weighting for different optimization criteria - double t = 0.0; - - for (double tt = 0; tt <= weightsum; tt+= kinv) - { - double iterStressSum = 0.0; - if (m_radial || m_upward) t = tt; - else t = 0.0; - //compute inverse norm of position for radial distance constraints - forall_nodes(v, G) - { - double px = GA.x(v); - double py = GA.y(v); - //set values a_i as in paper pseudo code (simplified) - double tmp = px*px+py*py; - if (DIsGreater(tmp, 0.0)) - invPosNorm[v] = 1/double(sqrt(tmp)); - else invPosNorm[v] = 0.0; - //cout << "invPosNorm: "<degree()/100.0; - } - - if(m_radial) - { - double tmp = radius(v); - OGDF_ASSERT(DIsGreater(tmp, 0.0)) - tmpinvsq = 1/(tmp*tmp); - double tmppart = t*tmpinvsq*tmp*invPosNorm[v]; - - radOfsX = tmppart*GA.x(v); - radOfsY = tmppart*GA.y(v); - } - - //upward constraints - double upOfs = 0.0; //only for y coordinate - - //sum over all other nodes - node w; - double stressSumX = 0.0; - double stressSumY = 0.0; - forall_nodes(w, G) - { - if ( v != w ) - { - stressSumX += weights[v][w]*(GA.x(w)+oLength[v][w]*(GA.x(v)-GA.x(w))*invDistb[v][w]); - stressSumY += weights[v][w]*(GA.y(w)+oLength[v][w]*(GA.y(v)-GA.y(w))*invDistb[v][w]); - //also add the influence of adjacent nodes that are not placed correctly - if (m_upward) - { - double val = upWeight[v][w]; - //adjacent nodes influence each other - if (!DIsEqual(val, 0.0)) - { - if (DIsGreater(val, 0.0)) //v is source - { - if (GA.y(v) > GA.y(w)-1.0) - { - upOfs -= val*(GA.y(w)-1.0*invDistb[v][w]); - } - } -// else //v is target -// { -// if (GA.y(w) > GA.y(v)-1.0) -// { -// upOfs -= val*(GA.y(w)+(fabs(GA.y(v)-GA.y(w)))*invDistb[v][w]); -// } -// } - } - - } - } - } - upOfs *= upWeightSum; - if (m_radial || m_upward) - { - stressSumX *= (1-t); - stressSumY *= (1-t); - } - - //main fraction - newX[v] = (stressSumX+radOfsX)/double(((1-t)*wijSum[v]+t*tmpinvsq)); - //experimental, only valid if disjoint constraints - newY[v] = (stressSumY+radOfsY+0.2*upOfs)/double(((1-t)*wijSum[v]+t*tmpinvsq+0.2*upWeightSum)); - GA.x(v) = newX[v]; - GA.y(v) = newY[v]; - iterStressSum += stressSumX; - iterStressSum += stressSumY; - } - //Alternatively, we can do the update after the computation step - // forall_nodes(v, G) - // { - //GA.x(v) = newX[v]; - //GA.y(v) = newY[v]; - // } - if (finished(iterStressSum)) - { - cout << iterStressSum<<"\n"; - break; - } - }//outer loop: iterations or threshold - -}//mainStep - - -void StressMajorization::doCall(GraphAttributes& GA, const EdgeArray& eLength, bool simpleBFS) -{ - const Graph& G = GA.constGraph(); - double maxDist; //maximum distance between nodes - NodeArray< NodeArray > oLength(G);//first distance, then original length - NodeArray< NodeArray > weights(G);//standard weights as in MCGee,Kamada/Kawai - - //only for debugging - OGDF_ASSERT(isConnected(G)); - - //compute relevant values - initialize(GA, eLength, oLength, weights, maxDist, simpleBFS); - - //main loop with node movement - mainStep(GA, oLength, weights, maxDist); - - if (simpleBFS) scale(GA); -} - - -void StressMajorization::call(GraphAttributes& GA) -{ - const Graph &G = GA.constGraph(); - if(G.numberOfEdges() < 1) - return; - - EdgeArray eLength(G);//, 1.0);is not used - doCall(GA, eLength, true); -}//call - - -void StressMajorization::call(GraphAttributes& GA, const EdgeArray& eLength) -{ - const Graph &G = GA.constGraph(); - if(G.numberOfEdges() < 1) - return; - - doCall(GA, eLength, false); -}//call with edge lengths - - -//changes given edge lengths (interpreted as weight factors) -//according to additional parameters like node size etc. -void StressMajorization::adaptLengths( - const Graph& G, - const GraphAttributes& GA, - const EdgeArray& eLengths, - EdgeArray& adaptedLengths) -{ - //we use the edge lengths as factor and try to respect - //the node sizes such that each node has enough distance - edge e; - //adapt to node sizes - forall_edges(e, G) - { - double smax = max(GA.width(e->source()), GA.height(e->source())); - double tmax = max(GA.width(e->target()), GA.height(e->target())); - if (smax+tmax > 0.0) - adaptedLengths[e] = (1+eLengths[e])*((smax+tmax));///2.0); - else adaptedLengths[e] = 5.0*eLengths[e]; - } -}//adaptLengths - - -void StressMajorization::shufflePositions(GraphAttributes& GA) -{ - //random layout? FMMM? classical MDS? see Paper of Pich and Brandes - //just hope that we have low sigma values (distance error) - FMMMLayout fm; - //fm.call(GA); -}//shufflePositions - - - -/** - * Initialise the original estimates from nodes and edges. - */ - -//we could speed this up by not using nested NodeArrays and -//by not doing the fully symmetrical computation on undirected graphs -//All Pairs Shortest Path Floyd, initializes the whole matrix -//returns maximum distance. Does not detect negative cycles (lead to neg. values on diagonal) -//threshold is the value for the distance of non-adjacent nodes, distance has to be -//initialized with -// The weight parameter here is just for the stress majorization -// and directly set here for speedup -double StressMajorization::allpairssp( - const Graph& G, - const EdgeArray& eLengths, - NodeArray< NodeArray >& distance, - NodeArray< NodeArray >& weights, - const double threshold) -{ - node v; - edge e; - double maxDist = -threshold; - - forall_nodes(v, G) - { - distance[v][v] = 0.0f; - weights[v][v] = 0.0f; - } - - //TODO: Experimentally compare this against - // all nodes and incident edges (memory access) on huge graphs - forall_edges(e, G) - { - distance[e->source()][e->target()] = eLengths[e]; - distance[e->target()][e->source()] = eLengths[e]; - } - -///** -// * And run the main loop of the algorithm. -// */ - node u, w; - forall_nodes(v, G) - { - forall_nodes(u, G) - { - forall_nodes(w, G) - { - if ((distance[u][v] < threshold) && (distance[v][w] < threshold)) - { - distance[u][w] = min( distance[u][w], distance[u][v] + distance[v][w] ); - weights[u][w] = 1/(distance[u][w]*distance[u][w]); - //distance[w][u] = distance[u][w]; //is done anyway afterwards - } - if (distance[u][w] < threshold) - maxDist = max(maxDist,distance[u][w]); - } - } - } - //debug output -#ifdef OGDF_DEBUG - forall_nodes(v, G) - { - if (distance[v][v] < 0.0) cerr << "\n###Error in shortest path computation###\n\n"; - } - cout << "Maxdist: "<index() << " -> "<index()<<" "< >& distance, - NodeArray< NodeArray >& weights) -{ - node v; - double maxDist = 0; - - forall_nodes(v, G) - { - distance[v][v] = 0.0f; - } - - v = G.firstNode(); - - //start in each node once - while (v != 0) - { - //do a bfs - NodeArray mark(G, true); - SListPure bfs; - bfs.pushBack(v); - mark[v] = false; - - while (!bfs.empty()) - { - node w = bfs.popFrontRet(); - edge e; - double d = distance[v][w]+1.0f; - forall_adj_edges(e,w) - { - node u = e->opposite(w); - if (mark[u]) - { - mark[u] = false; - bfs.pushBack(u); - distance[v][u] = d; - weights[v][u] = 1/(d*d); - maxDist = max(maxDist,d); - } - } - }//while - - v = v->succ(); - }//while - //check for negative cycles - forall_nodes(v, G) - { - if (distance[v][v] < 0.0) cerr << "\n###Error in shortest path computation###\n\n"; - } - -//debug output -#ifdef OGDF_DEBUG - node u, w; - cout << "Maxdist: "<index() << " -> "<index()<<" "<source())*GA.width(e->source())+ - GA.height(e->source())*GA.height(e->source())); - double w2 = sqrt(GA.width(e->target())*GA.width(e->target())+ - GA.height(e->target())*GA.height(e->target())); - w2 = (w1+w2)/2.0; //half length of both diagonals - double xdist = GA.x(e->source())-GA.x(e->target()); - double ydist = GA.y(e->source())-GA.y(e->target()); - double elength = sqrt(xdist*xdist+ydist*ydist); - w2 = m_distFactor * w2 / elength;//relative to edge length - if (w2 > maxFac) - maxFac = w2; - } - - if (maxFac > 0.0) - { - forall_nodes(v, GA.constGraph()) - { - GA.x(v) = GA.x(v)*maxFac; - GA.y(v) = GA.y(v)*maxFac; - } -#ifdef OGDF_DEBUG - cout << "Scaled by factor "< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -namespace ogdf { - const double UniformGrid::m_epsilon = 0.000001; - const double UniformGrid::m_edgeMultiplier = 1.0; - -// int UniformGrid::constructorcounter = 0; - - void UniformGrid::ModifiedBresenham( - const IPoint &p1, - const IPoint &p2, - SList &crossedCells) const{ - crossedCells.clear(); - - int Ax = p1.m_x; - int Ay = p1.m_y; - int Bx = p2.m_x; - int By = p2.m_y; - //------------------------------------------------------------------------ - // INITIALIZE THE COMPONENTS OF THE ALGORITHM THAT ARE NOT AFFECTED BY THE - // SLOPE OR DIRECTION OF THE LINE - //------------------------------------------------------------------------ - int dX = abs(Bx-Ax); // store the change in X and Y of the line endpoints - int dY = abs(By-Ay); - - //------------------------------------------------------------------------ - // DETERMINE "DIRECTIONS" TO INCREMENT X AND Y (REGARDLESS OF DECISION) - //------------------------------------------------------------------------ - int Xincr, Yincr,Xoffset,Yoffset; - if (Ax > Bx) { Xincr=-1; Xoffset = -1;} else { Xincr=1; Xoffset = 0;} // which direction in X? - if (Ay > By) { Yincr=-1; Yoffset = -1;} else { Yincr=1; Yoffset = 0;} // which direction in Y? - // the offsets are necessary because we always want the cell left and below - // the point were bresenham wants to draw it - - //------------------------------------------------------------------------ - // DETERMINE INDEPENDENT VARIABLE (ONE THAT ALWAYS INCREMENTS BY 1 (OR -1) ) - // AND INITIATE APPROPRIATE LINE DRAWING ROUTINE (BASED ON FIRST OCTANT - // ALWAYS). THE X AND Y'S MAY BE FLIPPED IF Y IS THE INDEPENDENT VARIABLE. - //------------------------------------------------------------------------ - if (dX >= dY) // if X is the independent variable - { - int dPr = dY<<1; // amount to increment decision if right is chosen (always) - int dPru = dPr - (dX<<1); // amount to increment decision if up is chosen - int P = dPr - dX; // decision variable start value - int secondY = Ay+Yincr; //Y-coordinate of secondary point - int testval = P; //if P is equal to testval, the the next point is drawn exactly - // on the segment. If P is smaller than testval, it is below the - //segment - - - for (; dX>=0; dX--) // process each point in the line one at a time (just use dX) - { - crossedCells.pushBack(IPoint(Ax+Xoffset,Ay+Yoffset));//add the primary cell - crossedCells.pushBack(IPoint(Ax+Xoffset,secondY+Yoffset));//add the secondary cell - if (P > 0) // is the pixel going right AND up? - { - Ax+=Xincr; // increment independent variable - Ay+=Yincr; // increment dependent variable - P+=dPru; // increment decision (for up) - } - else // is the pixel just going right? - { - Ax+=Xincr; // increment independent variable - P+=dPr; // increment decision (for right) - } - if(P - testval < 0) //primary cell above the line - secondY = Ay-Yincr; - else secondY = Ay+Yincr;//primary cell below the line - } - } - else // if Y is the independent variable - { - int dPr = dX<<1; // amount to increment decision if right is chosen (always) - int dPru = dPr - (dY<<1); // amount to increment decision if up is chosen - int P = dPr - dY; // decision variable start value - int testval = P; // substracting this from P tells us if the cell is drawn left or - // right from the actual segment - int secondX = Ax+Xincr; //X-Coordinate of secondary cell - - for (; dY>=0; dY--) // process each point in the line one at a time (just use dY) - { - crossedCells.pushBack(IPoint(Ax+Xoffset,Ay+Yoffset));// add the primary cell - crossedCells.pushBack(IPoint(secondX+Xoffset,Ay+Yoffset));// add the secondary cell - if (P > 0) // is the pixel going up AND right? - { - Ax+=Xincr; // increment dependent variable - Ay+=Yincr; // increment independent variable - P+=dPru; // increment decision (for up) - } - else // is the pixel just going up? - { - Ay+=Yincr; // increment independent variable - P+=dPr; // increment decision (for right) - } - if(P - testval < 0) //primary cell left of the line - secondX = Ax-Xincr; - else secondX = Ax+Xincr;//primary cell right of the line - } - } - - } - - void UniformGrid::DoubleModifiedBresenham( - const DPoint &p1, - const DPoint &p2, - SList &crossedCells) const{ - crossedCells.clear(); - //------------------------------------------------------------------------ - // INITIALIZE THE COMPONENTS OF THE ALGORITHM THAT ARE NOT AFFECTED BY THE - // SLOPE OR DIRECTION OF THE LINE - //------------------------------------------------------------------------ - double dX = fabs(p2.m_x-p1.m_x); // store the change in X and Y of the line endpoints - double dY = fabs(p1.m_y-p2.m_y); - - - //------------------------------------------------------------------------ - // DETERMINE INDEPENDENT VARIABLE (ONE THAT ALWAYS INCREMENTS BY 1 (OR -1) ) - // AND INITIATE APPROPRIATE LINE DRAWING ROUTINE (BASED ON FIRST OCTANT - // ALWAYS). THE X AND Y'S MAY BE FLIPPED IF Y IS THE INDEPENDENT VARIABLE. - //------------------------------------------------------------------------ - if (dX >= dY) // if X is the independent variable - { - DPoint left,right; - if(p1.m_x > p2.m_x) { - left = p2; - right = p1; - } - else { - left = p1; - right= p2; - } - //Now we determine the coordinates of the start cell - //and the end cell - IPoint start(computeGridPoint(left)); - if(p1 == p2) { - crossedCells.pushBack(start); - return; - } - IPoint end(computeGridPoint(right)); - //Since computeGridPoint rounds down, this gives us the point p1 and - //below each of the points. This is the address of the cell that contains - //the point - //int Yincr = 1; - //if(left.m_y > right.m_y) Yincr = -1; - double slope = (right.m_y-left.m_y)/(right.m_x-left.m_x); - double c = left.m_y-slope*left.m_x; - OGDF_ASSERT(fabs(slope*right.m_x+c - right.m_y) < m_epsilon); - int endX = end.m_x+1; - double dYincr = slope * m_CellSize; - double OldYPos = slope*start.m_x*m_CellSize+c; - int oldY = (int)floor(OldYPos/m_CellSize); - for(int i = start.m_x; i <= endX; i++) { - crossedCells.pushBack(IPoint(i,oldY)); - double newY = OldYPos + dYincr; - OGDF_ASSERT(newY - ((i+1)*m_CellSize*slope+c) < m_epsilon) - int newCellY = (int)floor(newY/m_CellSize); - if(newCellY != oldY) { - oldY = newCellY; - crossedCells.pushBack(IPoint(i,oldY)); - } - OldYPos = newY; - } - } - else // if Y is the independent variable - { - DPoint bottom,top; - if(p1.m_y > p2.m_y) { - bottom = p2; - top = p1; - } - else { - bottom = p1; - top = p2; - } - IPoint start(computeGridPoint(bottom)); - IPoint end(computeGridPoint(top)); - //int Xincr = 1; - //if(bottom.m_x > top.m_x) Xincr = -1; - double slope = (top.m_x-bottom.m_x)/(top.m_y-bottom.m_y); - double c = bottom.m_x-slope*bottom.m_y; - OGDF_ASSERT(fabs(slope*top.m_y+c - top.m_x) < m_epsilon); - int endY = end.m_y+1; - double dXincr = slope * m_CellSize; - double OldXPos = slope*start.m_y*m_CellSize+c; - int oldX = (int)floor(OldXPos/m_CellSize); - for(int i = start.m_y; i <= endY; i++) { - crossedCells.pushBack(IPoint(oldX,i)); - double newX = OldXPos + dXincr; - OGDF_ASSERT(newX - ((i+1)*m_CellSize*slope+c) < m_epsilon) - int newCellX = (int)floor(newX/m_CellSize); - if(newCellX != oldX) { - oldX = newCellX; - crossedCells.pushBack(IPoint(oldX,i)); - } - OldXPos = newX; - } - } - - } -//constructor for computing the grid and the crossings from scratch for the -//layout given by AG -UniformGrid::UniformGrid(const GraphAttributes &AG) : - m_layout(AG), - m_graph(AG.constGraph()), - m_crossings(m_graph), - m_cells(m_graph), - m_CellSize(0.0), - m_crossNum(0) -{ - //cout<<"New grid \n"; - node v = m_graph.firstNode(); - DPoint pos(m_layout.x(v),m_layout.y(v)); -#ifdef OGDF_DEBUG - m_crossingTests = 0; - m_maxEdgesPerCell = 0; - usedTime(m_time); -#endif - IntersectionRectangle ir; - computeGridGeometry(v,pos,ir); - double maxLength = max(ir.height(),ir.width()); - m_CellSize = maxLength/(m_edgeMultiplier*(m_graph).numberOfEdges()); - List L; - m_graph.allEdges(L); - computeCrossings(L,v,pos); -#ifdef OGDF_DEBUG - m_time = usedTime(m_time); -#endif -} - -//constructor for computing the grid and the crossings from scratch for -//the given layout where node v is moved to newPos -UniformGrid::UniformGrid( - const GraphAttributes &AG, - const node v, - const DPoint& newPos) -: - m_layout(AG), - m_graph(AG.constGraph()), - m_crossings(m_graph), - m_cells(m_graph), - m_CellSize(0.0), - m_crossNum(0) -{ -#ifdef OGDF_DEBUG - m_crossingTests = 0; - m_maxEdgesPerCell = 0; - usedTime(m_time); -#endif - IntersectionRectangle ir; - computeGridGeometry(v,newPos,ir); - double maxLength = max(ir.height(),ir.width()); - m_CellSize = maxLength/(m_edgeMultiplier*(m_graph).numberOfEdges()); - List L; - m_graph.allEdges(L); - computeCrossings(L,v,newPos); -#ifdef OGDF_DEBUG - m_time = usedTime(m_time); -#endif -} - -//constructor for computing an updated grid for a given grid where one -//vertex is moved to a new position -UniformGrid::UniformGrid( - const UniformGrid &ug, - const node v, - const DPoint& newPos) : - m_layout(ug.m_layout), - m_graph(ug.m_graph), - m_grid(ug.m_grid), - m_crossings(ug.m_crossings), - m_cells(ug.m_cells), - m_CellSize(ug.m_CellSize), - m_crossNum(ug.m_crossNum) -{ - //constructorcounter++; -#ifdef OGDF_DEBUG - m_crossingTests = 0; - m_maxEdgesPerCell = 0; - usedTime(m_time); - IntersectionRectangle ir; - computeGridGeometry(v,newPos,ir); - double l = max(ir.width(),ir.height()); - l/=(m_graph.numberOfEdges()*m_edgeMultiplier); - OGDF_ASSERT(l > 0.5*m_CellSize && l < 2.0*m_CellSize); -#endif - //compute the list of edge incident to v - List incident; - m_graph.adjEdges(v,incident); - //set the crossings of all these edges to zero, update the global crossing - //number, remove them from their cells. Note that we cannot insert the edge - //with its new position into the grid in the same loop because we may get - //crossings with other edges incident to v - ListIterator it1; - for(it1 = incident.begin(); it1.valid(); ++it1) { - edge& e = *it1; - //we clear the list of crossings of e and delete e from the - //crossings lists of all the edges it crosses - List& c = m_crossings[e]; - while(!c.empty()) { - edge crossed = c.popFrontRet(); - List& cl = m_crossings[crossed]; - ListIterator it2 = cl.begin(); - while(*it2 != e) ++it2; - cl.del(it2); - m_crossNum--; - } - List& cells = m_cells[e]; - //delete e from all its cells - while(!cells.empty()) { - IPoint p = cells.popFrontRet(); - List& eList = m_grid(p.m_x,p.m_y); - ListIterator it2 = eList.begin(); - while(*it2 != e) ++it2; - eList.del(it2); - } - }// at this point, all the data structures look as if the edges in the - //list incident where not present. Now we reinsert the edges into the - //grid with their new positions and update the crossings - computeCrossings(incident,v,newPos); -#ifdef OGDF_DEBUG - m_time = usedTime(m_time); -#endif -} - - -void UniformGrid::computeGridGeometry( - const node moved, - const DPoint& newPos, - IntersectionRectangle& ir) const -{ - //first we compute the resolution and size of the grid - double MinX = DBL_MAX, MinY = DBL_MAX, MaxX =DBL_MIN, MaxY = DBL_MIN; - //find lower left and upper right vertex - node v; - forall_nodes(v,m_graph) { - double x = 0.0, y = 0.0; - if(v != moved) {// v is the node that was moved - x = m_layout.x(v); - y = m_layout.y(v); - } - else {// v is not the moved node - x = newPos.m_x; - y = newPos.m_y; - } - if(x < MinX) MinX = x; - if(x > MaxX) MaxX = x; - if(y < MinY) MinY = y; - if(y > MaxY) MaxY = y; - } - ir = IntersectionRectangle(MinX,MinY,MaxX,MaxY); -} - - -void UniformGrid::computeCrossings( - const List& toInsert, - const node moved, - const DPoint& newPos) -{ - //now we compute all the remaining data of the class in one loop - //going through all edges and storing them in the grid. - ListConstIterator it; - for(it = toInsert.begin(); it.valid(); ++it) { - const edge& e = *it; - SList crossedCells; - DPoint sPos,tPos; - const node& s = e->source(); - if(s != moved) sPos = DPoint(m_layout.x(s),m_layout.y(s)); - else sPos = newPos; - const node& t = e->target(); - if(t != moved) tPos = DPoint(m_layout.x(t),m_layout.y(t)); - else tPos = newPos; - DoubleModifiedBresenham(sPos,tPos,crossedCells); - SListConstIterator it1; - for(it1 = crossedCells.begin(); it1.valid(); ++it1) { - const IPoint& p = *it1; - (m_cells[e]).pushBack(p); - List& edgeList = m_grid(p.m_x,p.m_y); - if(!edgeList.empty()) { //there are already edges in that list - ListConstIterator it2; - OGDF_ASSERT(!edgeList.empty()); - for(it2 = edgeList.begin(); it2.valid(); ++it2) { - if(crossingTest(e,*it2,moved,newPos,p)) { //two edges cross in p - ++m_crossNum; - m_crossings[e].pushBack(*it2); - m_crossings[*it2].pushBack(e); - } - } - } - //now we insert the new edge into the list and store the position - //returned by pushBack in the corresponding list of m_storedIn - edgeList.pushBack(e); -#ifdef OGDF_DEBUG - if(m_maxEdgesPerCell < edgeList.size()) - m_maxEdgesPerCell = edgeList.size(); -#endif - } - } -#ifdef OGDF_DEBUG - int SumCros = 0; - edge e; - forall_edges(e,m_graph) SumCros += m_crossings[e].size(); - OGDF_ASSERT((SumCros >> 1) == m_crossNum); -#endif -} - - -//returns true if both edges are not adjacent and cross inside the given cell -bool UniformGrid::crossingTest( - const edge e1, - const edge e2, - const node moved, - const DPoint& newPos, - const IPoint& cell) -{ - bool crosses = false; - node s1 = e1->source(), t1 = e1->target(); - node s2 = e2->source(), t2 = e2->target(); - if(s1 != s2 && s1 != t2 && t1 != s2 && t1 != t2) {//not adjacent - double xLeft = cell.m_x*m_CellSize; - double xRight = (cell.m_x+1)*m_CellSize; - double xBottom = cell.m_y*m_CellSize; - double xTop = (cell.m_y+1)*m_CellSize; - DPoint ps1,pt1,ps2,pt2; - if(s1 != moved) ps1 = DPoint(m_layout.x(s1),m_layout.y(s1)); - else ps1 = newPos; - if(t1 != moved) pt1 = DPoint(m_layout.x(t1),m_layout.y(t1)); - else pt1 = newPos; - if(s2 != moved) ps2 = DPoint(m_layout.x(s2),m_layout.y(s2)); - else ps2 = newPos; - if(t2 != moved) pt2 = DPoint(m_layout.x(t2),m_layout.y(t2)); - else pt2 = newPos; - DLine l1(ps1,pt1),l2(ps2,pt2); - DPoint crossPoint; -#ifdef OGDF_DEBUG - m_crossingTests++; -#endif - if(l1.intersection(l2,crossPoint)) { - if(crossPoint.m_x >= xLeft && crossPoint.m_x < xRight && - crossPoint.m_y >= xBottom && crossPoint.m_y < xTop) { - crosses = true; - } - } - } - return crosses; -} - -#ifdef OGDF_DEBUG - -void UniformGrid::markCells(SList &result, Array2D &cells) const { - while(!result.empty()) { - IPoint p = result.popFrontRet(); - if(cells.low1() <= p.m_x && cells.high1() >= p.m_x - && cells.low2() <= p.m_y && cells.high2() >= p.m_y) - cells(p.m_x,p.m_y) = true; - } -} - - -void UniformGrid::checkBresenham(DPoint p1, DPoint p2) const -{ - int crossed = 0; - DPoint bottomleft(min(p1.m_x,p2.m_x),min(p1.m_y,p2.m_y)); - DPoint topright(max(max(p1.m_x,p2.m_x),bottomleft.m_x+1.0), - max(max(p1.m_y,p2.m_y),bottomleft.m_y+1.0)); - IPoint ibl(computeGridPoint(bottomleft)); - IPoint itr(computeGridPoint(topright)); - Array2D cells(ibl.m_x,itr.m_x+1,ibl.m_y,itr.m_y+1,false); - SList result; - DoubleModifiedBresenham(p1,p2,result); - cout << "\nList computed by Bresenham:\n"; - - for(SListIterator it = result.begin(); it.valid(); ++it) { - cout << computeRealPoint(*it) << " "; - } - - markCells(result,cells); - cout << "\nCrossed cells:\n"; - if(p1.m_x == p2.m_x) { //vertical segment - int cellXcoord = (int)floor(p1.m_x/m_CellSize); - double b = floor(min(p1.m_y,p2.m_y)/m_CellSize); - double t = ceil(max(p1.m_y,p2.m_y)/m_CellSize); - OGDF_ASSERT(isInt(b) && isInt(t)); - int intT = (int)t; - for(int i = int(b); i < intT; i++) { - crossed++; - IPoint p(cellXcoord,i); - cout << computeRealPoint(p) << " "; - if(!cells(p.m_x,p.m_y)) { - cout << "\nCell " << computeRealPoint(p) << " is not marked!"; - exit(1); - } - } - } - else { - if(p1.m_y == p2.m_y) { //horizontal segment - double tmp = floor(p1.m_y/m_CellSize); - assert(isInt(tmp)); - int cellYcoord = (int)tmp; - double l = floor(min(p1.m_x,p2.m_x)/m_CellSize); - double r = ceil(max(p1.m_x,p2.m_x)/m_CellSize); - assert(isInt(l) && isInt(r)); - int intR = (int)r; - for(int i = int(l); i < intR; i++) { - crossed++; - IPoint p(i,cellYcoord); - cout << computeRealPoint(p) << " "; - if(!cells(p.m_x,p.m_y)) { - cout << "\nCell " << computeRealPoint(p) << " is not marked!"; - exit(1); - } - } - } - else { - for(int i = cells.low1(); i <= cells.high1(); i++) { - for(int j = cells.low2(); j <= cells.high2(); j++) { - IPoint p(i,j); - if(crossesCell(p1,p2,p)) { - crossed++; - cout << computeRealPoint(p) << " "; - if(!cells(p.m_x,p.m_y)) { - cout << "\n Cell " << computeRealPoint(p) << " is not marked!"; - exit(1); - } - } - } - } - - } - } - if(crossed < max(fabs(p1.m_x-p2.m_x)/m_CellSize,fabs(p1.m_y-p2.m_y)/m_CellSize)) { - cout << "\nNot enough crossed cells for " << p1 << " " << p2 << "\n"; - exit(1); - } - cout << "\n"; - -} - - -void UniformGrid::checkBresenham(IPoint p1, IPoint p2) const -{ - int crossed = 0; - int left = min(p1.m_x,p2.m_x)-1; - int right = max(max(p1.m_x,p2.m_x),left+1); - int bottom = min(p1.m_y,p2.m_y)-1; - int top = max(max(p1.m_y,p2.m_y),bottom+1); - Array2D cells(left,right,bottom,top,false); - SList result; - ModifiedBresenham(p1,p2,result); - cout << "\nList computed by Bresenham:\n" << result; - markCells(result,cells); - cout << "\nCrossed cells:\n"; - if(p1.m_x == p2.m_x) { //vertical segment - for(int i = min(p1.m_y,p2.m_y); i < max(p1.m_y,p2.m_y); i++) { - crossed++; - IPoint p(p1.m_x,i); - cout << p << " "; - if(!cells(p.m_x,p.m_y)) { - cout << "\nCell " << p << " is not marked!"; - exit(1); - } - } - } - else { - if(p1.m_y == p2.m_y) { //horizontal segment - for(int i = min(p1.m_x,p2.m_x); i < max(p1.m_x,p2.m_x); i++) { - crossed++; - IPoint p(i,p1.m_y); - cout << p << " "; - if(!cells(i,p1.m_y)) { - cout << "\nCell " << p <<" is not marked!"; - exit(1); - } - } - } - else { - for(int i = cells.low1(); i <= cells.high1(); i++) { - for(int j = cells.low2(); j <= cells.high2(); j++) { - IPoint p(i,j); - if(crossesCell(p1,p2,p)) { - crossed++; - cout << p << " "; - if(!cells(p.m_x,p.m_y)) { - cout << "\n Cell " << p << " is not marked!"; - exit(1); - } - } - } - } - - } - } - if(crossed < max(abs(p1.m_x-p2.m_x),abs(p1.m_y-p2.m_y))) { - cout << "\nNot enough crossed cells for " << p1 << " " << p2 << "\n"; - exit(1); - } - cout << "\n"; - -} - - -//the upper and left boundary does not belong to a cell -bool UniformGrid::crossesCell( - IPoint A, - IPoint B, - const IPoint &CellAdr) const -{ - bool crosses = false; - if(A.m_x == B.m_x) {//line segment is vertical - if(A.m_x >= CellAdr.m_x && A.m_x < CellAdr.m_x+1) { - if(intervalIntersect(A.m_y,B.m_y,CellAdr.m_y,CellAdr.m_y+1)) - crosses = true; - } - } - else {//line segment not vertical - if(A.m_x > B.m_x) swap(A,B); - double m = double(B.m_y-A.m_y)/double(B.m_x-A.m_x); - double c = A.m_y-A.m_x*m; - double y1 = m*CellAdr.m_x + c; - double y2 = m*(CellAdr.m_x+1)+c; - crosses = intervalIntersect(A.m_x,B.m_x,CellAdr.m_x,CellAdr.m_x+1); - crosses = crosses && intervalIntersect(y1,y2,CellAdr.m_y,CellAdr.m_y+1); - } - return crosses; -} - - -//the upper and left boundary does not belong to a cell -bool UniformGrid::crossesCell( - DPoint A, - DPoint B, - const IPoint &CellAdr) const -{ - bool crosses = false; - double xLowCell = CellAdr.m_x * m_CellSize; - double xHighCell = xLowCell + m_CellSize; - double yLowCell = CellAdr.m_y * m_CellSize; - double yHighCell = yLowCell + m_CellSize; - if(A.m_x == B.m_x) {//line segment is vertical - if(A.m_x >= xLowCell && A.m_x < xHighCell) { - if(intervalIntersect(A.m_y,B.m_y,yLowCell,yHighCell)) - crosses = true; - } - } - else {//line segment not vertical - if(A.m_x > B.m_x) swap(A,B); - double m = (B.m_y-A.m_y)/(B.m_x-A.m_x); - double c = A.m_y-A.m_x*m; - double y1 = m * xLowCell + c; - double y2 = m * xHighCell + c; - crosses = intervalIntersect(A.m_x,B.m_x,xLowCell,xHighCell); - crosses = crosses && intervalIntersect(min(A.m_y,B.m_y),max(A.m_y,B.m_y), - yLowCell,yHighCell); - crosses = crosses && intervalIntersect(y1,y2,yLowCell,yHighCell); - } - return crosses; -} - - -bool UniformGrid::intervalIntersect( - double a1, - double a2, - double cell1, - double cell2) const -{ - double epsilon = 0.000001; - bool intersect = true; - if(min(a1,a2)+epsilon >= max(cell1,cell2) || min(cell1,cell2)+epsilon >= max(a1,a2)) intersect = false; - return intersect; -} - - -ostream &operator<<(ostream &out, const UniformGrid &ug) -{ - out << "\nGrid Size: " << ug.m_CellSize; - out << "\nEpsilon: " << ug.m_epsilon; - out << "\nEdge Multiplier: " << ug.m_edgeMultiplier; - out << "\nCrossing number: " << ug.m_crossNum; -#ifdef OGDF_DEBUG - out << "\nCrossing tests: " << ug.m_crossingTests; - out << "\nMax edges per cell: " << ug.m_maxEdgesPerCell; - out << "\nConstruction time: " << ug.m_time; - IntersectionRectangle ir; - node v = ug.m_graph.firstNode(); - ug.computeGridGeometry(v,DPoint(ug.m_layout.x(v),ug.m_layout.y(v)),ir); - double l = max(ir.width(),ir.height()); - cout << "\nPreferred Cell Size: " << l/(ug.m_graph.numberOfEdges()*ug.m_edgeMultiplier); -#endif - return out; -} - - -#endif -}//namespace diff --git a/ext/OGDF/src/energybased/WSPD.cpp b/ext/OGDF/src/energybased/WSPD.cpp deleted file mode 100644 index 2b0fbc743..000000000 --- a/ext/OGDF/src/energybased/WSPD.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class WSPD (well-separated pair decomposition). - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include "WSPD.h" -#include "FastUtils.h" - -namespace ogdf { - -WSPD::WSPD(__uint32 maxNumNodes) : m_maxNumNodes(maxNumNodes) -{ - m_maxNumPairs = maxNumNodes*2; - m_numPairs = 0; - allocate(); - clear(); -} - - -WSPD::~WSPD(void) -{ - deallocate(); -} - - -unsigned long WSPD::sizeInBytes() const -{ - return m_maxNumNodes*sizeof(WSPDNodeInfo) + - m_maxNumPairs*sizeof(WSPDPairInfo); -} - - -void WSPD::allocate() -{ - m_nodeInfo = (WSPDNodeInfo*)MALLOC_16(m_maxNumNodes*sizeof(WSPDNodeInfo)); - m_pairs = (WSPDPairInfo*)MALLOC_16(m_maxNumPairs*sizeof(WSPDPairInfo)); -} - - -void WSPD::deallocate() -{ - FREE_16(m_nodeInfo); - FREE_16(m_pairs); -} - - -void WSPD::clear() -{ - for (__uint32 i = 0; i < m_maxNumNodes; i++) - { - m_nodeInfo[i].numWSNodes = 0; - } - m_numPairs = 0; -} - -} // end of namespace ogdf diff --git a/ext/OGDF/src/energybased/WSPD.h b/ext/OGDF/src/energybased/WSPD.h deleted file mode 100644 index d8568cf5e..000000000 --- a/ext/OGDF/src/energybased/WSPD.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class WSPD (well-separated pair decomposition). - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifndef OGDF_WSPD_H -#define OGDF_WSPD_H - -#include "LinearQuadtree.h" - -namespace ogdf { - -//! class for storing per node information -struct WSPDNodeInfo -{ - __uint32 numWSNodes; // total count of pairs where is either the first or second node - __uint32 firstEntry; // the first pair in the nodes chain - __uint32 lastEntry; // the last pair in the nodes chain -}; - - -//! class for storing per pair information -struct WSPDPairInfo -{ - __uint32 a; // first node of the pair - __uint32 b; // second node of the pair - __uint32 a_next;// next pair in the chain of the first node - __uint32 b_next;// next pair in the chain of the second node -}; - - -//! class for the Well-Separated-Pairs-Decomposition (WSPD) -class WSPD -{ -public: - typedef LinearQuadtree::NodeID NodeID; - - //! the constructor. allocates the mem - WSPD(__uint32 maxNumNodes); - - //! destructor - ~WSPD(void); - - //! returns the max number of nodes. (Equals the max number of nodes in the lin quadtree) - inline __uint32 maxNumNodes() const - { - return m_maxNumNodes; - } - - //! returns the number of well separated nodes for node a - inline __uint32 numWSNodes(NodeID a) const - { - return m_nodeInfo[a].numWSNodes; - } - - //! returns the total number of pairs - inline __uint32 numPairs() const - { - return m_numPairs; - } - - //! returns the maximum number of pairs - inline __uint32 maxNumPairs() const - { - return m_maxNumPairs; - } - - //! resets the array - void clear(); - - //! add a well separated pair (a, b) - void addWSP(NodeID a, NodeID b) - { - // get the index of a free element - __uint32 e_index = m_numPairs++; - - // get the pair entry - WSPDPairInfo& e = pairInfo(e_index); - - // (a,b) is the pair we are adding - e.a = a; - e.b = b; - - // get the node info - WSPDNodeInfo& aInfo = nodeInfo(a); - WSPDNodeInfo& bInfo = nodeInfo(b); - - // if a is part of at least one pair - if (aInfo.numWSNodes) - { - // adjust the links - WSPDPairInfo& a_e = pairInfo(aInfo.lastEntry); - // check which one is a - if (a==a_e.a) - a_e.a_next = e_index; - else - a_e.b_next = e_index; - } else - { - // this pair is the first for a => set the firstEntry link - aInfo.firstEntry = e_index; - } - - // same for b: if a is part of at least one pair - if (bInfo.numWSNodes) - { - // adjust the links - WSPDPairInfo& b_e = pairInfo(bInfo.lastEntry); - // check which one is b - if (b==b_e.a) - b_e.a_next = e_index; - else - b_e.b_next = e_index; - } else - { - // this pair is the first for b => set the firstEntry link - bInfo.firstEntry = e_index; - } - // and the lastEntry link - aInfo.lastEntry = e_index; - bInfo.lastEntry = e_index; - // one more pair for each node - aInfo.numWSNodes++; - bInfo.numWSNodes++; - } - - //! returns the PairInfo by index - inline WSPDPairInfo& pairInfo(__uint32 pairIndex) const - { - return m_pairs[pairIndex]; - } - - //! returns the NodeInfo by index - inline WSPDNodeInfo& nodeInfo(NodeID node) const - { - return m_nodeInfo[node]; - } - - //! returns the index of the next pair of curr for node a - inline __uint32 nextPair(__uint32 currPairIndex, NodeID a) const - { - const WSPDPairInfo& currInfo = pairInfo(currPairIndex); - if (currInfo.a == a) - return currInfo.a_next; - return currInfo.b_next; - } - - //! returns the other node a is paired with in pair with the given index - inline __uint32 wsNodeOfPair(__uint32 currPairIndex, NodeID a) const - { - const WSPDPairInfo& currInfo = pairInfo(currPairIndex); - if (currInfo.a == a) - return currInfo.b; - return currInfo.a; - } - - //! returns the index of the first pair of node node - inline __uint32 firstPairEntry(NodeID node) const - { - return m_nodeInfo[node].firstEntry; - } - - // returns the size excluding small member vars (for profiling only) - unsigned long sizeInBytes() const; - -private: - //! allocates all memory - void allocate(); - - //! releases all memory - void deallocate(); - - //! the max number of nodes. (Equals the max number of nodes in the lin quadtree) - __uint32 m_maxNumNodes; - - //! the array which holds the wspd information for one quadtree node - WSPDNodeInfo* m_nodeInfo; - - //! the array containing all pairs - WSPDPairInfo* m_pairs; - - //! the total number of pairs - __uint32 m_numPairs; - - //! the upper bound for the number of pairs - __uint32 m_maxNumPairs; -}; - -} // end of namespace ogdf - -#endif - diff --git a/ext/OGDF/src/energybased/multilevelmixer/BarycenterPlacer.cpp b/ext/OGDF/src/energybased/multilevelmixer/BarycenterPlacer.cpp deleted file mode 100644 index f1572c1c9..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/BarycenterPlacer.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes at the barycenter position of its neighbors. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -void BarycenterPlacer::placeOneLevel(MultilevelGraph &MLG) -{ - int level = MLG.getLevel(); - while (MLG.getLevel() == level && MLG.getLastMerge() != 0) - { - placeOneNode(MLG); - } -} - - -void BarycenterPlacer::placeOneNode(MultilevelGraph &MLG) -{ - node merged = MLG.undoLastMerge(); - double x = 0.0; - double y = 0.0; - double i = 0.0; - adjEntry adj; - forall_adj(adj, merged) { - if(m_weightedPositions) { - double weight = 1.0 / MLG.weight(adj->theEdge()); - i = i + weight; - x += MLG.x(adj->twinNode()) * weight; - y += MLG.y(adj->twinNode()) * weight; - } else { - i = i + 1.f; - x += MLG.x(adj->twinNode()); - y += MLG.y(adj->twinNode()); - } - } - - OGDF_ASSERT(i > 0); - x = x / i; - y = y / i; - - MLG.x(merged, x + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); - MLG.y(merged, y + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); -} - - -BarycenterPlacer::BarycenterPlacer() -:m_weightedPositions(false) -{ -} - - -void BarycenterPlacer::weightedPositionPriority( bool on ) -{ - m_weightedPositions = on; -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/CirclePlacer.cpp b/ext/OGDF/src/energybased/multilevelmixer/CirclePlacer.cpp deleted file mode 100644 index 5d445a17e..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/CirclePlacer.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places nodes on a circle around the barycenter of its neighbors. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - -namespace ogdf { - -CirclePlacer::CirclePlacer() -:m_circleSize(0.0f), m_fixedRadius(false), m_nodeSelection(nsNew) -{ -} - - -void CirclePlacer::setRadiusFixed(bool fixed) -{ - m_fixedRadius = fixed; -} - - -void CirclePlacer::setCircleSize(float sizeIncrease) -{ - m_circleSize = sizeIncrease; -} - - -void CirclePlacer::setNodeSelection(NodeSelection nodeSel) -{ - m_nodeSelection = nodeSel; -} - - -void CirclePlacer::placeOneLevel(MultilevelGraph &MLG) -{ - DPoint center(0.0, 0.0); - double radius = 0.0; - - std::map oldNodes; - Graph &G = MLG.getGraph(); - double n = G.numberOfNodes(); - if (n > 0) { - node v; - forall_nodes(v, G) { - oldNodes[v] = true; - center = center + DPoint( MLG.x(v), MLG.y(v) ); - } - center = DPoint(center.m_x / n, center.m_y / n); - forall_nodes(v, G) { - double r = sqrt( MLG.x(v) * MLG.x(v) + MLG.y(v) * MLG.y(v) ); - if (r > radius) radius = r; - } - radius += m_circleSize; - } else { - radius = 0.0f + m_circleSize; - } - - BarycenterPlacer BP; - BP.placeOneLevel(MLG); - - node v; - forall_nodes(v, G) { - if (!m_fixedRadius) { - radius = (float)center.distance(DPoint(MLG.x(v), MLG.y(v))) + m_circleSize; - } - if (m_nodeSelection == nsAll - || (m_nodeSelection == nsNew && oldNodes[v]) - || (m_nodeSelection == nsOld && !oldNodes[v])) - { - float angle = (float)(atan2( MLG.x(v) - center.m_x, -MLG.y(v) + center.m_y) - 0.5 * Math::pi); - MLG.x(v, cos(angle) * radius + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); - MLG.y(v, sin(angle) * radius + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); - } - } -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/EdgeCoverMerger.cpp b/ext/OGDF/src/energybased/multilevelmixer/EdgeCoverMerger.cpp deleted file mode 100644 index 0e9a4a846..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/EdgeCoverMerger.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -EdgeCoverMerger::EdgeCoverMerger() -:m_levelSizeFactor(2.0) -{ -} - -bool EdgeCoverMerger::buildOneLevel(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - int level = MLG.getLevel() + 1; - m_substituteNodes.init(G, 0); - - int numNodes = G.numberOfNodes(); - - if (numNodes <= 3) { - return false; - } - - NodeArray nodeMarks(G, false); - std::vector untouchedEdges; - std::vector matching; - std::vector edgeCover; - std::vector rest; - edge e; - forall_edges(e, G) { - untouchedEdges.push_back(e); - } - - while (!untouchedEdges.empty()) - { - int rndIndex = randomNumber(0, (int)untouchedEdges.size()-1); - edge randomEdge = untouchedEdges[rndIndex]; - untouchedEdges[rndIndex] = untouchedEdges.back(); - untouchedEdges.pop_back(); - - node one = randomEdge->source(); - node two = randomEdge->target(); - if (!nodeMarks[one] && !nodeMarks[two]) { - matching.push_back(randomEdge); - nodeMarks[one] = true; - nodeMarks[two] = true; - } else { - rest.push_back(randomEdge); - } - } - - while (!rest.empty()) - { - int rndIndex = randomNumber(0, (int)rest.size()-1); - edge randomEdge = rest[rndIndex]; - rest[rndIndex] = rest.back(); - rest.pop_back(); - - node one = randomEdge->source(); - node two = randomEdge->target(); - if (!nodeMarks[one] || !nodeMarks[two]) { - edgeCover.push_back(randomEdge); - nodeMarks[one] = true; - nodeMarks[two] = true; - } - } - - bool retVal = false; - - while ((!matching.empty() || !edgeCover.empty()) && G.numberOfNodes() > numNodes / m_levelSizeFactor) { - int rndIndex; - edge coveringEdge; - - if (!matching.empty()) { - rndIndex = randomNumber(0, (int)matching.size()-1); - coveringEdge = matching[rndIndex]; - matching[rndIndex] = matching.back(); - matching.pop_back(); - } else { - rndIndex = randomNumber(0, (int)edgeCover.size()-1); - coveringEdge = edgeCover[rndIndex]; - edgeCover[rndIndex] = edgeCover.back(); - edgeCover.pop_back(); - } - - node mergeNode; - node parent; - - // choose high degree node as parent! - mergeNode = coveringEdge->source(); - parent = coveringEdge->target(); - if (mergeNode->degree() > parent->degree()) { - mergeNode = coveringEdge->target(); - parent = coveringEdge->source(); - } - - while(m_substituteNodes[parent] != 0) { - parent = m_substituteNodes[parent]; - } - while(m_substituteNodes[mergeNode] != 0) { - mergeNode = m_substituteNodes[mergeNode]; - } - - if (MLG.getNode(parent->index()) != parent - || MLG.getNode(mergeNode->index()) != mergeNode - || parent == mergeNode) - { - continue; - } - - retVal = doMerge(MLG, parent, mergeNode, level); - } - - return retVal; -} - - -void EdgeCoverMerger::setFactor(double factor) -{ - m_levelSizeFactor = factor; -} - - -// tracks substitute Nodes -bool EdgeCoverMerger::doMerge( MultilevelGraph &MLG, node parent, node mergePartner, int level ) -{ - NodeMerge * NM = new NodeMerge(level); - bool ret = MLG.changeNode(NM, parent, MLG.radius(parent), mergePartner); - OGDF_ASSERT( ret ); - MLG.moveEdgesToParent(NM, mergePartner, parent, true, m_adjustEdgeLengths); - ret = MLG.postMerge(NM, mergePartner); - if( !ret ) { - delete NM; - return false; - } - m_substituteNodes[mergePartner] = parent; - return true; -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/IndependentSetMerger.cpp b/ext/OGDF/src/energybased/multilevelmixer/IndependentSetMerger.cpp deleted file mode 100644 index 0d5fdbf39..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/IndependentSetMerger.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -IndependentSetMerger::IndependentSetMerger() -:m_base(2.f) -{ -} - - -void IndependentSetMerger::buildAllLevels(MultilevelGraph &MLG) -{ - m_numLevels = 1; - MLG.updateReverseIndizes(); - - std::vector< std::vector > levelNodes; - Graph &G = MLG.getGraph(); - - // calc MIS - NodeArray nodeMarks(G, false); - std::vector IScandidates; - node v; - forall_nodes(v, G) { - IScandidates.push_back(v); - } - levelNodes.push_back(std::vector()); - while(!IScandidates.empty()) { - // select random node - int index = randomNumber(0, (int)IScandidates.size()-1); - node ISnode = IScandidates[index]; - IScandidates[index] = IScandidates.back(); - IScandidates.pop_back(); - - if(!nodeMarks[ISnode]) { - adjEntry adj; - forall_adj(adj, ISnode) { - nodeMarks[adj->twinNode()] = true; - } - levelNodes[0].push_back(ISnode); - } - } - - bool end = false; - unsigned int i = 0; - do { - std::vector lvl = prebuildLevel(G, levelNodes[i], i); - end = lvl.size() <= 2; - if(!end) { - levelNodes.push_back(std::vector(lvl)); - i++; - } - } while (!end); - - for (i = 0; i < levelNodes.size(); i++) { - if (levelNodes[i].empty()) { - continue; - } - buildOneLevel(MLG, levelNodes[i]); - m_numLevels++; - } - - MLG.updateReverseIndizes(); -} - - -std::vector IndependentSetMerger::prebuildLevel(const Graph &G, const std::vector &oldLevel, int level) -{ - std::vector levelNodes; - std::vector oldLevelNodes; - std::map marks; - for (std::vector::const_iterator i = oldLevel.begin(); i != oldLevel.end(); i++) { - marks[*i] = 1; - oldLevelNodes.push_back(*i); - } - - while (!oldLevelNodes.empty()) { - int index = randomNumber(0, (int)oldLevelNodes.size()-1); - node oldNode = oldLevelNodes[index]; - oldLevelNodes[index] = oldLevelNodes.back(); - oldLevelNodes.pop_back(); - - if (marks[oldNode] == 1) { - NodeArray seen(G, false); - std::vector stacks[2]; - int one = 1; - int two = 0; - stacks[one].push_back(oldNode); - levelNodes.push_back(oldNode); - // BFS bis m_base^level - unsigned int depth = 0; - while(!stacks[one].empty()) { - node bfsNode = stacks[one].back(); - stacks[one].pop_back(); - - if (!seen[bfsNode]) { - if (marks[bfsNode] == 1) { - marks[bfsNode] = 2; - } - seen[bfsNode] = true; - adjEntry adj; - forall_adj(adj, bfsNode) { - stacks[two].push_back(adj->twinNode()); - } - } - if (stacks[one].empty()) { - depth++; - int temp = one; - one = two; - two = temp; - if (depth > pow(m_base, level)) { - break; - } - } - } - } - } - - return levelNodes; -} - - -bool IndependentSetMerger::buildOneLevel(MultilevelGraph &MLG, std::vector &levelNodes) -{ - Graph &G = MLG.getGraph(); - int level = MLG.getLevel() + 1; - - int numNodes = G.numberOfNodes(); - - if (numNodes <= 3) { - return false; - } - - std::map parents; - node v; - forall_nodes(v, G) { - parents[v] = 0; - } - - std::vector mergeOrder; - NodeArray seen(G, false); - std::vector stacks[2]; - int one = 1; - int two = 0; - for(std::vector::iterator i = levelNodes.begin(); i != levelNodes.end(); i++) { - stacks[one].push_back(*i); - parents[*i] = *i; - } - // parallel BFS auf allen levelNodes - while (!stacks[one].empty()) { - node bfsNode = stacks[one].back(); - stacks[one].pop_back(); - - if (!seen[bfsNode]) { - seen[bfsNode] = true; - adjEntry adj; - forall_adj(adj, bfsNode) { - node twin = adj->twinNode(); - stacks[two].push_back(twin); - if(parents[twin] == 0) { - parents[twin] = bfsNode; - mergeOrder.push_back(twin); - } - } - } - if (stacks[one].empty()) { - int temp = one; - one = two; - two = temp; - } - } - - for (std::vector::iterator i = mergeOrder.begin(); i != mergeOrder.end(); i++) { - node mergeNode = *i; - node parent = mergeNode; - while(parents[parent] != parent) { - parent = parents[parent]; - } - - NodeMerge * NM = new NodeMerge(level); - bool ret = MLG.changeNode(NM, parent, MLG.radius(parent), mergeNode); - OGDF_ASSERT( ret ); - MLG.moveEdgesToParent(NM, mergeNode, parent, true, m_adjustEdgeLengths); - ret = MLG.postMerge(NM, mergeNode); - if( !ret ) { - delete NM; - } - } - - return true; -} - -void IndependentSetMerger::setSearchDepthBase( float base ) -{ - m_base = base; -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/LocalBiconnectedMerger.cpp b/ext/OGDF/src/energybased/multilevelmixer/LocalBiconnectedMerger.cpp deleted file mode 100644 index e224905ce..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/LocalBiconnectedMerger.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - -namespace ogdf { - -LocalBiconnectedMerger::LocalBiconnectedMerger() -:m_levelSizeFactor(2.0) -{ -} - - -bool LocalBiconnectedMerger::canMerge( Graph &G, node parent, node mergePartner ) -{ - return canMerge(G, parent, mergePartner, 1) && canMerge(G, parent, mergePartner, 0); -} - - -bool LocalBiconnectedMerger::canMerge( Graph &G, node parent, node mergePartner, int testStrength ) -{ - if ( parent->degree() <= 2 || mergePartner->degree() <= 2 || m_isCut[parent] || m_isCut[mergePartner] ) { - return true; - } - - unsigned int nodeLimit = (int)log((double)G.numberOfNodes()) * 2 + 50; - unsigned int visitedNodes = 0; - m_realNodeMarks.clear(); - HashArray nodeMark(-1); - - HashArray seen(false); - seen[parent] = true; - seen[mergePartner] = true; - - HashArray neighborStatus(0); - neighborStatus[parent] = -1; - neighborStatus[mergePartner] = -1; - - List bfsQueue; - List neighbors; - int minIndex = INT_MAX; - adjEntry adj; - forall_adj(adj, parent) { - node temp = adj->twinNode(); - bfsQueue.pushBack(temp); - nodeMark[temp] = temp->index(); - if(neighborStatus[temp] == 0) { - neighbors.pushBack(temp); - neighborStatus[temp] = 1; - if (temp->index() < minIndex) { - minIndex = temp->index(); - } - } - } - forall_adj(adj, mergePartner) { - node temp = adj->twinNode(); - bfsQueue.pushBack(temp); - nodeMark[temp] = temp->index(); - if(neighborStatus[temp] == 0) { - neighbors.pushBack(temp); - neighborStatus[temp] = 1; - if (temp->index() < minIndex) { - minIndex = temp->index(); - } - } - } - - List nonReachedNeighbors; - - if (testStrength > 0) - { - minIndex = INT_MAX; - for (List::iterator i = neighbors.begin(); i != neighbors.end(); i++) { - node temp = *i; - forall_adj(adj, temp) { - node neighbor = adj->twinNode(); - if (neighborStatus[neighbor] == 0 && !seen[neighbor]) { - nonReachedNeighbors.pushBack(neighbor); - neighborStatus[neighbor] = 2; - bfsQueue.pushBack(neighbor); - nodeMark[neighbor] = neighbor->index(); - if (neighbor->index() < minIndex) { - minIndex = neighbor->index(); - } - } - } - } - - for (List::iterator i = neighbors.begin(); i != neighbors.end(); i++) { - seen[*i] = true; - } - neighbors.clear(); - } - - nonReachedNeighbors.conc(neighbors); - - if (nonReachedNeighbors.empty()) { - return true; - } - - // BFS from all neighbors - while(!bfsQueue.empty() && visitedNodes < nodeLimit) { - node temp = bfsQueue.popFrontRet(); - if (seen[temp] || m_isCut[temp]) { - continue; - } - seen[temp] = true; - visitedNodes++; - - forall_adj(adj, temp) { - node neighbor = adj->twinNode(); - if (neighbor == parent || neighbor == mergePartner) { - continue; - } - if (nodeMark[neighbor] == -1) { - nodeMark[neighbor] = realNodeMark(nodeMark[temp]); - } else { - int neighborNM = realNodeMark(nodeMark[neighbor]); - int tempNM = realNodeMark(nodeMark[temp]); - int minNM = min(tempNM, neighborNM); - if (tempNM != neighborNM) { - int maxNM = max(tempNM, neighborNM); - nodeMark[neighbor] = minNM; - nodeMark[temp] = minNM; - m_realNodeMarks[maxNM] = minNM; - if (minNM == minIndex) { - // check nonReachedNeighbors - for (List::iterator i = nonReachedNeighbors.begin(); i != nonReachedNeighbors.end(); ) { - if (realNodeMark(nodeMark[*i]) == minIndex) { - List::iterator j = i; - i++; - nonReachedNeighbors.del(j); - } else { - i++; - } - } - if (nonReachedNeighbors.empty()) { - return true; - } - } - } - } - if (!seen[neighbor]) { - bfsQueue.pushBack(neighbor); - } - } - } - - // free some space - m_realNodeMarks.clear(); - return false; -} - - -bool LocalBiconnectedMerger::doMergeIfPossible( Graph &G, MultilevelGraph &MLG, node parent, node mergePartner, int level ) -{ - if (canMerge(G, parent, mergePartner)) { - return doMerge(MLG, parent, mergePartner, level); - } - return true; -} - - -// tracks substitute Nodes -// updates the bi-connectivity check data structure m_isCut -// merges the nodes -bool LocalBiconnectedMerger::doMerge( MultilevelGraph &MLG, node parent, node mergePartner, int level ) -{ - NodeMerge * NM = new NodeMerge(level); - bool ret = MLG.changeNode(NM, parent, MLG.radius(parent), mergePartner); - OGDF_ASSERT( ret ); - MLG.moveEdgesToParent(NM, mergePartner, parent, true, m_adjustEdgeLengths); - ret = MLG.postMerge(NM, mergePartner); - if( !ret ) { - delete NM; - return false; - } - m_substituteNodes[mergePartner] = parent; - if (m_isCut[mergePartner]) { - m_isCut[parent] = true; - } - return true; -} - - -void LocalBiconnectedMerger::initCuts(Graph &G) -{ - // BCTree does not work for large graphs due to recursion depth (stack overflow) - // Uncomment below to get speedup once BCTree is fixed. - -// BCTree BCT(G); - m_isCut.init(G, false); - -/* node v; - forall_nodes(v, G) { - if( BCT.typeOfGNode(v) == BCTree::GNodeType::CutVertex ) { - m_isCut[v] = true; - } - }*/ -} - - -bool LocalBiconnectedMerger::buildOneLevel(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - int level = MLG.getLevel() + 1; -// std::cout << "Level: " << level << std::endl; - - m_substituteNodes.init(G, 0); - initCuts(G); - - int numNodes = G.numberOfNodes(); - - if (numNodes <= 3) { - return false; - } - - NodeArray nodeMarks(G, false); - std::vector untouchedEdges; - std::vector matching; - std::vector edgeCover; - std::vector rest; - edge e; - forall_edges(e, G) { - untouchedEdges.push_back(e); - } - - while (!untouchedEdges.empty()) - { - int rndIndex = randomNumber(0, (int)untouchedEdges.size()-1); - edge randomEdge = untouchedEdges[rndIndex]; - untouchedEdges[rndIndex] = untouchedEdges.back(); - untouchedEdges.pop_back(); - - node one = randomEdge->source(); - node two = randomEdge->target(); - if (!nodeMarks[one] && !nodeMarks[two]) { - matching.push_back(randomEdge); - nodeMarks[one] = true; - nodeMarks[two] = true; - } else { - rest.push_back(randomEdge); - } - } - - while (!rest.empty()) - { - int rndIndex = randomNumber(0, (int)rest.size()-1); - edge randomEdge = rest[rndIndex]; - rest[rndIndex] = rest.back(); - rest.pop_back(); - - node one = randomEdge->source(); - node two = randomEdge->target(); - if (!nodeMarks[one] || !nodeMarks[two]) { - edgeCover.push_back(randomEdge); - nodeMarks[one] = true; - nodeMarks[two] = true; - } - } - - bool retVal = false; - - while ((!matching.empty() || !edgeCover.empty()) && G.numberOfNodes() > numNodes / m_levelSizeFactor) { - int rndIndex; - edge coveringEdge; - - if (!matching.empty()) { - rndIndex = randomNumber(0, (int)matching.size()-1); - coveringEdge = matching[rndIndex]; - matching[rndIndex] = matching.back(); - matching.pop_back(); - } else { - rndIndex = randomNumber(0, (int)edgeCover.size()-1); - coveringEdge = edgeCover[rndIndex]; - edgeCover[rndIndex] = edgeCover.back(); - edgeCover.pop_back(); - } - - node mergeNode; - node parent; - - // choose high degree node as parent! - mergeNode = coveringEdge->source(); - parent = coveringEdge->target(); - if (mergeNode->degree() > parent->degree()) { - mergeNode = coveringEdge->target(); - parent = coveringEdge->source(); - } - - while(m_substituteNodes[parent] != 0) { - parent = m_substituteNodes[parent]; - } - while(m_substituteNodes[mergeNode] != 0) { - mergeNode = m_substituteNodes[mergeNode]; - } - - if (MLG.getNode(parent->index()) != parent - || MLG.getNode(mergeNode->index()) != mergeNode - || parent == mergeNode) - { - continue; - } - //KK: looks like a flaw? TODO: Check the return value concept - retVal = doMergeIfPossible(G, MLG, parent, mergeNode, level); - } - - if (numNodes == G.numberOfNodes()) { - return false; - } else { - return retVal; - } -} - - -void LocalBiconnectedMerger::setFactor(double factor) -{ - m_levelSizeFactor = factor; -} - - -int LocalBiconnectedMerger::realNodeMark( int index ) -{ - if (!m_realNodeMarks.isDefined(index) || m_realNodeMarks[index] == index) { - return index; - } else { - return realNodeMark(m_realNodeMarks[index]); - } -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/MMMExampleFastLayout.cpp b/ext/OGDF/src/energybased/multilevelmixer/MMMExampleFastLayout.cpp deleted file mode 100644 index 054542090..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/MMMExampleFastLayout.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief useable example of the Modular Multilevel Mixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace ogdf { - -MMMExampleFastLayout::MMMExampleFastLayout() -{ -} - - -void MMMExampleFastLayout::call(GraphAttributes &GA) -{ - MultilevelGraph MLG(GA); - call(MLG); - MLG.exportAttributes(GA); -} - - -void MMMExampleFastLayout::call(MultilevelGraph &MLG) -{ - // Fast Multipole Embedder - FastMultipoleEmbedder *FME = new FastMultipoleEmbedder(); - FME->setNumIterations(1000); - FME->setRandomize(false); - - // Solar Merger - SolarMerger * SM = new SolarMerger(false, false); - - // Solar Placer - SolarPlacer * SP = new SolarPlacer(); - - // No Scaling - ScalingLayout * SL = new ScalingLayout(); - SL->setExtraScalingSteps(0); - SL->setScaling(2.0, 2.0); - SL->setScalingType(ScalingLayout::st_relativeToDrawing); - SL->setSecondaryLayout(FME); - SL->setLayoutRepeats(1); - - ModularMultilevelMixer *MMM = new ModularMultilevelMixer; - MMM->setLayoutRepeats(1); -// MMM->setAllEdgeLenghts(5.0); -// MMM->setAllNodeSizes(1.0); - MMM->setLevelLayoutModule(SL); - MMM->setInitialPlacer(SP); - MMM->setMultilevelBuilder(SM); - - ComponentSplitterLayout *CS = new ComponentSplitterLayout; - CS->setLayoutModule(MMM); - PreprocessorLayout PPL; - PPL.setLayoutModule(CS); - PPL.setRandomizePositions(true); - - PPL.call(MLG); -} - -} // namespace ogdf - diff --git a/ext/OGDF/src/energybased/multilevelmixer/MMMExampleNiceLayout.cpp b/ext/OGDF/src/energybased/multilevelmixer/MMMExampleNiceLayout.cpp deleted file mode 100644 index 611462324..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/MMMExampleNiceLayout.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief useable example of the Modular Multilevel Mixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace ogdf { - -MMMExampleNiceLayout::MMMExampleNiceLayout() -{ -} - - -void MMMExampleNiceLayout::call(GraphAttributes &GA) -{ - MultilevelGraph MLG(GA); - call(MLG); - MLG.exportAttributes(GA); -} - - -void MMMExampleNiceLayout::call(MultilevelGraph &MLG) -{ - // Fast Multipole Embedder - FastMultipoleEmbedder * FME = new FastMultipoleEmbedder(); - FME->setNumIterations(1000); - FME->setRandomize(false); - - // Fast Edges Only Embedder - FastMultipoleEmbedder * FEOE = new FastMultipoleEmbedder(); - FEOE->setNumIterations(0); - FEOE->setRandomize(false); - - // Edge Cover Merger - EdgeCoverMerger * ECM = new EdgeCoverMerger(); - ECM->setFactor(2.0); - ECM->setEdgeLengthAdjustment(0); // BEFORE (but arg is int!): ECM->setEdgeLengthAdjustment(0.1); - - // Barycenter Placer with weighted Positions - BarycenterPlacer * BP = new BarycenterPlacer(); - BP->weightedPositionPriority(true); - - // No Scaling - ScalingLayout * SL = new ScalingLayout(); - SL->setExtraScalingSteps(0); - SL->setScaling(1.0, 1.0); - SL->setScalingType(ScalingLayout::st_relativeToDrawing); - SL->setSecondaryLayout(FME); - SL->setLayoutRepeats(1); - - ModularMultilevelMixer *MMM = new ModularMultilevelMixer; - MMM->setLayoutRepeats(1); -// MMM->setAllEdgeLenghts(5.0); -// MMM->setAllNodeSizes(1.0); - MMM->setLevelLayoutModule(SL); - MMM->setInitialPlacer(BP); - MMM->setMultilevelBuilder(ECM); - - ComponentSplitterLayout *CS = new ComponentSplitterLayout; - CS->setLayoutModule(MMM); - PreprocessorLayout PPL; - PPL.setLayoutModule(CS); - PPL.setRandomizePositions(true); - - PPL.call(MLG); -} - -} // namespace ogdf - diff --git a/ext/OGDF/src/energybased/multilevelmixer/MMMExampleNoTwistLayout.cpp b/ext/OGDF/src/energybased/multilevelmixer/MMMExampleNoTwistLayout.cpp deleted file mode 100644 index afef8dda2..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/MMMExampleNoTwistLayout.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief useable example of the Modular Multilevel Mixer - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace ogdf { - -MMMExampleNoTwistLayout::MMMExampleNoTwistLayout() -{ -} - - -void MMMExampleNoTwistLayout::call(GraphAttributes &GA) -{ - MultilevelGraph MLG(GA); - call(MLG); - MLG.exportAttributes(GA); -} - - -void MMMExampleNoTwistLayout::call(MultilevelGraph &MLG) -{ - // Fast Multipole Embedder - FastMultipoleEmbedder * FME = new FastMultipoleEmbedder(); - FME->setNumIterations(1000); - FME->setRandomize(false); - - // Local Biconnected Merger - LocalBiconnectedMerger * LBCM = new LocalBiconnectedMerger(); - LBCM->setFactor(2.0); - LBCM->setEdgeLengthAdjustment(0); // BEFORE (but arg is int!): LBCM->setEdgeLengthAdjustment(0.1); - - // Barycenter Placer with weighted Positions - BarycenterPlacer * BP = new BarycenterPlacer(); - BP->weightedPositionPriority(true); - - // No Scaling - ScalingLayout *SL = new ScalingLayout(); - SL->setExtraScalingSteps(1); - SL->setScaling(5.0, 10.0); - SL->setScalingType(ScalingLayout::st_relativeToDesiredLength); - SL->setSecondaryLayout(FME); - SL->setLayoutRepeats(1); - - ModularMultilevelMixer *MMM = new ModularMultilevelMixer; - MMM->setLayoutRepeats(1); -// MMM->setAllEdgeLenghts(5.0); -// MMM->setAllNodeSizes(1.0); - MMM->setLevelLayoutModule(SL); - MMM->setInitialPlacer(BP); - MMM->setMultilevelBuilder(LBCM); - - ComponentSplitterLayout *CS = new ComponentSplitterLayout; - CS->setLayoutModule(MMM); - PreprocessorLayout PPL; - PPL.setLayoutModule(CS); - PPL.setRandomizePositions(true); - - PPL.call(MLG); -} - -} // namespace ogdf - diff --git a/ext/OGDF/src/energybased/multilevelmixer/MatchingMerger.cpp b/ext/OGDF/src/energybased/multilevelmixer/MatchingMerger.cpp deleted file mode 100644 index dad03306d..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/MatchingMerger.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -MatchingMerger::MatchingMerger() -:m_selectByMass(false) -{ -} - -bool MatchingMerger::buildOneLevel(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - int level = MLG.getLevel() + 1; - - int numNodes = G.numberOfNodes(); - - if (level == 1 && m_selectByMass) { - m_mass.init(G, 1); - } - - if (numNodes <= 3) { - return false; - } - - NodeArray nodeMarks(G, false); - std::vector matching; - std::vector candidates; - - node v; - forall_nodes(v, G) { - candidates.push_back(v); - } - - while (!candidates.empty()) - { - int rndIndex = randomNumber(0, (int)candidates.size()-1); - node one = candidates[rndIndex]; - candidates[rndIndex] = candidates.back(); - candidates.pop_back(); - - if (nodeMarks[one]) { - continue; - } - nodeMarks[one] = true; - - std::vector candNeighbors; - std::vector candEdges; - adjEntry adj; - unsigned int minMass = UINT_MAX; - forall_adj(adj, one) { - node cand = adj->twinNode(); - if (!nodeMarks[cand] && (!m_selectByMass || m_mass[cand] <= minMass)) - { - if (m_selectByMass && m_mass[cand] < minMass) { - minMass = m_mass[cand]; - candNeighbors.clear(); - candEdges.clear(); - } - candNeighbors.push_back(cand); - candEdges.push_back(adj->theEdge()); - } - } - if (candNeighbors.empty()) { - continue; - } - int index = randomNumber(0, int(candNeighbors.size())-1); - nodeMarks[candNeighbors[index]] = true; - matching.push_back(candEdges[index]); - } - - while (!matching.empty()) { - edge matchingEdge = matching.back(); - matching.pop_back(); - - node mergeNode; - node parent; - - // choose high degree node as parent! - mergeNode = matchingEdge->source(); - parent = matchingEdge->target(); - if (mergeNode->degree() > parent->degree()) { - mergeNode = matchingEdge->target(); - parent = matchingEdge->source(); - } - - NodeMerge * NM = new NodeMerge(level); - bool ret = MLG.changeNode(NM, parent, MLG.radius(parent), mergeNode); - OGDF_ASSERT( ret ); - if (m_selectByMass) { - m_mass[parent] = m_mass[parent] + m_mass[mergeNode]; - } - MLG.moveEdgesToParent(NM, mergeNode, parent, true, m_adjustEdgeLengths); - ret = MLG.postMerge(NM, mergeNode); - if( !ret ) { - delete NM; - } - } - - return true; -} - - -void MatchingMerger::selectByNodeMass( bool on ) -{ - m_selectByMass = on; -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/MedianPlacer.cpp b/ext/OGDF/src/energybased/multilevelmixer/MedianPlacer.cpp deleted file mode 100644 index 1e5bae008..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/MedianPlacer.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places Nodes at the Positio of the merge-partner - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void MedianPlacer::placeOneLevel(MultilevelGraph &MLG) -{ - int level = MLG.getLevel(); - while (MLG.getLevel() == level && MLG.getLastMerge() != 0) - { - placeOneNode(MLG); - } -} - - -void MedianPlacer::placeOneNode(MultilevelGraph &MLG) -{ - node merged = MLG.undoLastMerge(); - int i = 0; - std::vector xVector; - std::vector yVector; - adjEntry adj; - forall_adj(adj, merged) { - i++; - xVector.push_back(MLG.x(adj->twinNode())); - yVector.push_back(MLG.y(adj->twinNode())); - } - std::nth_element(xVector.begin(), xVector.begin()+(i/2), xVector.end()); - std::nth_element(yVector.begin(), yVector.begin()+(i/2), yVector.end()); - double x = xVector[i/2]; - double y = yVector[i/2]; - if (i % 2 == 0) { - std::nth_element(xVector.begin(), xVector.begin()+(i/2)-1, xVector.end()); - std::nth_element(yVector.begin(), yVector.begin()+(i/2)-1, yVector.end()); - x += xVector[i/2 - 1]; - y += yVector[i/2 - 1]; - x /= 2.0; - y /= 2.0; - } - MLG.x(merged, x + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); - MLG.y(merged, y + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/MixedForceLayout.cpp b/ext/OGDF/src/energybased/multilevelmixer/MixedForceLayout.cpp deleted file mode 100644 index 507e62fa0..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/MixedForceLayout.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Uses Fruchtermann Rheingold and Fast Multipole Embedder for faster and better FR results. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -MixedForceLayout::MixedForceLayout() -{ - SpringEmbedderFR * FR = new SpringEmbedderFR(); - FR->scaling(SpringEmbedderFR::scInput); - m_FR = FR; - - FastMultipoleEmbedder * FME = new FastMultipoleEmbedder(); - FME->setNumIterations(1000); - FME->setRandomize(false); - FME->setNumberOfThreads(2); - - m_FME = FME; -} - - -void MixedForceLayout::call(GraphAttributes &GA) -{ - m_FME->call(GA); - m_FR->call(GA); -} - - -void MixedForceLayout::call(MultilevelGraph &MLG) -{ - m_FME->call(MLG.getGraphAttributes()); - m_FR->call(MLG.getGraphAttributes()); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/ModularMultilevelMixer.cpp b/ext/OGDF/src/energybased/multilevelmixer/ModularMultilevelMixer.cpp deleted file mode 100644 index 3e4f85ae1..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/ModularMultilevelMixer.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief MMM is a Multilevel Graph drawing Algorithm that can use different modules. - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - - -#include -#include -#include -#include -#include -#include -#include - -#ifdef OGDF_MMM_LEVEL_OUTPUTS -#include -#include -#endif - - -namespace ogdf { - -ModularMultilevelMixer::ModularMultilevelMixer() -{ - // options - m_times = 1; - m_fixedEdgeLength = -1.0f; - m_fixedNodeSize = -1.0f; - m_coarseningRatio = 1.0; - m_levelBound = false; - m_randomize = false; - - // module options - setMultilevelBuilder(new SolarMerger); - setInitialPlacer (new BarycenterPlacer); - setLevelLayoutModule(new SpringEmbedderFR); -} - - -void ModularMultilevelMixer::call(GraphAttributes &GA) -{ //ensure consistent behaviour of the two call Methods - MultilevelGraph MLG(GA); - call(MLG); - MLG.exportAttributes(GA); -} - - -void ModularMultilevelMixer::call(MultilevelGraph &MLG) -{ - const Graph &G = MLG.getGraph(); - - m_errorCode = ercNone; - clock_t time = clock(); - if ((m_multilevelBuilder.valid() == false || m_initialPlacement.valid() == false) && m_oneLevelLayoutModule.valid() == false) { - OGDF_THROW(AlgorithmFailureException); - } - - if (m_fixedEdgeLength > 0.0) { - edge e; - forall_edges(e,G) { - MLG.weight(e, m_fixedEdgeLength); - } - } - - if (m_fixedNodeSize > 0.0) { - node v; - forall_nodes(v,G) { - MLG.radius(v, m_fixedNodeSize); - } - } - - if (m_multilevelBuilder.valid() && m_initialPlacement.valid()) - { - double lbound = 16.0 * log(double(G.numberOfNodes()))/log(2.0); - m_multilevelBuilder.get().buildAllLevels(MLG); - - //Part for experiments: Stop if number of levels too high -#ifdef OGDF_MMM_LEVEL_OUTPUTS - int nlevels = m_multilevelBuilder.get().getNumLevels(); -#endif - if (m_levelBound) - { - if ( m_multilevelBuilder.get().getNumLevels() > lbound) - { - m_errorCode = ercLevelBound; - return; - } - } - node v; - if (m_randomize) - { - forall_nodes(v,G) { - MLG.x(v, (float)randomDouble(-1.0, 1.0)); - MLG.y(v, (float)randomDouble(-1.0, 1.0)); - } - } - - while(MLG.getLevel() > 0) - { - if (m_oneLevelLayoutModule.valid()) { - for(int i = 1; i <= m_times; i++) { - m_oneLevelLayoutModule.get().call(MLG.getGraphAttributes()); - } - } - -#ifdef OGDF_MMM_LEVEL_OUTPUTS - //Debugging output - std::stringstream ss; - ss << nlevels--; - std::string s; - ss >> s; - s = "LevelLayout"+s; - String fs(s.c_str()); - fs += ".gml"; - MLG.writeGML(fs); -#endif - - MLG.moveToZero(); - - int nNodes = G.numberOfNodes(); - m_initialPlacement.get().placeOneLevel(MLG); - m_coarseningRatio = float(G.numberOfNodes()) / nNodes; - -#ifdef OGDF_MMM_LEVEL_OUTPUTS - //debug only - s = s+"_placed.gml"; - MLG.writeGML(String(s.c_str())); -#endif - } //while level - } - - //Final level - - if(m_finalLayoutModule.valid() || m_oneLevelLayoutModule.valid()) - { - LayoutModule &lastLayoutModule = (m_finalLayoutModule.valid() != 0 ? m_finalLayoutModule.get() : m_oneLevelLayoutModule.get()); - - for(int i = 1; i <= m_times; i++) { - lastLayoutModule.call(MLG.getGraphAttributes()); - } - } - - time = clock() - time; -} - - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/RandomMerger.cpp b/ext/OGDF/src/energybased/multilevelmixer/RandomMerger.cpp deleted file mode 100644 index 5f7dbc567..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/RandomMerger.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Merges nodes with neighbour to get a Multilevel Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -RandomMerger::RandomMerger() -:m_levelSizeFactor(2.0) -{ -} - -bool RandomMerger::buildOneLevel(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - int level = MLG.getLevel() + 1; - int numNodes = G.numberOfNodes(); - - if (numNodes <= 3) { - return false; - } - - node v; - int index = 0; - Array candidates(numNodes); - forall_nodes(v, G) { - candidates[index] = v; - index++; - } - - int candSize = candidates.size(); - while (candSize > numNodes / m_levelSizeFactor) - { - index = randomNumber(0, candSize-1); - node mergeNode = candidates[index]; - candidates[index] = candidates[candSize-1]; - candSize--; - node parent; - - if (mergeNode->degree() > 0) { - int index = randomNumber(0, mergeNode->degree()-1); - int i = 0; - adjEntry adj; - forall_adj(adj, mergeNode) { - if (i == index) { - parent = adj->twinNode(); - break; - } else { - i++; - } - } - } else { - do { - index = randomNumber(0, candSize-1); - parent = candidates[index]; - } while (parent == mergeNode); - candidates[index] = candidates[candSize-1]; - candSize--; - } - - NodeMerge * NM = new NodeMerge(level); - bool ret = MLG.changeNode(NM, parent, MLG.radius(parent), mergeNode); - OGDF_ASSERT( ret ); - MLG.moveEdgesToParent(NM, mergeNode, parent, true, m_adjustEdgeLengths); - ret = MLG.postMerge(NM, mergeNode); - if( !ret ) { - delete NM; - } - } - - return true; -} - - -void RandomMerger::setFactor(double factor) -{ - m_levelSizeFactor = factor; -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/RandomPlacer.cpp b/ext/OGDF/src/energybased/multilevelmixer/RandomPlacer.cpp deleted file mode 100644 index 6405c04b7..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/RandomPlacer.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places Nodes at the Positio of the merge-partner - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -namespace ogdf { - -RandomPlacer::RandomPlacer() -:m_circleSizeFactor(1.0) -{ -} - - -void RandomPlacer::setCircleSize(double factor) -{ - m_circleSizeFactor = factor; -} - - -void RandomPlacer::placeOneLevel(MultilevelGraph &MLG) -{ - int level = MLG.getLevel(); - DPoint center(0.0, 0.0); - double radius = 0.0; - - Graph &G = MLG.getGraph(); - double n = G.numberOfNodes(); - if (n > 0) { - node v; - forall_nodes(v, G) { - center = center + DPoint( MLG.x(v), MLG.y(v) ); - } - center = DPoint(center.m_x / n, center.m_y / n); - forall_nodes(v, G) { - double r = sqrt( MLG.x(v) * MLG.x(v) + MLG.y(v) * MLG.y(v) ); - if (r > radius) radius = r; - } - radius *= m_circleSizeFactor; - } else { - radius = 10.0 * m_circleSizeFactor; - } - - while (MLG.getLevel() == level && MLG.getLastMerge() != 0) - { - placeOneNode(MLG, center, radius); - } -} - - -void RandomPlacer::placeOneNode(MultilevelGraph &MLG, DPoint center, double radius) -{ - node merged = MLG.undoLastMerge(); - float angle = (float)randomDouble(0.0, 2 * Math::pi); - float randRadius = float(sqrt(randomDouble(0.0, radius * radius))); - MLG.x(merged, cos(angle) * randRadius + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); - MLG.y(merged, sin(angle) * randRadius + ((m_randomOffset)?(float)randomDouble(-1.0, 1.0):0.f)); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/ScalingLayout.cpp b/ext/OGDF/src/energybased/multilevelmixer/ScalingLayout.cpp deleted file mode 100644 index 80fb2beec..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/ScalingLayout.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief ScalingLayout scales and calls a secondary layout - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - -ScalingLayout::ScalingLayout() : - m_minScaling(1.0), - m_maxScaling(2.0), - m_mmm(NULL), - m_desEdgeLength(1.0), - m_extraScalingSteps(0), - m_layoutRepeats(1), - m_scalingType(st_relativeToDrawing) -{ -} - - -void ScalingLayout::call(GraphAttributes &GA) -{ - MultilevelGraph MLG(GA); - call(MLG); - MLG.exportAttributes(GA); -} - - -void ScalingLayout::call(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - double avgDesiredEdgeLength = 0.0; - edge e; - - if (m_scalingType == st_relativeToAvgLength) { - forall_edges(e, G) { - avgDesiredEdgeLength += MLG.weight(e); - } - avgDesiredEdgeLength /= G.numberOfNodes(); - } - - double finalScaling = m_maxScaling; - if ( (m_scalingType == st_absolute) && (m_mmm != 0)) - { - finalScaling = max(m_mmm->coarseningRatio(), m_minScaling); - } - - double avgStartEdgeLength = 0.0; - for (unsigned int i = 0; i <= m_extraScalingSteps; i++) { - double step; - //KK this looks strange, shouldn't we start with step = 1 if extrascaling? - //now we scale from max to min... - if (m_extraScalingSteps > 0) { - step = (double)i / (double)m_extraScalingSteps; - } else { - step = 0; - } - double scalingFactor = m_minScaling * step + finalScaling * (1.0-step); - - if (m_scalingType == st_absolute) - { - MLG.moveToZero(); - #ifdef OGDF_DEBUG - cout << "Fix Scaling: "<source()) - MLG.x(e->target()); - double y = MLG.y(e->source()) - MLG.y(e->target()); - avgEdgeLength += sqrt( x*x + y*y ); - } - avgEdgeLength /= G.numberOfNodes(); - - if(avgEdgeLength <= 0.0) { - MLG.moveToZero(); - } else { - double scaling = 1.0; - if (m_scalingType == st_relativeToDrawing) { - if (i == 0) { - avgStartEdgeLength = avgEdgeLength; - } - scaling = scalingFactor * avgStartEdgeLength / avgEdgeLength; - } else { - if (m_scalingType == st_relativeToDesiredLength) - { - scaling = scalingFactor * m_desEdgeLength / avgEdgeLength; - } else //st_relativeToAvgLength - scaling = scalingFactor * avgDesiredEdgeLength / avgEdgeLength; - #ifdef OGDF_DEBUG - cout << "Scaling: F/s "< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -SolarMerger::SolarMerger(bool simple, bool massAsNodeRadius) -:m_sunSelectionSimple(simple), m_massAsNodeRadius(massAsNodeRadius) -{ -} - - -int SolarMerger::calcSystemMass(node v) { - unsigned int sum = m_mass[v]; - adjEntry adj; - forall_adj(adj, v) { - sum += m_mass[adj->twinNode()]; - } - return sum; -} - - -std::vector SolarMerger::selectSuns(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - std::vector suns; - std::vector candidates; - - node v; - forall_nodes(v, G) { - candidates.push_back(v); - } - - if (m_sunSelectionSimple) { - while (!candidates.empty()) { - // select random node - int index = randomNumber(0, (int)candidates.size()-1); - node sun = candidates[index]; - candidates[index] = candidates.back(); - candidates.pop_back(); - if (m_celestial[sun] != 0) { - continue; - } - bool hasForeignPlanet = false; - adjEntry adj; - forall_adj(adj, sun) { - if(m_celestial[adj->twinNode()] != 0) { - hasForeignPlanet = true; - break; - } - } - if (hasForeignPlanet) { - continue; - } - // mark node as sun - m_celestial[sun] = 1; - suns.push_back(sun); - // mark neighbours as planet - forall_adj(adj, sun) { - m_celestial[adj->twinNode()] = 2; - m_orbitalCenter[adj->twinNode()] = sun; - m_distanceToOrbit[adj->twinNode()] = MLG.weight(adj->theEdge()); - } - } - } else { - while (!candidates.empty()) { - std::vector< std::pair > sunCandidates; - int i = 1; - int n = 10; - while (i<=n && !candidates.empty()) { - // select random node - int index = randomNumber(0, (int)candidates.size()-1); - node rndNode = candidates[index]; - candidates[index] = candidates.back(); - candidates.pop_back(); - if (m_celestial[rndNode] != 0) { - continue; - } - bool hasForeignPlanet = false; - adjEntry adj; - forall_adj(adj, rndNode) { - if(m_celestial[adj->twinNode()] != 0) { - hasForeignPlanet = true; - break; - } - } - if (hasForeignPlanet) { - continue; - } - unsigned int mass = calcSystemMass(rndNode); - sunCandidates.push_back(std::pair(rndNode, mass)); - i++; - } - if (sunCandidates.empty()) { - continue; - } - - node minNode = sunCandidates.front().first; - unsigned int minMass = sunCandidates.front().second; - // select sun with smalles mass from sunCandidates - for (std::vector< std::pair >::iterator i = sunCandidates.begin(); - i != sunCandidates.end(); i++) - { - node nod = (*i).first; - unsigned int mass = (*i).second; - if (mass < minMass) { - minMass = mass; - minNode = nod; - } - } - - for (std::vector< std::pair >::iterator i = sunCandidates.begin(); - i != sunCandidates.end(); i++) - { - node temp = (*i).first; - if (temp == minNode) { - continue; - } - candidates.push_back(temp); - } - - // mark node as sun - m_celestial[minNode] = 1; - suns.push_back(minNode); - // mark neighbours as planet - adjEntry adj; - forall_adj(adj, minNode) { - m_celestial[adj->twinNode()] = 2; - m_orbitalCenter[adj->twinNode()] = minNode; - m_distanceToOrbit[adj->twinNode()] = MLG.weight(adj->theEdge()); - } - } - } - - forall_nodes(v, G) { - if (m_celestial[v] == 0) { - m_celestial[v] = 3; - adjEntry adj; - std::vector planets; - node planet; - forall_adj(adj, v) { - planet = adj->twinNode(); - if (m_celestial[planet] == 2) { - planets.push_back(adj); - } - } - OGDF_ASSERT(planets.size() > 0); - int index = randomNumber(0, (int)planets.size()-1); - planet = planets[index]->twinNode(); - m_orbitalCenter[v] = planet; - m_distanceToOrbit[v] = MLG.weight(planets[index]->theEdge()); - } - } - - return suns; -} - - -void SolarMerger::buildAllLevels(MultilevelGraph &MLG) -{ - m_numLevels = 1; - Graph &G = MLG.getGraph(); - if (m_massAsNodeRadius || !m_sunSelectionSimple) { - m_mass.init(G, 1); - m_radius.init(G); - node v; - forall_nodes(v, G) { - m_radius[v] = MLG.radius(v); - } - } - MLG.updateReverseIndizes(); - while (buildOneLevel(MLG)) - {//this is not needed anymore locally since Multilevelbuilder keeps this info - m_numLevels++; - } - MLG.updateReverseIndizes(); -} - - -node SolarMerger::sunOf(node object) -{ - if (object == 0 || m_celestial[object] == 0) { - return 0; - } - if (m_celestial[object] == 1) { - return object; - } - return sunOf(m_orbitalCenter[object]); -} - - -void SolarMerger::addPath(node sourceSun, node targetSun, double distance) -{ - node source = sourceSun; - node target = targetSun; - if (targetSun->index() < sourceSun->index()) { - source = targetSun; - target = sourceSun; - } - PathData data = m_interSystemPaths[source->index()][target->index()]; - OGDF_ASSERT(data.targetSun == target->index() || data.number == 0); - - int num = data.number; - double len = data.length; - - len = len * num + distance; - num++; - len /= num; - data.length = len; - data.number = num; - data.targetSun = target->index(); - - m_interSystemPaths[source->index()][target->index()] = data; -} - - -double SolarMerger::distanceToSun(node object, MultilevelGraph &MLG) -{ - double dist = 0.0; - - if (object == 0 || m_celestial[object] <= 1) { - return dist; - } - - node center = m_orbitalCenter[object]; - OGDF_ASSERT(center != 0); - - bool found = false; - adjEntry adj; - forall_adj(adj, object) { - if (adj->twinNode() == center) { - found = true; - dist = MLG.weight(adj->theEdge()); - OGDF_ASSERT(dist > 0); - break; - } - } - OGDF_ASSERT(found); - - return distanceToSun(center, MLG) + dist; -} - - -void SolarMerger::findInterSystemPaths(Graph &G, MultilevelGraph &MLG) -{ - edge e; - forall_edges(e, G) { - node source = e->source(); - node target = e->target(); - if (sunOf(source) != sunOf(target)) { - // construct intersystempath - double len = distanceToSun(source, MLG) + distanceToSun(target, MLG) + MLG.weight(e); - OGDF_ASSERT(len > 0); - addPath(sunOf(source), sunOf(target), len); - - // save positions of nodes on the path. - node src = source; - do { - double dist = distanceToSun(src, MLG); - m_pathDistances[src].push_back(PathData(sunOf(target)->index(), dist / len, 1)); - src = m_orbitalCenter[src]; - } while(src != 0); - - node tgt = target; - do { - double dist = distanceToSun(tgt, MLG); - m_pathDistances[tgt].push_back(PathData(sunOf(source)->index(), dist / len, 1)); - tgt = m_orbitalCenter[tgt]; - } while(tgt != 0); - } - } -} - - -bool SolarMerger::buildOneLevel(MultilevelGraph &MLG) -{ - Graph &G = MLG.getGraph(); - int level = MLG.getLevel() + 1; - - int numNodes = G.numberOfNodes(); - - if (numNodes <= 3) { - return false; - } - - m_orbitalCenter.init(G, 0); - m_distanceToOrbit.init(G, 1.0); - m_pathDistances.init(G, std::vector()); - m_celestial.init(G, 0); - m_interSystemPaths.clear(); - - std::vector suns = selectSuns(MLG); - - if (suns.empty()) { - return false; - } - - findInterSystemPaths(G, MLG); - - for(std::vector::iterator i = suns.begin(); i != suns.end(); i++) { - if (!collapsSolarSystem(MLG, *i, level)) { - return false; - } - } - - NodeMerge * lastMerge = MLG.getLastMerge(); - edge e; - forall_edges(e, G) { - node source = e->source(); - node target = e->target(); - if (target->index() < source->index()) - { - node temp = source; - source = target; - target = temp; - } - - if (!m_interSystemPaths[source->index()].empty()) { - if (m_interSystemPaths[source->index()][target->index()].number != 0) { - MLG.changeEdge(lastMerge, e, m_interSystemPaths[source->index()][target->index()].length, source, target); - } - } - } - - return true; -} - - -bool SolarMerger::collapsSolarSystem(MultilevelGraph &MLG, node sun, int level) -{ - bool retVal = false; - - std::vector systemNodes; - unsigned int mass = 0; - if (m_massAsNodeRadius || !m_sunSelectionSimple) { - mass = m_mass[sun]; - } - - OGDF_ASSERT(m_celestial[sun] == 1) - - adjEntry adj; - forall_adj(adj, sun) { -#ifdef OGDF_DEBUG - node planet = adj->twinNode(); -#endif - OGDF_ASSERT(m_celestial[planet] == 2) - OGDF_ASSERT(m_orbitalCenter[planet] == sun) - systemNodes.push_back(adj->twinNode()); - } - forall_adj(adj, sun) { - node planet = adj->twinNode(); - OGDF_ASSERT(m_celestial[planet] == 2) - OGDF_ASSERT(m_orbitalCenter[planet] == sun) - adjEntry adj2; - forall_adj(adj2, planet) { - node moon = adj2->twinNode(); - if(m_celestial[moon] == 3 && m_orbitalCenter[moon] == planet) { - systemNodes.push_back(moon); - } - } - } - - if (m_massAsNodeRadius || !m_sunSelectionSimple) { - for(std::vector::iterator i = systemNodes.begin(); i != systemNodes.end(); i++) { - mass += m_mass[*i]; - } - m_mass[sun] = mass; - } - - for(std::vector::iterator i = systemNodes.begin(); i != systemNodes.end(); i++) { - node mergeNode = *i; - - if (MLG.getNode(sun->index()) != sun - || MLG.getNode(mergeNode->index()) != mergeNode) - { - return false; - } - - NodeMerge * NM = new NodeMerge(level); - std::vector positions = m_pathDistances[mergeNode]; - for (std::vector::iterator j = positions.begin(); j != positions.end(); j++) { - NM->m_position.push_back(std::pair((*j).targetSun, (*j).length)); - } - - bool ret; - if (i == systemNodes.begin() && m_massAsNodeRadius) { - ret = MLG.changeNode(NM, sun, sqrt((float)m_mass[sun]) * m_radius[sun], mergeNode); - } else { - ret = MLG.changeNode(NM, sun, MLG.radius(sun), mergeNode); - } - OGDF_ASSERT( ret ); - MLG.moveEdgesToParent(NM, mergeNode, sun, true, m_adjustEdgeLengths); - ret = MLG.postMerge(NM, mergeNode); - if( !ret ) { - delete NM; - } else { - retVal = true; - } - } - - return retVal; -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/SolarPlacer.cpp b/ext/OGDF/src/energybased/multilevelmixer/SolarPlacer.cpp deleted file mode 100644 index 32f1887c0..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/SolarPlacer.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places Nodes with Solar System rules - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -void SolarPlacer::placeOneLevel(MultilevelGraph &MLG) -{ - int level = MLG.getLevel(); - while (MLG.getLevel() == level && MLG.getLastMerge() != 0) - { - placeOneNode(MLG); - } -} - - -void SolarPlacer::placeOneNode(MultilevelGraph &MLG) -{ - NodeMerge * lastNM = MLG.getLastMerge(); - double x = 0.0; - double y = 0.0; - int i = 0; - - node sun = MLG.getNode(lastNM->m_changedNodes.front()); - std::vector< std::pair > positions = lastNM->m_position; - - node merged = MLG.undoLastMerge(); - - if (positions.size() > 0) { - for (std::vector< std::pair >::iterator j = positions.begin(); j != positions.end(); j++) { - double factor = (*j).second; - node other_sun = MLG.getNode((*j).first); - i++; - x += MLG.x(sun) * factor + MLG.x(other_sun) * (1.0f-factor); - y += MLG.y(sun) * factor + MLG.y(other_sun) * (1.0f-factor); - } - } else { - i++; - x += MLG.x(sun); - y += MLG.y(sun); - } - - OGDF_ASSERT(i > 0); - if (positions.size() == 0 || m_randomOffset) { - x += randomDouble(-1.0, 1.0); - y += randomDouble(-1.0, 1.0); - } - MLG.x(merged, (x / static_cast(i))); - MLG.y(merged, (y / static_cast(i))); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/multilevelmixer/ZeroPlacer.cpp b/ext/OGDF/src/energybased/multilevelmixer/ZeroPlacer.cpp deleted file mode 100644 index 80f0fe8c8..000000000 --- a/ext/OGDF/src/energybased/multilevelmixer/ZeroPlacer.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Places Nodes at the Positio of the merge-partner - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -ZeroPlacer::ZeroPlacer() -:m_randomRange(1.0) -{ -} - - -void ZeroPlacer::setRandomRange(double range) -{ - m_randomRange = range; -} - - -void ZeroPlacer::placeOneLevel(MultilevelGraph &MLG) -{ - int level = MLG.getLevel(); - while (MLG.getLevel() == level && MLG.getLastMerge() != 0) - { - placeOneNode(MLG); - } -} - - -void ZeroPlacer::placeOneNode(MultilevelGraph &MLG) -{ - NodeMerge * NM = MLG.getLastMerge(); - node parent = MLG.getNode(NM->m_changedNodes[0]); - node merged = MLG.undoLastMerge(); - MLG.x(merged, MLG.x(parent) + ((m_randomOffset)?(float)randomDouble(-m_randomRange, m_randomRange):0.f)); - MLG.y(merged, MLG.y(parent) + ((m_randomOffset)?(float)randomDouble(-m_randomRange, m_randomRange):0.f)); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/energybased/numexcept.cpp b/ext/OGDF/src/energybased/numexcept.cpp deleted file mode 100644 index 56cc3c049..000000000 --- a/ext/OGDF/src/energybased/numexcept.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class numexcept (handling of numeric problems). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "numexcept.h" -#include - -#define epsilon 0.1 -#define POS_SMALL_DOUBLE 1e-300 -#define POS_BIG_DOUBLE 1e+300 - - -namespace ogdf { - - -DPoint numexcept::choose_distinct_random_point_in_disque(DPoint old_point, - double xmin,double xmax,double ymin,double ymax) -{ - const int BILLION = 1000000000; - double mindist;//minimal distance from old_point to the boundaries of the disc - double mindist_to_xmin,mindist_to_xmax,mindist_to_ymin,mindist_to_ymax; - double rand_x,rand_y; - DPoint new_point; - - mindist_to_xmin = old_point.m_x - xmin; - mindist_to_xmax = xmax - old_point.m_x; - mindist_to_ymin = old_point.m_y - ymin; - mindist_to_ymax = ymax - old_point.m_y; - - mindist = min(min(mindist_to_xmin,mindist_to_xmax), min(mindist_to_ymin,mindist_to_ymax)); - - if(mindist > 0) - do { - //assign random double values in range (-1,1) - rand_x = 2*(double(randomNumber(1,BILLION)+1)/(BILLION+2)-0.5); - rand_y = 2*(double(randomNumber(1,BILLION)+1)/(BILLION+2)-0.5); - new_point.m_x = old_point.m_x+mindist*rand_x*epsilon; - new_point.m_y = old_point.m_y+mindist*rand_y*epsilon; - } while((old_point == new_point)||((old_point-new_point).norm() >= mindist*epsilon)); - - else if(mindist == 0) //old_point lies at the boundaries - {//else1 - double mindist_x =0; - double mindist_y =0; - - if (mindist_to_xmin > 0) - mindist_x = (-1)* mindist_to_xmin; - else if (mindist_to_xmax > 0) - mindist_x = mindist_to_xmax; - if (mindist_to_ymin > 0) - mindist_y = (-1)* mindist_to_ymin; - else if (mindist_to_ymax > 0) - mindist_y = mindist_to_ymax; - - if((mindist_x != 0)||(mindist_y != 0)) - do { - //assign random double values in range (0,1) - rand_x = double(randomNumber(1,BILLION)+1)/(BILLION+2); - rand_y = double(randomNumber(1,BILLION)+1)/(BILLION+2); - new_point.m_x = old_point.m_x+mindist_x*rand_x*epsilon; - new_point.m_y = old_point.m_y+mindist_y*rand_y*epsilon; - } while(old_point == new_point); - else - cout<<"Error DIM2:: box is equal to old_pos"< POS_BIG_LIMIT) - { - //create random number in range (0,1) - double randx = double(randomNumber(1,BILLION)+1)/(BILLION+2); - double randy = double(randomNumber(1,BILLION)+1)/(BILLION+2); - int rand_sign_x = randomNumber(0,1); - int rand_sign_y = randomNumber(0,1); - force.m_x = POS_SMALL_LIMIT*(1+randx)*pow(-1.0,rand_sign_x); - force.m_y = POS_SMALL_LIMIT*(1+randy)*pow(-1.0,rand_sign_y); - return true; - - } else if (distance < POS_SMALL_LIMIT) - { - //create random number in range (0,1) - double randx = double(randomNumber(1,BILLION)+1)/(BILLION+2); - double randy = double(randomNumber(1,BILLION)+1)/(BILLION+2); - int rand_sign_x = randomNumber(0,1); - int rand_sign_y = randomNumber(0,1); - force.m_x = POS_BIG_LIMIT*randx*pow(-1.0,rand_sign_x); - force.m_y = POS_BIG_LIMIT*randy*pow(-1.0,rand_sign_y); - return true; - - } else - return false; -} - - -bool numexcept::f_near_machine_precision(double distance,DPoint& force ) -{ - const double POS_BIG_LIMIT = POS_BIG_DOUBLE * 1e-190; - const double POS_SMALL_LIMIT = POS_SMALL_DOUBLE * 1e190; - const int BILLION = 1000000000; - - if(distance < POS_SMALL_LIMIT) - { - //create random number in range (0,1) - double randx = double(randomNumber(1,BILLION)+1)/(BILLION+2); - double randy = double(randomNumber(1,BILLION)+1)/(BILLION+2); - int rand_sign_x = randomNumber(0,1); - int rand_sign_y = randomNumber(0,1); - force.m_x = POS_SMALL_LIMIT*(1+randx)*pow(-1.0,rand_sign_x); - force.m_y = POS_SMALL_LIMIT*(1+randy)*pow(-1.0,rand_sign_y); - return true; - - } else if (distance > POS_BIG_LIMIT) - { - //create random number in range (0,1) - double randx = double(randomNumber(1,BILLION)+1)/(BILLION+2); - double randy = double(randomNumber(1,BILLION)+1)/(BILLION+2); - int rand_sign_x = randomNumber(0,1); - int rand_sign_y = randomNumber(0,1); - force.m_x = POS_BIG_LIMIT*randx*pow(-1.0,rand_sign_x); - force.m_x = POS_BIG_LIMIT*randy*pow(-1.0,rand_sign_y); - return true; - - } else - return false; -} - - -bool numexcept::nearly_equal(double a,double b) -{ - double delta = 1e-10; - double small_b,big_b; - - if(b > 0) { - small_b = b*(1-delta); - big_b = b*(1+delta); - - } else //b <= 0 - { - small_b = b*(1+delta); - big_b = b*(1-delta); - } - - if((small_b <= a) && (a <= big_b)) - return true; - else - return false; -} - -}//namespace ogdf diff --git a/ext/OGDF/src/energybased/numexcept.h b/ext/OGDF/src/energybased/numexcept.h deleted file mode 100644 index cd744dec3..000000000 --- a/ext/OGDF/src/energybased/numexcept.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of class numexcept (handling of numeric problems). - * - * \author Stefan Hachul - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_NUMEXCEPT_H -#define OGDF_NUMEXCEPT_H - -#include - -namespace ogdf { - -//-------------------------------------------------------------------------- -// this class is developed for exceptions that might occure, when nodes are -// placed at the same position and a new random position has to be found, or -// when the calculated forces are near the machine accuracy, where no -// reasonable numeric and logic calculations are possible any more -//--------------------------------------------------------------------------- - - class numexcept - { - public: - - //Returns a distinct random point within the smallest disque D with center - //old_point that is contained in the box defined by xmin,...,ymax; The size of - //D is shrunk by multiplying with epsilon = 0.1; Precondition: - //old_point is contained in the box and the box is not equal to old_point. - DPoint choose_distinct_random_point_in_disque( - DPoint old_point, - double xmin, - double xmax, - double ymin, - double ymax); - - //A random point (distinct from old_pos) on the disque around old_pos with - //radius epsilon = 0.1 is computed. - DPoint choose_distinct_random_point_in_radius_epsilon(DPoint old_pos); - - //If distance has a value near the machine precision the repulsive force calculation - //is not possible (calculated values exceed the machine accuracy) in this cases - //true is returned and force is set to a reasonable value that does - //not cause problems; Else false is returned and force keeps unchanged. - bool f_rep_near_machine_precision(double distance, DPoint& force); - - //If distance has a value near the machine precision the (attractive)force - //calculation is not possible (calculated values exceed the machine accuracy) in - //this cases true is returned and force is set to a reasonable value that does - //not cause problems; Else false is returned and force keeps unchanged. - bool f_near_machine_precision(double distance, DPoint& force); - - //Returns true if a is "nearly" equal to b (needed, when machine accuracy is - //insufficient in functions well_seperated and bordering of NMM) - bool nearly_equal(double a, double b); - - }; - -}//namespace ogdf -#endif - diff --git a/ext/OGDF/src/external/coin.cpp b/ext/OGDF/src/external/coin.cpp deleted file mode 100644 index aa25a7543..000000000 --- a/ext/OGDF/src/external/coin.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - * $Revision: 2614 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-16 11:30:08 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementations of a collection of classes used to drive - * Coin. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef USE_COIN - -#include -#include -#include -#include - -#ifdef COIN_OSI_CPX - #include // CPLEX - #include "cplex.h" - #include -#elif COIN_OSI_SYM - #include // Symphony -#elif COIN_OSI_CLP - #include // Coin-OR LP -#else - #error "Compiler-flag USE_COIN requires an additional COIN_OSI_xxx-flag to select the LP solver backend." -#endif - -namespace ogdf { - -#ifdef COIN_OSI_CPX - - int CPXPUBLIC CPX_CutCallback(CPXCENVptr xenv, void *cbdata, - int wherefrom, void *cbhandle, int *useraction_p) { -// cout << "Entering CPX Callback\n" << flush; - CPXLPptr nodelp; - CPXgetcallbacknodelp(xenv, cbdata, wherefrom, &nodelp); - - CoinCallbacks* ccc = (CoinCallbacks*)cbhandle; - - int length = CPXgetnumcols(xenv,nodelp) - 1; //hey, don't ask me! some VERY WIERD PHENOMENON... crap - double objVal; - double* solution = new double[length]; - CPXgetcallbacknodeobjval(xenv, cbdata, wherefrom, &objVal); - CPXgetcallbacknodex(xenv, cbdata, wherefrom, solution, 0, length-1); - - OsiCuts* cuts = new OsiCuts(); - CoinCallbacks::CutReturn ret = ccc->cutCallback(objVal, solution, cuts); - - if(ret == CoinCallbacks::CR_AddCuts) { - for(int i = cuts->sizeRowCuts(); i-->0;) { - const OsiRowCut& c = cuts->rowCut(i); - const CoinPackedVector& vec = c.row(); - - if(c.globallyValid()) - /* Old Cplex-Versions did NOT have the last parameter (now set to "false"). - * If you compile agains an older CPLEX version, simple *REMOVE* - * ", false" - * from the calls to CPXcutscallbackadd - */ - CPXcutcallbackadd(xenv, cbdata, wherefrom, - vec.getNumElements(), c.rhs(), c.sense(), vec.getIndices(), vec.getElements(), false); //default to non-purgable cuts - else - CPXcutcallbackaddlocal(xenv, cbdata, wherefrom, - vec.getNumElements(), c.rhs(), c.sense(), vec.getIndices(), vec.getElements()); - cuts->eraseRowCut(i); - } - if(cuts->sizeColCuts() > 0) { - cerr << "ColCuts currently not supported...\n"; - OGDF_THROW_PARAM(LibraryNotSupportedException, lnscFunctionNotImplemented); - } - } - - *useraction_p = - ( ret == CoinCallbacks::CR_Error) ? CPX_CALLBACK_FAIL : - ( ret == CoinCallbacks::CR_AddCuts ) ? CPX_CALLBACK_SET : CPX_CALLBACK_DEFAULT; - delete cuts; - delete[] solution; -// cout << "Leaving CPX Callback\n" << flush; - return 0; // success - } - - int CPXPUBLIC CPX_HeuristicCallback (CPXCENVptr env, void *cbdata, int wherefrom, - void *cbhandle, double *objval_p, double *x, int *checkfeas_p, int *useraction_p) { - CoinCallbacks* ccc = (CoinCallbacks*)cbhandle; - CoinCallbacks::HeuristicReturn ret = ccc->heuristicCallback(*objval_p, x); - *checkfeas_p = 0; // no check. callback has to ensure that new solution (if any) is integer feasible - switch(ret) { - case CoinCallbacks::HR_Error: - *useraction_p = CPX_CALLBACK_FAIL; - break; - case CoinCallbacks::HR_Ignore: - *useraction_p = CPX_CALLBACK_DEFAULT; - break; - case CoinCallbacks::HR_Update: - *useraction_p = CPX_CALLBACK_SET; - break; - default: - OGDF_THROW_PARAM(LibraryNotSupportedException, lnscFunctionNotImplemented); - } - return 0; - } - - int CPXPUBLIC CPX_IncumbentCallback (CPXCENVptr env, void *cbdata, int wherefrom, - void *cbhandle, double objval, double *x, int *isfeas_p, int *useraction_p) { - CoinCallbacks* ccc = (CoinCallbacks*)cbhandle; - CoinCallbacks::IncumbentReturn ret = ccc->incumbentCallback(objval, x); - switch(ret) { - case CoinCallbacks::IR_Error: - *useraction_p = CPX_CALLBACK_FAIL; - break; - case CoinCallbacks::IR_Update: - *isfeas_p = 1; - *useraction_p = CPX_CALLBACK_SET; - break; - case CoinCallbacks::IR_Ignore: - *isfeas_p = 0; - *useraction_p = CPX_CALLBACK_SET; - break; - default: - OGDF_THROW_PARAM(LibraryNotSupportedException, lnscFunctionNotImplemented); - } - return 0; - } -/* - int CPXPUBLIC CPX_BranchCallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle, - int type, int sos, int nodecnt, int bdcnt, double *nodeest, int *nodebeg, int *indices, - char *lu, int *bd, int *useraction_p) { - CoinCallbacks* ccc = (CoinCallbacks*)cbhandle; - CoinCallbacks::BranchReturn ret = ccc->branchCallback(objVal, x, ...); // callbacks to setbounds etc... - - switch(ret) { - case CoinCallbacks::BR_Error: - *useraction_p = CPX_CALLBACK_FAIL; - break; - case CoinCallbacks::BR_Take: - *infeas_p = 1; - *useraction_p = CPX_CALLBACK_SET; - break; - case CoinCallbacks::BR_ThrowAway: - *infeas_p = 0; - *useraction_p = CPX_CALLBACK_SET; - break; - default: - OGDF_THROW_PARAM(LibraryNotSupportedException, lnscFunctionNotImplemented); - } - return 0; - } - */ - -#endif // COIN_OSI_CPX - - OsiSolverInterface* CoinManager::createCorrectOsiSolverInterface() { - OsiSolverInterface* ret = new - #ifdef COIN_OSI_CPX - OsiCpxSolverInterface(); // CPLEX - #elif COIN_OSI_SYM - OsiSymSolverInterface(); // Symphony - #else // COIN_OSI_CLP - OsiClpSolverInterface(); // Coin-OR LP - #endif - logging(ret, !Logger::globalStatisticMode() && Logger::globalLogLevel() <= Logger::LL_MINOR); - return ret; - } - - void CoinManager::logging(OsiSolverInterface* osi, bool logMe) { - osi->messageHandler()->setLogLevel(logMe ? 1 : 0); - } - - bool CoinCallbacks::registerCallbacks(OsiSolverInterface* posi, int callbackTypes) { - #ifdef COIN_OSI_CPX - OsiCpxSolverInterface* x = dynamic_cast(posi); - CPXENVptr envptr = x->getEnvironmentPtr(); - CPXLPptr lpptr = x->getLpPtr(); - if(callbackTypes & CT_Cut) - CPXsetcutcallbackfunc(envptr, &CPX_CutCallback, this); - if(callbackTypes & CT_Heuristic) - CPXsetheuristiccallbackfunc(envptr, &CPX_HeuristicCallback, this); - if(callbackTypes & CT_Incumbent) - CPXsetincumbentcallbackfunc(envptr, &CPX_IncumbentCallback, this); -// if(callbackTypes & CT_Branch) -// CPXsetbranchcallbackfunc(envptr, &CPX_BranchCallback, this); - - CPXsetintparam(envptr, CPX_PARAM_MIPCBREDLP, CPX_OFF); - - CPXsetintparam(envptr, CPX_PARAM_PRELINEAR, 0); - CPXsetintparam(envptr, CPX_PARAM_HEURFREQ, -1); - CPXsetintparam(envptr, CPX_PARAM_PREIND, 0); - CPXsetintparam(envptr, CPX_PARAM_BNDSTRENIND, 0); - CPXsetintparam(envptr, CPX_PARAM_AGGIND, 0); - CPXsetintparam(envptr, CPX_PARAM_COEREDIND, 0); - CPXsetintparam(envptr, CPX_PARAM_RELAXPREIND, 0); - CPXsetintparam(envptr, CPX_PARAM_PREPASS, 0); - // CPXsetintparam(envptr, CPX_PARAM_REPEATPRESOLVE, 0); // only exists on cplex10 - CPXsetintparam(envptr, CPX_PARAM_REDUCE, 0); - - return true; - #else - //#warning "CoinCallbacks disabled. Currently only applicable for CPLEX. I'm sorry." - return false; - #endif - } - -} - -#endif // USE_COIN diff --git a/ext/OGDF/src/fileformats/DinoLineBuffer.cpp b/ext/OGDF/src/fileformats/DinoLineBuffer.cpp deleted file mode 100644 index 1ae8a0f3a..000000000 --- a/ext/OGDF/src/fileformats/DinoLineBuffer.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of a line buffer serving the class DinoXmlScanner - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - -#include -#include - -extern ofstream os; - -namespace ogdf { - - // Initialize static variables - const int DinoLineBuffer::c_maxStringLength = OGDF_STRING_BUFFER_SIZE; - const int DinoLineBuffer::c_maxLineLength = 200; - const int DinoLineBuffer::c_maxNoOfLines = 20; - - // - // ---------- D i n o L i n e B u f f e r P o s i t i o n ---------- - // - - // - // C o n s t r u c t o r - // - DinoLineBufferPosition::DinoLineBufferPosition( - int lineNumber, - int lineUpdateCount, - int linePosition) - { - set(lineNumber, lineUpdateCount, linePosition); - } - - // - // C o p y C o n s t r u c t o r - // - DinoLineBufferPosition::DinoLineBufferPosition(const DinoLineBufferPosition &position) - { - m_lineNumber = position.m_lineNumber; - m_lineUpdateCount = position.m_lineUpdateCount; - m_linePosition = position.m_linePosition; - } - - // - // s e t - // - void DinoLineBufferPosition::set(int lineNumber, int lineUpdateCount, int linePosition) - { - OGDF_ASSERT((lineNumber >= 0) && (lineNumber < DinoLineBuffer::c_maxNoOfLines)) - OGDF_ASSERT(lineUpdateCount >= 0) - OGDF_ASSERT((linePosition >= 0) && (linePosition < DinoLineBuffer::c_maxLineLength)) - - m_lineNumber = lineNumber; - m_lineUpdateCount = lineUpdateCount; - m_linePosition = linePosition; - - } // set - - // - // i n c r e m e n t P o s i t i o n - // - void DinoLineBufferPosition::incrementPosition() - { - ++m_linePosition; - - OGDF_ASSERT((m_linePosition >= 0) && (m_linePosition < DinoLineBuffer::c_maxLineLength)) - - } // increasePosition - - // - // o p e r a t o r ! = - // - bool DinoLineBufferPosition::operator!=(const DinoLineBufferPosition &position) const - { - if ((m_lineNumber != position.m_lineNumber) || - (m_lineUpdateCount != position.m_lineUpdateCount) || - (m_linePosition != position.m_linePosition)) - { - return true; - } - - return false; - - } // operator!= - - // - // o p e r a t o r = - // - const DinoLineBufferPosition & - DinoLineBufferPosition::operator=(const DinoLineBufferPosition &position) - { - if (&position != this){ - - m_lineNumber = position.getLineNumber(); - m_lineUpdateCount = position.getLineUpdateCount(); - m_linePosition = position.getLinePosition(); - - } - - return *this; - - } // operator= - - // - // ---------- D i n o L i n e B u f f e r ---------- - // - - // - // C o n s t r u c t o r - // - DinoLineBuffer::DinoLineBuffer(const char *fileName) : - m_pIs(0), - m_pLinBuf(0), - m_numberOfMostRecentlyReadLine(0), - m_inputFileLineCounter(0) - { - // Open file - m_pIs = new ifstream(fileName, ios::in); - if (!(*m_pIs)) { - DinoTools::reportError("DinoLineBuffer::DinoLineBuffer", __LINE__, "Error opening file!"); - } - - // Create and initialize lineUpdateCountArray - m_lineUpdateCountArray = new int[DinoLineBuffer::c_maxNoOfLines]; - int i; - for (i = 0; i < DinoLineBuffer::c_maxNoOfLines; i++){ - m_lineUpdateCountArray[i] = 0; - } - - // Create and initialize line buffer - m_pLinBuf = new char[(DinoLineBuffer::c_maxNoOfLines * DinoLineBuffer::c_maxLineLength)]; - if (m_pLinBuf == 0) - OGDF_THROW(InsufficientMemoryException); - for (i = 0; i < DinoLineBuffer::c_maxNoOfLines * DinoLineBuffer::c_maxLineLength; i++){ - m_pLinBuf[i] = '0'; - } - - // Read first line - if (!m_pIs->eof()){ - - // Read first line - m_pIs->getline(m_pLinBuf, DinoLineBuffer::c_maxLineLength); - - // Increase inputFileLineCounter - ++m_inputFileLineCounter; - - // Increase updateCount - ++(m_lineUpdateCountArray[0]); - - } - // End of file is reached immeadiately - else{ - - // Set eof marker - *m_pLinBuf = EOF; - - } - - // Set position - m_currentPosition.set(0, m_lineUpdateCountArray[0], 0); - - } // DinoLineBuffer::DinoLineBuffer - - // - // D e s t r u c t o r - // - DinoLineBuffer::~DinoLineBuffer() - { - // destroy line buffer - delete [] m_pLinBuf; - - // destroy lineUpdateCountArray - delete [] m_lineUpdateCountArray; - - // Close file - delete m_pIs; - - } // DinoLineBuffer::~DinoLineBuffer - - // - // m o v e T o N e x t C h a r a c t e r - // - char DinoLineBuffer::moveToNextCharacter(){ - - // Return if end of file is reached - if (getCurrentCharacter() == EOF){ - return EOF; - } - - // Increment position - m_currentPosition.incrementPosition(); - - // End of line is reached, there can be some consecutive lines - // with only \0 in it; hence we use a while loop - while (getCurrentCharacter() == '\0'){ - - // Current line is equal to most recently read line, - // i.e. we have to read a new line from the file - if (m_currentPosition.getLineNumber() == m_numberOfMostRecentlyReadLine){ - - // Increment line pointer (modulo c_maxNoOfLines - 1) - if (m_numberOfMostRecentlyReadLine == (DinoLineBuffer::c_maxNoOfLines - 1)){ - m_numberOfMostRecentlyReadLine = 0; - } - else { - ++m_numberOfMostRecentlyReadLine; - } - - // Increment update count - ++(m_lineUpdateCountArray[m_numberOfMostRecentlyReadLine]); - - // Increment inputFileLineCounter - ++m_inputFileLineCounter; - - // Set current position - m_currentPosition.set( - m_numberOfMostRecentlyReadLine, - m_lineUpdateCountArray[m_numberOfMostRecentlyReadLine], - 0); - - // End of file is reached - if (m_pIs->eof()){ - - // Set eof marker - setCurrentCharacter(EOF); - - } - // Read next line and put it to the new position - else{ - - m_pIs->getline(getCurrentCharacterPointer(), DinoLineBuffer::c_maxLineLength); - } - - } // Current line is equal to most recently read line - - // Current line is NOT equal to most recently read line, i.e. - // it is not necessary to read a new line from the file but to - // set the currentPosition to the next line which is already in - // the line buffer. - else{ - - int newLine; - - // Increment current line pointer (modulo c_maxNoOfLines - 1) - if (m_currentPosition.getLineNumber() == (DinoLineBuffer::c_maxNoOfLines - 1)){ - newLine = 0; - } - else { - newLine = m_currentPosition.getLineNumber() + 1; - } - - // Set current position - m_currentPosition.set(newLine, m_lineUpdateCountArray[newLine], 0); - - } // Current line is NOT equal to most recently read line - - } // End of line is reached - - return getCurrentCharacter(); - - } // moveToNextCharacter - - // - // s e t C u r r e n t P o s i t i o n - // - bool DinoLineBuffer::setCurrentPosition(const DinoLineBufferPosition &newPosition){ - - // Given positon is not valid - if (!isValidPosition(newPosition)) - { - return false; - } - - m_currentPosition = newPosition; - - return true; - - } // setCurrentPosition - - // - // s k i p W h i t e s p a c e - // - void DinoLineBuffer::skipWhitespace() - { - - if (getCurrentCharacter() == EOF) { - return; - } - - while ((isspace(getCurrentCharacter())) && (!(getCurrentCharacter() == EOF))) - { - moveToNextCharacter(); - } - - } // skipWhitespace - - // - // e x t r a c t S t r i n g - // - bool DinoLineBuffer::extractString( - const DinoLineBufferPosition &startPosition, - const DinoLineBufferPosition &endPosition, - char *targetString) - { - - // StartPosition invalid, probably because the line of the startPosition - // has already been overwritten, i.e. the string is too long - if (!isValidPosition(startPosition)) - { - ogdf::strcpy(targetString, DinoLineBuffer::c_maxStringLength, "String too long!"); - return false; - } - - // EndPosition must be valid - OGDF_ASSERT(isValidPosition(endPosition)) - - // Remember original currentPosition - DinoLineBufferPosition originalCurrentPosition = getCurrentPosition(); - - // Begin at startPosition - setCurrentPosition(startPosition); - - // Copy characters to tempString - int targetStringIndex = 0; - while (getCurrentPosition() != endPosition) - { - - // Check if eof - OGDF_ASSERT(getCurrentCharacter() != EOF) - - // Put character into targetString - targetString[targetStringIndex] = getCurrentCharacter(); - ++targetStringIndex; - - // String too long - if (targetStringIndex >= DinoLineBuffer::c_maxStringLength - 1){ - - ogdf::strcpy(targetString, DinoLineBuffer::c_maxStringLength, "String too long!"); - - // Set back the original current position - setCurrentPosition(originalCurrentPosition); - - return false; - - } - - // Move to next character - moveToNextCharacter(); - - } // Copy characters to tempString - - // Set back the original current position - setCurrentPosition(originalCurrentPosition); - - // Terminate string - targetString[targetStringIndex] = '\0'; - - return true; - - } // extractString - - // - // i s V a l i d P o s i t i o n - // - bool DinoLineBuffer::isValidPosition(const DinoLineBufferPosition &position) const - { - - // We can assume that the position is valid according to - // array ranges since these things are checked in constructor and set of - // class DinoLineBufferPosition - - // The line of the given position has already been overwritten - if (position.getLineUpdateCount() != - m_lineUpdateCountArray[position.getLineNumber()]) - { - return false; - } - - return true; - - } // isValidPosition - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/DinoTools.cpp b/ext/OGDF/src/fileformats/DinoTools.cpp deleted file mode 100644 index 25d73c1ff..000000000 --- a/ext/OGDF/src/fileformats/DinoTools.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of some tools - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -namespace ogdf { - - // - // s t r i n g T o D o u b l e A r r a y - // - void DinoTools::stringToDoubleArray(const String &str, Array &doubleArray) - { - size_t strIndex = 0; - char tempString[20]; - int tempStringIndex = 0; - - for (int i = 0; i < 4; i++){ - - tempStringIndex = 0; - - // Skip whitespace - while (isspace(str[strIndex])){ - ++strIndex; - } - - // Copy characters of double value - // values are separated by comma - while (str[strIndex] != ','){ - - tempString[tempStringIndex] = str[strIndex]; - ++tempStringIndex; - ++strIndex; - - } - - // Skip over ',' - ++strIndex; - - // Terminate string - tempString[tempStringIndex] = '\0'; - - // Put double value into array - doubleArray[i] = atof(tempString); - - } // for - - } // stringToDoubleArray - - // - // r e p o r t E r r o r - // - void DinoTools::reportError( - const char *functionName, - int sourceLine, - const char *message, - int inputFileLine, - bool abort) - { - cerr << "Error reported!" << endl; - cerr << "\tFunction: " << functionName << "(), Source line: " << sourceLine << endl; - cerr << "\tMessage: " << message << endl; - if (inputFileLine != -1) { - cerr << "\tCurrent line of input file: " << inputFileLine; - } - - cerr << endl; - - if (abort) - exit(1); - - } // reportError - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/DinoUmlDiagramGraph.cpp b/ext/OGDF/src/fileformats/DinoUmlDiagramGraph.cpp deleted file mode 100644 index f4bb0f876..000000000 --- a/ext/OGDF/src/fileformats/DinoUmlDiagramGraph.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class DinoUmlDiagramGraph - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - // - // C o n s t r u c t o r - // - DinoUmlDiagramGraph::DinoUmlDiagramGraph(const DinoUmlModelGraph ¨ModelGraph, - UmlDiagramType diagramType, - String diagramName): - m_modelGraph(umlModelGraph), - m_diagramName(diagramName), - m_diagramType(diagramType) - { - } - - // - // D e s t r u c t o r - // - DinoUmlDiagramGraph::~DinoUmlDiagramGraph() - { - // Remove elements from lists - m_containedNodes.clear(); - m_containedEdges.clear(); - m_x.clear(); - m_y.clear(); - m_w.clear(); - m_h.clear(); - } - - // - // a d d N o d e W i t h G e o m e t r y - // - void DinoUmlDiagramGraph::addNodeWithGeometry( - NodeElement* node, - double x, double y, - double w, double h) - { - // Append node to the end of the list - m_containedNodes.pushBack(node); - - // Dito with coordinates - m_x.pushBack(x); - m_y.pushBack(y); - m_w.pushBack(w); - m_h.pushBack(h); - - } - - // - // a d d E d g e - // - void DinoUmlDiagramGraph::addEdge(EdgeElement* edge) - { - // Append edge to the end of the list - m_containedEdges.pushBack(edge); - } - - // - // g e t D i a g r a m T y p e S t r i n g - // - String DinoUmlDiagramGraph::getDiagramTypeString() const - { - switch(m_diagramType){ - - case (classDiagram): - return String("Class diagram"); - break; - case (moduleDiagram): - return String("Module diagram"); - break; - case (sequenceDiagram): - return String("Sequence diagram"); - break; - case (collaborationDiagram): - return String("Collaboration diagram"); - break; - case (componentDiagram): - return String("Component diagram"); - break; - case (unknownDiagram): - return String("Unknown type diagram"); - break; - default: - return String(""); - } - - } // getDiagramTypeString - - - - // - // o u t p u t O p e r a t o r for DinoUmlDiagramGraph - // - ostream &operator<<(ostream &os, const DinoUmlDiagramGraph &diagramGraph) - { - // Header with diagram name and type - os << "\n--- " << diagramGraph.getDiagramTypeString() - << " \"" << diagramGraph.m_diagramName << "\" ---\n" << endl; - - // Nodes - - // Initialize iterators - SListConstIterator nodeIt = diagramGraph.m_containedNodes.begin(); - SListConstIterator xIt = diagramGraph.m_x.begin(); - SListConstIterator yIt = diagramGraph.m_y.begin(); - SListConstIterator wIt = diagramGraph.m_w.begin(); - SListConstIterator hIt = diagramGraph.m_h.begin(); - - // Traverse lists - while (nodeIt.valid()){ - - os << "Node " << diagramGraph.m_modelGraph.getNodeLabel(*nodeIt) - << " with geometry (" - << *xIt << ", " - << *yIt << ", " - << *wIt << ", " - << *hIt << ")." << endl; - - ++nodeIt; - ++xIt; - ++yIt; - ++wIt; - ++hIt; - - } // while - - // Edges - - // Traverse lists - SListConstIterator edgeIt = diagramGraph.m_containedEdges.begin(); - for (edgeIt = diagramGraph.m_containedEdges.begin(); - edgeIt.valid(); - ++edgeIt) - { - os << "Edge between " - << diagramGraph.m_modelGraph.getNodeLabel((*edgeIt)->source()) - << " and " - << diagramGraph.m_modelGraph.getNodeLabel((*edgeIt)->target()) - << endl; - } - - return os; - - } // << - - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/DinoUmlModelGraph.cpp b/ext/OGDF/src/fileformats/DinoUmlModelGraph.cpp deleted file mode 100644 index 45f068d4b..000000000 --- a/ext/OGDF/src/fileformats/DinoUmlModelGraph.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class DinoUmlModelGraph - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - // - // C o n s t r u c t o r - // - DinoUmlModelGraph::DinoUmlModelGraph(){ - - // Initialize arrays - m_nodeLabel.init(*this); - m_eType.init(*this,Graph::association); - m_vType.init(*this,Graph::vertex); - - } - - // - // D e s t r u c t o r - // - DinoUmlModelGraph::~DinoUmlModelGraph(){ - - // ??? Destroy arrays - } - - // - // o u t p u t O p e r a t o r for DinoUmlModelGraph - // - ostream &operator<<(ostream &os, const DinoUmlModelGraph &modelGraph) - { - // Header - os << "\n--- UmlModelGraph ---\n" << endl; - - // Traverse graph - - // Nodes - NodeElement *v; - os << "Classes/Interfaces:\n" << endl; - forall_nodes(v,modelGraph) { - os << "\t" << modelGraph.getNodeLabel(v) << endl; - } - - // Edges - EdgeElement *e; - os << "\nRelations:\n" << endl; - forall_edges(e,modelGraph) { - os << "\t"; - - if (modelGraph.type(e) == Graph::association){ - os << "Association between "; - } - if (modelGraph.type(e) == Graph::generalization){ - os << "Generalization between "; - } - if (modelGraph.type(e) == Graph::dependency){ - os << "Dependency between "; - } - - os << modelGraph.getNodeLabel(e->source()) << " and " - << modelGraph.getNodeLabel(e->target()) << endl; - } - - return os; - - } // << - - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/DinoUmlToGraphConverter.cpp b/ext/OGDF/src/fileformats/DinoUmlToGraphConverter.cpp deleted file mode 100644 index 9b26b679a..000000000 --- a/ext/OGDF/src/fileformats/DinoUmlToGraphConverter.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class DinoUmlToGraphConverter - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -namespace ogdf { - - - // - // C o n s t r u c t o r - // - DinoUmlToGraphConverter::DinoUmlToGraphConverter(const char *fileName) - { - // Create parser and get reference to hash table - m_xmlParser = new DinoXmlParser(fileName); - - // Fill hash table of the parser with predefined info indices - initializePredefinedInfoIndices(); - - // Create the parse tree - m_xmlParser->createParseTree(); - - // Create the uml model graph - m_modelGraph = new DinoUmlModelGraph(); - if (!createModelGraph(*m_modelGraph)){ - - // Error - return; - } - - // Create the uml diagram graphs - if (!createDiagramGraphs()){ - - // Error - return; - } - - // Create the diagram graph in UMLGraph format - if(!createDiagramGraphsInUMLGraphFormat(m_diagramGraphsInUMLGraphFormat)){ - - // Error - return; - } - } // DinoUmlToGraphConverter - - // - // D e s t r u c t o r - // - DinoUmlToGraphConverter::~DinoUmlToGraphConverter() - { - // Delete diagram graphs in UMLGraph format - SListConstIterator umlgIt; - for (umlgIt = m_diagramGraphsInUMLGraphFormat.begin(); umlgIt.valid(); ++umlgIt){ - const Graph & associatedGraph = (const Graph &)(**umlgIt); - delete *umlgIt; - delete &associatedGraph; - } - m_diagramGraphsInUMLGraphFormat.clear(); - - - // Delete diagram graphs - SListConstIterator dgIt; - for (dgIt = m_diagramGraphs.begin(); dgIt.valid(); ++dgIt){ - delete *dgIt; - } - m_diagramGraphs.clear(); - - // Destroy model graph - delete m_modelGraph; - - // Destroy parser - delete m_xmlParser; - } - - // - // i n i t i a l i z e P r e d e f i n e d I n f o I n d i c e s - // - void DinoUmlToGraphConverter::initializePredefinedInfoIndices() - { - m_xmlParser->addNewHashElement("XMI", xmi); - m_xmlParser->addNewHashElement("XMI.content", xmiContent); - m_xmlParser->addNewHashElement("xmi.id", xmiId); - m_xmlParser->addNewHashElement("UML:Model", umlModel); - m_xmlParser->addNewHashElement("UML:Namespace.ownedElement", umlNamespaceOwnedElement); - m_xmlParser->addNewHashElement("UML:Class", umlClass); - m_xmlParser->addNewHashElement("name", name); - m_xmlParser->addNewHashElement("UML:Generalization", umlGeneralization); - m_xmlParser->addNewHashElement("child", child); - m_xmlParser->addNewHashElement("parent", parent); - m_xmlParser->addNewHashElement("UML:Association", umlAssociation); - m_xmlParser->addNewHashElement("UML:Association.connection", umlAssociationConnection); - m_xmlParser->addNewHashElement("UML:AssociationEnd", umlAssociationEnd); - m_xmlParser->addNewHashElement("type", type); - m_xmlParser->addNewHashElement("UML:Diagram", umlDiagram); - m_xmlParser->addNewHashElement("UML:Diagram.element", rootUmlDiagramElement); - m_xmlParser->addNewHashElement("UML:DiagramElement", umlDiagramElement); - m_xmlParser->addNewHashElement("geometry", geometry); - m_xmlParser->addNewHashElement("subject", subject); - m_xmlParser->addNewHashElement("UML:Package", umlPackage); - m_xmlParser->addNewHashElement("UML:Interface", umlInterface); - m_xmlParser->addNewHashElement("UML:Dependency", umlDependency); - m_xmlParser->addNewHashElement("client", client); - m_xmlParser->addNewHashElement("supplier", supplier); - m_xmlParser->addNewHashElement("diagramType", diagramType); - m_xmlParser->addNewHashElement("ClassDiagram", classDiagram); - m_xmlParser->addNewHashElement("ModuleDiagram", moduleDiagram); - - } // initializePredefinedInfoIndices - - - // - // p r i n t I d T o N o d e M a p p i n g T a b l e - // - void DinoUmlToGraphConverter::printIdToNodeMappingTable(ofstream &os) - { - // Header - os << "\n--- Content of Hash table: m_m_idToNode ---\n" << endl; - - // Get iterator - HashConstIterator it; - - // Traverse table - for( it = m_idToNode.begin(); it.valid(); ++it){ - os << "\"" << it.key() << "\" has index " - << m_modelGraph->getNodeLabel(it.info()) << endl; - } - - } // printIdToNodeMappingTable - - // - // p r i n t D i a g r a m s I n U M L G r a p h F o r m a t - // - void DinoUmlToGraphConverter::printDiagramsInUMLGraphFormat(ofstream &os) - { - // Traverse diagrams - SListConstIterator diagramIt; - for (diagramIt = m_diagramGraphsInUMLGraphFormat.begin(); diagramIt.valid(); ++diagramIt) - { - // Get underlying graphs - const Graph &G = (const Graph &)**diagramIt; - const GraphAttributes &AG = **diagramIt; - - // Nodes - os << "Classes:" << endl; - NodeElement *v; - forall_nodes(v,G) - { - os << "\t" << AG.labelNode(v); - - os << " with geometry (" - << AG.x(v) << ", " - << AG.y(v) << ", " - << AG.width(v) << ", " - << AG.height(v) << ")"; - - os << endl; - } - - // Edges - EdgeElement *e; - os << "Relations:" << endl; - forall_edges(e,G) - { - os << "\t"; - - if (AG.type(e) == Graph::association) - os << "Association between "; - if (AG.type(e) == Graph::generalization) - os << "Generalization between "; - - os << AG.labelNode(e->source()) << " and " - << AG.labelNode(e->target()) << endl; - } - - os << "---------------------------------------------------------------\n\n" << endl; - - } // Traverse diagrams - - } // printDiagramsInUMLGraphFormat - - - // - // c r e a t e M o d e l G r a p h - // - bool DinoUmlToGraphConverter::createModelGraph(DinoUmlModelGraph &modelGraph){ - - // Message - //cout << "Creating model graph..." << endl; - - // Check root element (must be ) - if (m_xmlParser->getRootTag().m_pTagName->info() != xmi){ - - // Error: Root tag is not - return false; - } - - // Find first ; this is the father tag - Array path(3); - path[0] = xmiContent; - path[1] = umlModel; - path[2] = umlNamespaceOwnedElement; - const XmlTagObject *fatherTag; - String rootPackageName(""); - if (!m_xmlParser->traversePath(m_xmlParser->getRootTag(), path, fatherTag)){ - - // Error: Path xmiContent, umlModel, umlNamespaceOwnedElement not found! - return false; - } - - // Traverse packages and insert classifier nodes - if (!traversePackagesAndInsertClassifierNodes( - *fatherTag, - rootPackageName, - modelGraph)) - { - return false; - } - - // Note that first alle nodes have to be inserted into the model graph - // and after that the edges should be inserted. The reason is that it - // is possible that edges are specified prior to that one or both nodes - // have been created. - - - // Traverse packages and insert association edges - if (!traversePackagesAndInsertAssociationEdges(*fatherTag, modelGraph)) - { - return false; - } - - // Traverse packages and insert generalization edges - if (!traversePackagesAndInsertGeneralizationEdges(*fatherTag, modelGraph)) - { - return false; - } - - // Insert dependency edges - if (!insertDependencyEdges(*fatherTag, modelGraph)) - { - return false; - } - - return true; - - } // createModelGraph - - - // - // t r a v e r s e P a c k a g e s A n d I n s e r t C l a s s i f i e r N o d e s - // - bool DinoUmlToGraphConverter::traversePackagesAndInsertClassifierNodes( - const XmlTagObject ¤tRootTag, - String currentPackageName, - DinoUmlModelGraph &modelGraph) - { - // We proceed in a DFS manner. As long as we are inside a package - // and there is a subpackage inside, we dive into that subpackage - // by calling this function recursively (with a new rootTag). Along - // this we also construct the appropriate package name. - // - // If we arrive at a level where either all subpackages have been - // already traversed or no subpackage is inside we proceed to find - // the classifiers contained at the current level. - // - // At the moment we consider classed and interfaces. - // - // TODO: In Java it is possible that there classes contained in other classe, - // This is currently not detected. - - // Identify contained packages () - const XmlTagObject *packageSon = 0; - m_xmlParser->findSonXmlTagObject(currentRootTag, umlPackage, packageSon); - while(packageSon != 0){ - - // Create new name for the subpackage - const XmlAttributeObject *nameAttribute; - m_xmlParser->findXmlAttributeObject(*packageSon, name, nameAttribute); - OGDF_ASSERT(nameAttribute != 0) - String subPackageName = currentPackageName; - if (currentPackageName.length() != 0){ - subPackageName += "::"; - } - subPackageName += nameAttribute->m_pAttributeValue->key(); - - // Find son umlNamespaceOwnedElement which indicates a nested package - // if nonexistent then continue - const XmlTagObject *newRootTag; - if(m_xmlParser->findSonXmlTagObject(*packageSon, umlNamespaceOwnedElement, newRootTag)){ - - // Call this function recursively - if (!traversePackagesAndInsertClassifierNodes(*newRootTag, subPackageName, modelGraph)) - { - // Something went wrong - return false; - } - - } - - // Next package (will be put into packageSon) - m_xmlParser->findBrotherXmlTagObject(*packageSon, umlPackage, packageSon); - - } // while - - // Identify contained classes () - if (!insertSpecificClassifierNodes(currentRootTag, currentPackageName, umlClass, modelGraph)) - { - // Something went wrong - return false; - } - - // Identify contained interfaces () - if (!insertSpecificClassifierNodes(currentRootTag, currentPackageName, umlInterface, modelGraph)) - { - // Something went wrong - return false; - } - - return true; - - } // traversePackagesAndInsertClassifierNodes - - - // - // i n s e r t S p e c i f i c C l a s s i f i e r N o d e s - // - bool DinoUmlToGraphConverter::insertSpecificClassifierNodes(const XmlTagObject ¤tRootTag, - String currentPackageName, - int desiredClassifier, - DinoUmlModelGraph &modelGraph) - { - const XmlTagObject *classifierSon; - m_xmlParser->findSonXmlTagObject(currentRootTag, desiredClassifier, classifierSon); - while (classifierSon != 0){ - - // Use the infoIndex of value of attribute xmi.id as reference to the node - // it is unique for each classifier and is used to reference it in the - // relation specifications - const XmlAttributeObject *xmiIdAttr; - - // Did not find attribute xmi.id of classifier - if (!m_xmlParser->findXmlAttributeObject(*classifierSon, xmiId, xmiIdAttr)){ - - // Error: Did not find attribute xmi.id of Classifier. - return false; - } - - // We get an unique node id by the value of attribute xmi.id - int nodeId = xmiIdAttr->m_pAttributeValue->info(); - - // Find out name of the classifier - const XmlAttributeObject *nameAttr; - - // Did not find name attribute - if (!m_xmlParser->findXmlAttributeObject(*classifierSon, name, nameAttr)){ - - // Error: Did not find name attribute of Classifier. - return false; - } - - // Name of the classifier is contained in the tag value - HashedString *nodeName = nameAttr->m_pAttributeValue; - - // Create classifier name by prefixing it with the package name - String nodeNameString = currentPackageName; - if (currentPackageName.length() != 0){ - nodeNameString += "::"; - } - nodeNameString += nodeName->key(); - - // Check if node already exists - if (m_idToNode.lookup(nodeId) != 0){ - - // Error: Node already exists - return false; - } - - // Create a node for the graph - NodeElement *node = modelGraph.newNode(); - modelGraph.labelNode(node) = nodeNameString; - modelGraph.type(node) = Graph::vertex; - - // Put node into hash table - m_idToNode.fastInsert(nodeId, node); - - // Proceed with next class (will be put into classifierSon) - m_xmlParser->findBrotherXmlTagObject(*classifierSon, desiredClassifier, classifierSon); - - } // while (classifierSon != 0) - - return true; - - } // insertSpecificClassifierNodes - - - // - // t r a v e r s e P a c k a g e s A n d I n s e r t A s s o c i a t i o n E d g e s - // - bool DinoUmlToGraphConverter::traversePackagesAndInsertAssociationEdges(const XmlTagObject ¤tRootTag, - DinoUmlModelGraph &modelGraph) - { - // The traversion of the packages is identical with this of - // traversePackagesAndInsertClassifierNodes - - // Identify contained packages () - const XmlTagObject *packageSon; - m_xmlParser->findSonXmlTagObject(currentRootTag, umlPackage, packageSon); - while (packageSon != 0){ - - // Find son umlNamespaceOwnedElement - // if nonexistent then continue - const XmlTagObject *newRootTag; - - if (m_xmlParser->findSonXmlTagObject(*packageSon, umlNamespaceOwnedElement, newRootTag)) - { - // Call this function recursively - if (!traversePackagesAndInsertAssociationEdges(*newRootTag, modelGraph)) - { - return false; - } - - } - - // Next package - m_xmlParser->findBrotherXmlTagObject(*packageSon, umlPackage, packageSon); - - } // while - - // Find all associations () - const XmlTagObject *associationSon; - m_xmlParser->findSonXmlTagObject(currentRootTag, umlAssociation, associationSon); - while (associationSon != 0){ - - // Find out the reference number of this edge - const XmlAttributeObject *edgeIdAttr = 0; - m_xmlParser->findXmlAttributeObject(*associationSon, xmiId, edgeIdAttr); - int edgeId = edgeIdAttr->m_pAttributeValue->info(); - - // Go to - const XmlTagObject *connection; - m_xmlParser->findSonXmlTagObject(*associationSon, umlAssociationConnection, connection); - - // We assume binary associations - - // Investigate association ends - const XmlTagObject *end1 = 0; - m_xmlParser->findSonXmlTagObject(*connection, umlAssociationEnd, end1); - const XmlTagObject *end2 = 0; - m_xmlParser->findBrotherXmlTagObject(*end1, umlAssociationEnd, end2); - - // Something wrong - if (!end1 || !end2){ - - // Warning: Current association tag does not contain both end tags! - - // Next association - m_xmlParser->findBrotherXmlTagObject(*associationSon, umlAssociation, associationSon); - continue; - } - - // Use the infoIndex of value of attribute type to find - // the corresponding nodes - const XmlAttributeObject *typeAttr1; - m_xmlParser->findXmlAttributeObject(*end1, type, typeAttr1); - const XmlAttributeObject *typeAttr2; - m_xmlParser->findXmlAttributeObject(*end2, type, typeAttr2); - int nodeId1 = typeAttr1->m_pAttributeValue->info(); - int nodeId2 = typeAttr2->m_pAttributeValue->info(); - - // Create an edge for the graph - HashElement *node1HE = m_idToNode.lookup(nodeId1); - HashElement *node2HE = m_idToNode.lookup(nodeId2); - - // Both nodes were found - if (node1HE && node2HE){ - NodeElement *node1 = node1HE->info(); - NodeElement *node2 = node2HE->info(); - EdgeElement *edge = modelGraph.newEdge(node1, node2); - modelGraph.type(edge) = Graph::association; - - // Insert edge id and edge element into hashing table - m_idToEdge.fastInsert(edgeId, edge); - } - - // If condition above does not hold: Error! - // At least one node is not contained in the node hashtable - // One reason could be that we have an association between at least - // one element other than class or interface - - // Next association - m_xmlParser->findBrotherXmlTagObject(*associationSon, umlAssociation, associationSon); - - } // while (associationSon != 0) - - return true; - - } // traversePackagesAndInsertAssociationEdges - - // - // t r a v e r s e P a c k a g e s A n d I n s e r t G e n e r a l i z a t i o n E d g e s - // - bool DinoUmlToGraphConverter::traversePackagesAndInsertGeneralizationEdges( - const XmlTagObject ¤tRootTag, - DinoUmlModelGraph &modelGraph) - { - // TODO: The generalization tags can also occur inside interface classifiers (in Java) - // Currently we only consider classes. - - // Identify contained packages () - const XmlTagObject *packageSon; - m_xmlParser->findSonXmlTagObject(currentRootTag, umlPackage, packageSon); - while (packageSon != 0){ - - // Find son umlNamespaceOwnedElement - // if nonexistent then continue - const XmlTagObject *newRootTag; - m_xmlParser->findSonXmlTagObject(*packageSon, umlNamespaceOwnedElement, newRootTag); - if (newRootTag != 0){ - - // Call this function recursively - if (!traversePackagesAndInsertGeneralizationEdges(*newRootTag, modelGraph)) - { - return false; - } - - } - - // Next package - m_xmlParser->findBrotherXmlTagObject(*packageSon, umlPackage, packageSon); - - } // while - - // Find all classes () - const XmlTagObject *classSon; - m_xmlParser->findSonXmlTagObject(currentRootTag, umlClass, classSon); - while (classSon != 0){ - - Array path(2); - path[0] = umlNamespaceOwnedElement; - path[1] = umlGeneralization; - const XmlTagObject *generalizationTag = 0; - - // Found a tag - if (m_xmlParser->traversePath(*classSon, path, generalizationTag)){ - - // Find out the reference number of this edge - const XmlAttributeObject *edgeIdAttr = 0; - m_xmlParser->findXmlAttributeObject(*generalizationTag, xmiId, edgeIdAttr); - int edgeId = edgeIdAttr->m_pAttributeValue->info(); - - // Find child and parent attributes - const XmlAttributeObject *childAttr = 0; - m_xmlParser->findXmlAttributeObject(*generalizationTag, child, childAttr); - const XmlAttributeObject *parentAttr = 0; - m_xmlParser->findXmlAttributeObject(*generalizationTag, parent, parentAttr); - - // Something wrong - if (!childAttr || !parentAttr){ - - // Warning: Current dependency tag does not contain both attributes child and parent. - - // Next class - m_xmlParser->findBrotherXmlTagObject(*classSon, umlClass, classSon); - continue; - } - - // Get ids and nodes - int childId = childAttr->m_pAttributeValue->info(); - int parentId = parentAttr->m_pAttributeValue->info(); - - // Get hash elements - HashElement *childNodeHE = m_idToNode.lookup(childId); - HashElement *parentNodeHE = m_idToNode.lookup(parentId); - - // Create an edge for the graph - if (childNodeHE && parentNodeHE){ - - NodeElement *childNode = childNodeHE->info(); - NodeElement *parentNode = parentNodeHE->info(); - - EdgeElement *edge = modelGraph.newEdge(childNode, parentNode); - modelGraph.type(edge) = Graph::generalization; - - // Insert edge id and edge element into hashing table - m_idToEdge.fastInsert(edgeId, edge); - } - // If condition above does not hold: Error! - // At least one node is not contained in the node hashtable - - } // Found generalization tag - - // Next class - m_xmlParser->findBrotherXmlTagObject(*classSon, umlClass, classSon); - - } // while (classSon != 0) - - return true; - - } // traversePackagesAndInsertGeneralizationEdges - - - // - // i n s e r t D e p e n d e n c y E d g e s - // - bool DinoUmlToGraphConverter::insertDependencyEdges(const XmlTagObject ¤tRootTag, - DinoUmlModelGraph &modelGraph) - { - // Find first dependency tag () - const XmlTagObject *currentDependencyTag = 0; - m_xmlParser->findSonXmlTagObject(currentRootTag, umlDependency, currentDependencyTag); - - // Find all dependencys - while (currentDependencyTag != 0){ - - // Find out the reference number of this edge - const XmlAttributeObject *edgeIdAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDependencyTag, xmiId, edgeIdAttr); - int edgeId = edgeIdAttr->m_pAttributeValue->info(); - - // Find client and supplier attributes - const XmlAttributeObject *clientAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDependencyTag, client, clientAttr); - const XmlAttributeObject *supplierAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDependencyTag, supplier, supplierAttr); - - // Something wrong - if (!clientAttr || !supplierAttr){ - - // Warning: Current dependency tag does not contain both attributes client and supplier. - - // Next dependency - m_xmlParser->findBrotherXmlTagObject(*currentDependencyTag, umlDependency, currentDependencyTag); - continue; - } - - // Get ids - int clientId = clientAttr->m_pAttributeValue->info(); - int supplierId = supplierAttr->m_pAttributeValue->info(); - - // Get Hashelements - HashElement *clientNodeHE = m_idToNode.lookup(clientId); - HashElement *supplierNodeHE = m_idToNode.lookup(supplierId); - - // Create an edge for the graph - if (clientNodeHE && supplierNodeHE){ - - NodeElement *clientNode = clientNodeHE->info(); - NodeElement *supplierNode = supplierNodeHE->info(); - - EdgeElement *edge = modelGraph.newEdge(clientNode, supplierNode); - modelGraph.type(edge) = Graph::dependency; - - // Insert edge id and edge element into hashing table - m_idToEdge.fastInsert(edgeId, edge); - } - // If condition above does not hold: Error! - // At least one node is not contained in the node hashtable - - // Next dependency - m_xmlParser->findBrotherXmlTagObject(*currentDependencyTag, umlDependency, currentDependencyTag); - - } // while (currentDependecyTag != 0) - - return true; - - } // insertDependencyEdges - - - // - // c r e a t e D i a g r a m G r a p h s - // - bool DinoUmlToGraphConverter::createDiagramGraphs() - { - // We want to create a diagram graph for each subtree found - // in the parse tree. - // - // Currently we are only interested in class diagrams. - - // Model graph must exist! - OGDF_ASSERT(m_modelGraph != 0) - - // Message - //cout << "Creating diagram graph(s)..." << endl; - - // Check root element (must be ) - if (m_xmlParser->getRootTag().m_pTagName->info() != xmi){ - - // Error: Root tag is not - return false; - } - - // Find the first tag starting at - Array path(2); - path[0] = xmiContent; - path[1] = umlDiagram; - const XmlTagObject *currentDiagramTag = 0; - m_xmlParser->traversePath(m_xmlParser->getRootTag(), path, currentDiagramTag); - - // Traverse diagrams - while (currentDiagramTag != 0){ - - // Find out name of the diagram - const XmlAttributeObject *nameAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDiagramTag, name, nameAttr); - String diagramName(""); - if (nameAttr != 0){ - diagramName = nameAttr->m_pAttributeValue->key(); - } - - // Find out type of the diagram - const XmlAttributeObject *diagramTypeAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDiagramTag, diagramType, diagramTypeAttr); - - // No diagramTypeAttribute found --> we continue with the next diagram - if (diagramTypeAttr == 0){ - - // Next diagram - m_xmlParser->findBrotherXmlTagObject(*currentDiagramTag, umlDiagram, currentDiagramTag); - continue; - } - - // Check which type of diagram we have - DinoUmlDiagramGraph::UmlDiagramType diagramType; - switch (diagramTypeAttr->m_pAttributeValue->info()){ - - case (classDiagram) : - diagramType = DinoUmlDiagramGraph::classDiagram; - break; - case (moduleDiagram) : - diagramType = DinoUmlDiagramGraph::moduleDiagram; - break; - default: - diagramType = DinoUmlDiagramGraph::unknownDiagram; - break; - - } // switch - - // Currently we only allow class diagrams; in all other cases - // we continue with the next diagram - if (diagramType != DinoUmlDiagramGraph::classDiagram){ - - // Next diagram - m_xmlParser->findBrotherXmlTagObject(*currentDiagramTag, umlDiagram, currentDiagramTag); - continue; - } - - // Create a new diagram graph and add it to the list of diagram graphs - DinoUmlDiagramGraph *diagramGraph = - new DinoUmlDiagramGraph(*m_modelGraph, - diagramType, - diagramName); - m_diagramGraphs.pushBack(diagramGraph); - - - // First pass the tag - const XmlTagObject *rootDiagramElementTag = 0; - m_xmlParser->findSonXmlTagObject(*currentDiagramTag, rootUmlDiagramElement, rootDiagramElementTag); - - // No such tag found --> we continue with the next diagram - if (rootDiagramElementTag == 0){ - - // Next diagram - m_xmlParser->findBrotherXmlTagObject(*currentDiagramTag, umlDiagram, currentDiagramTag); - continue; - } - - // Now investigate the diagram elements - const XmlTagObject *currentDiagramElementTag = 0; - m_xmlParser->findSonXmlTagObject(*rootDiagramElementTag, umlDiagramElement, currentDiagramElementTag); - - // Traverse all diagram elements () - while (currentDiagramElementTag != 0){ - - // We have to investigate the subject attribute which contains the - // reference number of the represented element; then we can check if - // a node or edge with this reference exists - const XmlAttributeObject *subjectAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDiagramElementTag, subject, subjectAttr); - - // Not found --> continue with the next diagram element - if (subjectAttr == 0){ - - // Next diagram element - m_xmlParser->findBrotherXmlTagObject(*currentDiagramElementTag, umlDiagramElement, currentDiagramElementTag); - - continue; - } - - // Check wether node or edge with this reference does exist - int elementId = subjectAttr->m_pAttributeValue->info(); - - // Node exists for that reference - if (m_idToNode.lookup(elementId) != 0){ - - // Get hash element - HashElement *nodeHashElement = m_idToNode.lookup(elementId); - - // Get node element - NodeElement* geometricNode = nodeHashElement->info(); - - // Extract geometric information - const XmlAttributeObject *geometryAttr = 0; - m_xmlParser->findXmlAttributeObject(*currentDiagramElementTag, geometry, geometryAttr); - - // Not found - if (geometryAttr == 0){ - break; - } - - // Get double values of geometry - Array geometryArray(4); - DinoTools::stringToDoubleArray(geometryAttr->m_pAttributeValue->key(), geometryArray); - - // Add node to diagram graph - diagramGraph->addNodeWithGeometry( - geometricNode, - geometryArray[0], - geometryArray[1], - geometryArray[2], - geometryArray[3]); - - } // Node exists - // Node does not exist - else{ - - // Edge exists for that reference - if (m_idToEdge.lookup(elementId) != 0){ - - // Get hash element - HashElement *edgeHashElement = m_idToEdge.lookup(elementId); - - // Get node element - EdgeElement* geometricEdge = edgeHashElement->info(); - - // Add edge to diagram graph - diagramGraph->addEdge(geometricEdge); - - } // Edge exists - - } // else - - // Next diagram element - m_xmlParser->findBrotherXmlTagObject(*currentDiagramElementTag, - umlDiagramElement, - currentDiagramElementTag); - - } // while (currentDiagramElementTag != 0) - - // Next diagram - m_xmlParser->findBrotherXmlTagObject(*currentDiagramTag, umlDiagram, currentDiagramTag); - - - } // while (currentDiagramTag != 0) - - return true; - - } // createDiagramGraphs - - // - // c r e a t e D i a g r a m G r a p h s I n U M L G r a p h F o r m a t - // - bool DinoUmlToGraphConverter::createDiagramGraphsInUMLGraphFormat(SList &diagramGraphsInUMLGraphFormat) - { - // We want to create an instance of UMLGraph for each instance of DinoUmlDiagramGraph - // contained in the given list. Implicitly we have to create also an instance of class Graph - // for each UMLGraph. - // We maintain a hash list for mapping the nodes and edges of the model graph to the - // new nodes and edges of the graph created for the diagram. - // We use as key the unique index of the node resp. edge. - - // Message - //cout << "Creating diagram graph(s) in UMLGraph format..." << endl; - - // Traverse list of diagram graphs - SListConstIterator diagramGraphIterator; - for (diagramGraphIterator = m_diagramGraphs.begin(); - diagramGraphIterator.valid(); - ++diagramGraphIterator) - { - - // Mapping from the index of the existing node to the new nodeElement - Hashing indexToNewNode; - - // Mapping from the index of the existing edge to the new edgeElement - Hashing indexToNewEdge; - - // Create instance of class graph - Graph *graph = new Graph(); - - // Traverse list of nodes contained in the diagram - const SList diagramNodes = (*diagramGraphIterator)->getNodes(); - SListConstIterator nodeIt; - for (nodeIt = diagramNodes.begin(); nodeIt.valid(); ++nodeIt) - { - // Create a new "pendant" node for the existing node - NodeElement *newNode = graph->newNode(); - - // Insert mapping from index of the existing node to the pendant node - // into hashtable - indexToNewNode.fastInsert((*nodeIt)->index(), newNode); - - } // Traverse list of nodes contained in the diagram - - // Traverse list of edges contained in the diagram - const SList diagramEdges = (*diagramGraphIterator)->getEdges(); - SListConstIterator edgeIt; - for (edgeIt = diagramEdges.begin(); edgeIt.valid(); ++edgeIt) - { - // Find out source and target of the edge - NodeElement *source = (*edgeIt)->source(); - NodeElement *target = (*edgeIt)->target(); - - // Find pendant nodes - HashElement *sourceHashElement = - indexToNewNode.lookup(source->index()); - HashElement *targetHashElement = - indexToNewNode.lookup(target->index()); - NodeElement *pendantSource = sourceHashElement->info(); - NodeElement *pendantTarget = targetHashElement->info(); - - // Insert new edge between pendant nodes - EdgeElement *newEdge = graph->newEdge(pendantSource, pendantTarget); - - // Insert mapping from index of the existing edgeto the pendant edge - // into hashtable - indexToNewEdge.fastInsert((*edgeIt)->index(), newEdge); - - } // Traverse list of edges contained in the diagram - - // Create instance of class UMLGraph - UMLGraph *umlGraph = new UMLGraph(*graph, GraphAttributes::nodeLabel); - - // Now we want to add the geometry information and the node label - const SList xList = (*diagramGraphIterator)->getX(); - const SList yList = (*diagramGraphIterator)->getY(); - const SList wList = (*diagramGraphIterator)->getWidth(); - const SList hList = (*diagramGraphIterator)->getHeight(); - SListConstIterator xIt, yIt, wIt, hIt; - - // Traverse node list and geometry lists synchronously - xIt = xList.begin(); - yIt = yList.begin(); - wIt = wList.begin(); - hIt = hList.begin(); - nodeIt = diagramNodes.begin(); - while (nodeIt.valid()) - { - // Get pendant node - HashElement *nodeHashElement = - indexToNewNode.lookup((*nodeIt)->index()); - NodeElement *pendantNode = nodeHashElement->info(); - - // Insert geometry information into umlGraph - umlGraph->x(pendantNode) = *xIt; - umlGraph->y(pendantNode) = *yIt; - umlGraph->width(pendantNode) = *wIt; - umlGraph->height(pendantNode) = *hIt; - - // Insert label - String &label = umlGraph->labelNode(pendantNode); - label = m_modelGraph->getNodeLabel(*nodeIt); - - // Next iteration - ++xIt; - ++yIt; - ++wIt; - ++hIt; - ++nodeIt; - - } // Traverse node list and geometry lists synchronously - - // Traverse list of edges contained in the diagram - for (edgeIt = diagramEdges.begin(); edgeIt.valid(); ++edgeIt) - { - // Find pendant edge - HashElement *edgeHashElement = - indexToNewEdge.lookup((*edgeIt)->index()); - EdgeElement *pendantEdge = edgeHashElement->info(); - - // Insert type information into umlGraph - umlGraph->type(pendantEdge) = m_modelGraph->type(*edgeIt); - - } // Traverse edge list and insert type information for the new edges. - - // Add new umlGraph to list - diagramGraphsInUMLGraphFormat.pushBack(umlGraph); - - } // Traverse list of diagram graphs - - return true; - - } // createDiagramGraphsInUMLGraphFormat - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/DinoXmlParser.cpp b/ext/OGDF/src/fileformats/DinoXmlParser.cpp deleted file mode 100644 index f3bdf4ccf..000000000 --- a/ext/OGDF/src/fileformats/DinoXmlParser.cpp +++ /dev/null @@ -1,913 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of XML parser (class DinoXmlParser) - * (used for parsing and reading XML files) - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -#include -#include - - -namespace ogdf { - - //----------------------------------------------------- - //Methods for handling XML objects for OGML file format - //----------------------------------------------------- - bool XmlTagObject::isLeaf() const { - if(this->m_pFirstSon) return false; - else return true; - } - - bool XmlTagObject::findSonXmlTagObjectByName( - const String sonsName, - XmlTagObject *&son) const - { - XmlTagObject *currentSon = this->m_pFirstSon; - while(currentSon && currentSon->m_pTagName->key() != sonsName) - { - currentSon = currentSon->m_pBrother; - } - - if(currentSon) { - son = currentSon; - return true; - } - - son = 0; - return false; - } - - bool XmlTagObject::findSonXmlTagObjectByName( - const String sonsName, - List &sons) const - { - bool found; - XmlTagObject *currentSon = this->m_pFirstSon; - while(currentSon) - { - if(currentSon->m_pTagName->key() == sonsName) { - found = true; - sons.pushBack(currentSon); - } - currentSon = currentSon->m_pBrother; - } - - return found; - } - - bool XmlTagObject::hasMoreSonXmlTagObject(const List &sonNamesToIgnore) const { - const XmlTagObject *currentSon = this->m_pFirstSon; - while(currentSon) - { - - //Proof if name of currentSon is inequal to all in sonsName - ListConstIterator it; - bool found = false; - for(it = sonNamesToIgnore.begin(); it.valid() && !found; it++) { - if(*it == currentSon->m_pTagName->key()) found = true; - } - if(!found) return true; - currentSon = currentSon->m_pBrother; - } - - return false; - } - - bool XmlTagObject::findXmlAttributeObjectByName( - const String attName, - XmlAttributeObject*& attribute) const - { - XmlAttributeObject *currentAttribute = this->m_pFirstAttribute; - while ((currentAttribute != 0) && - (currentAttribute->m_pAttributeName->key() != attName)) - { - currentAttribute = currentAttribute->m_pNextAttribute; - } - - // Attribute found - if (currentAttribute != 0){ - attribute = currentAttribute; - return true; - } - - // Not found - attribute = 0; - return false; - } - - bool XmlTagObject::isAttributeLess() const { - if(this->m_pFirstAttribute) return false; - else return true; - } - - - // - // ---------- D i n o X m l P a r s e r ------------------------ - // - - // - // C o n s t r u c t o r - // - DinoXmlParser::DinoXmlParser(const char *fileName) : - m_pRootTag(0), - m_hashTableInfoIndex(0), - m_recursionDepth(0) - { - // Create scanner - m_pScanner = new DinoXmlScanner(fileName); - - } // DinoXmlParser::DinoXmlParser - - // - // D e s t r u c t o r - // - DinoXmlParser::~DinoXmlParser() - { - // Delete parse tree - if (m_pRootTag) - destroyParseTree(m_pRootTag); - - // Delete scanner - delete m_pScanner; - - } // DinoXmlParser::~DinoXmlParser - - - // - // c r e a t e P a r s e T r e e - // - void DinoXmlParser::createParseTree() - { - - // Info - //cout << "Parsing..." << endl; - - // create parse tree - m_pRootTag = parse(); - - // recursion depth not correct - if (m_recursionDepth != 0) { - DinoTools::reportError("DinoXmlParser::createParseTree", __LINE__, "Recursion depth not equal to zero after parsing!"); - } - - } // createParseTree - - // - // d e s t r o y P a r s e T r e e - // - void DinoXmlParser::destroyParseTree(XmlTagObject *root) - { - // Destroy all attributes of root - XmlAttributeObject *currentAttribute = root->m_pFirstAttribute; - while (currentAttribute != 0){ - XmlAttributeObject *nextAttribute = currentAttribute->m_pNextAttribute; - delete currentAttribute; - currentAttribute = nextAttribute; - } - - // Traverse children of root and destroy them - XmlTagObject *currentChild = root->m_pFirstSon; - while (currentChild != 0){ - XmlTagObject *nextChild = currentChild->m_pBrother; - destroyParseTree(currentChild); - currentChild = nextChild; - } - - // Destroy root itself - delete root; - - } // destroyParseTree - - - // - // p a r s e - // - // Take a look at the state machine of parse() to understand - // what is going on here. - // - // TODO: It seems to be useful that this function throws an exception - // if something goes wrong. - XmlTagObject *DinoXmlParser::parse() - { - // Increment recursion depth - ++m_recursionDepth; - - // currentTagObject is the tag object we want to create - // in this invocation of parse() - XmlTagObject *currentTagObject = 0; - - // Now we are in the start state of the state machine - for( ; ; ) - { - XmlToken token = m_pScanner->getNextToken(); - - // Expect "<", otherwise failure - if (token != openingBracket){ - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Opening Bracket expected!", - getInputFileLineCounter()); - } - - // Let's look what comes after "<" - token = m_pScanner->getNextToken(); - - // Read "?", i.e. we have the XML header line - if (token == questionMark){ - - // Skip until we reach the matching question mark - if (!m_pScanner->skipUntil('?')){ - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Could not found the matching '?'", - getInputFileLineCounter()); - } - - // Consume ">", otherwise failure - token = m_pScanner->getNextToken(); - if (token != closingBracket){ - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Closing Bracket expected!", - getInputFileLineCounter()); - } - - // Go to start state of the state machine - continue; - - } // end of Read "?" - - // Read "!", i.e. we have a XML comment - if (token == exclamationMark){ - - // A preambel comment which could be also nested - if ((m_pScanner->getNextToken() != minus) || - (m_pScanner->getNextToken() != minus)) - { - if (!m_pScanner->skipUntilMatchingClosingBracket()){ - - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Could not find closing comment bracket!", - getInputFileLineCounter()); - } - - continue; - } - - // Find end of comment - bool endOfCommentFound = false; - while (!endOfCommentFound){ - - // Skip until we find a - (and skip over it) - if (!m_pScanner->skipUntil('-', true)){ - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Closing --> of comment not found!", - getInputFileLineCounter()); - } - - // The next characters must be -> (note that one minus is already consumed) - if ((m_pScanner->getNextToken() == minus) && - (m_pScanner->getNextToken() == closingBracket)) - { - endOfCommentFound = true; - } - - } // while - - // Go to start state of the state machine - continue; - - } // end of Read "!" - - // We have found an identifier, i.e. a tag name - if (token == identifier){ - - // Get hash element of token string - HashedString *tagName = - hashString(m_pScanner->getCurrentTokenString()); - - // Create new tag object - currentTagObject = new XmlTagObject(tagName); - if (currentTagObject == 0){ - OGDF_THROW(InsufficientMemoryException); - } - //push (opening) tagName to stack - m_tagObserver.push(tagName->key()); - // set depth of current tag object - currentTagObject->setDepth(m_recursionDepth); - - // set line of the tag object in the parsed xml document - currentTagObject->setLine(getInputFileLineCounter()); - - // Next token - token = m_pScanner->getNextToken(); - - // Again we found an identifier, so it must be an attribute - if (token == identifier){ - - // Read list of attributes - do { - // Save the attribute name - HashedString *attributeName = - hashString(m_pScanner->getCurrentTokenString()); - - // Consume "=", otherwise failure - token = m_pScanner->getNextToken(); - if (token != equalSign) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Equal Sign expected!", - getInputFileLineCounter()); - } - - // Read value - token = m_pScanner->getNextToken(); - if ((token != quotedValue) && - (token != identifier) && - (token != attributeValue)) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "No valid attribute value!", - getInputFileLineCounter()); - } - - // Create a new XmlAttributeObject - XmlAttributeObject *currentAttributeObject = - new XmlAttributeObject(attributeName, hashString(m_pScanner->getCurrentTokenString())); - if (currentAttributeObject == 0){ - OGDF_THROW(InsufficientMemoryException); - } - - // Append attribute to attribute list of the current tag object - appendAttributeObject(currentTagObject, currentAttributeObject); - - // Get next token - token = m_pScanner->getNextToken(); - - } - while (token == identifier); - - } // Found an identifier of an attribute - - // Read "/", i.e. the tag is ended immeadiately, e.g. - // without a closing tag - if (token == slash){ - - // Consume ">", otherwise failure - token = m_pScanner->getNextToken(); - if (token != closingBracket) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Closing Bracket expected!", - getInputFileLineCounter()); - } - - // The tag is closed and ended so we return - String s = m_tagObserver.pop(); - --m_recursionDepth; - return currentTagObject; - - } // end of Read "/" - - // Read ">", i.e. the tag is closed and we - // expect some content - if (token == closingBracket){ - - // We read something different from "<", so we have to - // deal with a tag value now, i.e. a string inbetween the - // opening and the closing tag, e.g. lalala - if (m_pScanner->testNextToken() != openingBracket){ - - // Read the characters until "<" is reached and put them into - // currentTagObject - m_pScanner->readStringUntil('<'); - currentTagObject->m_pTagValue = hashString(m_pScanner->getCurrentTokenString()); - - // We expect a closing tag now, i.e. - token = m_pScanner->getNextToken(); - if (token != openingBracket) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Opening Bracket expected!", - getInputFileLineCounter()); - } - - token = m_pScanner->getNextToken(); - if (token != slash) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Slash expected!", - getInputFileLineCounter()); - } - - token = m_pScanner->getNextToken(); - if (token != identifier) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Identifier expected!", - getInputFileLineCounter()); - } - - // next token is the closing tag - String nextTag(m_pScanner->getCurrentTokenString()); - // pop corresponding tag from stack - String s = m_tagObserver.pop(); - // compare the two tags - if (s != nextTag) - { - // the closing tag doesn't correspond to the opening tag: - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "wrong closing tag!", - getInputFileLineCounter()); - } - - token = m_pScanner->getNextToken(); - if (token != closingBracket) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Closing Bracket expected!", - getInputFileLineCounter()); - } - - // The tag is closed so we return - --m_recursionDepth; - return currentTagObject; - - } // end of read something different from "<" - - // Found "<", so a (series of) new tag begins and we have to perform - // recursive invocation of parse() - // - // There are two exceptions: - // - a slash follows afer <, i.e. we have a closing tag - // - an exclamation mark follows after <, i.e. we have a comment - while (m_pScanner->testNextToken() == openingBracket){ - - // Leave the while loop if a closing tag occurs - if (m_pScanner->testNextNextToken() == slash){ - break; - } - - // Ignore comments - if (m_pScanner->testNextNextToken() == exclamationMark){ - - // Comment must start with of comment not found!", - getInputFileLineCounter()); - } - - // The next characters must be -> (note that one minus is already consumed) - if ((m_pScanner->getNextToken() == minus) && - (m_pScanner->getNextToken() == closingBracket)) - { - endOfCommentFound = true; - } - - } // while - - // Proceed with outer while loop - continue; - - } // Ignore comments - - // The new tag object is a son of the current tag object - XmlTagObject *sonTagObject = parse(); - appendSonTagObject(currentTagObject, sonTagObject); - - } // while - - // Now we have found all tags. - // We expect a closing tag now, i.e. - token = m_pScanner->getNextToken(); - if (token != openingBracket) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Opening Bracket expected!", - getInputFileLineCounter()); - } - - token = m_pScanner->getNextToken(); - if (token != slash) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Slash expected!", - getInputFileLineCounter()); - } - - token = m_pScanner->getNextToken(); - if (token != identifier) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Identifier expected!", - getInputFileLineCounter()); - } - - // next token is the closing tag - String nextTag(m_pScanner->getCurrentTokenString()); - // pop corresponding tag from stack - String s = m_tagObserver.pop(); - // compare the two tags - if (s != nextTag) - { - // the closing tag doesn't correspond to the opening tag: - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "wrong closing tag!", - getInputFileLineCounter()); - } - - token = m_pScanner->getNextToken(); - if (token != closingBracket) - { - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Closing Bracket expected!", - getInputFileLineCounter()); - } - - --m_recursionDepth; - - // check if Document contains code after the last closing bracket - if (m_recursionDepth == 0){ - token = m_pScanner->getNextToken(); - if (token != endOfFile){ - DinoTools::reportError("DinoXmlParser::parse", - __LINE__, - "Document contains code after the last closing bracket!", - getInputFileLineCounter()); - } - } - - return currentTagObject; - - } // end of Read ">" - - OGDF_ASSERT(false) - //continue; - - } // end of found identifier - - OGDF_ASSERT(false) - - } // end of while (true) - - } // parse - - // - // a p p e n d A t t r i b u t e O b j e c t - // - void DinoXmlParser::appendAttributeObject( - XmlTagObject *tagObject, - XmlAttributeObject *attributeObject) - { - - // No attribute exists yet - if (tagObject->m_pFirstAttribute == 0) { - tagObject->m_pFirstAttribute = attributeObject; - } - // At least one attribute exists - else{ - - XmlAttributeObject *currentAttribute = tagObject->m_pFirstAttribute; - - // Find the last attribute - while (currentAttribute->m_pNextAttribute != 0){ - currentAttribute = currentAttribute->m_pNextAttribute; - } - - // Append given attribute - currentAttribute->m_pNextAttribute = attributeObject; - - } - - } // appendAttributeObject - - // - // a p p e n d S o n T a g O b j e c t - // - void DinoXmlParser::appendSonTagObject( - XmlTagObject *currentTagObject, - XmlTagObject *sonTagObject) - { - // No Son exists yet - if (currentTagObject->m_pFirstSon == 0) { - currentTagObject->m_pFirstSon = sonTagObject; - } - // At least one son exists - else{ - - XmlTagObject *currentSon = currentTagObject->m_pFirstSon; - - // Find the last son - while (currentSon->m_pBrother != 0){ - currentSon = currentSon->m_pBrother; - } - - // Append given son - currentSon->m_pBrother = sonTagObject; - } - - } // appendSonTagObject - - // - // h a s h S t r i n g - // - HashedString *DinoXmlParser::hashString(const String &str) - { - // insertByNeed inserts a new element (str, -1) into the - // table if no element with key str exists; - // otherwise nothing is done - HashedString *key = m_hashTable.insertByNeed(str,-1); - - // String str was not contained in the table - // --> assign a new info index to the new string - if(key->info() == -1){ - key->info() = m_hashTableInfoIndex++; - } - - return key; - - } // hashString - - // - // t r a v e r s e P a t h - // - bool DinoXmlParser::traversePath( - const XmlTagObject &startTag, - const Array &infoIndexPath, - const XmlTagObject *&targetTag) const - { - // Traverse array - const XmlTagObject *currentTag = &startTag; - for (int i = 0; i < infoIndexPath.size(); i++){ - - const XmlTagObject *sonTag; - - // Not found - if (!findSonXmlTagObject(*currentTag, infoIndexPath[i], sonTag)){ - return false; - } - - // Found - currentTag = sonTag; - - } // for - - targetTag = currentTag; - return true; - - } // traversePath - - // - // f i n d S o n X m l T a g O b j e c t - // - bool DinoXmlParser::findSonXmlTagObject(const XmlTagObject &father, - int sonInfoIndex, - const XmlTagObject *&son) const - { - // Traverse sons - const XmlTagObject *currentSon = father.m_pFirstSon; - while ((currentSon != 0) && - (currentSon->m_pTagName->info() != sonInfoIndex)) - { - currentSon = currentSon->m_pBrother; - } - - // Son found - if (currentSon != 0){ - son = currentSon; - return true; - } - - // Not found - son = 0; - return false; - - } // findSonXmlTagObject - - // - // f i n d B r o t h e r X m l T a g O b j e c t - // - bool DinoXmlParser::findBrotherXmlTagObject(const XmlTagObject ¤tTag, - int brotherInfoIndex, - const XmlTagObject *&brother) const - { - - const XmlTagObject *currentBrother = currentTag.m_pBrother; - while ((currentBrother != 0) && - (currentBrother->m_pTagName->info() != brotherInfoIndex)) - { - currentBrother = currentBrother->m_pBrother; - } - - // brother found - if (currentBrother != 0){ - brother = currentBrother; - return true; - } - - // Not found - brother = 0; - return false; - - } // findBrotherXmlTagObject - - // - // f i n d X m l A t t r i b u t e O b j e c t - // - bool DinoXmlParser::findXmlAttributeObject( - const XmlTagObject ¤tTag, - int attributeInfoIndex, - const XmlAttributeObject *&attribute) const - { - const XmlAttributeObject *currentAttribute = currentTag.m_pFirstAttribute; - while ((currentAttribute != 0) && - (currentAttribute->m_pAttributeName->info() != attributeInfoIndex)) - { - currentAttribute = currentAttribute->m_pNextAttribute; - } - - // Attribute found - if (currentAttribute != 0){ - attribute = currentAttribute; - return true; - } - - // Not found - attribute = 0; - return false; - - } // findXmlAttributeObject - - // - // p r i n t H a s h T a b l e - // - void DinoXmlParser::printHashTable(ostream &os) - { - // Header - os << "\n--- Content of Hash table: m_hashTable ---\n" << endl; - - // Get iterator - HashConstIterator it; - - // Traverse table - for( it = m_hashTable.begin(); it.valid(); ++it){ - os << "\"" << it.key() << "\" has index " << it.info() << endl; - } - - } // printHashTable - - // - // p r i n t X m l T a g O b j e c t T r e e - // - void DinoXmlParser::printXmlTagObjectTree( - ostream &outs, - const XmlTagObject &rootObject, - int indent) const - { - printSpaces(outs, indent); - - // Opening tag (bracket and Tag name) - outs << "<" << rootObject.m_pTagName->key(); - - // Attributes - XmlAttributeObject *currentAttribute = rootObject.m_pFirstAttribute; - while (currentAttribute != 0){ - - outs << " " - << currentAttribute->m_pAttributeName->key() - << " = \"" - << currentAttribute->m_pAttributeValue->key() - << "\""; - - // Next attribute - currentAttribute = currentAttribute->m_pNextAttribute; - - } // while - - // Closing bracket - outs << ">" << endl; - - // Children - const XmlTagObject *currentChild = rootObject.m_pFirstSon; - while (currentChild != 0){ - - // Proceed recursively - printXmlTagObjectTree(outs, *currentChild, indent + 2); - - // Next child - currentChild = currentChild->m_pBrother; - - } // while - - // Content - if (rootObject.m_pTagValue != 0){ - - printSpaces(outs, indent + 2); - - outs << rootObject.m_pTagValue->key() << endl; - - } - - // Closing tag - printSpaces(outs, indent); - outs << "key() << ">" << endl; - - } // printXmlTagObjectTree - - // - // p r i n t S p a c e s - // - void DinoXmlParser::printSpaces(ostream &outs, int nOfSpaces) const - { - for (int i = 0; i < nOfSpaces; i++){ - outs << " "; - } - - } // printSpaces - - - // - // o u t p u t O p e r a t o r for DinoXmlParser - // - ostream &operator<<(ostream &os, const DinoXmlParser &parser) - { - parser.printXmlTagObjectTree(os, parser.getRootTag(), 0); - return os; - } - - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/DinoXmlScanner.cpp b/ext/OGDF/src/fileformats/DinoXmlScanner.cpp deleted file mode 100644 index d8f8e6518..000000000 --- a/ext/OGDF/src/fileformats/DinoXmlScanner.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class DinoXmlScanner serving the - * class DinoXmlParser - * - * \author Dino Ahr - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -#include -#include - -extern ofstream os; - -namespace ogdf { - - // - // C o n s t r u c t o r - // - DinoXmlScanner::DinoXmlScanner(const char *fileName) - { - // Create line buffer - m_pLineBuffer = new DinoLineBuffer(fileName); - - // Create current token string - m_pCurrentTokenString = new char[DinoLineBuffer::c_maxStringLength]; - if (m_pCurrentTokenString == 0) - OGDF_THROW(InsufficientMemoryException); - for (int i = 0; i < DinoLineBuffer::c_maxStringLength; i++){ - m_pCurrentTokenString[i] = '0'; - } - - } // DinoXmlScanner::DinoXmlScanner - - // - // D e s t r u c t o r - // - DinoXmlScanner::~DinoXmlScanner() - { - // Destroy current token string - delete [] m_pCurrentTokenString; - - // Destroy line buffer - delete m_pLineBuffer; - - } // DinoXmlScanner::~DinoXmlScanner - - // - // g e t N e x t T o k e n - // - // Take a look at the state machine of getNextToken() to understand - // what is going on here. - // - // TODO: It seems to be useful that this function throws an exception - // if something goes wrong. - XmlToken DinoXmlScanner::getNextToken(){ - - // First skip whitespaces - m_pLineBuffer->skipWhitespace(); - - // Let's have a look at the current character - char currentCharacter = m_pLineBuffer->getCurrentCharacter(); - - // End of file reached - if (currentCharacter == EOF){ - return endOfFile; - } - - // First we handle single characters with a switch statement - switch (currentCharacter){ - - // Opening Bracket - case '<': - { - m_pLineBuffer->moveToNextCharacter(); - return openingBracket; - } - break; - - // Closing Bracket - case '>': - { - m_pLineBuffer->moveToNextCharacter(); - return closingBracket; - } - break; - - // Question Mark - case '?': - { - m_pLineBuffer->moveToNextCharacter(); - return questionMark; - } - break; - - // Exclamation Mark - case '!': - { - m_pLineBuffer->moveToNextCharacter(); - return exclamationMark; - } - break; - - // Minus - case '-': - { - m_pLineBuffer->moveToNextCharacter(); - return minus; - } - break; - - // Slash - case '/': - { - m_pLineBuffer->moveToNextCharacter(); - return slash; - } - break; - - // Equal Sign - case '=': - { - m_pLineBuffer->moveToNextCharacter(); - return equalSign; - } - break; - - } // end of switch - - // Now we handle more complex token - - // Identifier - if (isalpha(currentCharacter)){ - - // Put a pointer to the beginning of the identifier - DinoLineBufferPosition startPosition = m_pLineBuffer->getCurrentPosition(); - - currentCharacter = m_pLineBuffer->moveToNextCharacter(); - - // Read valid identifier characters - while ((isalnum(currentCharacter)) || // a..z|A..Z|0..9 - (currentCharacter == '.') || - (currentCharacter == ':') || - (currentCharacter == '_')) - { - currentCharacter = m_pLineBuffer->moveToNextCharacter(); - } - - // Copy identifier to currentTokenString - m_pLineBuffer->extractString(startPosition, - m_pLineBuffer->getCurrentPosition(), - m_pCurrentTokenString); - - // Return identifier token - return identifier; - - } // end of identifier - - // Quoted characters " ... " or ' ... ' - if ((currentCharacter == '\"') || - (currentCharacter == '\'')) - { - // Distinguish what kind of quote sign we have - bool doubleQuote; - if (currentCharacter == '\"') - doubleQuote = true; - else - doubleQuote = false; - - // Skip quote sign - currentCharacter = m_pLineBuffer->moveToNextCharacter(); - - // Read until the closing quotation sign is found - // String is copied to m_pCurrentTokenString by readStringUntil() - if (doubleQuote){ - readStringUntil('\"', false); - } - else{ - readStringUntil('\'', false); - } - - // Skip over the end quote character - m_pLineBuffer->moveToNextCharacter(); - - // Return token for quoted value - return quotedValue; - - } // end of quoted characters - - // An atributeValue, i.e. a sequence of characters, digits, minus - or dot . - if ((isalnum(currentCharacter)) || - (currentCharacter == '-') || - (currentCharacter == '.')) - { - // Put a pointer to the beginning of the quoted text - DinoLineBufferPosition startPosition = m_pLineBuffer->getCurrentPosition();; - - // Read until until an invalid character occurs - currentCharacter = m_pLineBuffer->moveToNextCharacter(); - while ((isalnum(currentCharacter)) || - (currentCharacter == '-') || - (currentCharacter == '.')) - { - currentCharacter = m_pLineBuffer->moveToNextCharacter(); - } - - // Copy attributeValue to currentTokenString - m_pLineBuffer->extractString(startPosition, - m_pLineBuffer->getCurrentPosition(), - m_pCurrentTokenString); - - // Return token for attribute value - return attributeValue; - - } // end of an attributeValue - - // No valid token - m_pLineBuffer->moveToNextCharacter(); - return invalidToken; - - } // getNextToken - - // - // t e s t N e x t T o k e n - // - XmlToken DinoXmlScanner::testNextToken(){ - - // Save pointer to the current position - DinoLineBufferPosition originalPosition = m_pLineBuffer->getCurrentPosition(); - - // Call getNextToken() - XmlToken returnToken = getNextToken(); - - // Set pointer back to the original position - m_pLineBuffer->setCurrentPosition(originalPosition); - - // Return token - return returnToken; - - } // testNextToken - - // - // t e s t N e x t N e x t T o k e n - // - XmlToken DinoXmlScanner::testNextNextToken(){ - - // Save pointer to the current position - DinoLineBufferPosition originalPosition = m_pLineBuffer->getCurrentPosition(); - - // Call getNextToken() - getNextToken(); - - // Again Call getNextToken() - XmlToken returnToken = getNextToken(); - - // Set pointer back to the original position - m_pLineBuffer->setCurrentPosition(originalPosition); - - // Return token - return returnToken; - - } // testNextNextToken - - // - // s k i p U n t i l - // - bool DinoXmlScanner::skipUntil(char searchCharacter, bool skipOverSearchCharacter){ - - while (m_pLineBuffer->getCurrentCharacter() != EOF){ - - // Search character has been found! - if (m_pLineBuffer->getCurrentCharacter() == searchCharacter){ - - // Move to the position behind the search character if desired - if (skipOverSearchCharacter){ - m_pLineBuffer->moveToNextCharacter(); - } - - return true; - - } // Search character has been found! - - // Move to next character and proceed - m_pLineBuffer->moveToNextCharacter(); - - } // while (!EOF) - - return false; - - } // skipUntil - - // - // s k i p U n t i l M a t c h i n g C l o s i n g B r a c k e t - // - bool DinoXmlScanner::skipUntilMatchingClosingBracket(){ - - // We assume that the opening bracket has already been read - int bracketParity = 1; - - while ((m_pLineBuffer->getCurrentCharacter() != EOF) && - (bracketParity != 0)) - { - // Opening bracket has been found! - if (m_pLineBuffer->getCurrentCharacter() == '<'){ - - ++bracketParity; - } - - // Closing bracket has been found! - if (m_pLineBuffer->getCurrentCharacter() == '>'){ - - --bracketParity; - } - - // Move to next character and proceed - m_pLineBuffer->moveToNextCharacter(); - - } // while - - if (bracketParity != 0 ) - return false; - else - return true; - - } // skipUntilMatchingClosingBracket - - // - // r e a d S t r i n g U n t i l - // - bool DinoXmlScanner::readStringUntil(char searchCharacter, - bool includeSearchCharacter){ - - // Remember start position - DinoLineBufferPosition startPosition = m_pLineBuffer->getCurrentPosition(); - - // Use skipUntil() - if (skipUntil(searchCharacter, includeSearchCharacter)){ - - // Copy found string to m_pCurrentTokenString - m_pLineBuffer->extractString(startPosition, - m_pLineBuffer->getCurrentPosition(), - m_pCurrentTokenString); - - return true; - - } - // An error occurred - else{ - return false; - } - - } // getStringUntil - - // - // t e s t - // - void DinoXmlScanner::test(){ - - bool terminate = false; - XmlToken currentToken; - - while (!terminate){ - - cout << "Line " << getInputFileLineCounter() << ": "; - currentToken = getNextToken(); - - switch (currentToken){ - case openingBracket: - cout << "<" << endl; - break; - case closingBracket: - cout << ">" << endl; - break; - case questionMark: - cout << "?" << endl; - break; - case exclamationMark: - cout << "!" << endl; - break; - case minus: - cout << "-" << endl; - break; - case slash: - cout << "/" << endl; - break; - case equalSign: - cout << "<" << endl; - break; - case identifier: - cout << "Identifier: " << m_pCurrentTokenString << endl; - break; - case attributeValue: - cout << "Attribute value: " << m_pCurrentTokenString << endl; - break; - case quotedValue: - cout << "Quoted value: \"" << m_pCurrentTokenString << "\"" << endl; - break; - case endOfFile: - cout << "EOF" << endl; - terminate = true; - break; - default: - cout << "Invalid token!" << endl; - - } // switch - - } // while - - } // testScanner - -} // namespace ogdf diff --git a/ext/OGDF/src/fileformats/GmlParser.cpp b/ext/OGDF/src/fileformats/GmlParser.cpp deleted file mode 100644 index 0e5ceb2da..000000000 --- a/ext/OGDF/src/fileformats/GmlParser.cpp +++ /dev/null @@ -1,1315 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of GML parser (class GmlParser) - * (used for parsing and reading GML files) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - -extern ofstream os; - -namespace ogdf { - -GmlParser::GmlParser(const char *fileName, bool doCheck) -{ - ifstream is(fileName, ios::in); // open file - doInit(is,doCheck); -} - - -GmlParser::GmlParser(istream &is, bool doCheck) -{ - doInit(is,doCheck); -} - - -void GmlParser::doInit(istream &is, bool doCheck) -{ - m_objectTree = 0; - - if (!is) { - setError("Cannot open file."); - return; - } - - createObjectTree(is,doCheck); - - int minId, maxId; - m_graphObject = getNodeIdRange(minId, maxId); - m_mapToNode.init(minId,maxId,0); -} - - -void GmlParser::createObjectTree(istream &is, bool doCheck) -{ - initPredefinedKeys(); - m_error = false; - - m_is = &is; - m_doCheck = doCheck; // indicates more extensive checking - - // initialize line buffer (note: GML specifies a maximal line length - // of 254 characters!) - m_rLineBuffer = new char[256]; - if (m_rLineBuffer == 0) OGDF_THROW(InsufficientMemoryException); - - *m_rLineBuffer = '\n'; - m_lineBuffer = m_rLineBuffer+1; - - m_pCurrent = m_pStore = m_lineBuffer; - m_cStore = 0; // forces getNextSymbol() to read first line - - // create object tree - m_objectTree = parseList(gmlEOF,gmlListEnd); - - delete[] m_rLineBuffer; -} - -// we use predefined id constants for all relevant keys -// this allows us to use efficient switch() statemnts in read() methods -void GmlParser::initPredefinedKeys() -{ - m_hashTable.fastInsert("id", idPredefKey); - m_hashTable.fastInsert("label", labelPredefKey); - m_hashTable.fastInsert("Creator", CreatorPredefKey); - m_hashTable.fastInsert("name", namePredefKey); - m_hashTable.fastInsert("graph", graphPredefKey); - m_hashTable.fastInsert("version", versionPredefKey); - m_hashTable.fastInsert("directed", directedPredefKey); - m_hashTable.fastInsert("node", nodePredefKey); - m_hashTable.fastInsert("edge", edgePredefKey); - m_hashTable.fastInsert("graphics", graphicsPredefKey); - m_hashTable.fastInsert("x", xPredefKey); - m_hashTable.fastInsert("y", yPredefKey); - m_hashTable.fastInsert("w", wPredefKey); - m_hashTable.fastInsert("h", hPredefKey); - m_hashTable.fastInsert("type", typePredefKey); - m_hashTable.fastInsert("width", widthPredefKey); - m_hashTable.fastInsert("source", sourcePredefKey); - m_hashTable.fastInsert("target", targetPredefKey); - m_hashTable.fastInsert("arrow", arrowPredefKey); - m_hashTable.fastInsert("Line", LinePredefKey); - m_hashTable.fastInsert("line", linePredefKey); - m_hashTable.fastInsert("point", pointPredefKey); - m_hashTable.fastInsert("generalization", generalizationPredefKey); - m_hashTable.fastInsert("subgraph", subGraphPredefKey); - m_hashTable.fastInsert("fill", fillPredefKey); - m_hashTable.fastInsert("cluster", clusterPredefKey); - m_hashTable.fastInsert("rootcluster", rootClusterPredefKey); - m_hashTable.fastInsert("vertex", vertexPredefKey); - m_hashTable.fastInsert("color", colorPredefKey); - m_hashTable.fastInsert("height", heightPredefKey); - m_hashTable.fastInsert("stipple", stipplePredefKey); //linestyle - m_hashTable.fastInsert("pattern", patternPredefKey); //brush pattern - m_hashTable.fastInsert("lineWidth", lineWidthPredefKey);//line width - m_hashTable.fastInsert("template", templatePredefKey);//line width - m_hashTable.fastInsert("weight", edgeWeightPredefKey); - - // further keys get id's starting with NEXTPREDEFKEY - m_num = NEXTPREDEFKEY; -} - - -GmlObject *GmlParser::parseList(GmlObjectType closingKey, - GmlObjectType /* errorKey */) -{ - GmlObject *firstSon = 0; - GmlObject **pPrev = &firstSon; - - for( ; ; ) { - GmlObjectType symbol = getNextSymbol(); - - if (symbol == closingKey || symbol == gmlError) - return firstSon; - - if (symbol != gmlKey) { - setError("key expected"); - return firstSon; - } - - GmlKey key = m_keySymbol; - - symbol = getNextSymbol(); - GmlObject *object = 0; - - switch (symbol) { - case gmlIntValue: - object = OGDF_NEW GmlObject(key,m_intSymbol); - break; - - case gmlDoubleValue: - object = OGDF_NEW GmlObject(key,m_doubleSymbol); - break; - - case gmlStringValue: { - size_t len = strlen(m_stringSymbol)+1; - char *pChar = new char[len]; - if (pChar == 0) OGDF_THROW(InsufficientMemoryException); - - ogdf::strcpy(pChar,len,m_stringSymbol); - object = OGDF_NEW GmlObject(key,pChar); } - break; - - case gmlListBegin: - object = OGDF_NEW GmlObject(key); - object->m_pFirstSon = parseList(gmlListEnd,gmlEOF); - break; - - case gmlListEnd: - setError("unexpected end of list"); - return firstSon; - - case gmlKey: - setError("unexpected key"); - return firstSon; - - case gmlEOF: - setError("missing value"); - return firstSon; - - case gmlError: - return firstSon; - - OGDF_NODEFAULT // one of the cases above has to occur - } - - *pPrev = object; - pPrev = &object->m_pBrother; - } - - return firstSon; -} - - -void GmlParser::destroyObjectList(GmlObject *object) -{ - GmlObject *nextObject; - for(; object; object = nextObject) { - nextObject = object->m_pBrother; - - if (object->m_valueType == gmlStringValue) - delete[] const_cast(object->m_stringValue); - - else if (object->m_valueType == gmlListBegin) - destroyObjectList(object->m_pFirstSon); - - delete object; - } -} - - -GmlParser::~GmlParser() -{ - // we have to delete all objects and allocated char arrays in string values - destroyObjectList(m_objectTree); -} - - -bool GmlParser::getLine() -{ - do { - if (m_is->eof()) return false; - (*m_is) >> std::ws; // skip whitespace like spaces for indentation - m_is->getline(m_lineBuffer,255); - if (m_is->fail()) - return false; - for(m_pCurrent = m_lineBuffer; - *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; - } while (*m_pCurrent == '#' || *m_pCurrent == 0); - - return true; -} - - -GmlObjectType GmlParser::getNextSymbol() -{ - *m_pStore = m_cStore; - - // eat whitespace - for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; - - // get new line if required - if (*m_pCurrent == 0) { - if (!getLine()) return gmlEOF; - } - - // identify start of current symbol - char *pStart = m_pCurrent; - - // we currently do not support strings with line breaks! - if (*pStart == '\"') - { // string - m_stringSymbol = ++m_pCurrent; - char *pWrite = m_pCurrent; - while(*m_pCurrent != 0 && *m_pCurrent != '\"') - { - if (*m_pCurrent == '\\') - { - // note: this block is repeated below - switch(*(m_pCurrent+1)) { - case 0: - *m_pCurrent = 0; - break; - case '\\': - *pWrite++ = '\\'; - m_pCurrent += 2; - break; - case '\"': - *pWrite++ = '\"'; - m_pCurrent += 2; - break; - default: - // just copy the escape sequence as is - *pWrite++ = *m_pCurrent++; - *pWrite++ = *m_pCurrent++; - } - - } else - *pWrite++ = *m_pCurrent++; - } - - if (*m_pCurrent == 0) - { - *pWrite = 0; - m_longString = (pStart+1); - while(getLine()) - { - m_pCurrent = pWrite = m_lineBuffer; - while(*m_pCurrent != 0 && *m_pCurrent != '\"') - { - if (*m_pCurrent == '\\') - { - // (block repeated from above) - switch(*(m_pCurrent+1)) { - case 0: - *m_pCurrent = 0; - break; - case '\\': - *pWrite++ = '\\'; - m_pCurrent += 2; - break; - case '\"': - *pWrite++ = '\"'; - m_pCurrent += 2; - break; - default: - // just copy the escape sequence as is - *pWrite++ = *m_pCurrent++; - *pWrite++ = *m_pCurrent++; - } - - } else - *pWrite++ = *m_pCurrent++; - } - - if (*m_pCurrent == 0) { - *pWrite = 0; - m_longString += m_lineBuffer; - - } else { - m_cStore = *(m_pStore = m_pCurrent); - ++m_pCurrent; - *pWrite = 0; - m_longString += m_lineBuffer; - break; - } - } - m_stringSymbol = m_longString.cstr(); - - } else { - m_cStore = *(m_pStore = m_pCurrent); - ++m_pCurrent; - *pWrite = 0; - } - - return gmlStringValue; - } - - // identify end of current symbol - while(*m_pCurrent != 0 && !isspace(*m_pCurrent)) ++m_pCurrent; - - m_cStore = *(m_pStore = m_pCurrent); - *m_pCurrent = 0; - - if(isalpha(*pStart)) { // key - - // check if really a correct key (error if not) - if (m_doCheck) { - for (char *p = pStart+1; *p; ++p) - if (!(isalpha(*p) || isdigit(*p))) { - setError("malformed key"); - return gmlError; - } - } - - m_keySymbol = hashString(pStart); - return gmlKey; - - } else if (*pStart == '[') { - return gmlListBegin; - - } else if (*pStart == ']') { - return gmlListEnd; - - } else if (*pStart == '-' || isdigit(*pStart)) { // int or double - char *p = pStart+1; - while(isdigit(*p)) ++p; - - if (*p == '.') { // double - // check to be done - - sscanf(pStart,"%lf",&m_doubleSymbol); - return gmlDoubleValue; - - } else { // int - if (*p != 0) { - setError("malformed number"); - return gmlError; - } - - sscanf(pStart,"%d",&m_intSymbol); - return gmlIntValue; - } - } - - setError("unknown symbol"); - - return gmlError; -} - - -GmlKey GmlParser::hashString(const String &str) -{ - GmlKey key = m_hashTable.insertByNeed(str,-1); - if(key->info() == -1) key->info() = m_num++; - - return key; -} - - -GmlObject *GmlParser::getNodeIdRange(int &minId,int &maxId) -{ - minId = maxId = 0; - - GmlObject *graphObject = m_objectTree; - for(; graphObject; graphObject = graphObject->m_pBrother) - if (id(graphObject) == graphPredefKey) break; - - if (!graphObject || graphObject->m_valueType != gmlListBegin) return 0; - - bool first = true; - GmlObject *son = graphObject->m_pFirstSon; - for(; son; son = son->m_pBrother) { - if (id(son) == nodePredefKey && son->m_valueType == gmlListBegin) { - - GmlObject *nodeSon = son->m_pFirstSon; - for(; nodeSon; nodeSon = nodeSon->m_pBrother) { - if (id(nodeSon) == idPredefKey || - nodeSon->m_valueType == gmlIntValue) - { - int nodeSonId = nodeSon->m_intValue; - if (first) { - minId = maxId = nodeSonId; - first = false; - } else { - if (nodeSonId < minId) minId = nodeSonId; - if (nodeSonId > maxId) maxId = nodeSonId; - } - } - } - } - } - - return graphObject; -} - - -bool GmlParser::read(Graph &G) -{ - G.clear(); - - int minId = m_mapToNode.low(); - int maxId = m_mapToNode.high(); - int notDefined = minId-1; //indicates not defined id key - - GmlObject *son = m_graphObject->m_pFirstSon; - for(; son; son = son->m_pBrother) - { - switch(id(son)) - { - case nodePredefKey: { - if (son->m_valueType != gmlListBegin) break; - - // set attributes to default values - int vId = notDefined; - - // read all relevant attributes - GmlObject *nodeSon = son->m_pFirstSon; - for(; nodeSon; nodeSon = nodeSon->m_pBrother) { - if (id(nodeSon) == idPredefKey && - nodeSon->m_valueType == gmlIntValue) - { - vId = nodeSon->m_intValue; - } - } - - // check if everything required is defined correctly - if (vId == notDefined) { - setError("node id not defined"); - return false; - } - - // create new node if necessary - if (m_mapToNode[vId] == 0) m_mapToNode[vId] = G.newNode(); } - break; - - case edgePredefKey: { - if (son->m_valueType != gmlListBegin) break; - - // set attributes to default values - int sourceId = notDefined, targetId = notDefined; - - // read all relevant attributes - GmlObject *edgeSon = son->m_pFirstSon; - for(; edgeSon; edgeSon = edgeSon->m_pBrother) { - - switch(id(edgeSon)) { - case sourcePredefKey: - if (edgeSon->m_valueType != gmlIntValue) break; - sourceId = edgeSon->m_intValue; - break; - - case targetPredefKey: - if (edgeSon->m_valueType != gmlIntValue) break; - targetId = edgeSon->m_intValue; - break; - } - } - - // check if everything required is defined correctly - if (sourceId == notDefined || targetId == notDefined) { - setError("source or target id not defined"); - return false; - - } else if (sourceId < minId || maxId < sourceId || - targetId < minId || maxId < targetId) { - setError("source or target id out of range"); - return false; - } - - // create adjacent nodes if necessary and new edge - if (m_mapToNode[sourceId] == 0) m_mapToNode[sourceId] = G.newNode(); - if (m_mapToNode[targetId] == 0) m_mapToNode[targetId] = G.newNode(); - - G.newEdge(m_mapToNode[sourceId],m_mapToNode[targetId]); - }//case edge - break; - }//switch - }//for sons - - return true; -} - - -bool GmlParser::read(Graph &G, GraphAttributes &AG) -{ - OGDF_ASSERT(&G == &(AG.constGraph())) - - G.clear(); - - int minId = m_mapToNode.low(); - int maxId = m_mapToNode.high(); - int notDefined = minId-1; //indicates not defined id key - - DPolyline bends; - - GmlObject *son = m_graphObject->m_pFirstSon; - for(; son; son = son->m_pBrother) { - - switch(id(son)) { - case nodePredefKey: { - if (son->m_valueType != gmlListBegin) break; - - // set attributes to default values - int vId = notDefined; - double x = 0, y = 0, w = 0, h = 0; - String label; - String templ; - String fill; // the fill color attribute - String line; // the line color attribute - String shape; //the shape type - double lineWidth = 1.0; //node line width - int pattern = 1; //node brush pattern - int stipple = 1; //line style pattern - - // read all relevant attributes - GmlObject *nodeSon = son->m_pFirstSon; - for(; nodeSon; nodeSon = nodeSon->m_pBrother) { - switch(id(nodeSon)) { - case idPredefKey: - if(nodeSon->m_valueType != gmlIntValue) break; - vId = nodeSon->m_intValue; - break; - - case graphicsPredefKey: { - if (nodeSon->m_valueType != gmlListBegin) break; - - GmlObject *graphicsObject = nodeSon->m_pFirstSon; - for(; graphicsObject; - graphicsObject = graphicsObject->m_pBrother) - { - switch(id(graphicsObject)) { - case xPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) break; - x = graphicsObject->m_doubleValue; - break; - - case yPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) break; - y = graphicsObject->m_doubleValue; - break; - - case wPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) break; - w = graphicsObject->m_doubleValue; - break; - - case hPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) break; - h = graphicsObject->m_doubleValue; - break; - - case fillPredefKey: - if(graphicsObject->m_valueType != gmlStringValue) break; - fill = graphicsObject->m_stringValue; - break; - - case linePredefKey: - if(graphicsObject->m_valueType != gmlStringValue) break; - line = graphicsObject->m_stringValue; - break; - - case lineWidthPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) break; - lineWidth = graphicsObject->m_doubleValue; - break; - - case typePredefKey: - if(graphicsObject->m_valueType != gmlStringValue) break; - shape = graphicsObject->m_stringValue; - break; - case patternPredefKey: //fill style - if(graphicsObject->m_valueType != gmlIntValue) break; - pattern = graphicsObject->m_intValue; - case stipplePredefKey: //line style - if(graphicsObject->m_valueType != gmlIntValue) break; - stipple = graphicsObject->m_intValue; - } - } - break; } - - case templatePredefKey: - if (nodeSon->m_valueType != gmlStringValue) break; - - templ = nodeSon->m_stringValue; - break; - - case labelPredefKey: - if (nodeSon->m_valueType != gmlStringValue) break; - - label = nodeSon->m_stringValue; - break; - } - } - - // check if everything required is defined correctly - if (vId == notDefined) { - setError("node id not defined"); - return false; - } - - // create new node if necessary and assign attributes - if (m_mapToNode[vId] == 0) m_mapToNode[vId] = G.newNode(); - if (AG.attributes() & GraphAttributes::nodeGraphics) - { - AG.x(m_mapToNode[vId]) = x; - AG.y(m_mapToNode[vId]) = y; - AG.width (m_mapToNode[vId]) = w; - AG.height(m_mapToNode[vId]) = h; - if (shape == "oval") - AG.shapeNode(m_mapToNode[vId]) = GraphAttributes::oval; - else AG.shapeNode(m_mapToNode[vId]) = GraphAttributes::rectangle; - } - if ( (AG.attributes() & GraphAttributes::nodeColor) && - (AG.attributes() & GraphAttributes::nodeGraphics) ) - { - AG.colorNode(m_mapToNode[vId]) = fill; - AG.nodeLine(m_mapToNode[vId]) = line; - } - if (AG.attributes() & GraphAttributes::nodeLabel) - AG.labelNode(m_mapToNode[vId]) = label; - if (AG.attributes() & GraphAttributes::nodeTemplate) - AG.templateNode(m_mapToNode[vId]) = templ; - if (AG.attributes() & GraphAttributes::nodeId) - AG.idNode(m_mapToNode[vId]) = vId; - if (AG.attributes() & GraphAttributes::nodeStyle) - { - AG.nodePattern(m_mapToNode[vId]) = - GraphAttributes::intToPattern(pattern); - AG.styleNode(m_mapToNode[vId]) = - GraphAttributes::intToStyle(stipple); - AG.lineWidthNode(m_mapToNode[vId]) = - lineWidth; - } - }//node - //Todo: line style set stipple value - break; - - case edgePredefKey: { - String arrow; // the arrow type attribute - String fill; //the color fill attribute - int stipple = 1; //the line style - double lineWidth = 1.0; - double edgeWeight = 1.0; - int subGraph = 0; //edgeSubGraph attribute - String label; // label attribute - - if (son->m_valueType != gmlListBegin) break; - - // set attributes to default values - int sourceId = notDefined, targetId = notDefined; - Graph::EdgeType umlType = Graph::association; - - // read all relevant attributes - GmlObject *edgeSon = son->m_pFirstSon; - for(; edgeSon; edgeSon = edgeSon->m_pBrother) { - - switch(id(edgeSon)) { - case sourcePredefKey: - if (edgeSon->m_valueType != gmlIntValue) break; - sourceId = edgeSon->m_intValue; - break; - - case targetPredefKey: - if (edgeSon->m_valueType != gmlIntValue) break; - targetId = edgeSon->m_intValue; - break; - - case subGraphPredefKey: - if (edgeSon->m_valueType != gmlIntValue) break; - subGraph = edgeSon->m_intValue; - break; - - case labelPredefKey: - if (edgeSon->m_valueType != gmlStringValue) break; - label = edgeSon->m_stringValue; - break; - - case graphicsPredefKey: { - if (edgeSon->m_valueType != gmlListBegin) break; - - GmlObject *graphicsObject = edgeSon->m_pFirstSon; - for(; graphicsObject; - graphicsObject = graphicsObject->m_pBrother) - { - if(id(graphicsObject) == LinePredefKey && - graphicsObject->m_valueType == gmlListBegin) - { - readLineAttribute(graphicsObject->m_pFirstSon,bends); - } - if(id(graphicsObject) == arrowPredefKey && - graphicsObject->m_valueType == gmlStringValue) - arrow = graphicsObject->m_stringValue; - if(id(graphicsObject) == fillPredefKey && - graphicsObject->m_valueType == gmlStringValue) - fill = graphicsObject->m_stringValue; - if (id(graphicsObject) == stipplePredefKey && //line style - graphicsObject->m_valueType == gmlIntValue) - stipple = graphicsObject->m_intValue; - if (id(graphicsObject) == lineWidthPredefKey && //line width - graphicsObject->m_valueType == gmlDoubleValue) - lineWidth = graphicsObject->m_doubleValue; - if (id(graphicsObject) == edgeWeightPredefKey && - graphicsObject->m_valueType == gmlDoubleValue) - edgeWeight = graphicsObject->m_doubleValue; - }//for graphics - } - - case generalizationPredefKey: - if (edgeSon->m_valueType != gmlIntValue) break; - umlType = (edgeSon->m_intValue == 0) ? - Graph::association : Graph::generalization; - break; - - } - } - - // check if everything required is defined correctly - if (sourceId == notDefined || targetId == notDefined) { - setError("source or target id not defined"); - return false; - - } else if (sourceId < minId || maxId < sourceId || - targetId < minId || maxId < targetId) { - setError("source or target id out of range"); - return false; - } - - // create adjacent nodes if necessary and new edge - if (m_mapToNode[sourceId] == 0) m_mapToNode[sourceId] = G.newNode(); - if (m_mapToNode[targetId] == 0) m_mapToNode[targetId] = G.newNode(); - - edge e = G.newEdge(m_mapToNode[sourceId],m_mapToNode[targetId]); - if (AG.attributes() & GraphAttributes::edgeGraphics) - AG.bends(e).conc(bends); - if (AG.attributes() & GraphAttributes::edgeType) - AG.type(e) = umlType; - if(AG.attributes() & GraphAttributes::edgeSubGraph) - AG.subGraphBits(e) = subGraph; - if (AG.attributes() & GraphAttributes::edgeLabel) - AG.labelEdge(e) = label; - - if (AG.attributes() & GraphAttributes::edgeArrow) { - if (arrow == "none") - AG.arrowEdge(e) = GraphAttributes::none; - else if (arrow == "last") - AG.arrowEdge(e) = GraphAttributes::last; - else if (arrow == "first") - AG.arrowEdge(e) = GraphAttributes::first; - else if (arrow == "both") - AG.arrowEdge(e) = GraphAttributes::both; - else - AG.arrowEdge(e) = GraphAttributes::undefined; - } - - if (AG.attributes() & GraphAttributes::edgeColor) - AG.colorEdge(e) = fill; - if (AG.attributes() & GraphAttributes::edgeStyle) - { - AG.styleEdge(e) = AG.intToStyle(stipple); - AG.edgeWidth(e) = lineWidth; - } - - if (AG.attributes() & GraphAttributes::edgeDoubleWeight) - AG.doubleWeight(e) = edgeWeight; - - - break; } - case directedPredefKey: { - if(son->m_valueType != gmlIntValue) break; - AG.directed(son->m_intValue > 0); - break; } - } - } - - return true; -}//read - - -//to be called AFTER calling read(G, AG) -bool GmlParser::readAttributedCluster( - Graph &G, - ClusterGraph& CG, - ClusterGraphAttributes& ACG) -{ - OGDF_ASSERT(&CG.getGraph() == &G) - - - //now we need the cluster object - GmlObject *rootObject = m_objectTree; - for(; rootObject; rootObject = rootObject->m_pBrother) - if (id(rootObject) == rootClusterPredefKey) break; - - if(rootObject == 0) - return true; - - if (id(rootObject) != rootClusterPredefKey) - { - setError("missing rootcluster key"); - return false; - } - - if (rootObject->m_valueType != gmlListBegin) return false; - - attributedClusterRead(rootObject, CG, ACG); - - return true; -}//readAttributedCluster - - -//the clustergraph has to be initialized on G!!, -//no clusters other then root cluster may exist, which holds all nodes -bool GmlParser::readCluster(Graph &G, ClusterGraph& CG) -{ - OGDF_ASSERT(&CG.getGraph() == &G) - - //now we need the cluster object - GmlObject *rootObject = m_objectTree; - for(; rootObject; rootObject = rootObject->m_pBrother) - if (id(rootObject) == rootClusterPredefKey) break; - - //we have to check if the file does really contain clusters - //otherwise, rootcluster will suffice - if (rootObject == 0) return true; - if (id(rootObject) != rootClusterPredefKey) - { - setError("missing rootcluster key"); - return false; - } - - if (rootObject->m_valueType != gmlListBegin) return false; - - clusterRead(rootObject, CG); - - return true; -}//read clustergraph - - -//read all cluster tree information -bool GmlParser::clusterRead( - GmlObject* rootCluster, - ClusterGraph& CG) -{ - - //the root cluster is only allowed to hold child clusters and - //nodes in a list - - if (rootCluster->m_valueType != gmlListBegin) return false; - - // read all clusters and nodes - GmlObject *rootClusterSon = rootCluster->m_pFirstSon; - - for(; rootClusterSon; rootClusterSon = rootClusterSon->m_pBrother) - { - switch(id(rootClusterSon)) - { - case clusterPredefKey: - { - //we could delete this, but we aviod the call - if (rootClusterSon->m_valueType != gmlListBegin) return false; - // set attributes to default values - //we currently do not set any values - cluster c = CG.newCluster(CG.rootCluster()); - - //recursively read cluster - recursiveClusterRead(rootClusterSon, CG, c); - - } //case cluster - break; - case vertexPredefKey: //direct root vertices - { - if (rootClusterSon->m_valueType != gmlStringValue) return false; - String vIDString = rootClusterSon->m_stringValue; - - //we only allow a vertex id as string identification - if ((vIDString[0] != 'v') && - (!isdigit(vIDString[0])))return false; //do not allow labels - //if old style entry "v"i - if (!isdigit(vIDString[0])) //should check prefix? - vIDString[0] = '0'; //leading zero to allow conversion - int vID = atoi(vIDString.cstr()); - - OGDF_ASSERT(m_mapToNode[vID] != 0) - - //we assume that no node is already assigned ! Changed: - //all new nodes are assigned to root - //CG.reassignNode(mapToNode[vID], CG.rootCluster()); - //it seems that this may be unnessecary, TODO check - CG.reassignNode(m_mapToNode[vID], CG.rootCluster()); - //char* vIDChar = new char[vIDString.length()+1]; - //for (int ind = 1; ind < vIDString.length(); ind++) - // vIDChar - - }//case vertex - }//switch - }//for all rootcluster sons - - return true; - -}//clusterread - - -//the same for attributed graphs -//read all cluster tree information -//make changes to this as well as the recursive function -bool GmlParser::attributedClusterRead( - GmlObject* rootCluster, - ClusterGraph& CG, - ClusterGraphAttributes& ACG) -{ - - //the root cluster is only allowed to hold child clusters and - //nodes in a list - - if (rootCluster->m_valueType != gmlListBegin) return false; - - // read all clusters and nodes - GmlObject *rootClusterSon = rootCluster->m_pFirstSon; - - for(; rootClusterSon; rootClusterSon = rootClusterSon->m_pBrother) - { - switch(id(rootClusterSon)) - { - case clusterPredefKey: - { - //we could delete this, but we avoid the call - if (rootClusterSon->m_valueType != gmlListBegin) return false; - // set attributes to default values - //we currently do not set any values - cluster c = CG.newCluster(CG.rootCluster()); - - //recursively read cluster - recursiveAttributedClusterRead(rootClusterSon, CG, ACG, c); - - } //case cluster - break; - - case vertexPredefKey: //direct root vertices - { - if (rootClusterSon->m_valueType != gmlStringValue) return false; - String vIDString = rootClusterSon->m_stringValue; - - //we only allow a vertex id as string identification - if ((vIDString[0] != 'v') && - (!isdigit(vIDString[0])))return false; //do not allow labels - //if old style entry "v"i - if (!isdigit(vIDString[0])) //should check prefix? - vIDString[0] = '0'; //leading zero to allow conversion - int vID = atoi(vIDString.cstr()); - - OGDF_ASSERT(m_mapToNode[vID] != 0) - - //we assume that no node is already assigned - //CG.reassignNode(mapToNode[vID], CG.rootCluster()); - //changed: all nodes are already assigned to root - //this code seems to be obsolete, todo: check - CG.reassignNode(m_mapToNode[vID], CG.rootCluster()); - //char* vIDChar = new char[vIDString.length()+1]; - //for (int ind = 1; ind < vIDString.length(); ind++) - // vIDChar - - }//case vertex - }//switch - }//for all rootcluster sons - - return true; - -}//attributedclusterread - - -bool GmlParser::readClusterAttributes( - GmlObject* cGraphics, - cluster c, - ClusterGraphAttributes& ACG) -{ - String label; - String fill; // the fill color attribute - String line; // the line color attribute - double lineWidth = 1.0; //node line width - int pattern = 1; //node brush pattern - int stipple = 1; //line style pattern - - // read all relevant attributes - GmlObject *graphicsObject = cGraphics->m_pFirstSon; - for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) - { - switch(id(graphicsObject)) - { - case xPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) return false; - ACG.clusterXPos(c) = graphicsObject->m_doubleValue; - break; - - case yPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) return false; - ACG.clusterYPos(c) = graphicsObject->m_doubleValue; - break; - - case widthPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) return false; - ACG.clusterWidth(c) = graphicsObject->m_doubleValue; - break; - - case heightPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) return false; - ACG.clusterHeight(c) = graphicsObject->m_doubleValue; - break; - case fillPredefKey: - if(graphicsObject->m_valueType != gmlStringValue) return false; - ACG.clusterFillColor(c) = graphicsObject->m_stringValue; - break; - case patternPredefKey: - if(graphicsObject->m_valueType != gmlIntValue) return false; - pattern = graphicsObject->m_intValue; - break; - //line style - case colorPredefKey: // line color - if(graphicsObject->m_valueType != gmlStringValue) return false; - ACG.clusterColor(c) = graphicsObject->m_stringValue; - break; - - case stipplePredefKey: - if(graphicsObject->m_valueType != gmlIntValue) return false; - stipple = graphicsObject->m_intValue; - break; - case lineWidthPredefKey: - if(graphicsObject->m_valueType != gmlDoubleValue) return false; - lineWidth = - graphicsObject->m_doubleValue; - break; - //TODO: backgroundcolor - //case stylePredefKey: - //case boderwidthPredefKey: - }//switch - }//for - - //Hier eigentlich erst abfragen, ob clusterattributes setzbar in ACG, - //dann setzen - ACG.clusterLineStyle(c) = GraphAttributes::intToStyle(stipple); //defaulting 1 - ACG.clusterLineWidth(c) = lineWidth; - ACG.clusterFillPattern(c) = GraphAttributes::intToPattern(pattern); - - return true; -}//readclusterattributes - -//recursively read cluster subtree information -bool GmlParser::recursiveClusterRead(GmlObject* clusterObject, - ClusterGraph& CG, - cluster c) -{ - - //for direct root cluster sons, this is checked twice... - if (clusterObject->m_valueType != gmlListBegin) return false; - - GmlObject *clusterSon = clusterObject->m_pFirstSon; - - for(; clusterSon; clusterSon = clusterSon->m_pBrother) - { - //we dont read the attributes, therefore look only for - //id and sons - switch(id(clusterSon)) - { - case clusterPredefKey: - { - if (clusterSon->m_valueType != gmlListBegin) return false; - - cluster cson = CG.newCluster(c); - //recursively read child cluster - recursiveClusterRead(clusterSon, CG, cson); - } - break; - case vertexPredefKey: //direct cluster vertex entries - { - if (clusterSon->m_valueType != gmlStringValue) return false; - String vIDString = clusterSon->m_stringValue; - - //if old style entry "v"i - if ((vIDString[0] != 'v') && - (!isdigit(vIDString[0])))return false; //do not allow labels - //if old style entry "v"i - if (!isdigit(vIDString[0])) //should check prefix? - vIDString[0] = '0'; //leading zero to allow conversion - int vID = atoi(vIDString.cstr()); - - OGDF_ASSERT(m_mapToNode[vID] != 0) - - //we assume that no node is already assigned - //CG.reassignNode(mapToNode[vID], c); - //changed: all nodes are already assigned to root - CG.reassignNode(m_mapToNode[vID], c); - //char* vIDChar = new char[vIDString.length()+1]; - //for (int ind = 1; ind < vIDString.length(); ind++) - // vIDChar - - }//case vertex - }//switch - }//for clustersons - - return true; - -}//recursiveclusterread - -//recursively read cluster subtree information -bool GmlParser::recursiveAttributedClusterRead(GmlObject* clusterObject, - ClusterGraph& CG, - ClusterGraphAttributes& ACG, - cluster c) -{ - - //for direct root cluster sons, this is checked twice... - if (clusterObject->m_valueType != gmlListBegin) return false; - - GmlObject *clusterSon = clusterObject->m_pFirstSon; - - for(; clusterSon; clusterSon = clusterSon->m_pBrother) - { - //we dont read the attributes, therefore look only for - //id and sons - switch(id(clusterSon)) - { - case clusterPredefKey: - { - if (clusterSon->m_valueType != gmlListBegin) return false; - - cluster cson = CG.newCluster(c); - //recursively read child cluster - recursiveAttributedClusterRead(clusterSon, CG, ACG, cson); - } - break; - case labelPredefKey: - { - if (clusterSon->m_valueType != gmlStringValue) return false; - ACG.clusterLabel(c) = clusterSon->m_stringValue; - } - break; - case templatePredefKey: - { - if (clusterSon->m_valueType != gmlStringValue) return false; - ACG.templateCluster(c) = clusterSon->m_stringValue; - break; - } - case graphicsPredefKey: //read the info for cluster c - { - if (clusterSon->m_valueType != gmlListBegin) return false; - - readClusterAttributes(clusterSon, c , ACG); - }//graphics - break; - case vertexPredefKey: //direct cluster vertex entries - { - if (clusterSon->m_valueType != gmlStringValue) return false; - String vIDString = clusterSon->m_stringValue; - - if ((vIDString[0] != 'v') && - (!isdigit(vIDString[0])))return false; //do not allow labels - //if old style entry "v"i - if (!isdigit(vIDString[0])) //should check prefix? - vIDString[0] = '0'; //leading zero to allow conversion - int vID = atoi(vIDString.cstr()); - - OGDF_ASSERT(m_mapToNode[vID] != 0) - - //we assume that no node is already assigned - //changed: all nodes are already assigned to root - CG.reassignNode(m_mapToNode[vID], c); - - }//case vertex - }//switch - }//for clustersons - - return true; -}//recursiveAttributedClusterRead - -void GmlParser::readLineAttribute(GmlObject *object, DPolyline &dpl) -{ - dpl.clear(); - for(; object; object = object->m_pBrother) { - if (id(object) == pointPredefKey && - object->m_valueType == gmlListBegin) - { - DPoint dp; - - GmlObject *pointObject = object->m_pFirstSon; - for (; pointObject; pointObject = pointObject->m_pBrother) { - if (pointObject->m_valueType != gmlDoubleValue) continue; - if (id(pointObject) == xPredefKey) - dp.m_x = pointObject->m_doubleValue; - else if (id(pointObject) == yPredefKey) - dp.m_y = pointObject->m_doubleValue; - } - - dpl.pushBack(dp); - } - } -} - - -void GmlParser::setError(const char *errorString) -{ - m_error = true; - m_errorString = errorString; -} - - -void GmlParser::indent(ostream &os, int d) -{ - for(int i = 1; i <= d; ++i) - os << " "; -} - -void GmlParser::output(ostream &os, GmlObject *object, int d) -{ - for(; object; object = object->m_pBrother) { - indent(os,d); os << object->m_key->key(); - - switch(object->m_valueType) { - case gmlIntValue: - os << " " << object->m_intValue << "\n"; - break; - - case gmlDoubleValue: - os << " " << object->m_doubleValue << "\n"; - break; - - case gmlStringValue: - os << " \"" << object->m_stringValue << "\"\n"; - break; - - case gmlListBegin: - os << "\n"; - output(os, object->m_pFirstSon, d+2); - break; - case gmlListEnd: - break; - case gmlKey: - break; - case gmlEOF: - break; - case gmlError: - break; - } - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/fileformats/Ogml.cpp b/ext/OGDF/src/fileformats/Ogml.cpp deleted file mode 100644 index 1d724c3e3..000000000 --- a/ext/OGDF/src/fileformats/Ogml.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * $Revision: 2597 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 19:26:11 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Contains diverse enumerations and string constants. - * - * \author Christian Wolf, Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf -{ - - /// This vector contains the real names of all OGML tags - const String Ogml::s_tagNames[TAG_NUM] = - { - //"none" - "bool", - "composed", - "constraint", - "constraints", - "content", - "data", - "default", - "edge", - "edgeRef", - "edgeStyle", - "edgeStyleTemplate", - "template", - "endpoint", - "fill", - "font", - "graph", - "graphStyle", - "int", - "label", - "labelRef", - "labelStyle", - "labelStyleTemplate", - "template", - "layout", - "line", - "location", - "node", - "nodeRef", - "nodeStyle", - "nodeStyleTemplate", - "template", - "num", - "ogml", - "point", - "port", - "segment", - "shape", - "source", - "sourceStyle", - "string", - "structure", - "styles", - "styleTemplates", - "target", - "targetStyle", - "text", - "image" - }; - - - // This vector contains the real names of all OGML attributes. - const String Ogml::s_attributeNames[ATT_NUM] = - { - "alignment", - "angle", - "color", - "decoration", - "defaultEdgeTemplate", - "defaultLabelTemplate", - "defaultNodeTemplate", - "family", - "height", - "id", // id attribute - "idRef", // attribute idRef of elements source, target, nodeRef, nodeStyle - "idRef", // attribute idRef of elements edgeRef, edgeStyle - "idRef", // attribute idRef of elements edgeRef, edgeStyle - "idRef", // attribute idRef of element endpoint - "idRef", // attribute idRef of element endpoint - "idRef", // attribute idRef of subelement template of element nodeStyle - "idRef", // attribute idRef of subelement template of element edgeStyle - "idRef", // attribute idRef of subelement template of element labelStyle - "idRef", // attribute idRef of subelement endpoint of element segment - "name", - "type", // attribute type of subelement line of tag nodeStyleTemplate - "type", // attribute type of subelement shape of tag nodeStyleTemplate - "pattern", - "patternColor", - "rotation", - "size", - "stretch", - "style", - "transform", - "type", // attribute type of subelements source-/targetStyle of tag edgeStyleTemplate - "uri", - "value", - "value", - "value", - "variant", - "weight", - "width", - "x", - "y", - "z", - "uri", - "style", - "alignment", - "drawLine", - "width", - "height", - "type", - "disabled" - }; - - - // This vector contains the real names of all OGML values of attributes. - const String Ogml::s_attributeValueNames[ATT_VAL_NUM] = { - "any", // for any attributeValue - "blink", - "bold", - "bolder", - "bool", - "box", - "capitalize", - "center", - "checked", - "circle", - "condensed", - "cursive", - "dashed", - "esNoPen", // values for line style - "esSolid", - "esDash", - "esDot", - "esDashdot", - "esDashdotdot", - "diamond", - "dotted", - "double", - "doubleSlash", - "ellipse", - "expanded", - "extraCondensed", - "extraExpanded", - "fantasy", - "filledBox", - "filledCircle", - "filledDiamond", - "filledHalfBox", - "filledHalfCircle", - "filledHalfDiamond", - "filledHalfRhomb", - "filledRhomb", - "smurf", - "arrow", - "groove", - "halfBox", - "halfCircle", - "halfDiamond", - "halfRhomb", - "hexagon", - "hex", - "id", - "nodeId", // attribute idRef of elements source, target, nodeRef, nodeStyle - "edgeId", // attribute idRef of elements edgeRef, edgeStyle - "labelId", // attribute idRef of elements edgeRef, edgeStyle - "sourceId", // attribute idRef of element endpoint - "targetId", // attribute idRef of element endpoint - "nodeStyleTemplateId", // attribute idRef of subelement template of element nodeStyle - "edgeStyleTemplateId", // attribute idRef of subelement template of element edgeStyle - "labelStyleTemplateId", // attribute idRef of subelement template of element labelStyle - "pointId", // attribute idRef of subelement endpoint of element segment - "image", - "inset", - "int", - "italic", - "justify", - "left", - "lighter", - "line", - "lineThrough", - "lowercase", - "lParallelogram", - "monospace", - "narrower", - "none", - "normal", - "num", - "oblique", - "oct", - "octagon", - "outset", - "overline", - "pentagon", - "rect", - "rectSimple", - "rhomb", - "ridge", - "right", - "rParallelogram", - "sansSerif", - "semiCondensed", - "semiExpanded", - "serif", - "slash", - "smallCaps", - "solid", - "bpNone", // values for node patterns - "bpSolid", - "bpDense1", - "bpDense2", - "bpDense3", - "bpDense4", - "bpDense5", - "bpDense6", - "bpDense7", - "bpHorizontal", - "bpVertical", - "bpCross", - "bpBackwardDiagonal", - "bpForwardDiagonal", - "bpDiagonalCross", - "string", - "striped", - "trapeze", - "triangle", - "triple", - "ultraCondensed", - "ultraExpanded", - "umlClass", - "underline", - "uppercase", - "upTrapeze", - "uri", - "wider", - "freeScale", // image-style - "fixScale", // image-style - "topLeft", // image-alignemnt - "topCenter", // image-alignemnt - "topRight", // image-alignemnt - "centerLeft", // image-alignemnt - // "center", // just defined // image-alignemnt - "centerRight", // image-alignemnt - "bottomLeft", // image-alignemnt - "bottomCenter", // image-alignemnt - "bottomRight", // image-alignemnt - "Alignment", - "Anchor", - "Sequence" - }; - - - static const String s_graphTypeS[] = - { - "graph", - "clusterGraph", - "compoundGraph", - "corruptCompoundGraph" - }; - -}; //namspace ogdf diff --git a/ext/OGDF/src/fileformats/OgmlParser.cpp b/ext/OGDF/src/fileformats/OgmlParser.cpp deleted file mode 100644 index cf3685902..000000000 --- a/ext/OGDF/src/fileformats/OgmlParser.cpp +++ /dev/null @@ -1,3937 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of OGML parser. - * - * \author Christian Wolf and Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// OgmlParser::OgmlNodeTemplate -//--------------------------------------------------------- - -// struct definitions for mapping of templates -struct OgmlParser::OgmlNodeTemplate -{ - String m_id; - int m_shapeType; - double m_width; - double m_height; - String m_color; - GraphAttributes::BrushPattern m_pattern; - String m_patternColor; - GraphAttributes::EdgeStyle m_lineType; - double m_lineWidth; - String m_lineColor; - // nodeTemplate stores the graphical type - // e.g. rectangle, ellipse, hexagon, ... - String m_nodeTemplate; - - //Constructor: - OgmlNodeTemplate(const String &id): m_id(id) { } -}; - - -//--------------------------------------------------------- -// OgmlParser::OgmlEdgeTemplate -//--------------------------------------------------------- - -struct OgmlParser::OgmlEdgeTemplate -{ - String m_id; - GraphAttributes::EdgeStyle m_lineType; - double m_lineWidth; - String m_color; - int m_sourceType; // actually this is only a boolean value 0 or 1 - // ogdf doesn't support source-arrow-color and size - // String m_sourceColor; - // double m_sourceSize; - int m_targetType; // actually this is only a boolean value 0 or 1 - // ogdf doesn't support target-arrow-color and size - // String m_targetColor; - // double m_targetSize; - - //Constructor: - OgmlEdgeTemplate(const String &id): m_id(id) { } -}; - - -// struct OgmlParser::OgmlLabelTemplate{ -// String m_id; -// }; - - -//--------------------------------------------------------- -// OgmlParser::OgmlSegment -//--------------------------------------------------------- - -struct OgmlParser::OgmlSegment -{ - DPoint point1, point2; -}; - - -//--------------------------------------------------------- -// OgmlParser::OgmlAttributeValue -//--------------------------------------------------------- - -//! Objects of this class represent a value set of an attribute in Ogml. -class OgmlParser::OgmlAttributeValue -{ - int id; //!< Id of the attribute value; for possible ones see Ogml.h. - -public: - // Construction - OgmlAttributeValue() : id(Ogml::av_any) { } - - OgmlAttributeValue(int id) { - if(id >= 0 && id < Ogml::ATT_VAL_NUM) this->id = id; - else id = Ogml::av_any; - } - - // Destruction - ~OgmlAttributeValue() { } - - // Getter - const int& getId() const { return id; } - const String& getValue() const { return Ogml::s_attributeValueNames[id]; } - - // Setter - void setId(int id) { - if(id >= 0 && id < Ogml::ATT_VAL_NUM) this->id = id; - else id = Ogml::av_any; - } - - - /** - * Checks the type of the input given in string - * and returns an OgmlAttributeValueId defined in Ogml.h - */ - Ogml::AttributeValueId getTypeOfString(const String& input) const - { - // |--------------------| - // | char | ascii-value | - // |--------------------| - // | '.' | 46 | - // | '-' | 45 | - // | '+' | 43 | - // | '#' | 35 | - - // bool values - bool isInt = true; - bool isNum = true; - bool isHex = true; - - // value for point seperator - bool numPoint = false; - - // input is a boolean value - if (input == "true" || input == "false" /*|| input == "0" || input == "1"*/) - return Ogml::av_bool; - - if (input.length() > 0){ - char actChar = input[0]; - int actCharInt = static_cast(actChar); - //check the first char - if (!isalnum(actChar)){ - - if (actCharInt == 35){ - // support hex values with starting "#" - isInt = false; - isNum = false; - } - else - { - - // (actChar != '-') and (actChar != '+') - if (!(actCharInt == 45) && !(actChar == 43)){ - isInt = isNum = false; - } - else - { - // input[0] == '-' or '+' - if (input.length() > 1){ - // 2nd char have to be a digit or xdigit - actChar = input[1]; - actCharInt = static_cast(actChar); - if (!isdigit(actChar)){ - isInt = false; - isNum = false; - if (!isxdigit(actChar)) - return Ogml::av_string; - } - } - else - return Ogml::av_string; - } // else... (input[0] == '-') - } - } - else{ - if (!isdigit(actChar)){ - isInt = false; - isNum = false; - } - if (!isxdigit(actChar)){ - isHex = false; - } - } - - // check every input char - // and set bool value to false if char-type is wrong - for(size_t it=1; ( (it(actChar); - - // actChar == '.' - if (actChar == 46){ - isInt = false; - isHex = false; - if (!numPoint){ - numPoint = true; - } - else - isNum = false; - }// if (actChar == '.') - else { - if (!(isdigit(actChar))){ - isInt = false; - isNum = false; - } - if (!(isxdigit(actChar))) - isHex = false; - }//else... (actChar != '.') - }//for - }//if (input.length() > 0) - else{ - // input.length() == 0 - return Ogml::av_none; - } - // return correct value - if (isInt) return Ogml::av_int; - if (isNum) return Ogml::av_num; - if (isHex) return Ogml::av_hex; - // if all bool values are false return av_string - return Ogml::av_string; - - }//getTypeOfString - - - /** - * According to id this method proofs whether s is a valid value - * of the value set. - * E.g. if id=av_int s should contain an integer value. - * It returns the following validity states: - * vs_idNotUnique =-10, //id already exhausted - * vs_idRefErr = -9, //referenced id wasn't found or wrong type of referenced tag - * vs_idRefErr = -8, //referenced id wrong - * vs_attValueErr = -3, //attribute-value error - * Ogml::vs_valid = 1 //attribute-value is valid - * - * TODO: Completion of the switch-case statement. - */ - int validValue( - const String &attributeValue, - const XmlTagObject* xmlTag, //owns an attribute with attributeValue - Hashing& ids) const //hashtable with id-tagName pairs - { - //get attribute value type of string - Ogml::AttributeValueId stringType = getTypeOfString(attributeValue); - - HashElement* he; - - int valid = Ogml::vs_attValueErr; - - switch(id) { - case Ogml::av_any: - valid = Ogml::vs_valid; - break; - - case Ogml::av_int: - if (stringType == Ogml::av_int) valid = Ogml::vs_valid; - break; - - case Ogml::av_num: - if (stringType == Ogml::av_num) valid = Ogml::vs_valid; - if (stringType == Ogml::av_int) valid = Ogml::vs_valid; - break; - - case Ogml::av_bool: - if (stringType == Ogml::av_bool) valid = Ogml::vs_valid; - break; - - case Ogml::av_string: - valid = Ogml::vs_valid; - break; - - case Ogml::av_hex: - if (stringType == Ogml::av_hex) valid = Ogml::vs_valid; - if (stringType == Ogml::av_int) valid = Ogml::vs_valid; - break; - - case Ogml::av_oct: - valid = Ogml::vs_attValueErr; - break; - - case Ogml::av_id: - // id mustn't exist - if( !(he = ids.lookup(attributeValue)) ) { - ids.fastInsert(attributeValue, xmlTag); - valid = Ogml::vs_valid; - } - else valid = Ogml::vs_idNotUnique; - break; - - // attribute idRef of elements source, target, nodeRef, nodeStyle - case Ogml::av_nodeIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_node]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of elements edgeRef, edgeStyle - case Ogml::av_edgeIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_edge]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of elements labelRef, labelStyle - case Ogml::av_labelIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_label]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of element endpoint - case Ogml::av_sourceIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_source]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of element endpoint - case Ogml::av_targetIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_target]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of subelement template of element nodeStyle - case Ogml::av_nodeStyleTemplateIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_nodeStyleTemplate]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of subelement template of element edgeStyle - case Ogml::av_edgeStyleTemplateIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_edgeStyleTemplate]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - // attribute idRef of subelement template of element labelStyle - case Ogml::av_labelStyleTemplateIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_labelStyleTemplate]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - case Ogml::av_pointIdRef: - // element exists && is tagname expected - if( (he = ids.lookup(attributeValue)) && (he->info()->getName() == Ogml::s_tagNames[Ogml::t_point]) ) valid = Ogml::vs_valid; - else valid = Ogml::vs_idRefErr; - break; - - default: - // Proof string for equality - if(getValue() == attributeValue) valid = Ogml::vs_valid; - break; - } - - return valid; - } - -};//class OgmlAttributeValue - - -//--------------------------------------------------------- -// OgmlParser::OgmlAttribute -//--------------------------------------------------------- - -/** Objects of this class represent an attribute and its value set in Ogml. -*/ -class OgmlParser::OgmlAttribute -{ - /** - */ - int id; //!< Integer identifier of object; for possible ids see Ogml.h. - List values; //!< Represents the value set of this attribute. - -public: - - // Construction - OgmlAttribute() : id(Ogml::a_none), values() { } - - OgmlAttribute(int id) : values() { - if(id >= 0 && id < Ogml::ATT_NUM) this->id = id; - else this->id = Ogml::a_none; - } - - // Destruction - ~OgmlAttribute() { } - - // Getter - const int& getId() const { return id; } - const String& getName() const { return Ogml::s_attributeNames[id]; } - const List& getValueList() const { return values; } - - // Setter - void setId(int id) { - if(id >= 0 && id < Ogml::ATT_NUM) this->id = id; - else this->id = Ogml::a_none; - } - - /** - * Pushes pointers to OgmlAttributeValue objects back to list values. - * These value objects are looked up in hashtable values. - * - * NOTE: This method uses a variable parameter list. The last parameter - * need to be -1! - */ - void pushValues(Hashing *val, int key, ...) { - va_list argp; - int arg = key; - HashElement* he; - va_start(argp, key); - while(arg!=-1) { - if((he = val->lookup(arg))) values.pushBack( &(he->info()) ); - arg = va_arg(argp,int); - } - va_end(argp); - } - - // Prints the value set of the attribute. - void print(ostream &os) const { - ListConstIterator it; - os << "\"" << getName() << "\"={ "; - for(it = values.begin(); it.valid(); it++) { - os << (**it).getValue() << " "; - } - os << "}\n"; - } - - /**This method proofs whether o is a valid attribute in comparison - * to this object. - * That means if the name of o and this object are equal and if - * o has a valid value. - * It returns a validity state code (see Ogml.h). - **/ - int validAttribute(const XmlAttributeObject &xmlAttribute, - const XmlTagObject* xmlTag, - Hashing& ids) const - { - int valid = Ogml::vs_expAttNotFound; - - if( xmlAttribute.getName() == getName() ) { - ListConstIterator it; - for(it = values.begin(); it.valid(); it++) { - if ( (valid = (**it).validValue( xmlAttribute.getValue(), xmlTag, ids )) == Ogml::vs_valid ) break; - } - } - - return valid; - } -};//class OgmlAttribute - - - -//--------------------------------------------------------- -// OgmlParser::OgmlTag -//--------------------------------------------------------- - -/**Objects of this class represent a tag in Ogml with attributes. -*/ -class OgmlParser::OgmlTag -{ - int id; //!< Integer identifier of object; for possible ids see Ogml.h. - - int minOccurs, maxOccurs; // Min. occurs and max. occurs of this tag. - - /** - * Flag denotes whether tag content can be ignored. - * It is possible to exchange this flag by a list of contents for more - * complex purposes ;-) - */ - bool ignoreContent; - - List compulsiveAttributes; //!< Represents the compulsive attributes of this object. - List choiceAttributes; //!< Represents the attributes of this object of which at least one needs to exist. - List optionalAttributes; //!< Represents the optional attributes of this object. - - List compulsiveTags; - List choiceTags; - List optionalTags; - - - void printOwnedTags(ostream &os, int mode) const - { - String s; - const List *list; - - switch(mode) { - case 0: - list = &compulsiveTags; - s += "compulsive"; - break; - - case 1: - list = &choiceTags; - s += "selectable"; - break; - - case 2: - list = &optionalTags; - s += "optional"; - break; - - } - - if(list->empty()) - os << "Tag \"<" << getName() <<">\" doesn't include " << s << " tag(s).\n"; - else { - os << "Tag \"<" << getName() <<">\" includes the following " << s << " tag(s): \n"; - ListConstIterator currTag; - for(currTag = list->begin(); currTag.valid(); currTag++) - os << "\t<" << (**currTag).getName() << ">\n"; - } - } - - void printOwnedAttributes(ostream &os, int mode) const - { - String s; - const List *list; - - switch(mode) - case 0: { - list = &compulsiveAttributes; - s += "compulsive"; - break; - - case 1: - list = &choiceAttributes; - s += "selectable"; - break; - - case 2: - list = &optionalAttributes; - s += "optional"; - break; - - } - - if(list->empty()) - os << "Tag \"<" << getName() <<">\" doesn't include " << s << " attribute(s).\n"; - else { - cout << "Tag \"<" << getName() <<">\" includes the following " << s << " attribute(s): \n"; - ListConstIterator currAtt; - for(currAtt = list->begin(); currAtt.valid(); currAtt++) - os << "\t" << (**currAtt); - } - } - - -public: - - bool ownsCompulsiveTags() { - return !compulsiveTags.empty(); - } - - bool ownsChoiceTags() { - return !choiceTags.empty(); - } - - bool ownsOptionalTags() { - return !optionalTags.empty(); - } - - const List& getCompulsiveTags() const { return compulsiveTags; } - - const List& getChoiceTags() const { return choiceTags; } - - const List& getOptionalTags() const { return optionalTags; } - - - const int& getMinOccurs() const { return minOccurs; } - - const int& getMaxOccurs() const { return maxOccurs; } - - const bool& ignoresContent() const { return ignoreContent; } - - void setMinOccurs(int occurs) { minOccurs = occurs; } - - void setMaxOccurs(int occurs) { maxOccurs = occurs; } - - void setIgnoreContent(bool ignore) { ignoreContent = ignore; } - - //Construction - OgmlTag() : id(Ogml::t_none), ignoreContent(0) { } - - OgmlTag(int id) : id(Ogml::t_none), ignoreContent(0) { - if(id >= 0 && id < Ogml::TAG_NUM) this->id = id; - else id = Ogml::a_none; - } - - //Destruction - ~OgmlTag() {} - - //Getter - const int& getId() const { return id; } - const String& getName() const { return Ogml::s_tagNames[id]; } - - //Setter - void setId(int id){ - if(id >= 0 && id < Ogml::TAG_NUM) this->id = id; - else id = Ogml::a_none; - } - - - void printOwnedTags(ostream& os) const { - printOwnedTags(os, 0); - printOwnedTags(os, 1); - printOwnedTags(os, 2); - } - - void printOwnedAttributes(ostream& os) const { - printOwnedAttributes(os, 0); - printOwnedAttributes(os, 1); - printOwnedAttributes(os, 2); - } - - /**Pushes pointers to OgmlAttribute objects back to list reqAttributes. - * These value objects are looked up in hashtable attrib. - * - * NOTE: This method uses a variable parameter list. The last parameter - * need to be -1! - */ - void pushAttributes(int mode, Hashing *attrib, int key, ...) - { - List* list; - - if(mode==0) list = &compulsiveAttributes; - else if(mode==1) list = &choiceAttributes; - else list = &optionalAttributes; - - va_list argp; - int arg = key; - HashElement* he; - va_start(argp, key); - while(arg!=-1) { - if((he = attrib->lookup(arg))) - (*list).pushBack( &(he->info()) ); - arg = va_arg(argp,int); - } - va_end(argp); - } - - /**Pushes pointers to OgmlAttribute objects back to list reqAttributes. - * These value objects are looked up in hashtable tag. - * - * NOTE: This method uses a variable parameter list. The last parameter - * need to be -1! - */ - void pushTags(int mode, Hashing *tag, int key, ...) - { - List* list; - - if(mode==0) list = &compulsiveTags; - else if(mode==1) list = &choiceTags; - else list = &optionalTags; - - va_list argp; - int arg = key; - HashElement* he; - va_start(argp, key); - - while(arg!=-1) { - if((he = tag->lookup(arg))) - (*list).pushBack( &(he->info()) ); - arg = va_arg(argp,int); - } - va_end(argp); - } - - /**This method proofs whether o is a valid tag in comparison - * to this object. - * That means if the name of o and this object are equal and if - * the attribute list of o is valid (see also validAttribute(...) - * in OgmlAttribute.h). Otherwise false. - */ - int validTag(const XmlTagObject &o, - Hashing& ids) const - { - int valid = Ogml::vs_unexpTag; - - if( o.getName() == getName() ) { - - ListConstIterator it; - XmlAttributeObject* att; - - //Tag requires attributes - if(!compulsiveAttributes.empty()) { - - for(it = compulsiveAttributes.begin(); it.valid(); it++) { - //Att not found or invalid - if(!o.findXmlAttributeObjectByName((**it).getName(), att) ) - return valid = Ogml::vs_expAttNotFound; - if( (valid = (**it).validAttribute(*att, &o, ids) ) <0 ) - return valid; - //Att is valid - att->setValid(); - } - } - - //Choice attributes - if(!choiceAttributes.empty()) { - - bool tookChoice = false; - - for(it = choiceAttributes.begin(); it.valid(); it++) { - //Choice att found - if( o.findXmlAttributeObjectByName((**it).getName(), att) ) { - //Proof if valid - if( (valid = (**it).validAttribute(*att, &o, ids)) <0 ) - return valid; - tookChoice = true; - att->setValid(); - } - } - - if(!tookChoice) - return valid = Ogml::vs_expAttNotFound; - - } - - if(!optionalAttributes.empty() && !o.isAttributeLess()) { - - //Check optional attributes - for(it = optionalAttributes.begin(); it.valid(); it++) { - if( o.findXmlAttributeObjectByName((**it).getName(), att) ) { - if( (valid = (**it).validAttribute(*att, &o, ids)) <0 ) - return valid; - att->setValid(); - } - } - } - - //Are there still invalid attributes? - att = o.m_pFirstAttribute; - while(att) { - if(!att->valid()) - return valid = Ogml::vs_unexpAtt; - att = att->m_pNextAttribute; - } - - valid = Ogml::vs_valid; - } - - return valid; - } - -};//class OgmlTag - - - -//--------------------------------------------------------- -// OgmlParser -//--------------------------------------------------------- - -// Definition of Hashtables -Hashing < int, OgmlParser::OgmlTag > *OgmlParser::s_tags = 0; -Hashing < int, OgmlParser::OgmlAttribute > *OgmlParser::s_attributes = 0; -Hashing < int, OgmlParser::OgmlAttributeValue > *OgmlParser::s_attValues = 0; - - -// *********************************************************** -// -// b u i l d H a s h T a b l e s -// -// *********************************************************** -void OgmlParser::buildHashTables() -{ - if(s_tags != 0) // hash tables already built? - return; - - s_tags = new Hashing < int, OgmlParser::OgmlTag >; - s_attributes = new Hashing < int, OgmlParser::OgmlAttribute >; - s_attValues = new Hashing < int, OgmlParser::OgmlAttributeValue >; - - // Create OgmlAttributeValue objects and fill hashtable s_attValues. - - for (int i = 0; i < Ogml::ATT_VAL_NUM; i++) - s_attValues->fastInsert(i, OgmlAttributeValue(i)); - - for (int i = 0; i < Ogml::ATT_NUM; i++) - s_attributes->fastInsert(i, OgmlAttribute(i)); - - - // Create OgmlAttribute objects and fill hashtable attributes. - - for (int i = 0; i < Ogml::ATT_NUM; i++) { - - OgmlAttribute &att = s_attributes->lookup(i)->info(); - - switch (i) { - - case Ogml::a_alignment: - att.pushValues(s_attValues, - Ogml::av_left, - Ogml::av_center, - Ogml::av_right, - Ogml::av_justify, - -1); - break; - - case Ogml::a_angle: - att.pushValues(s_attValues, - Ogml::av_int, - -1); - break; - - case Ogml::a_color: - att.pushValues(s_attValues, - Ogml::av_hex, - -1); - break; - - case Ogml::a_decoration: - att.pushValues(s_attValues, - Ogml::av_underline, - Ogml::av_overline, - Ogml::av_lineThrough, - Ogml::av_blink, - Ogml::av_none, - -1); - break; - - case Ogml::a_defaultEdgeTemplate: - att.pushValues(s_attValues, Ogml::av_any, -1); - break; - - case Ogml::a_defaultLabelTemplate: - att.pushValues(s_attValues, Ogml::av_any, -1); - break; - - case Ogml::a_defaultNodeTemplate: - att.pushValues(s_attValues, Ogml::av_any, -1); - break; - - case Ogml::a_family: - att.pushValues(s_attValues, - Ogml::av_serif, - Ogml::av_sansSerif, - Ogml::av_cursive, - Ogml::av_fantasy, - Ogml::av_monospace, - -1); - break; - - case Ogml::a_height: - att.pushValues(s_attValues, Ogml::av_num, -1); - break; - - case Ogml::a_id: - att.pushValues(s_attValues, Ogml::av_id, -1); - break; - - case Ogml::a_nodeIdRef: - att.pushValues(s_attValues, Ogml::av_nodeIdRef, -1); - break; - - case Ogml::a_edgeIdRef: - att.pushValues(s_attValues, Ogml::av_edgeIdRef, -1); - break; - - case Ogml::a_labelIdRef: - att.pushValues(s_attValues, Ogml::av_labelIdRef, -1); - break; - - case Ogml::a_sourceIdRef: - att.pushValues(s_attValues, Ogml::av_nodeIdRef, Ogml::av_edgeIdRef, -1); - break; - - case Ogml::a_targetIdRef: - att.pushValues(s_attValues, Ogml::av_nodeIdRef, Ogml::av_edgeIdRef, -1); - break; - - case Ogml::a_nodeStyleTemplateIdRef: - att.pushValues(s_attValues, Ogml::av_nodeStyleTemplateIdRef, -1); - break; - - case Ogml::a_edgeStyleTemplateIdRef: - att.pushValues(s_attValues, Ogml::av_edgeStyleTemplateIdRef, -1); - break; - - case Ogml::a_labelStyleTemplateIdRef: - att.pushValues(s_attValues, Ogml::av_labelStyleTemplateIdRef, -1); - break; - - case Ogml::a_endpointIdRef: - att.pushValues(s_attValues, Ogml::av_pointIdRef, Ogml::av_sourceIdRef, Ogml::av_targetIdRef, -1); - break; - - case Ogml::a_name: - att.pushValues(s_attValues, Ogml::av_any, -1); - break; - - // attribute type of subelement line of tag nodeStyleTemplate - case Ogml::a_nLineType: - att.pushValues(s_attValues, - Ogml::av_solid, - Ogml::av_dotted, - Ogml::av_dashed, - Ogml::av_double, - Ogml::av_triple, - Ogml::av_groove, - Ogml::av_ridge, - Ogml::av_inset, - Ogml::av_outset, - Ogml::av_none, - Ogml::av_esNoPen, - Ogml::av_esSolid, - Ogml::av_esDash, - Ogml::av_esDot, - Ogml::av_esDashdot, - Ogml::av_esDashdotdot, - -1); - break; - - // attribute type of subelement shape of tag nodeStyleTemplate - case Ogml::a_nShapeType: - att.pushValues(s_attValues, - Ogml::av_rect, - Ogml::av_rectSimple, - Ogml::av_triangle, - Ogml::av_circle, - Ogml::av_ellipse, - Ogml::av_hexagon, - Ogml::av_rhomb, - Ogml::av_trapeze, - Ogml::av_upTrapeze, - Ogml::av_lParallelogram, - Ogml::av_rParallelogram, - Ogml::av_pentagon, - Ogml::av_octagon, - Ogml::av_umlClass, - Ogml::av_image, - -1); - break; - - case Ogml::a_pattern: - att.pushValues(s_attValues, - Ogml::av_solid, - Ogml::av_striped, - Ogml::av_checked, - Ogml::av_dotted, - Ogml::av_none, - Ogml::av_bpNone, - Ogml::av_bpSolid, - Ogml::av_bpDense1, - Ogml::av_bpDense2, - Ogml::av_bpDense3, - Ogml::av_bpDense4, - Ogml::av_bpDense5, - Ogml::av_bpDense6, - Ogml::av_bpDense7, - Ogml::av_bpHorizontal, - Ogml::av_bpVertical, - Ogml::av_bpCross, - Ogml::av_bpBackwardDiagonal, - Ogml::av_bpForwardDiagonal, - Ogml::av_bpDiagonalCross, -1); - break; - - case Ogml::a_patternColor: - att.pushValues(s_attValues, Ogml::av_hex, -1); - break; - - case Ogml::a_rotation: - att.pushValues(s_attValues, Ogml::av_int, -1); - break; - - case Ogml::a_size: - att.pushValues(s_attValues, Ogml::av_int, -1); - break; - - case Ogml::a_stretch: - att.pushValues(s_attValues, - Ogml::av_normal, - Ogml::av_wider, - Ogml::av_narrower, - Ogml::av_ultraCondensed, - Ogml::av_extraCondensed, - Ogml::av_condensed, - Ogml::av_semiCondensed, - Ogml::av_semiExpanded, - Ogml::av_expanded, - Ogml::av_extraExpanded, - Ogml::av_ultraExpanded, -1); - break; - - case Ogml::a_style: - att.pushValues(s_attValues, Ogml::av_normal, Ogml::av_italic, Ogml::av_oblique, -1); - break; - - case Ogml::a_transform: - att.pushValues(s_attValues, Ogml::av_capitalize, Ogml::av_uppercase, Ogml::av_lowercase, Ogml::av_none, -1); - break; - - // attribute type of subelements source-/targetStyle of tag edgeStyleTemplate - case Ogml::a_type: - att.pushValues(s_attValues, - Ogml::av_circle, - Ogml::av_halfCircle, - Ogml::av_filledCircle, - Ogml::av_filledHalfCircle, - Ogml::av_box, - Ogml::av_halfBox, - Ogml::av_filledBox, - Ogml::av_filledHalfBox, - Ogml::av_rhomb, - Ogml::av_halfRhomb, - Ogml::av_filledRhomb, - Ogml::av_filledHalfRhomb, - Ogml::av_diamond, - Ogml::av_halfDiamond, - Ogml::av_filledDiamond, - Ogml::av_filledHalfDiamond, - Ogml::av_smurf, - Ogml::av_arrow, - Ogml::av_slash, - Ogml::av_doubleSlash, - Ogml::av_solid, - Ogml::av_line, - Ogml::av_none, -1); - break; - - case Ogml::a_uri: - att.pushValues(s_attValues, Ogml::av_uri, -1); - break; - - case Ogml::a_intValue: - att.pushValues(s_attValues, Ogml::av_int, -1); - break; - - case Ogml::a_numValue: - att.pushValues(s_attValues, Ogml::av_num, -1); - break; - - case Ogml::a_boolValue: - att.pushValues(s_attValues, Ogml::av_bool, -1); - break; - - case Ogml::a_variant: - att.pushValues(s_attValues, Ogml::av_normal, Ogml::av_smallCaps, -1); - break; - - case Ogml::a_weight: - att.pushValues(s_attValues, - Ogml::av_normal, - Ogml::av_bold, - Ogml::av_bolder, - Ogml::av_lighter, - Ogml::av_int, - -1); - break; - - case Ogml::a_width: - att.pushValues(s_attValues, Ogml::av_num, -1); - break; - - case Ogml::a_x: - att.pushValues(s_attValues, Ogml::av_num, -1); - break; - - case Ogml::a_y: - att.pushValues(s_attValues, Ogml::av_num, -1); - break; - - case Ogml::a_z: - att.pushValues(s_attValues, Ogml::av_num, -1); - - case Ogml::a_imageUri: - att.pushValues(s_attValues, Ogml::av_string, -1); - - case Ogml::a_imageStyle: - att.pushValues(s_attValues, Ogml::av_freeScale, Ogml::av_fixScale, -1); - - case Ogml::a_imageAlignment: - att.pushValues(s_attValues, Ogml::av_topLeft, - Ogml::av_topCenter, - Ogml::av_topRight, - Ogml::av_centerLeft, - Ogml::av_center, - Ogml::av_centerRight, - Ogml::av_bottomLeft, - Ogml::av_bottomCenter, - Ogml::av_bottomRight, -1); - - case Ogml::a_imageDrawLine: - att.pushValues(s_attValues, Ogml::av_bool, -1); - - case Ogml::a_imageWidth: - att.pushValues(s_attValues, Ogml::av_num, -1); - - case Ogml::a_imageHeight: - att.pushValues(s_attValues, Ogml::av_num, -1); - - case Ogml::a_constraintType: - att.pushValues(s_attValues, Ogml::av_constraintAlignment, Ogml::av_constraintAnchor, Ogml::av_constraintSequence, -1); - - case Ogml::a_disabled: - att.pushValues(s_attValues, Ogml::av_bool, -1); - - } - } - - - // Create OgmlTag objects and fill hashtable tags. - - for (int i = 0; i < Ogml::TAG_NUM; i++) - s_tags->fastInsert(i, OgmlTag(i)); - - - enum Mode { compMode = 0, choiceMode, optMode }; - - // Create tag relations. - - for (int i = 0; i < Ogml::TAG_NUM; i++) - { - OgmlTag &tag = s_tags->lookup(i)->info(); - - switch (i) { - case Ogml::t_bool: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_boolValue, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - break; - - case Ogml::t_composed: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_num, Ogml::t_int, Ogml::t_bool, - Ogml::t_string, Ogml::t_nodeRef, Ogml::t_edgeRef, Ogml::t_labelRef, Ogml::t_composed, -1); - break; - - case Ogml::t_constraint: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_constraintType, -1); - tag.pushAttributes(choiceMode, s_attributes, Ogml::a_id, Ogml::a_name, Ogml::a_disabled, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_num, Ogml::t_int, Ogml::t_bool, - Ogml::t_string, Ogml::t_nodeRef, Ogml::t_edgeRef, Ogml::t_labelRef, Ogml::t_composed, Ogml::t_constraint, -1); - break; - - case Ogml::t_constraints: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushTags(compMode, s_tags, Ogml::t_constraint, -1); - break; - - case Ogml::t_content: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.setIgnoreContent(true); - break; - - case Ogml::t_data: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_int, Ogml::t_bool, Ogml::t_num, Ogml::t_string, Ogml::t_data, -1); - break; - - case Ogml::t_default: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - break; - - case Ogml::t_edge: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_source, Ogml::t_target, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_label, -1); - break; - - case Ogml::t_edgeRef: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_edgeIdRef, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - break; - - case Ogml::t_edgeStyle: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_edgeIdRef, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_edgeStyleTemplateRef, - Ogml::t_line, Ogml::t_sourceStyle, Ogml::t_targetStyle, Ogml::t_point, Ogml::t_segment, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, -1); - break; - - case Ogml::t_edgeStyleTemplate: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_line, Ogml::t_sourceStyle, Ogml::t_targetStyle, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_edgeStyleTemplateRef, -1); - break; - - case Ogml::t_endpoint: - tag.setMinOccurs(2); - tag.setMaxOccurs(2); - tag.pushAttributes(compMode, s_attributes, Ogml::a_endpointIdRef, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_type, Ogml::a_color, Ogml::a_size, -1); - break; - - case Ogml::t_fill: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_color, Ogml::a_pattern, Ogml::a_patternColor, -1); - break; - - case Ogml::t_font: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_family, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_style, - Ogml::a_variant, Ogml::a_weight, Ogml::a_stretch, Ogml::a_size, Ogml::a_color, -1); - break; - - case Ogml::t_graph: - tag.setMinOccurs(1); - tag.setMaxOccurs(1); - tag.pushTags(compMode, s_tags, Ogml::t_structure, -1); - tag.pushTags(optMode, s_tags, Ogml::t_layout, Ogml::t_data, -1); - break; - - case Ogml::t_graphStyle: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(choiceMode, s_attributes, - Ogml::a_defaultNodeTemplate, - Ogml::a_defaultEdgeTemplate, Ogml::a_defaultLabelTemplate, -1); - break; - - case Ogml::t_int: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_intValue, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - break; - - case Ogml::t_label: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(compMode, s_tags, Ogml::t_content, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, -1); - break; - - case Ogml::t_labelRef: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_labelIdRef, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - break; - - case Ogml::t_labelStyle: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_labelIdRef, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_labelStyleTemplateRef, - Ogml::t_data, Ogml::t_text, Ogml::t_font, Ogml::t_location, -1); - break; - - case Ogml::t_labelStyleTemplate: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(compMode, s_tags, Ogml::t_text, Ogml::t_font, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_labelStyleTemplateRef, -1); - break; - - case Ogml::t_layout: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_styleTemplates, Ogml::t_styles, Ogml::t_constraints, -1); - break; - - case Ogml::t_line: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(choiceMode, s_attributes, Ogml::a_nLineType, Ogml::a_width, Ogml::a_color, -1); - break; - - case Ogml::t_location: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_x, Ogml::a_y, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_z, -1); - break; - - case Ogml::t_node: - tag.setMinOccurs(1); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_label, Ogml::t_node, -1); - break; - - case Ogml::t_nodeRef: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_nodeIdRef, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - break; - - case Ogml::t_nodeStyle: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_nodeIdRef, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_location, Ogml::t_shape, Ogml::t_fill, Ogml::t_line, Ogml::t_image, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_nodeStyleTemplateRef, -1); - break; - - - case Ogml::t_nodeStyleTemplate: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(choiceMode, s_tags, Ogml::t_shape, Ogml::t_fill, Ogml::t_line, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_nodeStyleTemplateRef, -1); - break; - - case Ogml::t_num: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_numValue, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - break; - - case Ogml::t_ogml: - tag.setMinOccurs(1); - tag.setMaxOccurs(1); - tag.pushTags(compMode, s_tags, Ogml::t_graph, -1); - break; - - case Ogml::t_point: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, Ogml::a_x, Ogml::a_y, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_z, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, -1); - break; - - case Ogml::t_port: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_id, Ogml::a_x, Ogml::a_y, -1); - break; - - case Ogml::t_segment: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushTags(compMode, s_tags, Ogml::t_endpoint, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_line, -1); - break; - - case Ogml::t_shape: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(choiceMode, s_attributes, Ogml::a_nShapeType, Ogml::a_width, Ogml::a_height, /*a_uri,*/ -1); - // comment (BZ): uri is obsolete, images got an own tag - break; - - case Ogml::t_source: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_sourceIdRef, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_label, -1); - break; - - case Ogml::t_sourceStyle: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(choiceMode, s_attributes, Ogml::a_type, Ogml::a_color, Ogml::a_size, -1); - break; - - case Ogml::t_string: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(optMode, s_attributes, Ogml::a_name, -1); - tag.setIgnoreContent(true); - break; - - case Ogml::t_structure: - tag.setMinOccurs(1); - tag.setMaxOccurs(1); - tag.pushTags(compMode, s_tags, Ogml::t_node, -1); - tag.pushTags(optMode, s_tags, Ogml::t_edge, Ogml::t_label, Ogml::t_data, -1); - break; - - case Ogml::t_styles: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushTags(choiceMode, s_tags, Ogml::t_nodeStyle, Ogml::t_edgeStyle, Ogml::t_labelStyle, -1); - tag.pushTags(optMode, s_tags, Ogml::t_graphStyle, Ogml::t_data, -1); - break; - - case Ogml::t_styleTemplates: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushTags(choiceMode, s_tags, Ogml::t_nodeStyleTemplate, - Ogml::t_edgeStyleTemplate, Ogml::t_labelStyleTemplate, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, -1); - break; - - case Ogml::t_target: - tag.setMinOccurs(0); - tag.setMaxOccurs(Ogml::MAX_TAG_COUNT); - tag.pushAttributes(compMode, s_attributes, Ogml::a_targetIdRef, -1); - tag.pushAttributes(optMode, s_attributes, Ogml::a_id, -1); - tag.pushTags(optMode, s_tags, Ogml::t_data, Ogml::t_label, -1); - break; - - case Ogml::t_targetStyle: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(choiceMode, s_attributes, Ogml::a_type, Ogml::a_color, Ogml::a_size, -1); - break; - - case Ogml::t_labelStyleTemplateRef: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_labelStyleTemplateIdRef, -1); - break; - - case Ogml::t_nodeStyleTemplateRef: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_nodeStyleTemplateIdRef, -1); - break; - - case Ogml::t_edgeStyleTemplateRef: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_edgeStyleTemplateIdRef, -1); - break; - - case Ogml::t_text: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(choiceMode, s_attributes, Ogml::a_alignment, - Ogml::a_decoration, Ogml::a_transform, Ogml::a_rotation, -1); - break; - - case Ogml::t_image: - tag.setMinOccurs(0); - tag.setMaxOccurs(1); - tag.pushAttributes(compMode, s_attributes, Ogml::a_imageUri, -1); - tag.pushAttributes(optMode, s_attributes, - Ogml::a_imageStyle, - Ogml::a_imageAlignment, - Ogml::a_imageDrawLine, - Ogml::a_imageWidth, - Ogml::a_imageHeight, -1); - break; - } - } -} - - -// ******************************************************** -// -// v a l i d a t e -// -// ******************************************************** -int OgmlParser::validate(const XmlTagObject * xmlTag, int ogmlTagId) -{ - - OgmlTag *ogmlTag = &s_tags->lookup(ogmlTagId)->info(); - ListConstIterator < OgmlTag * > it; - XmlTagObject *sonTag; - int valid; - - // Perhaps xmlTag is already valid - if(xmlTag->valid()) - return valid = Ogml::vs_valid; - - if(!ogmlTag) { - cerr << "Didn't found tag with id \"" << ogmlTagId << "\" in hashtable in OgmlParser::validate! Aborting.\n"; - return false; - } - - if((valid = ogmlTag->validTag(*xmlTag, m_ids)) < 0) { - this->printValidityInfo(*ogmlTag, *xmlTag, valid, __LINE__); - return valid; - } - - // if tag ignores its content simply return - if(ogmlTag->ignoresContent()) { - xmlTag->setValid(); -#ifdef OGDF_DEBUG - this->printValidityInfo(*ogmlTag, *xmlTag, valid = Ogml::vs_valid, __LINE__); -#endif - return valid = Ogml::vs_valid; - } - - // Check if all required son tags exist - if(ogmlTag->ownsCompulsiveTags()) - { - // find all obligatoric sons: all obligatoric sons - for (it = ogmlTag->getCompulsiveTags().begin(); it.valid(); it++) - { - int cnt = 0; - - // search for untested sons - sonTag = xmlTag->m_pFirstSon; - while(sonTag) { - if(sonTag->getName() == (**it).getName()) { - cnt++; - if((valid = validate(sonTag, (**it).getId())) < 0) - return valid; - } - sonTag = sonTag->m_pBrother; - } - - // Exp. son not found - if(cnt == 0) { - this->printValidityInfo(*ogmlTag, *xmlTag, valid = Ogml::vs_expTagNotFound, __LINE__); - return valid; - } - - // Check cardinality - if(cnt < (**it).getMinOccurs() || cnt > (**it).getMaxOccurs()) { - this->printValidityInfo((**it), *xmlTag, valid = Ogml::vs_cardErr, __LINE__); - return valid; - } - } - } - - // Check if choice son tags exist - if(ogmlTag->ownsChoiceTags()) - { - bool tookChoice = false; - - // find all obligatoric sons: all obligatoric sons - for (it = ogmlTag->getChoiceTags().begin(); it.valid(); it++) - { - int cnt = 0; - - // search for untested sons - sonTag = xmlTag->m_pFirstSon; - while(sonTag) { - if(sonTag->getName() == (**it).getName()) { - if((valid = validate(sonTag, (**it).getId())) < 0) - return valid; - tookChoice = true; - cnt++; - } - sonTag = sonTag->m_pBrother; - } - - // Check cardinality - if(cnt > 0 && (cnt < (**it).getMinOccurs() - || cnt > (**it).getMaxOccurs())) { - this->printValidityInfo((**it), *xmlTag, valid = Ogml::vs_cardErr, __LINE__); - return valid; - } - - } - if ((!tookChoice) && (xmlTag->m_pFirstSon)) { - this->printValidityInfo((**it), *xmlTag, valid = Ogml::vs_tagEmptIncl, __LINE__); - return valid; - } - - } //Check choice son tags - - // Check if opt son tags exist - if(ogmlTag->ownsOptionalTags()) - { - // find all obligatoric sons: all obligatoric sons - for (it = ogmlTag->getOptionalTags().begin(); it.valid(); ++it) - { - int cnt = 0; - - // search for untested sons - sonTag = xmlTag->m_pFirstSon; - while(sonTag) { - - if(sonTag->getName() == (**it).getName()) { - if((valid = validate(sonTag, (**it).getId())) < 0) - return valid; - cnt++; - } - sonTag = sonTag->m_pBrother; - } - - // Check cardinality - // if( (cnt<(**it).getMinOccurs() || cnt>(**it).getMaxOccurs()) ) { - if(cnt > (**it).getMaxOccurs()) { - this->printValidityInfo((**it), *xmlTag, valid = Ogml::vs_cardErr, __LINE__); - return valid; - } - } - } - - // Are there invalid son tags left? - sonTag = xmlTag->m_pFirstSon; - while(sonTag) { - // tag already valid - if(!sonTag->valid()) { - this->printValidityInfo(*ogmlTag, *xmlTag, valid = Ogml::vs_unexpTag, __LINE__); - return valid; - } - sonTag = sonTag->m_pBrother; - } - - // Finally xmlTag is valid :-) - xmlTag->setValid(); - -#ifdef OGDF_DEBUG - this->printValidityInfo(*ogmlTag, *xmlTag, valid = Ogml::vs_valid, __LINE__); -#endif - - return Ogml::vs_valid; -} - - -// -// v a l i d a t e -// -void OgmlParser::validate(const char *fileName) -{ - DinoXmlParser p(fileName); - p.createParseTree(); - - const XmlTagObject *root = &p.getRootTag(); - buildHashTables(); - validate(root, Ogml::t_ogml); -} - - -// -// o p e r a t o r < < -// -ostream& operator<<(ostream& os, const OgmlParser::OgmlAttribute& oa) -{ - oa.print(os); - return os; -} - -// -// o p e r a t o r < < -// -ostream& operator<<(ostream& os, const OgmlParser::OgmlTag& ot) -{ - ot.printOwnedTags(os); - ot.printOwnedAttributes(os); - return os; -} - - -// *********************************************************** -// -// p r i n t V a l i d i t y I n f o -// -// *********************************************************** -void OgmlParser::printValidityInfo(const OgmlTag & ot, const XmlTagObject & xto, int valStatus, int line) -{ - const String &ogmlTagName = ot.getName(); - - switch (valStatus) { - - case Ogml::vs_tagEmptIncl: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" expects tag(s) to include! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - ot.printOwnedTags(cerr); - break; - - case Ogml::vs_idNotUnique: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" owns already assigned id! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - break; - - case Ogml::vs_idRefErr: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" references unknown or wrong id! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - break; - - case Ogml::vs_unexpTag: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" owns unexpected tag! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - ot.printOwnedTags(cerr); - break; - - case Ogml::vs_unexpAtt: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" owns unexpected attribute(s)! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - ot.printOwnedAttributes(cerr); - break; - - case Ogml::vs_expTagNotFound: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" doesn't own compulsive tag(s)! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - ot.printOwnedTags(cerr); - break; - - case Ogml::vs_expAttNotFound: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" doesn't own compulsive attribute(s)! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - ot.printOwnedAttributes(cerr); - break; - - case Ogml::vs_attValueErr: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" owns attribute with wrong value! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - ot.printOwnedAttributes(cerr); - break; - - case Ogml::vs_cardErr: - cerr << "ERROR: tag \"<" << ogmlTagName << - ">\" occurence exceeds the number of min. (" << ot. - getMinOccurs() << ") or max. (" << ot.getMaxOccurs() << ") occurences in its context! "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - break; - - case Ogml::vs_invalid: - cerr << "ERROR: tag \"<" << ogmlTagName << ">\" is invalid! No further information available. "; - cerr << "(Input source line: " << xto. - getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - cerr << ot; - break; - - case Ogml::vs_valid: - //cout << "INFO: tag \"<" << ogmlTagName << ">\" is valid :-) "; - //cout << "(Input source line: " << xto. - // getLine() << ", recursion depth: " << xto.getDepth() << ")\n"; - break; - } - -#ifdef OGDF_DEBUG - if(valStatus != Ogml::vs_valid) - cout << "(Line OgmlParser::validate: " << line << ")\n"; -#endif -} - - - -// *********************************************************** -// -// i s G r a p h H i e r a r c h i c a l -// -// *********************************************************** -bool OgmlParser::isGraphHierarchical(const XmlTagObject *xmlTag) const -{ - if(xmlTag->getName() == Ogml::s_tagNames[Ogml::t_node] && isNodeHierarchical(xmlTag)) - return true; - - // Depth-Search only if ret!=true - if(xmlTag->m_pFirstSon && isGraphHierarchical(xmlTag->m_pFirstSon)) - return true; - - // Breadth-Search only if ret!=true - if(xmlTag->m_pBrother && isGraphHierarchical(xmlTag->m_pBrother)) - return true; - - return false; -} - - - -// *********************************************************** -// -// i s N o d e H i e r a r c h i c a l -// -// *********************************************************** -bool OgmlParser::isNodeHierarchical(const XmlTagObject *xmlTag) const -{ - bool ret = false; - if(xmlTag->getName() == Ogml::s_tagNames[Ogml::t_node]) { - - XmlTagObject* dum; - // check if an ancestor is a node - ret = xmlTag->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_node], dum); - } - - return ret; -} - - - -// *********************************************************** -// -// c h e c k G r a p h T y p e -// -// *********************************************************** -bool OgmlParser::checkGraphType(const XmlTagObject *xmlTag) const -{ - if(xmlTag->getName() != Ogml::s_tagNames[Ogml::t_ogml]) { - cerr << "ERROR: Expecting root tag \"" << Ogml::s_tagNames[Ogml::t_ogml] << "\" in OgmlParser::checkGraphType!\n"; - return false; - } - - // Normal graph present - if(!isGraphHierarchical(xmlTag)) { - m_graphType = Ogml::graph; - return true; - } - - // Cluster-/Compound graph present - m_graphType = Ogml::clusterGraph; - - // Traverse the parse tree and collect all edge tags - List edges; - if(xmlTag->getName() == Ogml::s_tagNames[Ogml::t_edge]) edges.pushBack(xmlTag); - XmlTagObject* son = xmlTag->m_pFirstSon; - while(son) { - if(son->getName() == Ogml::s_tagNames[Ogml::t_edge]) edges.pushBack(son); - son = son->m_pBrother; - } - - // Cluster graph already present - if(edges.empty()) return true; - - // Traverse edges - ListConstIterator edgeIt; - for(edgeIt = edges.begin(); edgeIt.valid() && m_graphType != Ogml::compoundGraph; edgeIt++) - { - // Traverse the sources/targets - son = (*edgeIt)->m_pFirstSon; - - // Parse tree is valid so one edge contains at least one source/target - // with idRef attribute - while(son) { - XmlAttributeObject* att; - if(son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeIdRef], att)) { - const XmlTagObject *refTag = m_ids.lookup(att->getValue())->info(); - if(isNodeHierarchical(refTag)) { - m_graphType = Ogml::compoundGraph; - break; - } - } - son = son->m_pBrother; - } - } - - return true; -} - - - -// *********************************************************** -// -// a u x i l i a r y m e t h o d s -// -// *********************************************************** -// => Mapping of OGML to OGDF <= - - -// Mapping Brush Pattern -int OgmlParser::getBrushPatternAsInt(String s) -{ - if (s == Ogml::s_attributeValueNames[Ogml::av_bpNone]) - return 0; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpSolid]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense1]) - return 2; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense2]) - return 3; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense3]) - return 4; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense4]) - return 5; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense5]) - return 6; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense6]) - return 7; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDense7]) - return 8; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpHorizontal]) - return 9; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpVertical]) - return 10; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpCross]) - return 11; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpBackwardDiagonal]) - return 12; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpForwardDiagonal]) - return 13; - if (s == Ogml::s_attributeValueNames[Ogml::av_bpDiagonalCross]) - return 14; - // default return bpSolid - return 1; -} - - -// Mapping Shape to Integer -int OgmlParser::getShapeAsInt(String s) -{ - //TODO: has to be completed if other shape types are implemented!!! - // SMALL PROBLEM: OGML DOESN'T SUPPORT SHAPES - // -> change XSD, if necessary - - if (s=="rect" || s=="rectangle") - return GraphAttributes::rectangle; - // default return rectangle - - return GraphAttributes::rectangle; -} - - -// Mapping OgmlNodeShape to OGDF::NodeTemplate -String OgmlParser::getNodeTemplateFromOgmlValue(String s) -{ - // Mapping OGML-Values to ogdf - // rect | triangle | circle | ellipse | hexagon | rhomb - // | trapeze | upTrapeze | lParallelogram | rParallelogram | pentagon - // | octagon | umlClass | image - if (s == Ogml::s_attributeValueNames[Ogml::av_rect]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_rectSimple]) - return "ogdf:std:rect simple"; - if (s == Ogml::s_attributeValueNames[Ogml::av_triangle]) - s = "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_circle]) - return "ogdf:std:ellipse"; - if (s == Ogml::s_attributeValueNames[Ogml::av_ellipse]) - return "ogdf:std:ellipse"; - if (s == Ogml::s_attributeValueNames[Ogml::av_hexagon]) - return "ogdf:std:hexagon"; - if (s == Ogml::s_attributeValueNames[Ogml::av_rhomb]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_trapeze]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_upTrapeze]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_lParallelogram]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_rParallelogram]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_pentagon]) - return "ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_octagon]) - return"ogdf:std:rect"; - if (s == Ogml::s_attributeValueNames[Ogml::av_umlClass]) - return "ogdf:std:UML class"; - if (s == Ogml::s_attributeValueNames[Ogml::av_image]) - return "ogdf:std:rect"; - // default - return "ogdf:std:rect"; -} - - -// Mapping Line type to Integer -int OgmlParser::getLineTypeAsInt(String s) -{ - if (s == Ogml::s_attributeValueNames[Ogml::av_esNoPen]) - return 0; - if (s == Ogml::s_attributeValueNames[Ogml::av_esSolid]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_esDash]) - return 2; - if (s == Ogml::s_attributeValueNames[Ogml::av_esDot]) - return 3; - if (s == Ogml::s_attributeValueNames[Ogml::av_esDashdot]) - return 4; - if (s == Ogml::s_attributeValueNames[Ogml::av_esDashdotdot]) - return 5; - // Mapping OGML-Values to ogdf - // solid | dotted | dashed | double | triple - // | groove | ridge | inset | outset | none - if (s == Ogml::s_attributeValueNames[Ogml::av_solid]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_dotted]) - return 3; - if (s == Ogml::s_attributeValueNames[Ogml::av_dashed]) - return 2; - if (s == Ogml::s_attributeValueNames[Ogml::av_double]) - return 4; - if (s == Ogml::s_attributeValueNames[Ogml::av_triple]) - return 5; - if (s == Ogml::s_attributeValueNames[Ogml::av_groove]) - return 5; - if (s == Ogml::s_attributeValueNames[Ogml::av_ridge]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_inset]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_outset]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_none]) - return 0; - //default return bpSolid - return 1; -} - - -// Mapping ArrowStyles to Integer -int OgmlParser::getArrowStyleAsInt(String s, String sot) -{ - // sot = "source" or "target", actually not necessary - // TODO: Complete, if new arrow styles are implemented in ogdf - if (s == "none") - return 0; - else - return 1; - // default return 0 - return 0; -} - - -// Mapping ArrowStyles to EdgeArrow -GraphAttributes::EdgeArrow OgmlParser::getArrowStyle(int i) -{ - switch (i){ - case 0: - return GraphAttributes::none; - break; - case 1: - return GraphAttributes::last; - break; - case 2: - return GraphAttributes::first; - break; - case 3: - return GraphAttributes::both; - break; - default: - return GraphAttributes::last; - } -} - - -// Mapping Image Style to Integer -int OgmlParser::getImageStyleAsInt(String s) -{ - if (s == Ogml::s_attributeValueNames[Ogml::av_freeScale]) - return 0; - if (s == Ogml::s_attributeValueNames[Ogml::av_fixScale]) - return 1; - //default return freeScale - return 0; -} - - -// Mapping Image Alignment to Integer -int OgmlParser::getImageAlignmentAsInt(String s) -{ - if (s == Ogml::s_attributeValueNames[Ogml::av_topLeft]) - return 0; - if (s == Ogml::s_attributeValueNames[Ogml::av_topCenter]) - return 1; - if (s == Ogml::s_attributeValueNames[Ogml::av_topRight]) - return 2; - if (s == Ogml::s_attributeValueNames[Ogml::av_centerLeft]) - return 3; - if (s == Ogml::s_attributeValueNames[Ogml::av_center]) - return 4; - if (s == Ogml::s_attributeValueNames[Ogml::av_centerRight]) - return 5; - if (s == Ogml::s_attributeValueNames[Ogml::av_bottomLeft]) - return 6; - if (s == Ogml::s_attributeValueNames[Ogml::av_bottomCenter]) - return 7; - if (s == Ogml::s_attributeValueNames[Ogml::av_bottomRight]) - return 8; - //default return center - return 4; -} - - -// returns the string with "<" substituted for "<" -// and ">" substituted for ">" -String OgmlParser::getLabelCaptionFromString(String str) -{ - String output; - size_t i=0; - while (i it; - - if(!root) { - cout << "WARNING: can't determine layout information, no parse tree available!\n"; - - } else { - // root tag isn't a NULL pointer... let's start... - XmlTagObject* son = root->m_pFirstSon; - // first traverse to the structure- and the layout block - if (son->getName() != Ogml::s_tagNames[Ogml::t_graph]){ - while (son->getName() != Ogml::s_tagNames[Ogml::t_graph]){ - son = son->m_pFirstSon; - if (!son){ - // wrong rootTag given or graph tag wasn't found - return false; - } - } //while - } //if - - // now son is the graph tag which first child is structure - XmlTagObject* structure = son->m_pFirstSon; - if (structure->getName() != Ogml::s_tagNames[Ogml::t_structure]){ - return false; - } - // now structure is what it is meant to be - // traverse the children of structure - // and set the labels - son = structure->m_pFirstSon; - while(son) - { - //Set labels of nodes - if ((son->getName() == Ogml::s_tagNames[Ogml::t_node]) && (CGA.attributes() & GraphAttributes::nodeLabel)) - { - if (!isNodeHierarchical(son)) - { - // get the id of the actual node - XmlAttributeObject *att; - if(son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att)) - { - // lookup for node - node actNode = (m_nodes.lookup(att->getValue()))->info(); - // find label tag - XmlTagObject* label; - if (son->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_label], label)) - { - // get content tag - XmlTagObject* content = label->m_pFirstSon; - // get the content as string - if (content->m_pTagValue) { - String str = content->getValue(); - String labelStr = getLabelCaptionFromString(str); - // now set the label of the node - CGA.labelNode(actNode) = labelStr; - } - } - } - }// "normal" nodes - else - { - // get the id of the actual cluster - XmlAttributeObject *att; - if(son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att)) - { - // lookup for cluster - cluster actCluster = (m_clusters.lookup(att->getValue()))->info(); - // find label tag - XmlTagObject* label; - if (son->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_label], label)) - { - // get content tag - XmlTagObject* content = label->m_pFirstSon; - // get the content as string - if (content->m_pTagValue) { - String str = content->getValue(); - String labelStr = getLabelCaptionFromString(str); - // now set the label of the node - CGA.clusterLabel(actCluster) = labelStr; - } - } - } - // hierSon = hierarchical Son - XmlTagObject *hierSon; - if (son->m_pFirstSon) - { - hierSon = son->m_pFirstSon; - while(hierSon) { - // recursive call for setting labels of child nodes - if (!setLabelsRecursive(G, CGA, hierSon)) - return false; - hierSon = hierSon->m_pBrother; - } - } - }//cluster nodes - }// node labels - - //Set labels of edges - if ((son->getName() == Ogml::s_tagNames[Ogml::t_edge]) && (CGA.attributes() & GraphAttributes::edgeLabel)) - { - // get the id of the actual edge - XmlAttributeObject *att; - if (son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att)) - { - // lookup for edge - // 0, if (hyper)edge not read from file - if(m_edges.lookup(att->getValue())){ - edge actEdge = (m_edges.lookup(att->getValue()))->info(); - // find label tag - XmlTagObject* label; - if(son->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_label], label)) - { - // get content tag - XmlTagObject* content = label->m_pFirstSon; - // get the content as string - if (content->m_pTagValue) { - String str = content->getValue(); - String labelStr = getLabelCaptionFromString(str); - // now set the label of the node - CGA.labelEdge(actEdge) = labelStr; - } - } - } - } - }// edge labels - - // Labels - // ACTUALLY NOT IMPLEMENTED IN OGDF - //if (son->getName() == Ogml::s_tagNames[t_label]) { - // get the id of the actual edge - //XmlAttributeObject *att; - //if (son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att)){ - // lookup for label - //label actLabel = (labels.lookup(att->getValue()))->info(); - // get content tag - //XmlTagObject* content = son->m_pFirstSon; - // get the content as string - //if (content->m_pTagValue){ - //String str = content->getValue(); - //String labelStr = getLabelCaptionFromString(str); - //now set the label of the node - // CGA.labelLabel(actLabel) = labelStr; - //} - //} - //}// Labels - - // go to the next brother - son = son->m_pBrother; - }// while(son) // son <=> children of structure - - // get the layout tag - XmlTagObject* layout; - if (structure->m_pBrother != NULL) { - layout = structure->m_pBrother; - } - - if ((layout) && (layout->getName() == Ogml::s_tagNames[Ogml::t_layout])) - { - // layout exists - - // first get the styleTemplates - XmlTagObject *layoutSon; - if (layout->m_pFirstSon) - { - // layout has at least one child-tag - layoutSon = layout->m_pFirstSon; - // ->loop through all of them - while (layoutSon) - { - // style templates - if (layoutSon->getName() == Ogml::s_tagNames[Ogml::t_styleTemplates]) - { - // has children data, nodeStyleTemplate, edgeStyleTemplate, labelStyleTemplate - XmlTagObject *styleTemplatesSon; - if (layoutSon->m_pFirstSon) - { - styleTemplatesSon = layoutSon->m_pFirstSon; - - while (styleTemplatesSon) - { - // nodeStyleTemplate - if (styleTemplatesSon->getName() == Ogml::s_tagNames[Ogml::t_nodeStyleTemplate]) - { - XmlAttributeObject *actAtt; - if (styleTemplatesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], actAtt)) - { - const String &actKey = actAtt->getValue(); - OgmlNodeTemplate *actTemplate = new OgmlNodeTemplate(actKey); // when will this be deleted? - - XmlTagObject *actTag; - - // template inheritance - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_nodeStyleTemplateRef], actTag)) - { - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeStyleTemplateIdRef], actAtt)) { - // actual template references another - // get it from the hash table - OgmlNodeTemplate *refTemplate = m_ogmlNodeTemplates.lookup(actAtt->getValue())->info(); - if (refTemplate) { - // the referenced template was inserted into the hash table - // so copy the values - String actId = actTemplate->m_id; - *actTemplate = *refTemplate; - actTemplate->m_id = actId; - } - } - }// template inheritance - - // // data - // if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[t_data], actTag)){ - // // found data for nodeStyleTemplate - // // no implementation required for ogdf - // }// data - - // shape tag - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_shape], actTag)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nShapeType], actAtt)) { - // TODO: change, if shapes are expanded - // actually shape and template are calculated from the same value!!! - actTemplate->m_nodeTemplate = getNodeTemplateFromOgmlValue(actAtt->getValue()); - actTemplate->m_shapeType = getShapeAsInt(actAtt->getValue()); - } - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - actTemplate->m_width = atof(actAtt->getValue().cstr()); - // height - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_height], actAtt)) - actTemplate->m_height = atof(actAtt->getValue().cstr()); - // uri - //ACTUALLY NOT SUPPORTED - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_uri], actAtt)) - // CGA.uri(actNode) = actAtt->getValue(); - }// shape - - // fill tag - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_fill], actTag)) - { - // fill color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - actTemplate->m_color = actAtt->getValue(); - // fill pattern - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_pattern], actAtt)) - actTemplate->m_pattern = GraphAttributes::intToPattern(getBrushPatternAsInt(actAtt->getValue())); - // fill patternColor - //TODO: check if pattern color exists - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_patternColor], actAtt)); - // actTemplate->m_patternColor = actAtt->getValue()); - }// fill - - // line tag - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_line], actTag)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nLineType], actAtt)) - actTemplate->m_lineType = GraphAttributes::intToStyle(getLineTypeAsInt(actAtt->getValue())); - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - actTemplate->m_lineWidth = atof(actAtt->getValue().cstr()); - // color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - actTemplate->m_lineColor = actAtt->getValue(); - }// line - - //insert actual template into hash table - m_ogmlNodeTemplates.fastInsert(actKey, actTemplate); - } - }//nodeStyleTemplate - - // edgeStyleTemplate - if (styleTemplatesSon->getName() == Ogml::s_tagNames[Ogml::t_edgeStyleTemplate]) - { - XmlAttributeObject *actAtt; - if (styleTemplatesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], actAtt)) - { - const String &actKey = actAtt->getValue(); - OgmlEdgeTemplate *actTemplate = new OgmlEdgeTemplate(actKey); // when will this be deleted? - - XmlTagObject *actTag; - - // template inheritance - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_edgeStyleTemplateRef], actTag)){ - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_edgeStyleTemplateIdRef], actAtt)){ - // actual template references another - // get it from the hash table - OgmlEdgeTemplate *refTemplate = m_ogmlEdgeTemplates.lookup(actAtt->getValue())->info(); - if (refTemplate){ - // the referenced template was inserted into the hash table - // so copy the values - String actId = actTemplate->m_id; - *actTemplate = *refTemplate; - actTemplate->m_id = actId; - } - } - }// template inheritance - - // // data - // if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[t_data], actTag)){ - // // found data for edgeStyleTemplate - // // no implementation required for ogdf - // }// data - - // line tag - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_line], actTag)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_type], actAtt)) - actTemplate->m_lineType = GraphAttributes::intToStyle(getLineTypeAsInt(actAtt->getValue())); - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - actTemplate->m_lineWidth = atof(actAtt->getValue().cstr()); - // color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - actTemplate->m_color = actAtt->getValue(); - }// line - - // sourceStyle tag - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_sourceStyle], actTag)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_type], actAtt)) - actTemplate->m_sourceType = getArrowStyleAsInt(actAtt->getValue(), Ogml::s_tagNames[Ogml::t_source]); - // color - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_color], actAtt)) - // actTemplate->m_sourceColor = actAtt->getValue(); - // size - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_size], actAtt)) - // actTemplate->m_sourceSize = atof(actAtt->getValue()); - } - - // targetStyle tag - if (styleTemplatesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_targetStyle], actTag)){ - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_type], actAtt)) - actTemplate->m_targetType = getArrowStyleAsInt(actAtt->getValue(), Ogml::s_tagNames[Ogml::t_target]); - // color - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_color], actAtt)) - // actTemplate->m_targetColor = actAtt->getValue(); - // size - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_size], actAtt)) - // actTemplate->m_targetSize = atof(actAtt->getValue()); - } - - //insert actual template into hash table - m_ogmlEdgeTemplates.fastInsert(actKey, actTemplate); - } - - }//edgeStyleTemplate - - // labelStyleTemplate - if (styleTemplatesSon->getName() == Ogml::s_tagNames[Ogml::t_labelStyleTemplate]){ - // ACTUALLY NOT SUPPORTED - }//labelStyleTemplate - - styleTemplatesSon = styleTemplatesSon->m_pBrother; - } - } - }// styleTemplates - - //STYLES - if (layoutSon->getName() == Ogml::s_tagNames[Ogml::t_styles]) - { - // has children graphStyle, nodeStyle, edgeStyle, labelStyle - XmlTagObject *stylesSon; - if (layoutSon->m_pFirstSon) - { - stylesSon = layoutSon->m_pFirstSon; - - while (stylesSon) - { - // GRAPHSTYLE - if (stylesSon->getName() == Ogml::s_tagNames[Ogml::t_graphStyle]) - { - XmlAttributeObject *actAtt; - // defaultNodeTemplate - if (stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_defaultNodeTemplate], actAtt)) - { - OgmlNodeTemplate* actTemplate = m_ogmlNodeTemplates.lookup(actAtt->getValue())->info(); - - // XmlTagObject *actTag; - // // data - // if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[t_data], actTag)){ - // // found data for graphStyle - // // no implementation required for ogdf - // }// data - - // set values for ALL nodes - node v; - forall_nodes(v, G){ - - if (CGA.attributes() & GraphAttributes::nodeType){ - CGA.templateNode(v) = actTemplate->m_nodeTemplate; - CGA.shapeNode(v) = actTemplate->m_shapeType; - } - if (CGA.attributes() & GraphAttributes::nodeGraphics){ - CGA.width(v) = actTemplate->m_width; - CGA.height(v) = actTemplate->m_height; - } - if (CGA.attributes() & GraphAttributes::nodeColor) - CGA.colorNode(v) = actTemplate->m_color; - if (CGA.attributes() & GraphAttributes::nodeStyle){ - CGA.nodePattern(v) = actTemplate->m_pattern; - //CGA.nodePatternColor(v) = actTemplate->m_patternColor; - CGA.styleNode(v) = actTemplate->m_lineType; - CGA.lineWidthNode(v) = actTemplate->m_lineWidth; - CGA.nodeLine(v) = actTemplate->m_lineColor; - } - }// forall_nodes - }// defaultNodeTemplate - - // // defaultClusterTemplate - // if (stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_defaultCompoundTemplate], actAtt)){ - // // OgmlNodeTemplate* actTemplate = m_ogmlNodeTemplates.lookup(actAtt->getValue())->info(); - // // // set values for ALL Cluster - // cluster c; - // forall_clusters(c, G){ - // - // if (CGA.attributes() & GraphAttributes::nodeType){ - // CGA.templateCluster(c) = actTemplate->m_nodeTemplate; - // // no shape definition for clusters - // //CGA.shapeNode(c) = actTemplate->m_shapeType; - // } - // if (CGA.attributes() & GraphAttributes::nodeGraphics){ - // CGA.clusterWidth(c) = actTemplate->m_width; - // CGA.clusterHeight(c) = actTemplate->m_height; - // } - // if (CGA.attributes() & GraphAttributes::nodeColor) - // CGA.clusterFillColor(c) = actTemplate->m_color; - // if (CGA.attributes() & GraphAttributes::nodeStyle){ - // CGA.clusterFillPattern(c) = actTemplate->m_pattern; - // CGA.clusterBackColor(c) = actTemplate->m_patternColor; - // CGA.clusterLineStyle(c) = actTemplate->m_lineType; - // CGA.clusterLineWidth(c) = actTemplate->m_lineWidth; - // CGA.clusterColor(c) = actTemplate->m_lineColor; - // } - // }// forall_clusters - // }// defaultClusterTemplate - - - // defaultEdgeTemplate - if (stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_defaultEdgeTemplate], actAtt)) - { - OgmlEdgeTemplate* actTemplate = m_ogmlEdgeTemplates.lookup(actAtt->getValue())->info(); - - // set values for ALL edges - edge e; - forall_edges(e, G) - { - if (CGA.attributes() & GraphAttributes::edgeStyle) { - CGA.styleEdge(e) = actTemplate->m_lineType; - CGA.edgeWidth(e) = actTemplate->m_lineWidth; - } - if (CGA.attributes() & GraphAttributes::edgeColor) { - CGA.colorEdge(e) = actTemplate->m_color; - } - - //edgeArrow - if ((CGA.attributes()) & (GraphAttributes::edgeArrow)) - { - if (actTemplate->m_sourceType == 0) { - if (actTemplate->m_targetType == 0) { - // source = no_arrow, target = no_arrow // =>none - CGA.arrowEdge(e) = GraphAttributes::none; - } - else { - // source = no_arrow, target = arrow // =>last - CGA.arrowEdge(e) = GraphAttributes::last; - } - } - else { - if (actTemplate->m_targetType == 0){ - // source = arrow, target = no_arrow // =>first - CGA.arrowEdge(e) = GraphAttributes::first; - } - else { - // source = arrow, target = arrow // =>both - CGA.arrowEdge(e) = GraphAttributes::both; - } - } - }//edgeArrow - }//forall_edges - }//defaultEdgeTemplate - - // defaultLabelTemplate - //if (stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_defaultLabelTemplate], actAtt)){ - // // set values for ALL labels - // // ACTUALLY NOT IMPLEMENTED - // label l; - // forall_labels(l, G){ - // - // } - //}//defaultLabelTemplate - }// graphStyle - - // NODESTYLE - if (stylesSon->getName() == Ogml::s_tagNames[Ogml::t_nodeStyle]) - { - // get the id of the actual node - XmlAttributeObject *att; - if(stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeIdRef], att)) - { - // check if referenced id is a node or a cluster/compound - if (m_nodes.lookup(att->getValue())) - { - // lookup for node - node actNode = (m_nodes.lookup(att->getValue()))->info(); - - // actTag is the actual tag that is considered - XmlTagObject* actTag; - XmlAttributeObject *actAtt; - - // // data - // if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[t_data], actTag)){ - // // found data for nodeStyle - // // no implementation required for ogdf - // }// data - - // check if actual nodeStyle references a template - if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_nodeStyleTemplateRef], actTag)) - { - // get referenced template id - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeStyleTemplateIdRef], actAtt)) - { - // actual nodeStyle references a template - OgmlNodeTemplate* actTemplate = m_ogmlNodeTemplates.lookup(actAtt->getValue())->info(); - if (CGA.attributes() & GraphAttributes::nodeType) { - CGA.templateNode(actNode) = actTemplate->m_nodeTemplate; - CGA.shapeNode(actNode) = actTemplate->m_shapeType; - } - if (CGA.attributes() & GraphAttributes::nodeGraphics) { - CGA.width(actNode) = actTemplate->m_width; - CGA.height(actNode) = actTemplate->m_height; - } - if (CGA.attributes() & GraphAttributes::nodeColor) - CGA.colorNode(actNode) = actTemplate->m_color; - if (CGA.attributes() & GraphAttributes::nodeStyle) { - CGA.nodePattern(actNode) = actTemplate->m_pattern; - //CGA.nodePatternColor(actNode) = actTemplate->m_patternColor; - CGA.styleNode(actNode) = actTemplate->m_lineType; - CGA.lineWidthNode(actNode) = actTemplate->m_lineWidth; - CGA.nodeLine(actNode) = actTemplate->m_lineColor; - } - } - }//template - - // Graph::nodeType - //TODO: COMPLETE, IF NECESSARY - CGA.type(actNode) = Graph::vertex; - - // location tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_location], actTag)) - && (CGA.attributes() & GraphAttributes::nodeGraphics)) - { - // set location of node - // x - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_x], actAtt)) - CGA.x(actNode) = atof(actAtt->getValue().cstr()); - // y - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_y], actAtt)) - CGA.y(actNode) = atof(actAtt->getValue().cstr()); - // z - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_x], actAtt)) - //CGA.z(actNode) = atof(actAtt->getValue()); - }// location - - // shape tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_shape], actTag)) - && (CGA.attributes() & GraphAttributes::nodeType)) - { - // set shape of node - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nShapeType], actAtt)) { - CGA.templateNode(actNode) = getNodeTemplateFromOgmlValue(actAtt->getValue()); - // TODO: change, if shapes are expanded - // actually shape and template are calculated from the same value!!! - CGA.shapeNode(actNode) = getShapeAsInt(actAtt->getValue()); - } - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - CGA.width(actNode) = atof(actAtt->getValue().cstr()); - // height - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_height], actAtt)) - CGA.height(actNode) = atof(actAtt->getValue().cstr()); - // uri - //ACTUALLY NOT SUPPORTED - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_uri], actAtt)) - // CGA.uri(actNode) = actAtt->getValue(); - }// shape - - // fill tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_fill], actTag)) - && (CGA.attributes() & GraphAttributes::nodeStyle)) - { - // fill color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - CGA.colorNode(actNode) = actAtt->getValue(); - // fill pattern - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_pattern], actAtt)) - CGA.nodePattern(actNode) = GraphAttributes::intToPattern(getBrushPatternAsInt(actAtt->getValue())); - // fill patternColor - //TODO: check if pattern color exists - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_patternColor], actAtt)) - // CGA.nodePatternColor(actNode) = actAtt->getValue()); - }// fill - - // line tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_line], actTag)) - && (CGA.attributes() & GraphAttributes::nodeStyle)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nLineType], actAtt)) - CGA.styleNode(actNode) = GraphAttributes::intToStyle(getLineTypeAsInt(actAtt->getValue())); - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - CGA.lineWidthNode(actNode) = atof(actAtt->getValue().cstr()); - // color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - CGA.nodeLine(actNode) = actAtt->getValue().cstr(); - }// line - - // // ports - // // go through all ports with dummy tagObject port - // XmlTagObject* port = stylesSon->m_pFirstSon; - // while(port){ - // if (port->getName() == ogmlTagObjects[t_port]){ - // // TODO: COMPLETE - // // ACTUALLY NOT IMPLEMENTED IN OGDF - // } - // - // // go to next tag - // port = port->m_pBrother; - // } - - } - else - - // CLUSTER NODE STYLE - { - // get the id of the cluster/compound - XmlAttributeObject *att; - if(stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeIdRef], att)) - { - // lookup for node - cluster actCluster = (m_clusters.lookup(att->getValue()))->info(); - // actTag is the actual tag that is considered - XmlTagObject* actTag; - XmlAttributeObject *actAtt; - - // // data - // if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[t_data], actTag)){ - // // found data for nodeStyle (CLuster/Compound) - // // no implementation required for ogdf - // }// data - - // check if actual nodeStyle (equal to cluster) references a template - if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_nodeStyleTemplateRef], actTag)) - { - // get referenced template id - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeStyleTemplateIdRef], actAtt)) - { - // actual nodeStyle references a template - OgmlNodeTemplate* actTemplate = m_ogmlNodeTemplates.lookup(actAtt->getValue())->info(); - if (CGA.attributes() & GraphAttributes::nodeType) { - CGA.templateCluster(actCluster) = actTemplate->m_nodeTemplate; - // no shape definition for clusters - //CGA.shapeNode(actCluster) = actTemplate->m_shapeType; - } - if (CGA.attributes() & GraphAttributes::nodeGraphics) { - CGA.clusterWidth(actCluster) = actTemplate->m_width; - CGA.clusterHeight(actCluster) = actTemplate->m_height; - } - if (CGA.attributes() & GraphAttributes::nodeColor) - CGA.clusterFillColor(actCluster) = actTemplate->m_color; - if (CGA.attributes() & GraphAttributes::nodeStyle) { - CGA.clusterFillPattern(actCluster) = actTemplate->m_pattern; - CGA.clusterBackColor(actCluster) = actTemplate->m_patternColor; - CGA.clusterLineStyle(actCluster) = actTemplate->m_lineType; - CGA.clusterLineWidth(actCluster) = actTemplate->m_lineWidth; - CGA.clusterColor(actCluster) = actTemplate->m_lineColor; - } - } - }//template - - // Graph::nodeType - //TODO: COMPLETE, IF NECESSARY - // not supported for clusters!!! - //CGA.type(actCluster) = Graph::vertex; - - // location tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_location], actTag)) - && (CGA.attributes() & GraphAttributes::nodeGraphics)) - { - // set location of node - // x - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_x], actAtt)) - CGA.clusterXPos(actCluster) = atof(actAtt->getValue().cstr()); - // y - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_y], actAtt)) - CGA.clusterYPos(actCluster) = atof(actAtt->getValue().cstr()); - // z - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_x], actAtt)) - //CGA.clusterZPos(actCluster) = atof(actAtt->getValue()); - }// location - - // shape tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_shape], actTag)) - && (CGA.attributes() & GraphAttributes::nodeType)) - { - // set shape of node - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nShapeType], actAtt)) { - CGA.templateCluster(actCluster) = getNodeTemplateFromOgmlValue(actAtt->getValue().cstr()); - // no shape definition for clusters - //CGA.shapeNode(actCluster) = getShapeAsInt(actAtt->getValue()); - } - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - CGA.clusterWidth(actCluster) = atof(actAtt->getValue().cstr()); - // height - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_height], actAtt)) - CGA.clusterHeight(actCluster) = atof(actAtt->getValue().cstr()); - // uri - //ACTUALLY NOT SUPPORTED - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_uri], actAtt)) - // CGA.uriCluster(actCluster) = actAtt->getValue(); - }// shape - - // fill tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_fill], actTag)) - && (CGA.attributes() & GraphAttributes::nodeStyle)) - { - // fill color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - CGA.clusterFillColor(actCluster) = actAtt->getValue().cstr(); - // fill pattern - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_pattern], actAtt)) - CGA.clusterFillPattern(actCluster) = GraphAttributes::intToPattern(getBrushPatternAsInt(actAtt->getValue())); - // fill patternColor - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_patternColor], actAtt)) - CGA.clusterBackColor(actCluster) = actAtt->getValue().cstr(); - }// fill - - // line tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_line], actTag)) - && (CGA.attributes() & GraphAttributes::nodeStyle)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nLineType], actAtt)) - CGA.clusterLineStyle(actCluster) = GraphAttributes::intToStyle(getLineTypeAsInt(actAtt->getValue())); - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - CGA.clusterLineWidth(actCluster) = atof(actAtt->getValue().cstr()); - // color - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - CGA.clusterColor(actCluster) = actAtt->getValue(); - }// line - - - // // ports - // // go through all ports with dummy tagObject port - // XmlTagObject* port = stylesSon->m_pFirstSon; - // while(port){ - // if (port->getName() == ogmlTagObjects[t_port]){ - // // TODO: COMPLETE - // // no implementation required for ogdf - // } - // - // // go to next tag - // port = port->m_pBrother; - // } - - }//nodeIdRef (with cluster) - - }// nodeStyle for cluster - }//nodeIdRef - - }//nodeStyle - - // EDGESTYLE - if (stylesSon->getName() == Ogml::s_tagNames[Ogml::t_edgeStyle]) - { - // get the id of the actual edge - XmlAttributeObject *att; - if(stylesSon->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_edgeIdRef], att)) - { - // lookup for edge - edge actEdge = (m_edges.lookup(att->getValue()))->info(); - - // actTag is the actual tag that is considered - XmlTagObject* actTag; - XmlAttributeObject *actAtt; - - // // data - // if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[t_data], actTag)){ - // // found data for edgeStyle - // // no implementation required for ogdf - // }// data - - // check if actual edgeStyle references a template - if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_edgeStyleTemplateRef], actTag)) - { - // get referenced template id - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_edgeStyleTemplateIdRef], actAtt)) - { - // actual edgeStyle references a template - OgmlEdgeTemplate* actTemplate = m_ogmlEdgeTemplates.lookup(actAtt->getValue())->info(); - if (CGA.attributes() & GraphAttributes::edgeStyle) { - CGA.styleEdge(actEdge) = actTemplate->m_lineType; - CGA.edgeWidth(actEdge) = actTemplate->m_lineWidth; - } - if (CGA.attributes() & GraphAttributes::edgeColor) { - CGA.colorEdge(actEdge) = actTemplate->m_color; - } - - //edgeArrow - if ((CGA.attributes()) & (GraphAttributes::edgeArrow)) - { - if (actTemplate->m_sourceType == 0) { - if (actTemplate->m_targetType == 0) { - // source = no_arrow, target = no_arrow // =>none - CGA.arrowEdge(actEdge) = GraphAttributes::none; - } - else { - // source = no_arrow, target = arrow // =>last - CGA.arrowEdge(actEdge) = GraphAttributes::last; - } - } - else { - if (actTemplate->m_targetType == 0) { - // source = arrow, target = no_arrow // =>first - CGA.arrowEdge(actEdge) = GraphAttributes::first; - } - else { - // source = arrow, target = arrow // =>both - CGA.arrowEdge(actEdge) = GraphAttributes::both; - } - } - }//edgeArrow - - } - }//template - - // Graph::edgeType - //TODO: COMPLETE, IF NECESSARY - CGA.type(actEdge) = Graph::association; - - // line tag - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_line], actTag)) - && (CGA.attributes() & GraphAttributes::edgeType)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nLineType], actAtt)) - CGA.styleEdge(actEdge) = GraphAttributes::intToStyle(getLineTypeAsInt(actAtt->getValue())); - // width - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_width], actAtt)) - CGA.edgeWidth(actEdge) = atof(actAtt->getValue().cstr()); - // color - if ((actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_color], actAtt)) - && (CGA.attributes() & GraphAttributes::edgeType)) - CGA.colorEdge(actEdge) = actAtt->getValue(); - }// line - - // mapping of arrows - if (CGA.attributes() & GraphAttributes::edgeArrow) - { - // values for mapping edge arrows to GDE - // init to -1 for a simple check - int sourceInt = -1; - int targetInt = -1; - - // sourceStyle tag - if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_sourceStyle], actTag)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_type], actAtt)) - sourceInt = getArrowStyleAsInt((actAtt->getValue()), Ogml::s_attributeNames[Ogml::t_source]); - // color - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_color], actAtt)) - // ; - // size - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_size], actAtt)) - // ; - }// sourceStyle - - // targetStyle tag - if (stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_targetStyle], actTag)) - { - // type - if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_type], actAtt)) - targetInt = getArrowStyleAsInt((actAtt->getValue()), Ogml::s_attributeNames[Ogml::t_target]); - // color - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_color], actAtt)) - // ; - // size - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_size], actAtt)) - // ; - }// targetStyle - - // map edge arrows - if ((sourceInt != -1) || (targetInt != -1)) - { - if (sourceInt <= 0) { - if (targetInt <= 0) { - //source=no arrow, target=no arrow // => none - CGA.arrowEdge(actEdge) = GraphAttributes::none; - } - else { - // source=no arrow, target=arrow // => last - CGA.arrowEdge(actEdge) = GraphAttributes::last; - } - } - else { - if (targetInt <= 0) { - //source=arrow, target=no arrow // => first - CGA.arrowEdge(actEdge) = GraphAttributes::first; - } - else { - //source=target=arrow // => both - CGA.arrowEdge(actEdge) = GraphAttributes::both; - } - } - } - }//arrow - - // points & segments - // bool value for checking if segments exist - bool segmentsExist = stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_segment], actTag); - if ((stylesSon->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_point], actTag)) - && (CGA.attributes() & GraphAttributes::edgeGraphics)) - { - // at least one point exists - XmlTagObject *pointTag = stylesSon->m_pFirstSon; - DPolyline dpl; - dpl.clear(); - // traverse all points in the order given in the ogml file - while (pointTag) - { - if (pointTag->getName() == Ogml::s_tagNames[Ogml::t_point]) - { - - if (pointTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], actAtt)) { - DPoint dp; - // here we have a point - if (pointTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_x], actAtt)) { - dp.m_x = atof(actAtt->getValue().cstr()); - } - if (pointTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_y], actAtt)) { - dp.m_y = atof(actAtt->getValue().cstr()); - } - //if (actTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_z], actAtt)) - // dp.m_z = atof(actAtt->getValue()); - // insert point into hash table - pointTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], actAtt); - m_points.fastInsert(actAtt->getValue(), dp); - //insert point into polyline - if (!segmentsExist) - dpl.pushBack(dp); - } - } - // go to next tag - pointTag = pointTag->m_pBrother; - }// while (pointTag) - //concatenate polyline - if (!segmentsExist) { - CGA.bends(actEdge).conc(dpl); - } - else{ - // work with segments - // one error can occur: - // if a segments is going to be inserted, - // which doesn't match with any other, - // the order can be not correct at the end - // then the edge is relly corrupted!! - - // TODO: this implementation doesn't work with hyperedges - // cause hyperedges have more than one source/target - - // segmentsUnsorted stores all found segments - List segmentsUnsorted; - XmlTagObject *segmentTag = stylesSon->m_pFirstSon; - while (segmentTag) - { - if (segmentTag->getName() == Ogml::s_tagNames[Ogml::t_segment]) - { - XmlTagObject *endpointTag = segmentTag->m_pFirstSon; - OgmlSegment actSeg; - int endpointsSet = 0; - while ((endpointTag) && (endpointsSet <2)) { - if (endpointTag->getName() == Ogml::s_tagNames[Ogml::t_endpoint]) { - // get the referenced point - endpointTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_endpointIdRef], actAtt); - DPoint dp = (m_points.lookup(actAtt->getValue()))->info(); - - if (endpointsSet == 0) - actSeg.point1 = dp; - else - actSeg.point2 = dp; - endpointsSet++; - } - endpointTag = endpointTag->m_pBrother; - }// while - // now we created a segment - // we can insert this easily into in segmentsUnsorted - if (actSeg.point1 != actSeg.point2) { - segmentsUnsorted.pushBack(actSeg); - } // point1 != point2 - }// if (segment) - // go to next tag - segmentTag = segmentTag->m_pBrother; - }// while (segmentTag) - // now are the segments stored in the segmentsUnsorted list - // but we have to sort it in segments list while inserting - List segments; - ListIterator segIt; - // check the number of re-insertions - int checkNumOfSegReInserts = segmentsUnsorted.size()+2; - while ((segmentsUnsorted.size() > 0) && (checkNumOfSegReInserts > 0)) - { - OgmlSegment actSeg = segmentsUnsorted.front(); - segmentsUnsorted.popFront(); - // actSeg has to be inserted in correct order - // and then being deleted - // OR waiting in list until it can be inserted - // size == 0 => insert - if (segments.size() == 0) { - segments.pushFront(actSeg); - } - else { - // segments contains >1 segment - segIt = segments.begin(); - bool inserted = false; - while (segIt.valid() && !inserted) - { - if ((actSeg.point1 == (*segIt).point1) || - (actSeg.point1 == (*segIt).point2) || - (actSeg.point2 == (*segIt).point1) || - (actSeg.point2 == (*segIt).point2)) - { - // found two matching segments - // now we can insert - // there are some cases to check - if (actSeg.point1 == (*segIt).point1) { - DPoint dumP = actSeg.point1; - actSeg.point1 = actSeg.point2; - actSeg.point2 = dumP; - segments.insertBefore(actSeg, segIt); - } - else - if (actSeg.point2 == (*segIt).point1) { - segments.insertBefore(actSeg, segIt); - } - else - if ((actSeg.point2 == (*segIt).point2)) { - DPoint dumP = actSeg.point1; - actSeg.point1 = actSeg.point2; - actSeg.point2 = dumP; - segments.insertAfter(actSeg, segIt); - } - else { - segments.insertAfter(actSeg, segIt); - } - inserted = true; - } // first if - segIt++; - } //while - if (!inserted) { - // segment doesn't found matching segment, - // so insert it again into unsorted segments list - // so it will be inserted later - segmentsUnsorted.pushBack(actSeg); - checkNumOfSegReInserts--; - } - }//else - }//while segmentsUnsorted.size() > 0 - - - if (checkNumOfSegReInserts==0){ - cout << "WARNING! Segment definition is not correct" << endl << flush; - cout << "Not able to work with #"<< segmentsUnsorted.size() << " segments" << endl << flush; - cout << "Please check connection and sorting of segments!" << endl << flush; - // // inserting the bends although there might be an error - // // I commented this, because in this case in ogdf the edge will - // // be a straight edge and there will not be any artefacts - // // TODO: uncomment if desired - // for (segIt = segments.begin(); segIt.valid(); segIt++){ - // dpl.pushBack((*segIt).point1); - // dpl.pushBack((*segIt).point2); - } - else { - // the segments are now ordered (perhaps in wrong way)... - // so we have to check if the first and last point - // are graphically laying in the source- and target- node - bool invertSegments = false; - segIt = segments.begin(); - node target = actEdge->target(); - node source = actEdge->source(); - // check if source is a normal node or a cluster - //if (...){ - - //} - //else{ - // big if-check: if (first point is in target - // and not in source) - // AND - // (last point is in source - // and not in target) - if (( ( (CGA.x(target) + CGA.width(target))>= (*segIt).point1.m_x ) - && (CGA.x(target) <= (*segIt).point1.m_x ) - && ( (CGA.y(target) + CGA.height(target))>= (*segIt).point1.m_y ) - && (CGA.y(target) <= (*segIt).point1.m_y ) ) - && - (!( ( (CGA.x(source) + CGA.width(source))>= (*segIt).point1.m_x ) - && (CGA.x(source) <= (*segIt).point1.m_x ) - && ( (CGA.y(source) + CGA.height(source))>= (*segIt).point1.m_y ) - && (CGA.y(source) <= (*segIt).point1.m_y ) ))) - { - segIt = segments.rbegin(); - if (( ( (CGA.x(source) + CGA.width(source))>= (*segIt).point2.m_x ) - && (CGA.x(source) <= (*segIt).point2.m_x ) - && ( (CGA.y(source) + CGA.height(source))>= (*segIt).point2.m_y ) - && (CGA.y(source) <= (*segIt).point2.m_y ) ) - && - (!( ( (CGA.x(target) + CGA.width(source))>= (*segIt).point2.m_x ) - && (CGA.x(target) <= (*segIt).point2.m_x ) - && ( (CGA.y(target) + CGA.height(source))>= (*segIt).point2.m_y ) - && (CGA.y(target) <= (*segIt).point2.m_y ) ))) { - // invert the segment-line - invertSegments = true; - } - } - //} - if (!invertSegments){ - for (segIt = segments.begin(); segIt.valid(); segIt++) { - dpl.pushBack((*segIt).point1); - dpl.pushBack((*segIt).point2); - } - } - else { - for (segIt = segments.rbegin(); segIt.valid(); segIt--) { - dpl.pushBack((*segIt).point2); - dpl.pushBack((*segIt).point1); - } - } - // unify bends = delete superfluous points - dpl.unify(); - // finally concatenate/set the bends - CGA.bends(actEdge).conc(dpl); - }// else (checkNumOfSegReInserts==0) - }// else (segments exist) - }// points & segments - - }//edgeIdRef - - }// edgeStyle - - // // LABELSTYLE - // if (stylesSon->getName() == Ogml::s_tagNames[t_labelStyle]){ - // // labelStyle - // // ACTUALLY NOT SUPPORTED - // }// labelStyle - - stylesSon = stylesSon->m_pBrother; - } // while - - } - } //styles - - // CONSTRAINTS - if (layoutSon->getName() == Ogml::s_tagNames[Ogml::t_constraints]) { - - // this code is encapsulated in the method - // OgmlParser::buildConstraints - // has to be called by read methods after building - - // here we only set the pointer, - // so we don't have to traverse the parse tree - // to the constraints tag later - m_constraintsTag = layoutSon; - - }// constraints - - - // go to next brother - layoutSon = layoutSon->m_pBrother; - }// while(layoutSon) - }//if (layout->m_pFirstSon) - }// if ((layout) && (layout->getName() == Ogml::s_tagNames[t_layout])) - - - }// else - - - - - - // cout << "buildAttributedClusterGraph COMPLETE. Check... " << endl << flush; - // edge e; - // forall_edges(e, G){ - // //cout << "CGA.labelEdge" << e << " = " << CGA.labelEdge(e) << endl << flush; - // cout << "CGA.arrowEdge" << e << " = " << CGA.arrowEdge(e) << endl << flush; - // cout << "CGA.styleEdge" << e << " = " << CGA.styleEdge(e) << endl << flush; - // cout << "CGA.edgeWidth" << e << " = " << CGA.edgeWidth(e) << endl << flush; - // cout << "CGA.colorEdge" << e << " = " << CGA.colorEdge(e) << endl << flush; - // cout << "CGA.type " << e << " = " << CGA.type(e) << endl << flush; - // ListConstIterator it; - // for(it = CGA.bends(e).begin(); it!=CGA.bends(e).end(); ++it) { - // cout << "point " << " x=" << (*it).m_x << " y=" << (*it).m_y << endl << flush; - // } - // - // } - // - // node n; - // forall_nodes(n, G){ - // cout << "CGA.labelNode(" << n << ") = " << CGA.labelNode(n) << endl << flush; - // cout << "CGA.templateNode(" << n << ") = " << CGA.templateNode(n) << endl << flush; - // cout << "CGA.shapeNode(" << n << ") = " << CGA.shapeNode(n) << endl << flush; - // cout << "CGA.width(" << n << ") = " << CGA.width(n) << endl << flush; - // cout << "CGA.height(" << n << ") = " << CGA.height(n) << endl << flush; - // cout << "CGA.colorNode(" << n << ") = " << CGA.colorNode(n) << endl << flush; - // cout << "CGA.nodePattern(" << n << ") = " << CGA.nodePattern(n) << endl << flush; - // cout << "CGA.styleNode(" << n << ") = " << CGA.styleNode(n) << endl << flush; - // cout << "CGA.lineWidthNode(" << n << ") = " << CGA.lineWidthNode(n) << endl << flush; - // cout << "CGA.nodeLine(" << n << ") = " << CGA.nodeLine(n) << endl << flush; - // cout << "CGA.x(" << n << ") = " << CGA.x(n) << endl << flush; - // cout << "CGA.y(" << n << ") = " << CGA.y(n) << endl << flush; - // cout << "CGA.type(" << n << ") = " << CGA.type(n) << endl << flush; - // } - // - // cluster c; - // forall_clusters(c, CGA.constClusterGraph()){ - // cout << "CGA.templateCluster(" << c << ") = " << CGA.templateCluster(c) << endl << flush; - // cout << "CGA.clusterWidth(" << c << ") = " << CGA.clusterWidth(c) << endl << flush; - // cout << "CGA.clusterHeight(" << c << ") = " << CGA.clusterHeight(c) << endl << flush; - // cout << "CGA.clusterFillColor(" << c << ") = " << CGA.clusterFillColor(c) << endl << flush; - // cout << "CGA.clusterFillPattern(" << c << ") = " << CGA.clusterFillPattern(c) << endl << flush; - // cout << "CGA.clusterBackColor(" << c << ") = " << CGA.clusterBackColor(c) << endl << flush; - // cout << "CGA.clusterLineStyle(" << c << ") = " << CGA.clusterLineStyle(c) << endl << flush; - // cout << "CGA.clusterLineWidth(" << c << ") = " << CGA.clusterLineWidth(c) << endl << flush; - // cout << "CGA.clusterColor(" << c << ") = " << CGA.clusterColor(c) << endl << flush; - // cout << "CGA.clusterXPos(" << c << ") = " << CGA.clusterXPos(c) << endl << flush; - // cout << "CGA.clusterYPos(" << c << ") = " << CGA.clusterYPos(c) << endl << flush; - // } - - // cout << "buildAttributedClusterGraph COMPLETE... Check COMPLETE... Let's have fun in GDE ;) " << endl << flush; - - // building terminated, so return true - return true; - -}//buildAttributedClusterGraph - - - -// *********************************************************** -// -// s e t l a b e l s r e c u r s i v e f o r c l u s t e r s -// -// *********************************************************** -// sets the labels of hierarchical nodes => cluster -bool OgmlParser::setLabelsRecursive(Graph &G, ClusterGraphAttributes &CGA, XmlTagObject *root) -{ - if ((root->getName() == Ogml::s_tagNames[Ogml::t_node]) && (CGA.attributes() & GraphAttributes::nodeLabel)) - { - if (!isNodeHierarchical(root)) - { - // get the id of the actual node - XmlAttributeObject *att; - if(root->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att)) - { - // lookup for node - node actNode = (m_nodes.lookup(att->getValue()))->info(); - // find label tag - XmlTagObject* label; - if (root->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_label], label)) { - // get content tag - XmlTagObject* content = label->m_pFirstSon; - // get the content as string - if (content->m_pTagValue){ - String str = content->getValue(); - String labelStr = getLabelCaptionFromString(str); - // now set the label of the node - CGA.labelNode(actNode) = labelStr; - } - } - } - }// "normal" nodes - else - { - // get the id of the actual cluster - XmlAttributeObject *att; - if(root->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att)) - { - // lookup for cluster - cluster actCluster = (m_clusters.lookup(att->getValue()))->info(); - // find label tag - XmlTagObject* label; - if (root->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_label], label)) { - // get content tag - XmlTagObject* content = label->m_pFirstSon; - // get the content as string - if (content->m_pTagValue) { - String str = content->getValue(); - String labelStr = getLabelCaptionFromString(str); - // now set the label of the node - CGA.clusterLabel(actCluster) = labelStr; - } - } - } - // hierSon = hierarchical Son - XmlTagObject *hierSon; - if (root->m_pFirstSon) - { - hierSon = root->m_pFirstSon; - while(hierSon) { - // recursive call for setting labels of child nodes - if (!setLabelsRecursive(G, CGA, hierSon)) - return false; - hierSon = hierSon->m_pBrother; - } - } - - }//cluster nodes - } - return true; -}// setLabelsRecursive - - - -// *********************************************************** -// -// b u i l d g r a p h -// -// *********************************************************** -bool OgmlParser::buildGraph(Graph &G) -{ - G.clear(); - - int id = 0; - - //Build nodes first - HashConstIterator it; - - for(it = m_ids.begin(); it.valid(); ++it) - { - if( it.info()->getName() == Ogml::s_tagNames[Ogml::t_node] && !isNodeHierarchical(it.info())) - { - // get id string from xmlTag - XmlAttributeObject *idAtt; - if ( (it.info())->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], idAtt) - && (getIdFromString(idAtt->getValue(), id)) ) - { - // now we got an id from the id-string - // we have to check, if this id was assigned - if (m_nodeIds.lookup(id)) { - // new id was assigned to another node - id = G.maxNodeIndex() + 1; - } - } - else { - // default id setting - id = G.maxNodeIndex() + 1; - } - m_nodes.fastInsert(it.key(), G.newNode(id)); - m_nodeIds.fastInsert(id, idAtt->getValue()); - } - }//for nodes - - id = 0; - - //Build edges second - for(it = m_ids.begin(); it.valid(); ++it) - { - if( it.info()->getName() == Ogml::s_tagNames[Ogml::t_edge] ) - { - //Check sources/targets - Stack srcTgt; - const XmlTagObject* son = it.info()->m_pFirstSon; - while(son) { - if( son->getName() == Ogml::s_tagNames[Ogml::t_source] || - son->getName() == Ogml::s_tagNames[Ogml::t_target] ) - { - XmlAttributeObject *att; - son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_nodeIdRef], att); - //Validate if source/target is really a node - if(m_ids.lookup(att->getValue())->info()->getName() != Ogml::s_tagNames[Ogml::t_node]) { - cout << "WARNING: edge relation between graph elements of none type node " << - "are temporarily not supported!\n"; - } - else { - srcTgt.push(m_nodes.lookup(att->getValue())->info()); - } - } - son = son->m_pBrother; - } - if(srcTgt.size() != 2) { - cout << "WARNING: hyperedges are temporarily not supported! Discarding edge.\n"; - } - else { - // create edge - - // get id string from xmlTag - XmlAttributeObject *idAtt; - if ( (it.info())->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], idAtt) - && (getIdFromString(idAtt->getValue(), id)) ) - { - if (m_edgeIds.lookup(id)) { - // new id was assigned to another edge - id = G.maxEdgeIndex() + 1; - } - } - else { - // default id setting - id = G.maxEdgeIndex() + 1; - } - m_edges.fastInsert(it.key(), G.newEdge(srcTgt.pop(), srcTgt.pop(), id)); - m_edgeIds.fastInsert(id, idAtt->getValue()); - } - } - }//for edges - - //Structure data determined, so building the graph was successfull. - return true; -}//buildGraph - - - -// *********************************************************** -// -// b u i l d c l u s t e r -- g r a p h -// -// *********************************************************** -bool OgmlParser::buildClusterRecursive( - const XmlTagObject *xmlTag, - cluster parent, - Graph &G, - ClusterGraph &CG) -{ - // create new cluster - - // first get the id - int id = -1; - - XmlAttributeObject *idAtt; - if ( (xmlTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], idAtt)) - && (getIdFromString(idAtt->getValue(), id)) ) - { - if (m_clusterIds.lookup(id)) { - // id was assigned to another cluster - id = CG.maxClusterIndex() + 1; - } - } - else { - // default id setting - id = CG.maxClusterIndex() + 1; - } - // create cluster and insert into hash tables - cluster actCluster = CG.newCluster(parent, id); - m_clusters.fastInsert(idAtt->getValue(), actCluster); - m_clusterIds.fastInsert(id, idAtt->getValue()); - - // check children of cluster tag - XmlTagObject *son = xmlTag->m_pFirstSon; - - while(son) - { - if (son->getName() == Ogml::s_tagNames[Ogml::t_node]) { - if (isNodeHierarchical(son)) - // recursive call - buildClusterRecursive(son, actCluster, G, CG); - else { - // the actual node tag is a child of the cluster - XmlAttributeObject *att; - //parse tree is valid so tag owns id attribute - son->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], att); - // get node from lookup table with the id in att - node v = m_nodes.lookup(att->getValue())->info(); - // assign node to actual cluster - CG.reassignNode(v, actCluster); - } - } - - son = son->m_pBrother; - }//while - - return true; -}//buildClusterRecursive - - - -bool OgmlParser::buildCluster( - const XmlTagObject *rootTag, - Graph &G, - ClusterGraph &CG) -{ - CG.clear(); - CG.init(G); - - if(rootTag->getName() != Ogml::s_tagNames[Ogml::t_ogml]) { - cerr << "ERROR: Expecting root tag \"" << Ogml::s_tagNames[Ogml::t_ogml] << "\" in OgmlParser::buildCluster!\n"; - return false; - } - - //Search for first node tag - XmlTagObject *nodeTag; - rootTag->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_graph], nodeTag); - nodeTag->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_structure], nodeTag); - nodeTag->findSonXmlTagObjectByName(Ogml::s_tagNames[Ogml::t_node], nodeTag); - - while (nodeTag) - { - if(nodeTag->getName() == Ogml::s_tagNames[Ogml::t_node] && isNodeHierarchical(nodeTag)) { - if (!buildClusterRecursive(nodeTag, CG.rootCluster(), G, CG)) - return false; - } - - nodeTag = nodeTag->m_pBrother; - } - - return true; -}//buildCluster - - - - -// *********************************************************** -// -// b u i l d c o n s t r a i n t s -// -// *********************************************************** -//Commented out due to missing graphconstraints in OGDF -/* -bool OgmlParser::buildConstraints(Graph& G, GraphConstraints &GC) { - - // constraints-tag was already set - // if not, then return... job's done - if (!m_constraintsTag) - return true; - - if (m_constraintsTag->getName() != Ogml::s_tagNames[t_constraints]){ - cerr << "Error: constraints tag is not the required tag!" << endl; - return false; - } - - XmlTagObject* constraintTag; - if(! m_constraintsTag->findSonXmlTagObjectByName(Ogml::s_tagNames[t_constraint], constraintTag) ) { - cerr << "Error: no constraint block in constraints block of valid parse tree found!" << endl; - return false; - } - - - while(constraintTag) { - -// // found data -// if (constraintTag->getName() == Ogml::s_tagNames[t_data]){ -// // found data for constraints in general -// // no implementation required for ogdf -// }//data - - if(constraintTag->getName() == Ogml::s_tagNames[t_constraint]) { - - XmlAttributeObject* actAtt; - String cId; - String cType; - - if (constraintTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[Ogml::a_id], actAtt)) - // set id of the constraint - cId = actAtt->getValue(); - - if (constraintTag->findXmlAttributeObjectByName(Ogml::s_attributeNames[a_type], actAtt)) - cType = actAtt->getValue(); - else { - cerr << "Error: constraint doesn't own compulsive attribute \'type\' in valid parse tree!" << endl; - return false; - } - // now we need a constraint manager to create a constraint - // with the type of the name stored in cType - // create the constraint - Constraint* c = ConstraintManager::createConstraintByName(G, &cType); - // check if the constraintManager doesn't return a null pointer - // that occurs if cM doesn't know the constraint name - if (c) { - // let the constraint load itself - if (c->buildFromOgml(constraintTag, &m_nodes)){ - // add constraint if true is returned - GC.addConstraint(c); - } - else - cerr << "Error while building constraint with name \""<m_pBrother; - }//while - - // terminated, so return true - return true; - -} -*/ - - - -// *********************************************************** -// -// p u b l i c r e a d m e t h o d s -// -// *********************************************************** -bool OgmlParser::read( - const char* fileName, - Graph &G, - ClusterGraph &CG) -{ - try { - // DinoXmlParser for parsing the ogml file - DinoXmlParser p(fileName); - p.createParseTree(); - - // get root object of the parse tree - const XmlTagObject *root = &p.getRootTag(); - - // build the required hash tables - buildHashTables(); - - // valide the document - if ( validate(root, Ogml::t_ogml) == Ogml::vs_valid ) - { - checkGraphType(root); - // build graph - if (buildGraph(G)) - { - Ogml::GraphType gt = getGraphType(); - // switch GraphType - switch (gt){ - //normal graph - case Ogml::graph: - break; - - // cluster graph - case Ogml::clusterGraph: - // build cluster - if (!buildCluster(root, G, CG)) - return false; - break; - - // compound graph - case Ogml::compoundGraph: - // build cluster because we got a cluster graph variable - // although we have a compound graph in the ogml file - if (!buildCluster(root, G, CG)) - return false; - break; - - // corrupt compound graph - case Ogml::corruptCompoundGraph: - // build cluster because we got a cluster graph variable - // although we have a corrupted compound graph in the ogml file - if (!buildCluster(root, G, CG)) - return false; - break; - } - } else - return false; - } else - return false; - - } catch(const char *error) { - cout << error << endl << flush; - return false; - } - - return true; -}; - - -bool OgmlParser::read( - const char* fileName, - Graph &G, - ClusterGraph &CG, - ClusterGraphAttributes &CGA) -{ - try { - // DinoXmlParser for parsing the ogml file - DinoXmlParser p(fileName); - p.createParseTree(); - - // get root object of the parse tree - const XmlTagObject *root = &p.getRootTag(); - - // build the required hash tables - buildHashTables(); - - // valide the document - if ( validate(root, Ogml::t_ogml) == Ogml::vs_valid ) - { - checkGraphType(root); - - // build graph - if (buildGraph(G)) - { - Ogml::GraphType gt = getGraphType(); - // switch GraphType - switch (gt){ - // normal graph - case Ogml::graph: - if (!buildAttributedClusterGraph(G, CGA, root)) - return false; - break; - - // cluster graph - case Ogml::clusterGraph: - if (!buildCluster(root, G, CG)) - return false; - if (!buildAttributedClusterGraph(G, CGA, root)) - return false; - break; - - // compound graph - case Ogml::compoundGraph: - // build cluster because we got a cluster graph variable - // although we have a compound graph in the ogml file - if (!buildCluster(root, G, CG)) - return false; - if (!buildAttributedClusterGraph(G, CGA, root)) - return false; - break; - - // corrupt compound graph - case Ogml::corruptCompoundGraph: - // build cluster because we got a cluster graph variable - // although we have a corrupted compound graph in the ogml file - if (!buildCluster(root, G, CG)) - return false; - if (!buildAttributedClusterGraph(G, CGA, root)) - return false; - } - - } else - return false; - - } else - return false; - - } catch(const char *error) { - cout << error << endl << flush; - return false; - } - - return true; -}; - - -}//namespace ogdf - diff --git a/ext/OGDF/src/fileformats/XmlParser.cpp b/ext/OGDF/src/fileformats/XmlParser.cpp deleted file mode 100644 index 9edbe09d7..000000000 --- a/ext/OGDF/src/fileformats/XmlParser.cpp +++ /dev/null @@ -1,1204 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of XML parser (class XmlParser) - * (used for parsing and reading XML files) - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - -extern ofstream os; - -namespace ogdf { - - -#define BUFFERLENGTH 8192 - -XmlParser::XmlParser(const char *fileName, bool doCheck) -{ - // open file - ifstream is(fileName, ios::in);// | ios::nocreate); // not accepted by gnu 3.02 - if (!is) { - setError("Cannot open file."); return; - } - - createObjectTree(is, doCheck); -} - - -XmlParser::XmlParser(istream &is, bool doCheck) -{ - createObjectTree(is,doCheck); -} - - -void XmlParser::createObjectTree(istream &is, bool doCheck) -{ - initPredefinedKeys(); - m_error = false; - m_objectTree = 0; - - m_is = &is; - m_doCheck = doCheck; // indicates more extensive checking - - // initialize line buffer (note: XML specifies a maximal line length - // of 254 characters!) - // See als the workaround for Get2Chip in function getLine() - - m_rLineBuffer = new char[BUFFERLENGTH]; // get2Chip special: - // XML Standard: char[256]; - *m_rLineBuffer = '\n'; - m_lineBuffer = m_rLineBuffer+1; - - m_pCurrent = m_pStore = m_lineBuffer; - m_cStore = 0; // forces getNextSymbol() to read first line - m_keyName = 0; - - // create object tree - m_objectTree = parseList(xmlEOF,xmlListEnd,""); - - delete[] m_rLineBuffer; -} - - -// we use predefined id constants for all relevant keys -// this allows us to use efficient switch() statemnts in read() methods -void XmlParser::initPredefinedKeys() -{ - - m_hashTable.fastInsert("NAME", namePredefKey); - m_hashTable.fastInsert("GRAPH", graphPredefKey); - m_hashTable.fastInsert("NODE", nodePredefKey); - m_hashTable.fastInsert("TRANSITION",edgePredefKey); - m_hashTable.fastInsert("EDGE", edgePredefKey); - - m_hashTable.fastInsert("POSITION", positionPredefKey); - m_hashTable.fastInsert("X", xPredefKey); - m_hashTable.fastInsert("Y", yPredefKey); - - m_hashTable.fastInsert("SIZE", sizePredefKey); - m_hashTable.fastInsert("W", wPredefKey); - m_hashTable.fastInsert("H", hPredefKey); - m_hashTable.fastInsert("WIDTH", widthPredefKey); - m_hashTable.fastInsert("HEIGHT", heightPredefKey); - - m_hashTable.fastInsert("NODETYPE", nodetypePredefKey); - m_hashTable.fastInsert("EDGETYPE", edgetypePredefKey); - m_hashTable.fastInsert("TYPE", typePredefKey); - - m_hashTable.fastInsert("FROM", sourcePredefKey); - m_hashTable.fastInsert("SOURCE", sourcePredefKey); - m_hashTable.fastInsert("TO", targetPredefKey); - m_hashTable.fastInsert("TARGET", targetPredefKey); - m_hashTable.fastInsert("SENSE", sensePredefKey); - m_hashTable.fastInsert("PATH", pathPredefKey); - - - // further keys get id's starting with NEXTPREDEFKEY - m_num = NEXTPREDEFKEY; -} - - -XmlObject *XmlParser::parseList(XmlObjectType closingKey, - XmlObjectType /* errorKey */, - const char *objectBodyName) -{ - XmlObject *firstSon = 0; - XmlObject **pPrev = &firstSon; - - for( ; ; ) { - XmlObjectType symbol = getNextSymbol(); - - if (symbol == closingKey || symbol == xmlError) - return firstSon; - - XmlObject *object = 0; - - if (symbol == xmlListBegin) { - symbol = getNextSymbol(); - if (symbol != xmlKey) { - setError("key expected"); - return firstSon; - } - XmlKey key = m_keySymbol; - object = OGDF_NEW XmlObject(key); - - size_t len = strlen(m_keyName)+1; - char* newObjectBodyName = new char[len]; - m_objectBody.pushBack(newObjectBodyName); - ogdf::strcpy(newObjectBodyName,len,m_keyName); - - // Recursive call for building the tree. - object->m_pFirstSon = parseList(xmlListEnd,xmlEOF,newObjectBodyName); - } - - else if (m_eoTag) - { // must be the body of an element - if (symbol != xmlStringValue) { - setError("String expected"); - return firstSon; - } - size_t len = strlen(m_stringSymbol)+1; - char *pChar = new char[len]; - ogdf::strcpy(pChar,len,m_stringSymbol); - - object = OGDF_NEW XmlObject(hashString(objectBodyName),pChar); - } - else - { // must be a symbol - if (symbol != xmlKey) { - setError("key expected"); - return firstSon; - } - - XmlKey key = m_keySymbol; - - symbol = getNextSymbol(); - switch (symbol) { - case xmlIntValue: - object = OGDF_NEW XmlObject(key,m_intSymbol); - break; - - case xmlDoubleValue: - object = OGDF_NEW XmlObject(key,m_doubleSymbol); - break; - - case xmlStringValue: { - size_t len = strlen(m_stringSymbol)+1; - char *pChar = new char[len]; - ogdf::strcpy(pChar,len,m_stringSymbol); - object = OGDF_NEW XmlObject(key,pChar); } - break; - - case xmlListBegin: - setError("unexpected begin of list"); - break; - - case xmlListEnd: - setError("unexpected end of list"); - return firstSon; - - case xmlKey: - setError("unexpected key"); - return firstSon; - - case xmlEOF: - setError("missing value"); - return firstSon; - - case xmlError: - return firstSon; - } - } - - *pPrev = object; - pPrev = &object->m_pBrother; - - } - return firstSon; -} - - -void XmlParser::destroyObjectList(XmlObject *object) -{ - XmlObject *nextObject; - for(; object; object = nextObject) { - nextObject = object->m_pBrother; - - if (object->m_valueType == xmlStringValue) - delete[] const_cast(object->m_stringValue); - - else if (object->m_valueType == xmlListBegin) - destroyObjectList(object->m_pFirstSon); - - delete object; - } -} - - -XmlParser::~XmlParser() -{ - // we have to delete all objects and allocated char arrays in string values - destroyObjectList(m_objectTree); - while (!m_objectBody.empty()) - delete[] m_objectBody.popFrontRet(); - delete[] m_keyName; -} - - -bool XmlParser::getLine() -{ - do { -// Standard XML needs only this -// if (m_is->eof()) return false; -// m_is->getline(m_lineBuffer,255); - -// Workaround for Get2Chip. XML-Information may exceed 254 signs per line. -// Moreover, XML signs may be longer than 254 signs. Cut information at '>'. -// Workaround starts here. - char c; - int count = 0; - while ( ((c = m_is->get() ) != '>') && (count <= (BUFFERLENGTH - 2))){ - if (m_is->eof()) return false; - m_lineBuffer[count++] = c; - } - if ( (c == '>') && (count <= (BUFFERLENGTH - 2))) - m_lineBuffer[count++] = c; - m_lineBuffer[count] = '\0'; -// Workaround stops here. - - // Eat Whitespaces. - for(m_pCurrent = m_lineBuffer; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; - } while (*m_pCurrent == '#' || *m_pCurrent == 0); - - return true; -} - -/***************************************************************************** - getNextSymbol -******************************************************************************/ - - - -XmlObjectType XmlParser::getNextSymbol() -{ - *m_pStore = m_cStore; - m_eoTag = false; - bool digit = false; - - // eat whitespace - for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; - if (*m_pCurrent == '>') - { - m_pCurrent++; - m_eoTag = true; // end of a tag reached. - } - for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; - // get new line if required - if (*m_pCurrent == 0) { - if (!getLine()) return xmlEOF; - } - - - // identify start of current symbol - char *pStart = m_pCurrent; - - // we currently do not support strings with line breaks! - - if (*pStart == '=') - { // attribute value - // string or int or double expected - - // again: eat whitespace - pStart++;m_pCurrent++; - for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; - // again: get new line if required - if (*m_pCurrent == 0) { - if (!getLine()) return xmlEOF; - } - // again: identify start of current symbol - char *pStart = m_pCurrent; - - bool quotation = (*pStart == '\"' ? 1 : 0); - if (quotation) - { - pStart++; - m_pCurrent++; - } - if (*pStart == '-' || isdigit(*pStart)) // Check if int or double - { - digit = true; - char *pCheck = m_pCurrent; - pCheck++; - while(isdigit(*pCheck)) ++pCheck; // int or double - if (*pCheck == '.') - pCheck++; // only double - else if (quotation && *pCheck != '\"') - digit = false; // must be string - else if (!quotation && !isspace(*pCheck) && *pCheck != '>') - digit = false; // must be string - if (digit) - { - while(isdigit(*pCheck)) ++pCheck; - if (quotation && *pCheck != '\"') - digit = false; // must be string - else if (!quotation && !isspace(*pCheck) && *pCheck != '>') - digit = false; // must be string - } - } - -// if (!isdigit(*pStart) && (*pStart != '-')) { // string - if (!digit) // string - { - m_stringSymbol = m_pCurrent; - if (quotation){ - for(; *m_pCurrent != 0 && *m_pCurrent != '\"'; ++m_pCurrent) - if (*m_pCurrent == '\\') - ++m_pCurrent; // No quotation mark found yet. Drop the line. - } - else { - for(; *m_pCurrent != 0 && !isspace(*m_pCurrent) && *m_pCurrent != '>'; ++m_pCurrent) - if (*m_pCurrent == '\\') ++m_pCurrent; - } - if (quotation && *m_pCurrent == 0) { - m_longString = (pStart); - while(getLine()) { - for(m_pCurrent = m_lineBuffer; *m_pCurrent != 0 && *m_pCurrent != '\"'; ++m_pCurrent) - if (*m_pCurrent == '\\') ++m_pCurrent; - if (*m_pCurrent == 0) - m_longString += m_lineBuffer; - else { - m_cStore = *(m_pStore = m_pCurrent); - *m_pCurrent++ = 0; // Drop quotation mark. - m_longString += m_lineBuffer; - break; - } - } - m_stringSymbol = m_longString.cstr(); - - } - else { - m_cStore = *(m_pStore = m_pCurrent); - if (quotation) - *m_pCurrent++ = 0; // Drop quotation mark. - else - *m_pCurrent = 0; - } - - return xmlStringValue; - } -// else if (*pStart == '-' || isdigit(*pStart)) - else // int or double - { - m_pCurrent++; - while(isdigit(*m_pCurrent)) ++m_pCurrent; - - if (*m_pCurrent == '.') // double - { - // check to be done - - sscanf(pStart,"%lf",&m_doubleSymbol); - m_pCurrent++; - while (isdigit(*m_pCurrent)) ++m_pCurrent; - if (quotation){ - for(; *m_pCurrent != 0 && *m_pCurrent != '\"' && isdigit(*m_pCurrent); ++m_pCurrent) ; - - if (*m_pCurrent == '\"') - m_pCurrent++; - else - { - setError("malformed number"); - return xmlError; - } - } - return xmlDoubleValue; - - } - - else // int - { - if (isalpha(*m_pCurrent)) { - setError("malformed number"); - return xmlError; - } - if (quotation){ - for(; *m_pCurrent != 0 && *m_pCurrent != '\"'; ++m_pCurrent); - if (*m_pCurrent == '\"') - m_pCurrent++; - else{ - setError("malformed number"); - return xmlError; - } - } - sscanf(pStart,"%d",&m_intSymbol); - return xmlIntValue; - } - - } - } - - if (*pStart == '<') { - //check if end of list - m_pCurrent++; - for (; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent); - if (*m_pCurrent == '/'){ - for (; *m_pCurrent && *m_pCurrent != '>'; ++m_pCurrent); - m_cStore = *(m_pStore = m_pCurrent); - return xmlListEnd; - } - else { - m_cStore = *(m_pStore = m_pCurrent); - return xmlListBegin; - } - } - else if (*pStart == '/') { - m_pCurrent++; - for (; *m_pCurrent && *m_pCurrent == '>'; ++m_pCurrent); - m_cStore = *(m_pStore = m_pCurrent); - return xmlListEnd; - - } - - else // Invalid clause: if(isalpha(*pStart)). May contain numbers - { - // Tag name, Attribute Name (both are said to be keys) - // or body name (element) - - // check if really a correct key (error if not) - if (m_doCheck) { - m_pCurrent++; - for (;*m_pCurrent; ++m_pCurrent) - if (!(isalpha(*m_pCurrent) || isdigit(*m_pCurrent))) { - setError("malformed key"); - return xmlError; - } - } - if (m_eoTag) // its the body of an element - { - // Do not ignore whitespace, quotation marks etc. - // They belong to the element. - // Only search for the '<' of the next tag. - // The element is considered as string. - - // Get new line if required - if (*m_pCurrent == 0) { - if (!getLine()) return xmlEOF; - } - // again: identify start of current symbol - //char *pStart = m_pCurrent; - - - m_stringSymbol = m_pCurrent; - - while(*m_pCurrent != 0 && *m_pCurrent != '<' ) - ++m_pCurrent; - m_cStore = *(m_pStore = m_pCurrent); - *m_pCurrent = 0; - - return xmlStringValue; - } - else // it is a key - { - while(*m_pCurrent != 0 && - *m_pCurrent != '=' && - *m_pCurrent != '>' && - *m_pCurrent != '/' && - *m_pCurrent != '<' && - !isspace(*m_pCurrent) - ) - ++m_pCurrent; - m_cStore = *(m_pStore = m_pCurrent); - *m_pCurrent = 0; - - if (m_keyName != 0) - delete[] m_keyName; - size_t len = strlen(pStart)+6; - m_keyName = new char[len]; - ogdf::strcpy(m_keyName,len,pStart); - - m_keySymbol = hashString(pStart); - return xmlKey; - } - } - - // - //setError("unknown symbol"); - - //return xmlError; -} - - - - -XmlKey XmlParser::hashString(const String &str) -{ - XmlKey key = m_hashTable.insertByNeed(str,-1); - if(key->info() == -1) key->info() = m_num++; - - return key; -} - -/***************************************************************************** - getNodeIdRange -******************************************************************************/ - - -XmlObject *XmlParser::getNodeIdRange(int &minId,int &maxId, - int &nodetypeCount, - XmlObject *graphObject) - -{ - nodetypeCount = minId = maxId = -1; - - if (graphObject == 0) - graphObject = m_objectTree; - XmlObject *scanObject = graphObject; - - for(; scanObject; scanObject = scanObject->m_pBrother) - if (id(scanObject) == graphPredefKey) break; - - if (!scanObject || id(scanObject) != graphPredefKey) - { - scanObject = graphObject; - for(; scanObject; scanObject = scanObject->m_pBrother) - { - graphObject = getNodeIdRange(minId,maxId,nodetypeCount,scanObject->m_pFirstSon); - if (graphObject && id(graphObject) == graphPredefKey) - return graphObject; - } - } - - if (!scanObject || scanObject->m_valueType != xmlListBegin) return 0; - - XmlObject *son = scanObject->m_pFirstSon; - for(; son; son = son->m_pBrother) { - if (id(son) == nodePredefKey && son->m_valueType == xmlListBegin) - maxId++; - else if (id(son) == nodetypePredefKey && son->m_valueType == xmlListBegin) - nodetypeCount++; - } - - if (maxId >= 0) - minId = 0; - - return scanObject; -} - - - - -/***************************************************************************** - makeIdMap -******************************************************************************/ - - -bool XmlParser::makeIdMap( - int maxId, - Array & idMap, - int nodetypeCount, - Array & typeName, - Array & typeWidth, - Array & typeHeight, - XmlObject *graphObject) -{ - int idCount = 0; - int typeCount = 0; - for(; graphObject; graphObject = graphObject->m_pBrother) - if (id(graphObject) == graphPredefKey) break; - - if (!graphObject || graphObject->m_valueType != xmlListBegin) return 0; - - XmlObject *son = graphObject->m_pFirstSon; - for(; son; son = son->m_pBrother) { - if (id(son) == nodePredefKey && son->m_valueType == xmlListBegin) { - XmlObject *nodeSon = son->m_pFirstSon; - for(; nodeSon; nodeSon = nodeSon->m_pBrother) - if (id(nodeSon) == namePredefKey && nodeSon->m_valueType == xmlStringValue){ - if (idCount >= maxId+1) - return 0; - size_t len = strlen(nodeSon->m_stringValue)+1; - idMap[idCount] = new char[len]; - ogdf::strcpy(idMap[idCount++],len,nodeSon->m_stringValue); - } - } - else if (id(son) == nodetypePredefKey && son->m_valueType == xmlListBegin){ - XmlObject *nodeSon = son->m_pFirstSon; - if (typeCount <= nodetypeCount){ - for(; nodeSon; nodeSon = nodeSon->m_pBrother) { - if (id(nodeSon) == namePredefKey && nodeSon->m_valueType == xmlStringValue){ - size_t len = strlen(nodeSon->m_stringValue)+1; - typeName[typeCount] = new char[len]; - ogdf::strcpy(typeName[typeCount],len,nodeSon->m_stringValue); - } - else if (id(nodeSon) == widthPredefKey ){ - if (nodeSon->m_valueType == xmlIntValue) - typeWidth[typeCount] = (int) nodeSon->m_intValue; - else if (nodeSon->m_valueType == xmlDoubleValue) - typeWidth[typeCount] = nodeSon->m_doubleValue; - } - else if (id(nodeSon) == heightPredefKey ){ - if (nodeSon->m_valueType == xmlIntValue) - typeHeight[typeCount] = (int) nodeSon->m_intValue; - else if (nodeSon->m_valueType == xmlDoubleValue) - typeHeight[typeCount] = nodeSon->m_doubleValue; - } - } - typeCount++; - } - } - - } - if (idCount != maxId+1) - return 0; - else - return 1; -} - - -/***************************************************************************** - read -******************************************************************************/ - - -bool XmlParser::read(Graph &G) -{ - G.clear(); - - int minId, maxId, nodetypeCount; - XmlObject *graphObject = getNodeIdRange(minId, maxId, nodetypeCount,0); - - //cout << endl << minId << " " << maxId << endl; - if (!graphObject) { - setError("missing graph key"); - return false; - } - - Array typeWidth(0,nodetypeCount,0); - Array typeHeight(0,nodetypeCount,0); - Array typeName(nodetypeCount+1); - Array idMap(maxId+1); - if (!makeIdMap(maxId,idMap,nodetypeCount,typeName,typeWidth,typeHeight,graphObject)) { - setError("wrong name identifier"); - return false; - } - - Array mapToNode(minId,maxId,0); - int notDefined = minId-1; //indicates not defined id key - int idCount = minId; - - XmlObject *son = graphObject->m_pFirstSon; - for(; son; son = son->m_pBrother) { - - switch(id(son)) { - case nodePredefKey: { - if (son->m_valueType != xmlListBegin) break; - - // set attributes to default values - int vId = idCount++; - - // create new node if necessary and assign attributes - if (mapToNode[vId] == 0) - mapToNode[vId] = G.newNode(); - break; - } - case edgePredefKey: - if (son->m_valueType != xmlListBegin) break; - - // set attributes to default values - int sourceId = notDefined, targetId = notDefined; - // read all relevant attributes - XmlObject *edgeSon = son->m_pFirstSon; - for(; edgeSon; edgeSon = edgeSon->m_pBrother) { - int i = 0; - switch(id(edgeSon)) { - case sourcePredefKey: - if (edgeSon->m_valueType != xmlStringValue) break; - for (i = 0; i<= maxId;i++) - if (!strcmp(idMap[i],edgeSon->m_stringValue)) - sourceId = i; - break; - - case targetPredefKey: - if (edgeSon->m_valueType != xmlStringValue) break; - for (i = 0; i<= maxId;i++) - if (!strcmp(idMap[i],edgeSon->m_stringValue)) - targetId = i; - break; - - } - } - - // check if everything required is defined correctly - if (sourceId == notDefined || targetId == notDefined) { - setError("source or target id not defined"); - //cout << "source or target id not defined" << endl; - return false; - - } else if (sourceId < minId || maxId < sourceId || - targetId < minId || maxId < targetId) { - setError("source or target id out of range"); - //cout << "source or target id out of range" << endl; - return false; - } - - // create adjacent nodes if necessary and new edge - if (mapToNode[sourceId] == 0) mapToNode[sourceId] = G.newNode(); - if (mapToNode[targetId] == 0) mapToNode[targetId] = G.newNode(); - - - G.newEdge(mapToNode[sourceId],mapToNode[targetId]); - break; - } - } - - return true; -} - - -/***************************************************************************** - read -******************************************************************************/ - - -bool XmlParser::read(Graph &G, GraphAttributes &AG) -{ - OGDF_ASSERT(&G == &(const Graph &)AG) - - G.clear(); - - int minId, maxId, nodetypeCount; - XmlObject *graphObject = getNodeIdRange(minId, maxId, nodetypeCount,0); - - if (!graphObject) { - setError("missing graph key"); - return false; - } - - Array typeWidth(0,nodetypeCount,0); - Array typeHeight(0,nodetypeCount,0); - Array typeName(nodetypeCount+1); - Array idMap(maxId+1); - if (!makeIdMap(maxId,idMap,nodetypeCount,typeName,typeWidth,typeHeight,graphObject)) { - setError("wrong name identifier"); - closeLabels(idMap,typeName); - return false; - } - Array mapToNode(minId,maxId,0); - int notDefined = minId-1; //indicates not defined id key - int idCount = minId; - - DPolyline bends; - String label; - - XmlObject *son = graphObject->m_pFirstSon; - for(; son; son = son->m_pBrother) { - - switch(id(son)) { - case nodePredefKey: - { - if (son->m_valueType != xmlListBegin) break; - - // set attributes to default values - int vId = idCount++;; - double x = 0, y = 0, w = 0, h = 0; - bool typeDefined = 0; - // read all relevant attributes - - XmlObject *graphicsObject = son->m_pFirstSon; - for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) - { - switch(id(graphicsObject)) - { - case namePredefKey: - if (graphicsObject->m_valueType == xmlStringValue) - label = graphicsObject->m_stringValue; - break; - case xPredefKey: - if(graphicsObject->m_valueType == xmlDoubleValue) - x = graphicsObject->m_doubleValue; - else if (graphicsObject->m_valueType == xmlIntValue) - x = (int) graphicsObject->m_intValue; - break; - case yPredefKey: - if(graphicsObject->m_valueType == xmlDoubleValue) - y = graphicsObject->m_doubleValue; - else if (graphicsObject->m_valueType == xmlIntValue) - y = (int) graphicsObject->m_intValue; - break; - case wPredefKey: - if (!typeDefined) - { - if(graphicsObject->m_valueType == xmlDoubleValue) - w = graphicsObject->m_doubleValue; - else if (graphicsObject->m_valueType == xmlIntValue) - w = (int) graphicsObject->m_intValue; - } - break; - case hPredefKey: - if (!typeDefined) - { - if(graphicsObject->m_valueType == xmlDoubleValue) - h = graphicsObject->m_doubleValue; - else if (graphicsObject->m_valueType == xmlIntValue) - h = (int) graphicsObject->m_intValue; - } - break; - case widthPredefKey: - if (!typeDefined) - { - if(graphicsObject->m_valueType == xmlDoubleValue) - w = graphicsObject->m_doubleValue; - else if (graphicsObject->m_valueType == xmlIntValue) - w = (int) graphicsObject->m_intValue; - } - break; - case heightPredefKey: - if (!typeDefined) - { - if(graphicsObject->m_valueType == xmlDoubleValue) - h = graphicsObject->m_doubleValue; - else if (graphicsObject->m_valueType == xmlIntValue) - h = (int) graphicsObject->m_intValue; - } - break; - case typePredefKey: - if(graphicsObject->m_valueType == xmlStringValue) - { - int i = 0; - for (;i <= nodetypeCount && strcmp(typeName[i],graphicsObject->m_stringValue);i++); - if (i <= nodetypeCount) - { - w = typeWidth[i]; - h = typeHeight[i]; - typeDefined = 1; - } - } - break; - - - case positionPredefKey: - { - if (graphicsObject->m_valueType != xmlListBegin) break; - - - XmlObject *graphicsObjectElement = graphicsObject->m_pFirstSon; - for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) - { - switch(id(graphicsObjectElement)) - { - case xPredefKey: - if(graphicsObjectElement->m_valueType == xmlDoubleValue) - x = graphicsObjectElement->m_doubleValue; - else if (graphicsObjectElement->m_valueType == xmlIntValue) - x = (int) graphicsObjectElement->m_intValue; - break; - case yPredefKey: - if(graphicsObjectElement->m_valueType == xmlDoubleValue) - y = graphicsObjectElement->m_doubleValue; - else if (graphicsObjectElement->m_valueType == xmlIntValue) - y = (int) graphicsObjectElement->m_intValue; - break; - }// switch(id(graphicsObjectElement)) - }// for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) - break; - }// case positionPredefKey: - case sizePredefKey: - { - if (graphicsObject->m_valueType != xmlListBegin) break; - - - XmlObject *graphicsObjectElement = graphicsObject->m_pFirstSon; - for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) - { - switch(id(graphicsObjectElement)) - { - case wPredefKey: - if (!typeDefined) - { - if(graphicsObjectElement->m_valueType == xmlDoubleValue) - w = graphicsObjectElement->m_doubleValue; - else if (graphicsObjectElement->m_valueType == xmlIntValue) - w = (int) graphicsObjectElement->m_intValue; - } - break; - case hPredefKey: - if (!typeDefined) - { - if(graphicsObjectElement->m_valueType == xmlDoubleValue) - h = graphicsObjectElement->m_doubleValue; - else if (graphicsObjectElement->m_valueType == xmlIntValue) - h = (int) graphicsObjectElement->m_intValue; - } - break; - case widthPredefKey: - if (!typeDefined) - { - if(graphicsObjectElement->m_valueType == xmlDoubleValue) - w = graphicsObjectElement->m_doubleValue; - else if (graphicsObjectElement->m_valueType == xmlIntValue) - w = (int) graphicsObjectElement->m_intValue; - } - break; - case heightPredefKey: - if (!typeDefined) - { - if(graphicsObjectElement->m_valueType == xmlDoubleValue) - h = graphicsObjectElement->m_doubleValue; - else if (graphicsObjectElement->m_valueType == xmlIntValue) - h = (int) graphicsObjectElement->m_intValue; - } - break; - }// switch(id(graphicsObjectElement)) - }// for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) - - break; - }// case sizePredefKey: - - - - - }// switch(id(graphicsObject)) - }// for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) - - - // create new node if necessary and assign attributes - if (mapToNode[vId] == 0) mapToNode[vId] = G.newNode(); - AG.x(mapToNode[vId]) = x; - AG.y(mapToNode[vId]) = y; - if (w > 0) //skip negative width - AG.width (mapToNode[vId]) = w; - if (h > 0) // skip negative height - AG.height(mapToNode[vId]) = h; - AG.labelNode(mapToNode[vId]) = label; - break; - - }// case nodePredefKey: - - - - - - case edgePredefKey: - { - if (son->m_valueType != xmlListBegin) break; - - // set attributes to default values - int sourceId = notDefined, targetId = notDefined; - bool backward = false; - // read all relevant attributes - XmlObject *graphicsObject = son->m_pFirstSon; - for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) - { - int i = 0; - switch(id(graphicsObject)) - { - case namePredefKey: - if (graphicsObject->m_valueType == xmlStringValue) - label = graphicsObject->m_stringValue; - break; - case sourcePredefKey: - if (graphicsObject->m_valueType != xmlStringValue) break; - for (i = 0; i<= maxId;i++) - if (!strcmp(idMap[i],graphicsObject->m_stringValue)) - sourceId = i; - break; - - case targetPredefKey: - if (graphicsObject->m_valueType != xmlStringValue) break; - for (i = 0; i<= maxId;i++) - if (!strcmp(idMap[i],graphicsObject->m_stringValue)) - targetId = i; - break; - case sensePredefKey: - if (graphicsObject->m_valueType != xmlStringValue) break; - if (!strcmp("BACKWARD",graphicsObject->m_stringValue)) - backward = true; - case pathPredefKey: - { - if (graphicsObject->m_valueType != xmlListBegin) break; - DPoint dp; - - XmlObject *graphicsObjectElement = graphicsObject->m_pFirstSon; - for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) - { - switch(id(graphicsObjectElement)) - { - case positionPredefKey: - { - if (graphicsObjectElement->m_valueType != xmlListBegin) break; - DPoint dp; - - XmlObject *element = graphicsObjectElement->m_pFirstSon; - for(; element; element = element->m_pBrother) - { - switch(id(element)) - { - case xPredefKey: - if(element->m_valueType == xmlDoubleValue) - dp.m_x = element->m_doubleValue; - else if (element->m_valueType == xmlIntValue) - dp.m_x = (int) element->m_intValue; - break; - case yPredefKey: - if(element->m_valueType == xmlDoubleValue) - dp.m_y = element->m_doubleValue; - else if (element->m_valueType == xmlIntValue) - dp.m_y = (int) element->m_intValue; - break; - }// switch(id(element)) - }// for(; element; element = element->m_pBrother) - bends.pushBack(dp); - break; - }// case positionPredefKey: - }//switch(id(graphicsObjectElement)) - }//for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) - break; - }// case positionPredefKey: -/* - case graphicsPredefKey: - if (graphicsObject->m_valueType != xmlListBegin) break; - - XmlObject *graphicsObject = graphicsObject->m_pFirstSon; - for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { - if(id(graphicsObject) == LinePredefKey && - graphicsObject->m_valueType == xmlListBegin) - readLineAttribute(graphicsObject->m_pFirstSon,bends); - } -*/ - }// switch(id(graphicsObject)) - }// for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) - - // check if everything required is defined correctly - if (sourceId == notDefined || targetId == notDefined) - { - setError("source or target id not defined"); - closeLabels(idMap,typeName); - return false; - - } - else if (sourceId < minId || maxId < sourceId || - targetId < minId || maxId < targetId) - { - setError("source or target id out of range"); - closeLabels(idMap,typeName); - return false; - } - - // create adjacent nodes if necessary and new edge - if (mapToNode[sourceId] == 0) mapToNode[sourceId] = G.newNode(); - if (mapToNode[targetId] == 0) mapToNode[targetId] = G.newNode(); - - edge e; - if (backward) - e = G.newEdge(mapToNode[targetId],mapToNode[sourceId]); - else - e = G.newEdge(mapToNode[sourceId],mapToNode[targetId]); - AG.labelEdge(e) = label; - AG.bends(e).conc(bends); - break; - - }// case edgePredefKey: - - }// switch(id(son)) { - } - closeLabels(idMap,typeName); - return true; -} - - -void XmlParser::closeLabels(Array idMap, Array typeName) -{ - int i; - for (i = idMap.low(); i <= idMap.high();i++) - if (idMap[i]) - delete[] idMap[i]; - for (i = typeName.low(); i <= typeName.high();i++) - if (typeName[i]) - delete[] typeName[i]; -} - - -void XmlParser::readLineAttribute(XmlObject *object, DPolyline &dpl) -{ - dpl.clear(); - for(; object; object = object->m_pBrother) { - if (id(object) == pointPredefKey && object->m_valueType == xmlListBegin) { - DPoint dp; - - XmlObject *pointObject = object->m_pFirstSon; - for (; pointObject; pointObject = pointObject->m_pBrother) { - if (pointObject->m_valueType != xmlDoubleValue) continue; - if (id(pointObject) == xPredefKey) - dp.m_x = pointObject->m_doubleValue; - else if (id(pointObject) == yPredefKey) - dp.m_y = pointObject->m_doubleValue; - } - - dpl.pushBack(dp); - } - } -} - - -void XmlParser::setError(const char *errorString) -{ - m_error = true; - m_errorString = errorString; -} - - - -void XmlParser::indent(ostream &os, int d) -{ - for(int i = 1; i <= d; ++i) - os << " "; -} - -/* -void XmlParser::output(ostream &os, XmlObject *object, int d) -{ - for(; object; object = object->m_pBrother) { - indent(os,d); os << object->m_key->key(); - - switch(object->m_valueType) { - case xmlIntValue: - os << " " << object->m_intValue << "\n"; - break; - - case xmlDoubleValue: - os << " " << object->m_doubleValue << "\n"; - break; - - case xmlStringValue: - os << " \"" << object->m_stringValue << "\"\n"; - break; - - case xmlListBegin: - os << "\n"; - output(os, object->m_pFirstSon, d+2); - break; - } - } -} -*/ - -} // end namespace ogdf diff --git a/ext/OGDF/src/fileformats/simple_graph_load.cpp b/ext/OGDF/src/fileformats/simple_graph_load.cpp deleted file mode 100644 index 8e9d48253..000000000 --- a/ext/OGDF/src/fileformats/simple_graph_load.cpp +++ /dev/null @@ -1,710 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of simple graph loaders. - * - * See header-file simple_graph_load.h for more information. - * - * \author Markus Chimani, Carsten Gutwenger, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include - -#define SIMPLE_LOAD_BUFFER_SIZE 2048 - -namespace ogdf { - -bool loadRomeGraph(Graph &G, const char *fileName) { - ifstream is(fileName); - if(!is.good()) return false; - return loadRomeGraph(G, is); -} - - -bool loadRomeGraph(Graph &G, istream &is) { - G.clear(); - - char buffer[SIMPLE_LOAD_BUFFER_SIZE]; - bool readNodes = true; - Array indexToNode(1,250,0); - - while(!is.eof()) - { - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - - if(readNodes) { - if(buffer[0] == '#') { - readNodes = false; - continue; - } - - int index; - sscanf(buffer, "%d", &index); - if(index < 1 || index > 250 || indexToNode[index] != 0) { - Logger::slout() << "loadRomeGraph: illegal node index!\n"; - return false; - } - - indexToNode[index] = G.newNode(); - - } else { - int index, dummy, srcIndex, tgtIndex; - sscanf(buffer, "%d%d%d%d", &index, &dummy, &srcIndex, &tgtIndex); - - if(buffer[0] == 0) - continue; - - if(srcIndex < 1 || srcIndex > 250 || tgtIndex < 1 || tgtIndex > 250 || - indexToNode[srcIndex] == 0 || indexToNode[tgtIndex] == 0) - { - Logger::slout() << "loadRomeGraph: illegal node index in edge specification.\n"; - return false; - } - - G.newEdge(indexToNode[srcIndex], indexToNode[tgtIndex]); - } - } - return true; -} - - -bool loadChacoGraph(Graph &G, const char *fileName) { - ifstream is(fileName); - if(!is.good()) return false; - return loadChacoGraph(G, is); -} - - -//Reads the chaco (graph partitioning) file format (usually a .graph file). -bool loadChacoGraph(Graph &G, istream &is) -{ - G.clear(); - char buffer[SIMPLE_LOAD_BUFFER_SIZE]; - int numN = 0, runEdges = 0, lineNum = 0; - char* pch = NULL; - - //try to read the first line to get the graph size - if (!is.eof()) - { - //contains the size numbers - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - //char* context = NULL; - //now read the number of nodes - pch = strtok(buffer, " ");//strtok_s(buffer, " ", &context); - if (pch == NULL) return false; - numN = atoi(pch); - //now read the number of edges - pch = strtok(NULL, " ");//strtok_s(NULL, " ", &context); - if (pch == NULL) return false; - // extension: check here for weights - } - else return false; - - if (numN == 0) return true; - - Array indexToNode(1,numN,0); - for (int i = 1; i <= numN; i++) - { - //we assign new indexes here if they are not consecutive - //starting from 1 in the file! Thus, if the file is not in the correct - //format, node indices do not correspond to indices from the file. - indexToNode[i] = G.newNode(); - } - - while(!is.eof()) - { - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - if (strlen(buffer) == 0) continue; - lineNum++; - if (lineNum > numN) - { - cerr<< "File read error: More lines than expected number of nodes "<< lineNum <<":"< numN) - { - cerr<<"File read error: Illegal node index encountered\n"; - return false; - } - - //create edges - if (wind >= lineNum) - { - G.newEdge( indexToNode[lineNum], indexToNode[wind] ); - runEdges++; - } - - pch = strtok(NULL, " ");//strtok_s(NULL, " ", &context); - }//while node entries - }//while file - //cout <<"Read #nodes: "< indexToNode(1,numN,0); - for (int i = 1; i <= numN; i++) - { - //we assign new indexes here if they are not consecutive - //starting from 1 in the file! - indexToNode[i] = G.newNode(); - } - - while(!is.eof()) - { - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - - if(buffer[0] == 0) - continue; - - int srcIndex, tgtIndex; - sscanf(buffer, "%d%d", &srcIndex, &tgtIndex); - char* pch; - pch = strtok(buffer, " "); - if ( (strcmp(pch, "*END") == 0) || (strcmp(pch, "*CHECKSUM") == 0) ) - continue; - - if(srcIndex < 1 || srcIndex > numN || tgtIndex < 1 || tgtIndex > numN) - { - Logger::slout() << "loadSimpleGraph: illegal node index in edge specification.\n"; - return false; - } - - G.newEdge(indexToNode[srcIndex], indexToNode[tgtIndex]); - } - return true; -} - - -#define YG_NEXTBYTE(x) x = fgetc(lineStream); if(x == EOF || x == '\n') { Logger::slout() << "loadYGraph: line too short!"; return false; } x &= 0x3F; - -bool loadYGraph(Graph &G, FILE *lineStream) { - G.clear(); - - char c,s; - int n,i,j; - - YG_NEXTBYTE(n); - Array A(n); - for(i=n; i-->0;) - A[i] = G.newNode(); - - s = 0; - for(i = 1; i& hypernodes, List *shell, const char *fileName) { - ifstream is(fileName); - if(!is.good()) return false; - return loadBenchHypergraph(G, hypernodes, shell, is); -} - - -bool loadPlaHypergraph(Graph &G, List& hypernodes, List *shell, const char *fileName) { - ifstream is(fileName); - if(!is.good()) return false; - return loadPlaHypergraph(G, hypernodes, shell, is); -} - - -int extractIdentifierLength(char* from, int line) { - int p = 1; - while(from[p]!=',' && from[p]!=')' && from[p]!=' ' && from[p]!='(') { - ++p; - if(from[p]=='\0') { - cerr << "Loading Hypergraph: Error in line " << line << - ". Expected comma, bracket or whitespace before EOL; Ignoring.\n"; - break; - } - } - return p; -} - - -int newStartPos(char* from, int line) { - int p = 0; - while(from[p]=='\t' || from[p]==' ' || from[p]==',') { - ++p; - if(from[p]=='\0') { - cerr << "Loading Hypergraph: Error in line " << line << - ". Expected whitespace or delimiter before EOL; Ignoring.\n"; - break; - } - } - - return p; -} - - -int findOpen(char* from, int line) { - int p = 0; - while(from[p]!='(') { - ++p; - if(from[p]=='\0') { - cerr << "Loading Hypergraph: Error in line " << line << - ". Expected opening bracket before EOL; Ignoring.\n"; - break; - } - } - return p; -} - - -String inName(const String& s) { - size_t n = s.length(); - char *t = new char[n+4]; - ogdf::strcpy(t,s.length()+1,s.cstr()); - t[n] = '%';t[n+1] = '$';t[n+2] = '@';t[n+3] = '\0'; - String u(t); - delete[] t; - return u; -} - - -bool loadBenchHypergraph(Graph &G, List& hypernodes, List *shell, istream &is) { - G.clear(); - hypernodes.clear(); - if(shell) shell->clear(); - node si,so; - - char buffer[SIMPLE_LOAD_BUFFER_SIZE]; - -// Array indexToNode(1,250,0); - - HashArray hm(0); - - if(shell) { -// hypernodes.pushBack( si=G.newNode() ); -// hypernodes.pushBack( so=G.newNode() ); -// shell.pushBack( G.newEdge( si, so ) ); - shell->pushBack( G.newEdge( si=G.newNode(), so=G.newNode() ) ); - } - - int line = 0; - while(!is.eof()) - { - ++line; - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - size_t l = strlen(buffer); - if( l > 0 && buffer[l-1]=='\r' ) { // DOS line - buffer[l-1]='\0'; - } - if(!strlen(buffer) || buffer[0]==' ' || buffer[0]=='#') continue; - if(!strncmp("INPUT(",buffer,6)) { - String s(extractIdentifierLength(buffer+6, line),buffer+6); - node n = G.newNode(); - hm[s] = n; - hypernodes.pushBack(n); - if(shell) shell->pushBack( G.newEdge(si,n) ); -// cout << "input: " << s << " -> " << n->index() << "\n"; - } else if(!strncmp("OUTPUT(",buffer,7)) { - String s(extractIdentifierLength(buffer+7, line),buffer+7); - node n = G.newNode(); - hm[s] = n; - hypernodes.pushBack(n); - if(shell) shell->pushBack( G.newEdge(n,so) ); -// cout << "output: " << s << " -> " << n->index() << "\n"; - } else { - int p = extractIdentifierLength(buffer, line); - String s(p,buffer); // gatename - node m = hm[s]; // found as outputname -> refOut - if(!m) { - m = hm[inName(s)]; // found as innernode input. - if(!m) { // generate it anew. - node in = G.newNode(); - node out = G.newNode(); - hm[inName(s)] = in; - hm[s] = out; - hypernodes.pushBack(out); - G.newEdge(in,out); - m = in; - } - } - p = findOpen(buffer, line); - do { - ++p; - p += newStartPos(buffer+p, line); - int pp = extractIdentifierLength(buffer+p, line); - String s(pp,buffer+p); - p += pp; - node mm = hm[s]; - if(!mm) { - // new - node in = G.newNode(); - node out = G.newNode(); - hm[inName(s)] = in; - hm[s] = out; - hypernodes.pushBack(out); - G.newEdge(in,out); - mm = out; - } - G.newEdge(mm,m); -// cout << "Edge: " << s << "(" << hm[s]->index() << ") TO " << m->index() << "\n"; - } while(buffer[p] == ','); - } - } - - return true; -} - -bool loadPlaHypergraph(Graph &G, List& hypernodes, List *shell, istream &is) { - G.clear(); - hypernodes.clear(); - if(shell) shell->clear(); - node si,so; - - int i; - int numGates; - is >> numGates; -// cout << "numGates=" << numGates << "\n"; - - Array outport(1,numGates); - for(i = 1; i<=numGates; ++i) { - node out = G.newNode(); - outport[i] = out; - hypernodes.pushBack(out); - } - - for(i = 1; i<=numGates; ++i) { - int id, type, numinput; - is >> id >> type >> numinput; -// cout << "Gate=" << i << ", type=" << type << ", numinput=" << numinput << ":"; - if(id != i) cerr << "Error loading PLA hypergraph: ID and linenum does not match\n"; - node in = G.newNode(); - G.newEdge(in,outport[i]); - for(int j=0; j> from; -// cout << " " << from; - G.newEdge(outport[from],in); - } -// cout << "\n"; - is.ignore(500,'\n'); - } - - if(shell) { - shell->pushBack( G.newEdge( si=G.newNode(), so=G.newNode() ) ); - node n; - forall_nodes(n,G) { - if(n->degree()==1) { - if(n->firstAdj()->theEdge()->source()==n) { //input - shell->pushBack( G.newEdge( si, n ) ); - } else { // output - shell->pushBack( G.newEdge( n, so ) ); - } - } - } - } - - return true; -} - - - -bool loadEdgeListSubgraph(Graph &G, List &delEdges, const char *fileName) -{ - ifstream is(fileName); - if(!is.good()) return false; - return loadEdgeListSubgraph(G, delEdges, is); -} - - -bool loadEdgeListSubgraph(Graph &G, List &delEdges, istream &is) -{ - G.clear(); - delEdges.clear(); - - char buffer[SIMPLE_LOAD_BUFFER_SIZE]; - - if(is.eof()) return false; - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - - int n = 0, m = 0, m_del = 0; - sscanf(buffer, "%d%d%d", &n, &m, &m_del); - - if(n < 0 || m < 0 || m_del < 0) - return false; - - Array indexToNode(n); - for(int i = 0; i < n; ++i) - indexToNode[i] = G.newNode(); - - int m_all = m + m_del; - for(int i = 0; i < m_all; ++i) { - if(is.eof()) return false; - - is.getline(buffer, SIMPLE_LOAD_BUFFER_SIZE-1); - int src, tgt; - sscanf(buffer, "%d%d", &src, &tgt); - if(src < 0 || src >= n || tgt < 0 || tgt >= n) - return false; - - edge e = G.newEdge(indexToNode[src], indexToNode[tgt]); - - if(i >= m) - delEdges.pushBack(e); - } - - return true; -} - - -bool saveEdgeListSubgraph(const Graph &G, const List &delEdges, const char *fileName) -{ - ofstream os(fileName); - return saveEdgeListSubgraph(G,delEdges,os); -} - - -bool saveEdgeListSubgraph(const Graph &G, const List &delEdges, ostream &os) -{ - if(!os.good()) return false; - - const int m_del = delEdges.size(); - const int n = G.numberOfNodes(); - const int m = G.numberOfEdges() - m_del; - - os << n << " " << m << " " << m_del << "\n"; - - EdgeArray markSub(G,true); - for(ListConstIterator it = delEdges.begin(); it.valid(); ++it) - markSub[*it] = false; - - NodeArray index(G); - int i = 0; - node v; - forall_nodes(v,G) - index[v] = i++; - - edge e; - forall_edges(e,G) - if(markSub[e]) - os << index[e->source()] << " " << index[e->target()] << "\n"; - - for(ListConstIterator it = delEdges.begin(); it.valid(); ++it) - os << index[(*it)->source()] << " " << index[(*it)->target()] << "\n"; - - - return true; -} - - -bool loadChallengeGraph(Graph &G, GridLayout &gl, const char *fileName) -{ - ifstream is(fileName); - if(!is.good()) return false; - return loadChallengeGraph(G, gl, is); -} - - -#define CHALLENGE_LOAD_BUFFER_SIZE 4096 - -bool loadChallengeGraph(Graph &G, GridLayout &gl, istream &is) -{ - G.clear(); - char buffer[CHALLENGE_LOAD_BUFFER_SIZE]; - - int n = -1; - do { - if(is.eof()) return false; - is.getline(buffer,CHALLENGE_LOAD_BUFFER_SIZE); - if(buffer[0] != '#') { - sscanf(buffer, "%d", &n); - if(n < 0) return false; - } - } while(n < 0); - - Array indexToNode(n); - for(int i = 0; i < n; ) { - if(is.eof()) return false; - is.getline(buffer,CHALLENGE_LOAD_BUFFER_SIZE); - - if(buffer[0] != '#') { - node v = G.newNode(); - sscanf(buffer, "%d%d", &gl.x(v), &gl.y(v)); - indexToNode[i++] = v; - } - } - - while(!is.eof()) { - is.getline(buffer,CHALLENGE_LOAD_BUFFER_SIZE); - - if(buffer[0] != '#' && buffer[0] != 0) { - std::stringstream ss(buffer); - int srcIndex, tgtIndex; - - if(ss.eof()) return false; - ss >> srcIndex; - if(srcIndex < 0 || srcIndex >= n) return false; - - if(ss.eof()) return false; - ss >> tgtIndex; - if(tgtIndex < 0 || tgtIndex >= n) return false; - - node src = indexToNode[srcIndex]; - node tgt = indexToNode[tgtIndex]; - edge e = G.newEdge(src,tgt); - - std::string symbol; - if(ss.eof()) return false; - ss >> symbol; - if(symbol != "[") return false; - - IPolyline &ipl = gl.bends(e);; - for(;;) { - if(ss.eof()) return false; - ss >> symbol; - if(symbol == "]") break; - - IPoint ip; - ip.m_x = atoi(symbol.c_str()); - if(ss.eof()) return false; - ss >> ip.m_y; - ipl.pushBack(ip); - } - } - } - - return true; -} - - -bool saveChallengeGraph(const Graph &G, const GridLayout &gl, const char *fileName) -{ - ofstream os(fileName); - return saveChallengeGraph(G, gl, os); -} - - -bool saveChallengeGraph(const Graph &G, const GridLayout &gl, ostream &os) -{ - if(!os.good()) return false; - - os << "# Number of Nodes\n"; - os << G.numberOfNodes() << "\n"; - - os << "# Nodes\n"; - NodeArray index(G); - int i = 0; - node v; - forall_nodes(v,G) { - os << gl.x(v) << " " << gl.y(v) << "\n"; - index[v] = i++; - } - - os << "# Edges\n"; - edge e; - forall_edges(e,G) { - os << index[e->source()] << " " << index[e->target()] << " ["; - const IPolyline &ipl = gl.bends(e); - for(ListConstIterator it = ipl.begin(); it.valid(); ++it) - os << " " << (*it).m_x << " " << (*it).m_y; - os << " ]\n"; - } - - return true; -} - - -} diff --git a/ext/OGDF/src/graphalg/ConvexHull.cpp b/ext/OGDF/src/graphalg/ConvexHull.cpp deleted file mode 100644 index a0e5ecc53..000000000 --- a/ext/OGDF/src/graphalg/ConvexHull.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* - * $Revision: 2523 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of doubly linked lists and iterators - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -ConvexHull::ConvexHull() -{ -} - - -ConvexHull::~ConvexHull() -{ -} - - -bool ConvexHull::sameDirection(const DPoint &start, const DPoint &end, const DPoint &s, const DPoint &e) const -{ - DPoint a = (start - end); - DPoint b = (s - e); - DPoint c = a + b; - double len2_a = a.m_x * a.m_x + a.m_y * a.m_y; - double len2_b = b.m_x * b.m_x + b.m_y * b.m_y; - double len2_c = c.m_x * c.m_x + c.m_y * c.m_y; - - return (len2_c > max(len2_a, len2_b)); -} - - -DPoint ConvexHull::calcNormal(const DPoint &start, const DPoint &end) const -{ - double len = sqrt((end.m_x-start.m_x)*(end.m_x-start.m_x) + (end.m_y-start.m_y)*(end.m_y-start.m_y)); - return DPoint((start.m_y - end.m_y) / len, (end.m_x - start.m_x) / len); -} - - -double ConvexHull::leftOfLine(const DPoint &normal, const DPoint &point, const DPoint &pointOnLine) const -{ - return ((point.m_x - pointOnLine.m_x) * normal.m_x + (point.m_y - pointOnLine.m_y) * normal.m_y); -} - - -// calculates a convex hull very quickly but only works with cross-free Polygons! -// polygon order (cw/ccw) must be set correctly -DPolygon ConvexHull::conv(const DPolygon &poly) const -{ - DPolygon res(poly); - - DPolygon::iterator lastChange = res.cyclicPred(res.begin()); - for (DPolygon::iterator i = res.begin(); i != lastChange;) { - DPolygon::iterator h = res.cyclicPred(i); - DPolygon::iterator g = res.cyclicPred(h); - - if ((*i) == (*h)) { - res.del(h); - lastChange = g; - continue; - } - - if (g == i) { - i = res.cyclicSucc(i); - continue; - } - - DPoint norm = calcNormal(*h, *i); - if ((res.counterclock() && leftOfLine(norm, *g, *h) <= 0.0) || (!res.counterclock() && leftOfLine(norm, *g, *h) >= 0.0)) { - res.del(h); - lastChange = g; - } else { - i = res.cyclicSucc(i); - } - } - - return res; -} - - -void ConvexHull::leftHull(std::vector points, DPoint &start, DPoint &end, DPolygon &hullPoly) const -{ - // delete points faster by switching with last in vector! - DPoint q1; - DPoint q2; - unsigned int indexQ1; - unsigned int indexQ2; - for( ; ; ) { - if (points.size() == 1) { - hullPoly.pushBack(points.front()); - } - if (points.size() <= 1) { - return; - } - - indexQ1 = randomNumber(0, (int)points.size()-1); - q1 = points[indexQ1]; - indexQ2 = randomNumber(0, (int)points.size()-1); - q2 = points[indexQ2]; - - if (q1 == q2) { - if (indexQ1 != indexQ2) { - points[indexQ2] = points.back(); - points.pop_back(); - } - continue; - } - - DPolygon triangle(false); - triangle.pushBack(start); - triangle.pushBack(q2); - triangle.pushBack(end); - if (triangle.containsPoint(q1)) { - points[indexQ1] = points.back(); - points.pop_back(); - continue; - } - triangle.clear(); - triangle.pushBack(start); - triangle.pushBack(q1); - triangle.pushBack(end); - if (triangle.containsPoint(q2)) { - points[indexQ2] = points.back(); - points.pop_back(); - continue; - } - - break; - } - - if ((leftOfLine(calcNormal(q1, q2), start, q1) >= 0.0) && (leftOfLine(calcNormal(q1, q2), end, q1) >= 0.0)) { - swap(q1, q2); - swap(indexQ1, indexQ2); - } - - double dist = -DBL_MAX; - DPoint normal = calcNormal(q1, q2); - std::vector qCandidates; - std::vector qDistances; - for (unsigned int i = 0; i < points.size(); i++) { - double d = leftOfLine(normal, points[i], q1); - if (!DIsGreater(dist, d)) { - if (DIsGreater(d, dist)) { - qCandidates.clear(); - qDistances.clear(); - dist = d; - } - if (d > dist) { - dist = d; - } - qCandidates.push_back(i); - qDistances.push_back(d); - } - } - for (unsigned int i = 0; i < qCandidates.size();) { - if (DIsLess(qDistances[i], dist)) { - qCandidates[i] = qCandidates.back(); - qCandidates.pop_back(); - qDistances[i] = qDistances.back(); - qDistances.pop_back(); - } else { - i++; - } - } - - unsigned int indexQ = 0; - DPoint q(points[qCandidates[0]]); - for (unsigned int i = 0; i < qCandidates.size(); i++) { - if (indexQ != i && sameDirection(points[qCandidates[i]], q, q1, q2) ) { - q = points[qCandidates[i]]; - indexQ = i; - } - } - indexQ = qCandidates[indexQ]; - - OGDF_ASSERT(q2 != q || q1 == q); - - int del[3]; - del[0] = indexQ; - del[1] = indexQ1; - del[2] = indexQ2; - std::sort(del, del+3); - - int last = (int)points.size(); - for(int i = 2; i >= 0; i--) { - if (del[i] < last) - { - points[del[i]] = points.back(); - points.pop_back(); - last = del[i]; - } - } - - std::vector lPoints; - std::vector rPoints; - DPoint sqNormal = calcNormal(start, q); - DPoint qeNormal = calcNormal(q, end); - - if (indexQ1 != indexQ) - { - if (DIsGreater(leftOfLine(sqNormal, q1, q), 0.0)) { - lPoints.push_back(q1); - OGDF_ASSERT(!DIsGreater(leftOfLine(qeNormal, q1, q), 0.0)); - } else if (DIsGreater(leftOfLine(qeNormal, q1, q), 0.0)) { - rPoints.push_back(q1); - } - } - - if (indexQ2 != indexQ) - { - if (DIsGreater(leftOfLine(sqNormal, q2, q), 0.0)) { - lPoints.push_back(q2); - OGDF_ASSERT(!DIsGreater(leftOfLine(qeNormal, q2, q), 0.0)); - } else if (DIsGreater(leftOfLine(qeNormal, q2, q), 0.0)) { - rPoints.push_back(q2); - } - } - - if (!points.empty()) - { - DPolygon inner(false); - inner.pushBack(start); - inner.pushBack(q1); - inner.pushBack(q); - inner.pushBack(q2); - inner.pushBack(end); - inner = conv(inner); - - while (!points.empty()) { - int indexP = randomNumber(0, (int)points.size()-1); - DPoint p = points[indexP]; - points[indexP] = points.back(); - points.pop_back(); - - if (inner.containsPoint(p)) { - continue; - } - - if (points.size() > 0) { - // add p to inner2 - DPolygon inner2(inner); - DPolygon::iterator nearest = inner2.begin(); - dist = p.distance(*nearest); - for (DPolygon::iterator ip = inner2.begin(); ip != inner2.end(); ip++) { - double d = p.distance(*ip); - if (d > dist) { - dist = d; - nearest = ip; - } - } - // after x insert p x - inner2.insert(DPoint(*nearest), nearest); - inner2.insert(p, nearest); - inner2 = conv(inner2); - - int deletes = 0; - int times = 2; // experimentally determine this value - DPoint r; - int indexR; - do { - indexR = randomNumber(0, (int)points.size()-1); - r = points[indexR]; - if (inner2.containsPoint(r)) { - points[indexR] = points.back(); - points.pop_back(); - deletes++; - times++; // bonus try if a point was deleted - } else { - times--; - } - } while(times > 0 && points.size() > 0); - - if ((deletes > 0 && inner2.size() <= 10) || inner2.size() <= inner.size()) { - inner = inner2; - } else if (deletes == 0) { - points[indexR] = p; - p = r; - } - } - - if (DIsGreater(leftOfLine(sqNormal, p, q), 0.0)) { - lPoints.push_back(p); - OGDF_ASSERT(!DIsGreater(leftOfLine(qeNormal, p, q), 0.0)); - } else if (DIsGreater(leftOfLine(qeNormal, p, q), 0.0)) { - rPoints.push_back(p); - } - } - } - - leftHull(lPoints, start, q, hullPoly); - hullPoly.pushBack(q); - leftHull(rPoints, q, end, hullPoly); -} - - -DPolygon ConvexHull::call(std::vector points) const -{ - DPolygon hullPoly(false); - if (points.empty()) { - return hullPoly; - } - - // Find extremes in +-x, +-y, +-(x+-y) - DPoint xpoints[8]; - double extremes[8]; - unsigned int xIndex[8]; - for (int i=0; i<8; i++) { - xpoints[i] = *(points.begin()); - extremes[i] = -DBL_MAX; - xIndex[i] = 0; - } - - int num = 0; - for (int ix = -1; ix <= 1; ix++) { - for (int iy = -1; iy <= 1; iy++) { - if (ix == 0 && iy == 0) { - continue; - } - DPoint zero(0.0,0.0); - DPoint normal = calcNormal(zero, DPoint(ix, iy)); - for (unsigned int it = 0; it < points.size(); it++) { - double dist = leftOfLine(normal, points[it], zero); - if (dist >= extremes[num]) { - xpoints[num] = points[it]; - extremes[num] = dist; - xIndex[num] = it; - } - } - num++; - } - } - - std::sort(xIndex, xIndex+8); - - // delete known extremes - unsigned int last = (unsigned int)points.size(); - for (int i = 7; i >= 0; i--) { - if (xIndex[i] >= points.size() || xIndex[i] >= last) { - continue; - } - last = xIndex[i]; - points[xIndex[i]] = points.back(); - points.pop_back(); - } - - // Make Polygon - DPolygon poly(false); - poly.pushBack(xpoints[0]); - poly.pushBack(xpoints[1]); - poly.pushBack(xpoints[2]); - poly.pushBack(xpoints[4]); - poly.pushBack(xpoints[7]); - poly.pushBack(xpoints[6]); - poly.pushBack(xpoints[5]); - poly.pushBack(xpoints[3]); - poly = conv(poly); - - // Subdivide into Pointlists - std::vector normals; - for (DPolygon::iterator i = poly.begin(); i != poly.end(); i++) { - DPolygon::iterator j = poly.cyclicSucc(i); - normals.push_back(calcNormal(*i, *j)); - } - std::vector< std::vector > pointArray; - pointArray.resize(poly.size()); - for (std::vector::iterator p = points.begin(); p != points.end(); p++) { - int component = 0; - DPolygon::iterator sp = poly.begin(); - DPolygon::iterator spn = poly.cyclicSucc(sp); - for (std::vector::iterator n = normals.begin(); n != normals.end(); n++, sp++) { - if ((*sp != *p) && (*spn != *p) && DIsGreater(leftOfLine(*n, *p, *sp), 0.0)) { - pointArray[component].push_back(*p); - break; - } - component++; - } - } - - int component = 0; - for (DPolygon::iterator i = poly.begin(); i != poly.end(); i++, component++) { - hullPoly.pushBack(*i); - DPolygon::iterator j = poly.cyclicSucc(i); - leftHull(pointArray[component], *i, *j, hullPoly); - } - - return conv(hullPoly); -} - - -DPolygon ConvexHull::call(MultilevelGraph &MLG) const -{ - std::vector points; - - node v; - forall_nodes(v, MLG.getGraph()) { - points.push_back(DPoint(MLG.x(v), MLG.y(v))); - } - - return call(points); -} - - -DPolygon ConvexHull::call(GraphAttributes &GA) const -{ - std::vector points; - - node v; - forall_nodes(v, GA.constGraph()) { - points.push_back(DPoint(GA.x(v), GA.y(v))); - } - - return call(points); -} - -} // namespace ogdf diff --git a/ext/OGDF/src/graphalg/MinCostFlowModule.cpp b/ext/OGDF/src/graphalg/MinCostFlowModule.cpp deleted file mode 100644 index c5195f219..000000000 --- a/ext/OGDF/src/graphalg/MinCostFlowModule.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of some useful functions dealing with - * min-cost flow (generater, checker) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -namespace ogdf { - - -void MinCostFlowModule::generateProblem( - Graph &G, - int n, - int m, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply) -{ - ogdf::randomGraph(G,n,m); - - node s = G.firstNode(); - node t = G.lastNode(); - - node v; - forall_nodes(v,G) { - G.newEdge(s,v); - G.newEdge(v,t); - } - - edge e; - forall_edges(e,G) { - lowerBound[e] = 0; - upperBound[e] = (e->source() != s) ? ogdf::randomNumber(1,10) : ogdf::randomNumber(2,13); - cost[e] = ogdf::randomNumber(0,100); - } - - - - node vl; - for(v = G.firstNode(), vl = G.lastNode(); true; v = v->succ(), vl = vl->pred()) { - if (v == vl) { - supply[v] = 0; - break; - } - - supply[v] = -(supply[vl] = ogdf::randomNumber(-1,1)); - - if (vl == v->succ()) - break; - } - -} - -bool MinCostFlowModule::checkProblem( - const Graph &G, - const EdgeArray &lowerBound, - const EdgeArray &upperBound, - const NodeArray &supply) -{ - if(isConnected(G) == false) - return false; - - edge e; - forall_edges(e,G) { - if (lowerBound[e] > upperBound[e]) - return false; - } - - int sum = 0; - node v; - forall_nodes(v,G) { - sum += supply[v]; - } - - return (sum == 0); -} - - -bool MinCostFlowModule::checkComputedFlow( - const Graph &G, - EdgeArray &lowerBound, - EdgeArray &upperBound, - EdgeArray &cost, - NodeArray &supply, - EdgeArray &flow, - int &value) -{ - value = 0; - - edge e; - forall_edges(e,G) { - if (flow[e] < lowerBound[e] || upperBound[e] < flow[e]) { - return false; - } - - value += flow[e] * cost[e]; - } - - node v; - forall_nodes(v,G) { - int sum = 0; - forall_adj_edges(e,v) { - if(e->isSelfLoop()) - continue; - - if (e->source() == v) - sum += flow[e]; - else - sum -= flow[e]; - } - if (sum != supply[v]) - return false; - } - - return true; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/graphalg/MinCostFlowReinelt.cpp b/ext/OGDF/src/graphalg/MinCostFlowReinelt.cpp deleted file mode 100644 index 67abe3e1c..000000000 --- a/ext/OGDF/src/graphalg/MinCostFlowReinelt.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class MinCostFlowReinelt. - * - * \author Gerhard Reinelt, various adaptions by Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - - -namespace ogdf { - - -void MinCostFlowReinelt::start(Array &supply) -{ - /*----------------------------------------------------------------------*/ - /* determine intial basis tree and initialize data structure */ - /*----------------------------------------------------------------------*/ - - /* initialize artificial root node */ - root->father = root; - root->successor = &nodes[1]; - root->arc_id = NULL; - root->orientation = false; - root->dual = 0; - root->flow = 0; - root->nr_of_nodes = nn + 1; - root->last = &nodes[nn]; - root->name = nn + 1; - // artificials = nn; moved to mcf() [CG] - int highCost = 1 + (nn+1) * m_maxCost; - - for (int i = 1; i <= nn; i++) - { /* for every node an artificial arc is created */ - arctype *ep = OGDF_NEW arctype; - if (supply[i - 1] >= 0) { - ep->tail = &nodes[i]; - ep->head = root; - } else { - ep->tail = root; - ep->head = &nodes[i]; - } - ep->cost = highCost; - ep->upper_bound = infinity(); - ep->arcnum = mm + i - 1; - ep->next_arc = start_b; - start_b = ep; - nodes[i].father = root; - if (i < nn) - nodes[i].successor = &nodes[i+1]; - else - nodes[i].successor = root; - if (supply[i - 1] < 0) { - nodes[i].orientation = false; - nodes[i].dual = -highCost; - } else { - nodes[i].orientation = true; - nodes[i].dual = highCost; - } - nodes[i].flow = abs(supply[i - 1]); - nodes[i].nr_of_nodes = 1; - nodes[i].last = &nodes[i]; - nodes[i].arc_id = ep; - } /* for i */ - start_n1 = start_arc; -} /*start*/ - - - -/***************************************************************************/ -/* circle variant for determine basis entering arc */ -/***************************************************************************/ - -void MinCostFlowReinelt::beacircle( - arctype **eplus, - arctype **pre, - bool *from_ub) -{ - //the first arc with negative reduced costs is taken, but the search is - //started at the successor of the successor of eplus in the last iteration - - bool found = false; /* true<=>entering arc found */ - - *pre = startsearch; - if (*pre != NULL) - *eplus = (*pre)->next_arc; - else - *eplus = NULL; - searchend = *eplus; - - if (!*from_ub) { - - while (*eplus != NULL && !found) - { /* search in n' for an arc with negative reduced costs */ - if ((*eplus)->cost + (*eplus)->head->dual - - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - if (!found) /* entering arc still not found */ - { /* search in n'' */ - *from_ub = true; - *eplus = start_n2; - *pre = NULL; - - while (*eplus != NULL && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - - } /* while */ - - - if (!found) { /* search again in n' */ - *from_ub = false; - *eplus = start_n1; - *pre = NULL; - - while (*eplus != searchend && !found) { - if ((*eplus)->cost + - (*eplus)->head->dual - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - } /* search in n'' */ - } /* serch again in n' */ - } /* if from_ub */ - else { /* startsearch in n'' */ - - while (*eplus != NULL && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - if (!found) { /* search now in n' */ - *from_ub = false; - *eplus = start_n1; - *pre = NULL; - - while (*eplus != NULL && !found) { - if ((*eplus)->cost + - (*eplus)->head->dual - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - - if (!found) { /* search again in n'' */ - *from_ub = true; - *eplus = start_n2; - *pre = NULL; - - while (*eplus != searchend && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - } /* search in n' */ - } /* search in n'' */ - } /* from_ub = true */ - - - - if (!found) { - *pre = NULL; - *eplus = NULL; - } else - startsearch = (*eplus)->next_arc; - -} /* beacircle */ - - - -/***************************************************************************/ -/* doublecircle variant for determine basis entering arc */ -/***************************************************************************/ - -void MinCostFlowReinelt::beadouble( - arctype **eplus, - arctype **pre, - bool *from_ub) -{ - - /* search as in procedure beacircle, but in each list the search started is - at the last movement - */ - bool found = false; /* true<=>entering arc found */ - - if (!*from_ub) { - *pre = last_n1; - if (*pre != NULL) - *eplus = (*pre)->next_arc; - else - *eplus = NULL; - searchend_n1 = *eplus; - - while (*eplus != NULL && !found) - { /* search in n' for an arc with negative reduced costs */ - if ((*eplus)->cost + - (*eplus)->head->dual - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - if (!found) /* entering arc still not found */ - { /* search in n'' beginning at the last movement */ - *from_ub = true; - *pre = last_n2; - if (*pre != NULL) - *eplus = (*pre)->next_arc; - else - *eplus = NULL; - searchend_n2 = *eplus; - - while (*eplus != NULL && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - - } /* while */ - - if (!found) /* entering arc still not found */ - { /* search in n'' in the first part of the list */ - *eplus = start_n2; - *pre = NULL; - - while (*eplus != searchend_n2 && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - - } /* while */ - - - if (!found) { - /* search again in n' in the first part of the list*/ - *from_ub = false; - *eplus = start_n1; - *pre = NULL; - - while (*eplus != searchend_n1 && !found) { - if ((*eplus)->cost + - (*eplus)->head->dual - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - } /* first part n' */ - } /* first part n'' */ - } /* second part n'' */ - } /* if from_ub */ - else { /* startsearch in n'' */ - *pre = last_n2; - if (*pre != NULL) - *eplus = (*pre)->next_arc; - else - *eplus = NULL; - searchend_n2 = *eplus; - - while (*eplus != NULL && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - if (!found) { /* search now in n' beginning at the last movement */ - *from_ub = false; - *pre = last_n1; - if (*pre != NULL) - *eplus = (*pre)->next_arc; - else - *eplus = NULL; - searchend_n1 = *eplus; - - while (*eplus != NULL && !found) { - if ((*eplus)->cost + - (*eplus)->head->dual - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - - if (!found) { /* search now in n' in the first part */ - *eplus = start_n1; - *pre = NULL; - - while (*eplus != searchend_n1 && !found) { - if ((*eplus)->cost + - (*eplus)->head->dual - (*eplus)->tail->dual < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - - - if (!found) { /* search again in n'' in the first part */ - *from_ub = true; - *eplus = start_n2; - *pre = NULL; - - while (*eplus != searchend_n2 && !found) { - if ((*eplus)->tail->dual - - (*eplus)->head->dual - (*eplus)->cost < 0) - { - found = true; - } else { - *pre = *eplus; /* save predecessor */ - *eplus = (*eplus)->next_arc; /* go to next arc */ - } - } /* while */ - } /* first part of n'' */ - } /* first part of n' */ - } /* second part of n' */ - } /* from_ub = true */ - - - - if (!found) { - *pre = NULL; - *eplus = NULL; - return; - } - - if (*from_ub) - last_n2 = (*eplus)->next_arc; - else - last_n1 = (*eplus)->next_arc; - -} /* beadouble */ - - - -/***************************************************************************/ -/* Min Cost Flow Function */ -/***************************************************************************/ - - -int MinCostFlowReinelt::mcf( - int mcfNrNodes, - int mcfNrArcs, - Array &supply, - Array &mcfTail, - Array &mcfHead, - Array &mcfLb, - Array &mcfUb, - Array &mcfCost, - Array &mcfFlow, - Array &mcfDual, - int *mcfObj) -{ - int i; - int low,up; - - /************************************************/ - /* 1: Allocations (malloc's no longer required) */ - /************************************************/ - - root = &rootStruct; - - - /**********************/ - /* 2: Initializations */ - /**********************/ - - /* Number of nodes/arcs */ - nn = mcfNrNodes; - OGDF_ASSERT(nn >= 2); - mm = mcfNrArcs; - OGDF_ASSERT(mm >= 2); - - // number of artificial basis arcs - int artificials = nn; - - - /* Node space and pointers to nodes */ - nodes.init(nn+1); - nodes[0].name = -1; // for debuggin, should not occur(?) - for(i = 1; i <= nn; ++i) - nodes[i].name = i; - - /* Arc space and arc data */ - arcs.init(mm+1); - - int lb_cost = 0; // cost of lower bound - m_maxCost = 0; - int from = mcfTail[0]; // name of tail (input) - int toh = mcfHead[0]; // name of head (input) - low = mcfLb[0]; - up = mcfUb[0]; - int c = mcfCost[0]; // cost (input) - if (from<=0 || from>nn || toh<=0 || toh>nn || up<0 || low>up || low<0) { - return 4; - } - if(abs(c) > m_maxCost) m_maxCost = abs(c); - - start_arc = &arcs[1]; - start_arc->tail = &nodes[from]; - start_arc->head = &nodes[toh]; - start_arc->cost = c; - start_arc->upper_bound = up - low; - start_arc->arcnum = 0; - supply[from - 1] -= low; - supply[toh - 1] += low; - lb_cost += start_arc->cost * low; - - arctype *e = start_arc; - - int l; // lower bound (input) - for (l=2;l<=mm;l++) { - from = mcfTail[l-1]; - toh = mcfHead[l-1]; - low = mcfLb[l-1]; - up = mcfUb[l-1]; - c = mcfCost[l-1]; - if (from<=0 || from>nn || toh<=0 || toh>nn || - up<0 || low>up || low<0) - { - return 4; - } - if(abs(c) > m_maxCost) m_maxCost = abs(c); - - arctype *ep = &arcs[l]; - e->next_arc = ep; - ep->tail = &nodes[from]; - ep->head = &nodes[toh]; - ep->cost = c; - ep->upper_bound = up - low; - ep->arcnum = l-1; - supply[from-1] -= low; - supply[toh-1] += low; - lb_cost += ep->cost * low; - e = ep; - } - - e->next_arc = NULL; - // feasible = true <=> feasible solution exists - bool feasible = true; - - - /************************/ - /* 3: Starting solution */ - /************************/ - - start_n1 = NULL; - start_n2 = NULL; - start_b = NULL; - - start(supply); - - int step = 1; /* initialize iteration counter */ - - /*********************/ - /* 4: Iteration loop */ - /*********************/ - - /*************************************/ - /* 4.1: Determine basis entering arc */ - /*************************************/ - - // finished = true <=> iteration finished - bool finished = false; - // from_ub = true <=> entering arc at upper bound - bool from_ub = false; - startsearch = start_n1; - //startsearchpre = NULL; - last_n1 = NULL; - last_n2 = NULL; - nodetype *np; // general nodeptr - - do { - arctype *eplus; // ->basis entering arc - arctype *pre; // ->predecessor of eplus in list - beacircle(&eplus, &pre, &from_ub); - - if (eplus == NULL) { - finished = true; - } else { - - nodetype *iplus = eplus->tail; // -> tail of basis entering arc - nodetype *jplus = eplus->head; // -> head of basis entering arc - - /******************************************************/ - /* 4.2: Determine leaving arc and maximal flow change */ - /******************************************************/ - - int delta = eplus->upper_bound; // maximal flow change - nodetype *iminus = NULL; // -> tail of basis leaving arc - nodetype *p1 = iplus; - nodetype *p2 = jplus; - - bool to_ub; // to_ub = true <=> leaving arc goes to upperbound - bool xchange; // xchange = true <=> exchange iplus and jplus - while (p1 != p2) { - if (p1->nr_of_nodes<=p2->nr_of_nodes) { - np = p1; - if (from_ub==np->orientation) { - if (delta > np->arc_id->upper_bound - np->flow) { - iminus = np; - delta = np->arc_id->upper_bound - np->flow; - xchange = false; - to_ub = true; - } - } - else if (delta>np->flow) { - iminus = np; - delta = np->flow; - xchange = false; - to_ub = false; - } - p1 = np->father; - continue; - } - np = p2; - if (from_ub != np->orientation) { - if (delta > np->arc_id->upper_bound - np->flow) { - iminus = np; - delta = np->arc_id->upper_bound - np->flow; - xchange = true; - to_ub = true; - } - } - else if (delta > np->flow) { - iminus = np; - delta = np->flow; - xchange = true; - to_ub = false; - } - p2 = np->father; - } - // paths from iplus and jplus to root meet at w - nodetype *w = p1; - nodetype *iw; - nodetype *jminus; // -> head of basis leaving arc - - arctype *eminus; /// ->basis leaving arc - if (iminus == NULL) { - to_ub = !from_ub; - eminus = eplus; - iminus = iplus; - jminus = jplus; - } - else { - if (xchange) { - iw = jplus; - jplus = iplus; - iplus = iw; - } - jminus = iminus->father; - eminus = iminus->arc_id; - } - - // artif_to_lb = true <=> artif. arc goes to lower bound - bool artif_to_lb = false; - if (artificials>1) { - if (iminus==root || jminus==root) { - if (jplus!=root && iplus!=root) { - artificials--; - artif_to_lb = true; - } - else if (eminus==eplus) { - if (from_ub) { - artificials--; - artif_to_lb = true; - } else - artificials++; - } - } - else { - if (iplus == root || jplus == root) - artificials++; - } - } - - /*********************************/ - /* 4.3: Update of data structure */ - /*********************************/ - - int sigma; // change of dual variables - - if (eminus==eplus) { - if (from_ub) delta = -delta; - - bool s_orientation; - if (eminus->tail==iplus) s_orientation = true; - else s_orientation = false; - - np = iplus; - while (np!=w) { - if (np->orientation==s_orientation) { - np->flow -= delta; - } - else { - np->flow += delta; - } - np = np->father; - } - - np = jplus; - while (np!=w) { - if (np->orientation==s_orientation) { - np->flow += delta; - } - else { - np->flow -= delta; - } - np = np->father; - } - - } else { - /* 4.3.2.1 : initialize sigma */ - - if (eplus->tail==iplus) - sigma = eplus->cost + jplus->dual - iplus->dual; - else - sigma = jplus->dual - iplus->dual - eplus->cost; - - // 4.3.2.2 : find new succ. of jminus if current succ. is iminus - - nodetype *newsuc = jminus->successor; // -> new successor - if (newsuc==iminus) { - for (i=1; i<=iminus->nr_of_nodes; i++) - newsuc = newsuc->successor; - } - - /* 4.3.2.3 : initialize data for iplus */ - - nodetype *s_father = jplus; // save area - bool s_orientation; - if (eplus->tail==jplus) s_orientation = false; - else s_orientation = true; - - // eplus_ori = true <=> eplus=(iplus,jplus) - bool eplus_ori = s_orientation; - - int s_flow; - if (from_ub) { - s_flow = eplus->upper_bound - delta; - delta = -delta; - } - else - s_flow = delta; - - arctype *s_arc_id = eminus; - int oldnumber = 0; - nodetype *nd = iplus; // -> current node - nodetype *f = nd->father; // ->father of nd - - /* 4.3.2.4 : traverse subtree under iminus */ - - while (nd!=jminus) { - nodetype *pred = f; // ->predecessor of current node - while (pred->successor != nd) pred = pred->successor; - nodetype *lastnode = nd; // -> last node of subtree - i = 1; - int non = nd->nr_of_nodes - oldnumber; - while (isuccessor; - lastnode->dual += sigma; - i++; - } - nd->dual += sigma; - pred->successor = lastnode->successor; - - if (nd!=iminus) lastnode->successor = f; - else lastnode->successor = jplus->successor; - - nodetype *w_father = nd; // save area - arctype *w_arc_id = nd->arc_id; // save area - - bool w_orientation; - if (nd->arc_id->tail==nd) w_orientation = false; - else w_orientation = true; - - int w_flow; - if (w_orientation==eplus_ori) { - w_flow = nd->flow + delta; - } - else { - w_flow = nd->flow - delta; - } - - nd->father = s_father; - nd->orientation = s_orientation; - nd->arc_id = s_arc_id; - nd->flow = s_flow; - s_father = w_father; - s_orientation = w_orientation; - s_arc_id = w_arc_id; - s_flow = w_flow; - - oldnumber = nd->nr_of_nodes; - nd = f; - f = f->father; - - } - - jminus->successor = newsuc; - jplus->successor = iplus; - - // 4.3.2.5: assign new nr_of_nodes in path from iminus to iplus - - oldnumber = iminus->nr_of_nodes; - np = iminus; - while (np!=iplus) { - np->nr_of_nodes = oldnumber - np->father->nr_of_nodes; - np = np->father; - } - - iplus->nr_of_nodes = oldnumber; - - // 4.3.2.6: update flows and nr_of_nodes in path from jminus to w - - np = jminus; - while (np!=w) { - np->nr_of_nodes -= oldnumber; - if (np->orientation!=eplus_ori) { - np->flow += delta; - } - else { - np->flow -= delta; - } - np = np->father; - } - - // 4.3.2.7 update flows and nr_of_nodes in path from jplus to w - - np = jplus; - while (np!=w) { - np->nr_of_nodes += oldnumber; - if (np->orientation == eplus_ori) { - np->flow += delta; - } - else { - np->flow -= delta; - } - np = np->father; - } - - } - - /***********************************/ - /* 4.4: Update lists B, N' and N'' */ - /***********************************/ - - if (eminus==eplus) { - if (!from_ub) { - if (pre==NULL) - start_n1 = eminus->next_arc; - else - pre->next_arc = eminus->next_arc; - - eminus->next_arc = start_n2; - start_n2 = eminus; - } else { - if (pre==NULL) - start_n2 = eminus->next_arc; - else - pre->next_arc = eminus->next_arc; - eminus->next_arc = start_n1; - start_n1 = eminus; - } - } else { - int wcost = eminus->cost; - int wub = eminus->upper_bound; - int wnum = eminus->arcnum; - nodetype *w_head = eminus->head; - nodetype *w_tail = eminus->tail; - eminus->tail = eplus->tail; - eminus->head = eplus->head; - eminus->upper_bound = eplus->upper_bound; - eminus->arcnum = eplus->arcnum; - eminus->cost = eplus->cost; - eplus->tail = w_tail; - eplus->head = w_head; - eplus->upper_bound = wub; - eplus->cost = wcost; - eplus->arcnum = wnum; - arctype *ep = eplus; - - if (pre!=NULL) - pre->next_arc = ep->next_arc; - else { - if (from_ub) start_n2 = ep->next_arc; - else start_n1 = ep->next_arc; - } - - if (to_ub) { - ep->next_arc = start_n2; - start_n2 = ep; - } else { - if (!artif_to_lb) { - ep->next_arc = start_n1; - start_n1 = ep; - } - } - } - - step++; - - /***********************************************************/ - /* 4.5: Eliminate artificial arcs and artificial root node */ - /***********************************************************/ - - if (artificials==1) { - artificials = 0; - nodetype *nd = root->successor; - arctype *e1 = nd->arc_id; - - if (nd->flow>0) { - feasible = false; - finished = true; - } else { - feasible = true; - if (e1==start_b) { - start_b = e1->next_arc; - } else { - e = start_b; - while (e->next_arc!=e1) - e = e->next_arc; - e->next_arc = e1->next_arc; - } - - iw = root; - root = root->successor; - root->father = root; - sigma = root->dual; - - np = root; - while (np->successor!=iw) { - np->dual -= sigma; - np = np->successor; - } - - np->dual -= sigma; - np->successor = root; - - } - - } - - } - - } while (!finished); - - /*********************/ - /* 5: Return results */ - /*********************/ - - /* Feasible solution? */ - if (artificials!=0 && feasible) { - np = root->successor; - do { - if (np->father==root && np->flow>0) { - feasible = false; - np = root; - } - else - np = np->successor; - } while (np != root); - - arctype *ep = start_n2; - while (ep!=NULL && feasible) { - if (ep==NULL) - break; - if (ep->tail==root && ep->head==root) - feasible = false; - ep = ep->next_arc; - } - } - - int retValue; - - if (feasible) { - - /* Objective function value */ - int zfw = 0; // current total cost - np = root->successor; - while (np!=root) { - if (np->flow!=0) - zfw += np->flow * np->arc_id->cost; - np = np->successor; - } - arctype *ep = start_n2; - while (ep!=NULL) { - zfw += ep->cost * ep->upper_bound; - ep = ep->next_arc; - } - *mcfObj = zfw + lb_cost; - - /* Dual variables */ - // CG: removed computation of duals - np = root->successor; - while (np != root) { - mcfDual[np->name-1] = np->dual; - np = np->successor; - } - mcfDual[root->name-1] = root->dual; - - /* Arc flows */ - for (i=0;isuccessor; - while (np != root) { - // flow on artificial arcs has to be 0 to be ignored! [CG] - OGDF_ASSERT(np->arc_id->arcnum < mm || np->flow == 0); - - if (np->arc_id->arcnum < mm) - mcfFlow[np->arc_id->arcnum] += np->flow; - - np = np->successor; - } - - ep = start_n2; - while (ep!=NULL) { - mcfFlow[ep->arcnum] += ep->upper_bound; - ep = ep->next_arc; - } - - retValue = 0; - - } else { - retValue = 10; - } - - // deallocate artificial arcs - for(i = 1; i <= nn; ++i) - //delete p[i]->arc_id; - delete nodes[i].arc_id; - - return retValue; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/graphalg/MinimumCut.cpp b/ext/OGDF/src/graphalg/MinimumCut.cpp deleted file mode 100644 index 5a10ecbc9..000000000 --- a/ext/OGDF/src/graphalg/MinimumCut.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declares & Implements a minimum-cut algorithmn according - * to an approach of Stoer and Wagner 1997 - * - * \author Mathias Jansen - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -//used solely for efficiency and correctness checks of priority -//queue usage -//#define USE_PRIO - - -namespace ogdf { - - -MinCut::MinCut(Graph &G, EdgeArray &w) : m_GC(G) { - - // Due to the node contraction (which destroys the Graph step by step), - // we have to create a GraphCopy. - //m_GC = new GraphCopy(G); - - // Edge weights are initialized. - edge e; - m_w.init(m_GC); - forall_edges(e,m_GC) { - m_w[e] = w[(m_GC).original(e)]; - } - m_contractedNodes.init(m_GC); - m_minCut = 1e20; -} - - -MinCut::~MinCut() {} - - -void MinCut::contraction(node t, node s) { - - /* - * The contraction of the two nodes \as and \a t is performed as follows: - * in the first step, all edges between \a s and \a t are deleted, and all edges incident - * to \a s are redirected to \a t. Then, node \a s is deleted and the adjacency list of \a t - * is checked for parallel edges. If k parallel edges are found, k-1 of them are deleted - * and their weights are added to the edge that is left. - */ - - // Step 1: redirecting edges and deleting node \a s - adjEntry adj = s->firstAdj(); - while (adj != 0) - { - adjEntry succ = adj->succ(); - edge e = adj->theEdge(); - if (e->source() == t || e->target() == t) { - m_GC.delEdge(e); - } - else if (e->source() == s) { - m_GC.moveSource(e,t); - } - else { - m_GC.moveTarget(e,t); - } - adj = succ; - } - m_GC.delNode(s); - - /* - * Because of technical problems that occur when deleting edges and thus adjacency entries in a loop, - * a NodeArray is filled with the edges incident to node \a t. - * This NodeArray is checked for entries with more than one edge, which corresponds - * to parallel edges. - */ - - // NodeArray containing parallel edges - NodeArray > adjNodes(m_GC); - - forall_adj(adj,t) { - adjNodes[adj->twinNode()].pushBack(adj->theEdge()); - } - - // Step 2: deleting parallel edges and adding their weights - node v = m_GC.firstNode(); - while (v!=0) { - if (adjNodes[v].size() > 1) { - edge e = adjNodes[v].front(); - adjNodes[v].popFront(); - ListConstIterator it; - for (it=adjNodes[v].begin(); it.valid(); ++it) { - - // Add weight of current edge to \a e. - m_w[e] += m_w[(*it)]; - m_GC.delEdge(*it); - } - } - v = v->succ(); - } -} - - -double MinCut::minimumCutPhase() { - - /* - * This function computes the mincut of the current phase. - * First, nodes are added successively in descending order of the sum of - * their incident edge weights to the list \a markedNodes. - * Afterwards, the current mincut value \a cutOfThePhase is computed, which corresponds to the - * sum of the weights of those edges incident to node \a t, which is the node that has been - * added to list \a markedNodes at last. - * At the end, the two last added nodes (\a s and \a t) are contracted and the \cutOfThePhase - * is returned. - */ - - // Contains the mincut value according to the current phase. - double cutOfThePhase; - - List markedNodes; - List leftoverNodes; - - // Contains for each node the sum of the edge weights of those edges - // incident to nodes in list \a markedNodes - NodeArray nodePrio(m_GC); -#ifdef USE_PRIO - BinaryHeap pq(m_GC.numberOfNodes()); - NodeArray::Element*> pqEntry(m_GC); -#endif - // The two nodes that have been added last to the list \a markedNodes. - // These are the two nodes that have to be contracted at the end of the function. - node s,t; - - // Initialization of data structures - node v; - forall_nodes(v,m_GC) { - leftoverNodes.pushBack(v); -#ifdef USE_PRIO - pqEntry[v] = &(pq.insert(v, 0.0)); -#endif - } - nodePrio.fill(0.0); //should do this in constructor init above - - // The start-node can be chosen arbitrarily. It has no effect on the correctness of the algorithm. - // Here, always the first node in the list \a leftoverNodes is chosen. - v = leftoverNodes.popFrontRet(); markedNodes.pushBack(v); - adjEntry adj; - //assumes that no multiedges exist - forall_adj(adj,v) { - nodePrio[adj->twinNode()] = m_w[adj->theEdge()]; -#ifdef USE_PRIO - pq.decPriority(*pqEntry[adj->twinNode()], -m_w[adj->theEdge()]); -#endif - } - - // Temporary variables - ListIterator it1; - node maxWeightNode; ListIterator maxWeightNodeIt; - //replaces line above -#ifdef USE_PRIO - node maxWeightNodePq; -#endif - double mostTightly; - - // Successively adding the most tightly connected node. - while (markedNodes.size() != m_GC.numberOfNodes()) { - - mostTightly = 0.0; - maxWeightNode = NULL; -#ifdef USE_PRIO - //Find the most tightly connected node - maxWeightNodePq = NULL; - if (pq.top()->getPriority() < mostTightly) - { - mostTightly = (maxWeightNodePq = pq.extractMin())->getPriority(); - } -#endif - // The loop computing the most tightly connected node to the current set \a markedNodes. - // For better performance, this should be done using PriorityQueues! Since this algorithmn - // is only used for the Cut-separation within the Branch&Cut-algorithmn for MCPSP, only small - // and moderate Graph sizes are considered. Thus, the total running time is hardly affected. - for(it1=leftoverNodes.begin(); it1.valid(); ++it1) { - - if(nodePrio[(*it1)] > mostTightly) { - maxWeightNode = (*it1); - maxWeightNodeIt = it1; - mostTightly = nodePrio[(*it1)]; - } - } -#ifdef USE_PRIO - OGDF_ASSERT(maxWeightNode == maxWeightNodePq); -#endif - - // If the graph is not connected, maxWeightNode might not be updated in each iteration. - // Todo: Why not? Just because priority is zero? Then we can simplify this... - // Hence, in this case we simply choose one of the leftoverNodes (the first one). - if (maxWeightNode == NULL) { - maxWeightNode = leftoverNodes.front(); - maxWeightNodeIt = leftoverNodes.begin(); - } - - // Adding \a maxWeightNode to the list \a markedNodes - markedNodes.pushBack(maxWeightNode); - - // Deleting \a maxWeightNode from list \a leftoverNodes - leftoverNodes.del(maxWeightNodeIt); - - // Updating the node priorities - adjEntry a; - forall_adj(a,maxWeightNode) { - nodePrio[a->twinNode()] += m_w[a->theEdge()]; - } -#ifdef USE_PRIO - //replaces loop above - forall_adj(a, maxWeightNodePq) { - //should have some decreasePriorityBy instead... - pq.decPriority(*pqEntry[a->twinNode()], - pqEntry[a->twinNode()]->getPriority() - m_w[a->theEdge()]); - } -#endif - }// end of loop while(markedNodes.size()...) - - // Computing value \a cutOfThePhase - cutOfThePhase = 0.0; - ListConstIterator last = markedNodes.rbegin(); - t = (*last); s = *(last.pred()); - adjEntry t_adj; - forall_adj(t_adj,t) { - cutOfThePhase += m_w[t_adj->theEdge()]; - } - - // If the current \a cutOfThePhase is strictly smaller than the global mincut value, - // the partition defining the mincut has to be updated. - if(cutOfThePhase < m_minCut) { - m_partition.clear(); - m_partition.pushBack(m_GC.original(t)); - for(ListConstIterator it = m_contractedNodes[t].begin(); it.valid(); ++it) { - m_partition.pushBack(*it); - } - } - - // Since nodes in \a m_GC correspond to sets of nodes (due to the node contraction), - // the NodeArray \a m_contractedNodes has to be updated. - m_contractedNodes[t].pushBack(m_GC.original(s)); - ListConstIterator contractIt; - for (contractIt = m_contractedNodes[s].begin(); contractIt.valid(); ++contractIt) { - m_contractedNodes[t].pushBack((*contractIt)); - } - - // Performing the node contraction of nodes \a s and \a t. - contraction(t,s); - - return cutOfThePhase; -} - - -double MinCut::minimumCut() { - - /* - * Main loop of the algorithm - * As long as GraphCopy \a m_GC contains at least two nodes, - * function minimumCutPhase() is invoked and \a m_minCut is updated - */ - - for (int i=m_GC.numberOfNodes(); i>1; --i) { - m_minCut = min(m_minCut,minimumCutPhase()); - if (m_minCut == 0.0) return m_minCut; - } - return m_minCut; -} - - -void MinCut::partition(List &nodes) { - - nodes.clear(); - ListConstIterator it; - for (it=m_partition.begin(); it.valid(); ++it) { - nodes.pushBack(*it); - } -} - - -void MinCut::cutEdges(List &edges, Graph &G) { - - edges.clear(); - NodeArray inPartition(G); - inPartition.fill(false); - ListConstIterator nodeIt; - - for (nodeIt=m_partition.begin(); nodeIt.valid(); ++nodeIt) { - inPartition[*nodeIt] = true; - } - - for (nodeIt=m_partition.begin(); nodeIt.valid(); ++nodeIt) { - edge e; - forall_adj_edges(e,(*nodeIt)) { - if(e->source() == (*nodeIt)) { - if(inPartition[e->target()] == false) { - edges.pushBack(e); - } - } else { - if(inPartition[e->source()] == false) { - edges.pushBack(e); - } - } - } - } -} - -} diff --git a/ext/OGDF/src/graphalg/PageRank.cpp b/ext/OGDF/src/graphalg/PageRank.cpp deleted file mode 100644 index 954435446..000000000 --- a/ext/OGDF/src/graphalg/PageRank.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * $Revision: 2597 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-15 19:26:11 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of basic page rank. - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - - -void BasicPageRank::call( - const Graph& graph, - const EdgeArray& edgeWeight, - NodeArray& pageRankResult) -{ - const double initialPageRank = 1.0 / (double)graph.numberOfNodes(); - const double maxPageRankDeltaBound = initialPageRank * m_threshold; - - // the two ping pong buffer - NodeArray pageRankPing(graph, 0.0); - NodeArray pageRankPong(graph, 0.0); - - NodeArray* pCurrPageRank = &pageRankPing; - NodeArray* pNextPageRank = &pageRankPong; - - NodeArray nodeNorm(graph); - - for (node v = graph.firstNode(); v; v = v->succ()) - { - double sum = 0.0; - for (adjEntry adj = v->firstAdj(); adj; adj = adj->succ()) - { - edge e = adj->theEdge(); - sum += edgeWeight[e]; - } - nodeNorm[v] = 1.0 / sum; - } - - pCurrPageRank->init(graph, initialPageRank); - - // main iteration loop - int numIterations = 0; - bool converged = false; - // check conditions - while ( !converged && (numIterations < m_maxNumIterations) ) - { - // init the result of this iteration - pNextPageRank->init(graph, (1.0 - m_dampingFactor) / (double)graph.numberOfNodes()); - // calculate the transfer between each node - for (edge e = graph.firstEdge(); e; e = e->succ()) - { - node v = e->source(); - node w = e->target(); - - double vwTransfer = (edgeWeight[e] * nodeNorm[v] * (*pCurrPageRank)[v]); - double wvTransfer = (edgeWeight[e] * nodeNorm[w] * (*pCurrPageRank)[w]); - (*pNextPageRank)[w] += vwTransfer; - (*pNextPageRank)[v] += wvTransfer; - } - - // damping and calculating change - double maxPageRankDelta = 0.0; - for (node v = graph.firstNode(); v; v = v->succ()) - { - (*pNextPageRank)[v] *= m_dampingFactor; - double pageRankDelta = fabs((*pNextPageRank)[v] - (*pCurrPageRank)[v]); - maxPageRankDelta = std::max(maxPageRankDelta, pageRankDelta); - } - - // swap ping and pong, pong ping, ping pong, lalalala - std::swap(pNextPageRank, pCurrPageRank); - numIterations++; - - // check if the change is small enough - converged = (maxPageRankDelta < maxPageRankDeltaBound); - } - - // normalization - double maxPageRank = (*pCurrPageRank)[graph.firstNode()]; - double minPageRank = (*pCurrPageRank)[graph.firstNode()]; - for (node v = graph.firstNode(); v; v = v->succ()) - { - maxPageRank = std::max(maxPageRank, (*pCurrPageRank)[v]); - minPageRank = std::min(minPageRank, (*pCurrPageRank)[v]); - } - - // init result - pageRankResult.init(graph); - for (node v = graph.firstNode(); v; v = v->succ()) - { - double r = ((*pCurrPageRank)[v] - minPageRank) / (maxPageRank - minPageRank); - pageRankResult[v] = r; - } - // result is now between 0 and 1 -} - -} // end of namespace ogdf diff --git a/ext/OGDF/src/graphalg/ShortestPathsWithBFM.cpp b/ext/OGDF/src/graphalg/ShortestPathsWithBFM.cpp deleted file mode 100644 index 090624039..000000000 --- a/ext/OGDF/src/graphalg/ShortestPathsWithBFM.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class ShorthestPathWithBFM - * - * \author G. W. Klau - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ -// Purpose: -// implementation of shortest path computation -// via Bellman-Ford-Moore -// -// implementation follows Cormen/Leiserson/Rivest - - -#include -#include -#include - - -namespace ogdf { - - bool ShortestPathWithBFM::call - ( - const Graph &G, // directed graph - const node s, // source node - const EdgeArray &length, // length of an edge - NodeArray &d, // contains shortest path distances after call - NodeArray &pi // predecessors - ) - { - const int infinity = 20000000; // big number. danger. think about it. - - //Initialize-Single-Source(G, s): - node v; edge e; - forall_nodes (v, G) { - d[v] = infinity; - pi[v] = NULL; - } - d[s] = 0; - for (int i = 1; i < G.numberOfNodes(); ++i) { - forall_edges (e, G) { - //relax(u, v, w): // e == (u, v), length == w - if (d[e->target()] > d[e->source()] + length[e]) { - d[e->target()] = d[e->source()] + length[e]; - pi[e->target()] = e; - } - } - } - - //check for negative cycle: - forall_edges (e, G) { - if (d[e->target()] > d[e->source()] + length[e]) return false; - } - - return true; - } - - -} // end namespace ogdf diff --git a/ext/OGDF/src/graphalg/mcf_front_reinelt.cpp b/ext/OGDF/src/graphalg/mcf_front_reinelt.cpp deleted file mode 100644 index d8f02eec1..000000000 --- a/ext/OGDF/src/graphalg/mcf_front_reinelt.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief front-end for min-most flow algorithm (Reinelt) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - - - -namespace ogdf { - -bool MinCostFlowReinelt::call( - const Graph &G, - const EdgeArray &lowerBound, - const EdgeArray &upperBound, - const EdgeArray &cost, - const NodeArray &supply, - EdgeArray &flow) -{ - NodeArray dual(G); - return call(G, lowerBound, upperBound, cost, supply, flow, dual); -} - - -// computes min-cost-flow -// returns true if a minimum cost flow could be found -bool MinCostFlowReinelt::call( - const Graph &G, - const EdgeArray &lowerBound, - const EdgeArray &upperBound, - const EdgeArray &cost, - const NodeArray &supply, - EdgeArray &flow, - NodeArray &dual) -{ - OGDF_ASSERT(checkProblem(G,lowerBound,upperBound,supply) == true); - - const int n = G.numberOfNodes(); - const int m = G.numberOfEdges(); - - // assign indices 0, ..., n-1 to nodes in G - // (this is not guaranteed for v->index() ) - NodeArray vIndex(G); - // assigning supply - Array mcfSupply(n); - - node v; - int i = 0; - forall_nodes(v, G) { - mcfSupply[i] = supply[v]; - vIndex[v] = ++i; - } - - - // allocation of arrays for arcs - Array mcfTail(m); - Array mcfHead(m); - Array mcfLb(m); - Array mcfUb(m); - Array mcfCost(m); - Array mcfFlow(m); - Array mcfDual(n+1); // dual[n] = dual variable of root struct - - // set input data in edge arrays - int nSelfLoops = 0; - i = 0; - edge e; - forall_edges(e, G) - { - // We handle self-loops in the network already in the front-end - // (they are just set to the lower bound below when copying result) - if(e->isSelfLoop()) { - nSelfLoops++; - continue; - } - - mcfTail[i] = vIndex[e->source()]; - mcfHead[i] = vIndex[e->target()]; - mcfLb [i] = lowerBound[e]; - mcfUb [i] = upperBound[e]; - mcfCost[i] = cost[e]; - - ++i; - } - - - int retCode; // return (error or success) code - int objVal; // value of flow - - // call actual min-cost-flow function - // mcf does not support single nodes - if ( n > 1) - { - //mcf does not support single edges - if (m < 2) - { - if ( m == 1) - { - e = G.firstEdge(); - flow[e] = lowerBound[e]; - } - retCode = 0; - } - else retCode = mcf(n, m-nSelfLoops, mcfSupply, mcfTail, mcfHead, mcfLb, mcfUb, - mcfCost, mcfFlow, mcfDual, &objVal); - } - else retCode = 0; - - - // copy resulting flow for return - i = 0; - forall_edges(e, G) - { - if(e->isSelfLoop()) { - flow[e] = lowerBound[e]; - continue; - } - - flow[e] = mcfFlow[i]; - if (retCode == 0) { - OGDF_ASSERT( (flow[e]>=lowerBound[e]) && (flow[e]<= upperBound[e]) ) - } - ++i; - } - - // copy resulting dual values for return - i = 0; - forall_nodes(v, G) { - dual[v] = mcfDual[i]; - ++i; - } - - // successful if retCode == 0 - return (retCode == 0); -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/incremental/SimpleIncNodeInserter.cpp b/ext/OGDF/src/incremental/SimpleIncNodeInserter.cpp deleted file mode 100644 index 204c25938..000000000 --- a/ext/OGDF/src/incremental/SimpleIncNodeInserter.cpp +++ /dev/null @@ -1,665 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of simple incremental node inserter - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -//------------------------------------- -//zwei Moeglichkeiten in PlanRep Elemente inkrementell zu -//bearbeiten: Elemente verstecken mit hide/activate -//oder Elemente, die nicht aktiv sind, loeschen - -//Man kann noch spezialfaelle abfragen, zb braucht man nicht -//viel zu machen, wenn der Grad im insertionface 1 ist - -#include -#include - -namespace ogdf { - -SimpleIncNodeInserter::SimpleIncNodeInserter(PlanRepInc &PG) -: IncNodeInserter(PG), m_incidentEdges(PG, 0), m_forbidCrossings(true) -{ - -}//SimpleNodeInserter - -SimpleIncNodeInserter::~SimpleIncNodeInserter() -{ - node v; - forall_nodes(v, *m_planRep) - { - if (m_incidentEdges[v] != 0) - delete m_incidentEdges[v]; - }//forallnodes -}//destuctor - - -//insert a copy for original node v -void SimpleIncNodeInserter::insertCopyNode(node v, Graph::NodeType vTyp) -{ - OGDF_ASSERT(m_planRep->copy(v) == 0) - - //insert a new node copy - node vCopy = m_planRep->newCopy(v, vTyp); - if (v->degree() == 0) return; - //insert all adjacent edges to already inserted nodes - adjEntry adjOrig = v->firstAdj(); - do - { - node wOrig = adjOrig->twinNode(); - node wCopy = m_planRep->copy(wOrig); - edge e = adjOrig->theEdge(); - if (wCopy && (m_planRep->chain(e).size() == 0)) - { - //inserted edge copy - edge eCopy; - //newCopy can cope with zero value for adjEntry - if (v == e->source()) - eCopy = m_planRep->newCopy(vCopy, wCopy->firstAdj(), e); - else - eCopy = m_planRep->newCopy(wCopy, vCopy->firstAdj(), e); - - //TODO: update component number in planrepinc - - }//if edge to be inserted - adjOrig = adjOrig->cyclicSucc(); - } while (adjOrig != v->firstAdj()); -}//insertCopyNode - -//insert a copy for original node v respecting the given -//embedding, i.e. inserting crossings at adjacent edges -//if necessary -//has currently running time of m*n because faces in the embedding -//are recomputed, speed up by updating them manually -void SimpleIncNodeInserter::insertCopyNode( - node v, - CombinatorialEmbedding &E, - Graph::NodeType vTyp) -{ - m_nodeOf.init(E, 0); - m_insertFaceNode.init(*m_planRep, false); - m_vAdjNodes.init(*m_planRep, false); - m_incidentEdges.init(*m_planRep, 0); - - m_primalAdj.init(m_dual); - m_primalIsGen.init(m_dual, false); - - //--------------------------------------------- - //first identify a face to insert the node into - face f = 0; - if (m_planRep->numberOfEdges() > 0) - { - f = getInsertionFace(v, E);//, insertAfterAdj); - OGDF_ASSERT(f != 0) - } - - //ListIterator itAfter = insertAfterAdj.begin(); - //we insert v into f creating crossings for edges leading - //to nodes outside of f (if necessary) - node vCopy = m_planRep->newCopy(v, vTyp); - - //TODO: insert nodetypes here - - //----------------------------------------------------- - //after having selected a face for insertion, we insert - //the crossing free edges - adjEntry adExternal = 0; - if ((f != 0) && (f == E.externalFace())) - { - //stop if only selfloops - int count = 0; - int eNum = max(10, m_planRep->numberOfEdges()+1); - adExternal = E.externalFace()->firstAdj(); - while ( (adExternal->theNode() == adExternal->twinNode()) && - (count < eNum) ) - { - adExternal = adExternal->faceCycleSucc(); - count++; - } - OGDF_ASSERT(count < eNum) - } - insertFaceEdges(v, vCopy, f, E, adExternal); - //now the edges left are: - //edges to nodes with not yet existing copies - //edges to nodes outside the face f - - E.computeFaces();//should we manually update the face? - - if (adExternal) - { - E.setExternalFace(E.rightFace(adExternal)); - }//if external face - - //------------------------------------------------- - //then we insert the edges leading to nodes outside - //face f - //if (v->degree() != vCopy->degree()) - insertCrossingEdges(v, vCopy, E, adExternal); - - //TODO: remove reinsert for cross edges? Not necessary - -}//insertcopynode - - -//----------------- -//protected members - -//simple strategy: look for the face with the most nodes adjacent -//to v (in original) on its border -face SimpleIncNodeInserter::getInsertionFace(node v, CombinatorialEmbedding &E) - //List &insertAfterAdj) -{ - //we always return a face if one exists - if (v->degree() < 1) return E.maximalFace(); - - face bestFace = E.firstFace(); - - //E is on m_planRep, the copy, v is an original node - - //construct the dual graph - //Graph GDual; - //EdgeArray flow(GDual, 0); - - FaceArray numAdj(E, 0); - - //we iterate over all adjacent edges and over all - //touching faces on the opposite nodes - //in case of a tie, return the larger face - edge e; - forall_adj_edges(e, v) - { - node wCopy = m_planRep->copy(e->opposite(v)); - if (wCopy == 0) continue; //not yet inserted - - m_vAdjNodes[wCopy] = true; - if (m_incidentEdges[wCopy] == 0) - m_incidentEdges[wCopy] = OGDF_NEW List; - m_incidentEdges[wCopy]->pushBack(e); - OGDF_ASSERT(m_planRep->chain(e).size() == 0) - adjEntry adRun; - forall_adj(adRun, wCopy) - { - face f = E.rightFace(adRun); - numAdj[f]++; - - if (numAdj[f] > numAdj[bestFace]) - bestFace = f; - if ( (numAdj[f] == numAdj[bestFace]) && - ((f->size() > bestFace->size()) || (f == E.externalFace()))) - bestFace = f; - }//foralladj - }//foralledges - - return bestFace; -}//getInsertionFace - - -//insert copy for edges incident to v into face f, making vCopy a node -//in this face (which means we split this face on vCopy) -void SimpleIncNodeInserter::insertFaceEdges(node v, node vCopy, face f, - CombinatorialEmbedding &E, - adjEntry &adExternal) -{ - //it is easy to insert the edges in f by running around the border - //of f and process the edges in the m_incidentEdges list, - //this keeps the embedding, but we do not want to check new inserted edges - //we have to take care of the external face - //NodeArray processed(*m_planRep, false); - - //if we have no face given, we assume that we only have one node so far - //plus the new copy - if ((f == 0) && (m_planRep->numberOfNodes() == 2)) - { - edge e; - node sv = m_planRep->firstNode(); - node svOriginal = m_planRep->original(sv); - - //m_vAdjNodes is not set for this case! - //we first insert one single edge, compute faces and then insert the - //remaining multiple edges - bool firstEdge = true; - adjEntry behindAdj = 0; - forall_adj_edges(e, svOriginal) - { - if (e->opposite(svOriginal) == v) - { - edge e2 = 0; - if (firstEdge) - { - //just insert the edge - if (e->target() == v) - e2 = m_planRep->newCopy(sv, 0, e); - else e2 = m_planRep->newCopy(vCopy, 0, e); - - if (m_planRep->componentNumber(vCopy) == -1) - m_planRep->componentNumber(vCopy) = m_planRep->componentNumber(sv); - - E.computeFaces(); - firstEdge = false; - behindAdj = sv->firstAdj(); - } - else - { - //preserve embedding - e2 = m_planRep->newCopy(vCopy, behindAdj, e, E); - behindAdj = behindAdj->cyclicSucc(); - } - }//if adjacent to v - }//Foralladjedges - - //we don't have to care about the external face, just set one - return; - }//if f == 0 - - List faceAdj; - adjEntry adFace = f->firstAdj(); - do - { - faceAdj.pushBack(adFace); - adFace = adFace->faceCycleSucc(); - } while (adFace != f->firstAdj()); - ListIterator itAd = faceAdj.begin(); - //do - while (itAd.valid()) - { - adFace = (*itAd); - - //external face handling - ListIterator adLast = itAd.pred(); - //if (adLast != 0) - { - if ( adLast.valid() && ((*adLast) == adExternal) ) - { - adExternal = adFace; - } - } - - node u = adFace->theNode(); - m_insertFaceNode[u] = true; - //process all insertion edges at original(u) - //is this node adjacent to v? - if (m_vAdjNodes[u]) - { - //insert egdes one time for multiple occurences - m_vAdjNodes[u] = false; - //save external face - //adEntry adExt = 0; - //if (adFace == adExternal) - OGDF_ASSERT(m_incidentEdges[u] != 0) - ListIterator it = m_incidentEdges[u]->begin(); - OGDF_ASSERT(m_planRep->chain((*it)).size() == 0) - while (it.valid()) - { - //pushes edge onto the adjacency list of vCopy - //correct planar embedding is therefore preserved - //checks direction of inserted edge - m_planRep->newCopy(vCopy, adFace, (*it), E); - - //----------------------- - //component number update - //set new number or delete treeConnnection edge - if (m_planRep->componentNumber(vCopy) == -1) - m_planRep->componentNumber(vCopy) = m_planRep->componentNumber(u); - else if (m_planRep->componentNumber(vCopy) != m_planRep->componentNumber(u)) - {//we have to check the external face - edge tEdge = m_planRep->treeEdge(m_planRep->componentNumber(vCopy), - m_planRep->componentNumber(u)); - if (tEdge != 0) - { - if ((tEdge->adjSource() == adExternal) || - (tEdge->adjTarget() == adExternal)) - {//can never be the only edge at this node, cyclic is safe - if (tEdge->adjSource() == adExternal) - adExternal = tEdge->adjSource()->twin()->cyclicPred(); - else adExternal = tEdge->adjTarget()->cyclicSucc()->twin(); - - }//if adexternal edge deleted - }//if connectivity edge - m_planRep->deleteTreeConnection(m_planRep->componentNumber(vCopy), - m_planRep->componentNumber(u), E); - } - //----------------------- - - it++; - }//while edges incident to u - - }//if u incident to edges at v - - itAd++; - } - //} while (adFace != f->firstAdj()); - - //edge e; - //bool *completed = new bool[v->degree()]; - - -}//insertfaceedges - - -//insert edge copies at vCopy for edges at v that cannot be -//inserted without crossings in the current embedding -void SimpleIncNodeInserter::insertCrossingEdges(node v, node vCopy, - CombinatorialEmbedding &E, - adjEntry &adExternal) -{ - OGDF_ASSERT(m_planRep->copy(v) == vCopy) - //there can exist treeConnectivity edges - //if (v->degree() == vCopy->degree()) return; - bool processed = true; - edge e; - { - forall_adj_edges(e, v) - { - if (m_planRep->chain(e).size() == 0) - { - processed = false; - break; - } - } - }//foralledges - - if (processed) return; - - constructDual(*m_planRep, E, m_forbidCrossings); - - forall_adj_edges(e, v) - { - //already inserted face edge, unten weglassen - if (m_planRep->chain(e).size() != 0) - continue; - node wCopy = m_planRep->copy(e->opposite(v)); - //the node copy has to exist already - if (wCopy == 0) continue; - OGDF_ASSERT(wCopy) - - node vs = vCopy, vt = wCopy; - if (v == e->target()) - { - vs = wCopy; - vt = vCopy; - } - - SList crossedEdges; - //we already inserted a copy for edge e - if (m_planRep->chain(e).size() != 0) - continue; - findShortestPath(E, vs, vt, m_planRep->typeOrig(e), crossedEdges); - - insertEdge(E, e, crossedEdges, m_forbidCrossings); - //----------------------- - //component number update - //set new number or delete treeConnnection edge - if (m_planRep->componentNumber(vCopy) == -1) - m_planRep->componentNumber(vCopy) = m_planRep->componentNumber(wCopy); - else if (m_planRep->componentNumber(vCopy) != m_planRep->componentNumber(wCopy)) - {//we have to check the external face - edge tEdge = m_planRep->treeEdge(m_planRep->componentNumber(vCopy), - m_planRep->componentNumber(wCopy)); - if (tEdge != 0) - { - if ((tEdge->adjSource() == adExternal) || - (tEdge->adjTarget() == adExternal)) - {//can never be the only edge at this node, cyclic is safe - if (tEdge->adjSource() == adExternal) - adExternal = tEdge->adjSource()->twin()->cyclicPred(); - else adExternal = tEdge->adjTarget()->cyclicSucc()->twin(); - - }//if adexternal edge deleted - }//if connectivity edge - m_planRep->deleteTreeConnection(m_planRep->componentNumber(vCopy), - m_planRep->componentNumber(wCopy), E); - } - - //----------------------- - }//foralladjedges - -}//insertCrossingEdges - -void SimpleIncNodeInserter::constructDual(const Graph &G, - const CombinatorialEmbedding &E, - //node vCopy, - bool forbidCrossings) -{ - m_dual.clear(); - - // insert a node in the dual graph for each face in E - face f; - forall_faces(f,E) - m_nodeOf[f] = m_dual.newNode(); - - // Insert an edge into the dual graph for each adjacency entry in E. - // The edges are directed from the left face to the right face. - node v; - forall_nodes(v,G) - { - adjEntry adj; - forall_adj(adj,v) - { - node vLeft = m_nodeOf[E.leftFace (adj)]; - node vRight = m_nodeOf[E.rightFace(adj)]; - - edge e = m_dual.newEdge(vLeft,vRight); - m_primalAdj[e] = adj; - - // mark dual edges corresponding to generalizations - if (forbidCrossings) - if (m_planRep->typeOf(adj->theEdge()) == Graph::generalization) - m_primalIsGen[e] = true; - } - } - - // Augment the dual graph by two new vertices. These are used temporarily - // when searching for a shortest path in the dual graph. - m_vS = m_dual.newNode(); - m_vT = m_dual.newNode(); - -}//constructdual - - -//--------------------------------------------------------- -// finds a shortest path in the dual graph augmented by s and t (represented -// by m_vS and m_vT); returns list of crossed adjacency entries (corresponding -// to used edges in the dual) in crossed. -// Used to insert edges with crossings adjacent to insertion node v -void SimpleIncNodeInserter::findShortestPath( - const CombinatorialEmbedding &E, - node s, - node t, - Graph::EdgeType eType, - SList &crossed) -{ - OGDF_ASSERT(s != t); -//if (!isConnected(m_dual)) cout<<"Not connected\n"< spPred(m_dual,0); - QueuePure queue; - int oldIdCount = m_dual.maxEdgeIndex(); - - // augment dual by edges from s to all adjacent faces of s ... - adjEntry adj; - forall_adj(adj,s) - { - // starting edges of bfs-search are all edges leaving s - edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]); - m_primalAdj[eDual] = adj; - queue.append(eDual); - } - - // ... and from all adjacent faces of t to t - forall_adj(adj,t) { - edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT); - m_primalAdj[eDual] = adj; - } - - // actual search (using bfs on directed dual) - for( ; ; ) - { - // next candidate edge - edge eCand = queue.pop(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == m_vT) - { - // ... then search is done. - // constructed list of used edges (translated to crossed - // adjacency entries in PG) from t back to s (including first - // and last!) - - do { - edge eDual = spPred[v]; - crossed.pushFront(m_primalAdj[eDual]); - v = eDual->source(); - } while(v != m_vS); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if (v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - queue.append(e); - } - } - } - } - - - // remove augmented edges again - while ((adj = m_vS->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - while ((adj = m_vT->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - m_dual.resetEdgeIdCount(oldIdCount); -}//findshortestpath - -//--------------------------------------------------------- -// inserts edge e according to insertion path crossed. -// updates embedding and dual graph -// -void SimpleIncNodeInserter::insertEdge( - CombinatorialEmbedding &E, - edge eOrig, - const SList &crossed, - bool forbidCrossingGens) -{ - // remove dual nodes on insertion path - SListConstIterator it; - for(it = crossed.begin(); it != crossed.rbegin(); ++it) { - m_dual.delNode(m_nodeOf[E.rightFace(*it)]); - } - - // update primal - m_planRep->insertEdgePathEmbedded(eOrig,E,crossed); - - // insert new face nodes into dual - const List &path = m_planRep->chain(eOrig); - ListConstIterator itEdge; - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adj = (*itEdge)->adjSource(); - m_nodeOf[E.leftFace (adj)] = m_dual.newNode(); - m_nodeOf[E.rightFace(adj)] = m_dual.newNode(); - } - - // insert new edges into dual - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adjSrc = (*itEdge)->adjSource(); - face f = E.rightFace(adjSrc); // face to the right of adj in loop - node vRight = m_nodeOf[f]; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - node vLeft = m_nodeOf[E.leftFace(adj)]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_primalAdj[eLR] = adj; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_primalAdj[eRL] = adj->twin(); - - if(forbidCrossingGens && - m_planRep->typeOf(adj->theEdge()) == Graph::generalization) - { - m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - - // the other face adjacent to *itEdge ... - f = E.rightFace(adjSrc->twin()); - vRight = m_nodeOf[f]; - - adj1 = f->firstAdj(); - adj = adj1; - do { - node vLeft = m_nodeOf[E.leftFace(adj)]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_primalAdj[eLR] = adj; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_primalAdj[eRL] = adj->twin(); - - if(forbidCrossingGens && - m_planRep->typeOf(adj->theEdge()) == Graph::generalization) - { - m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - } -}//insertedge - -}//namespace ogdf - diff --git a/ext/OGDF/src/labeling/ELabelPosSimple.cpp b/ext/OGDF/src/labeling/ELabelPosSimple.cpp deleted file mode 100644 index 91d6a8209..000000000 --- a/ext/OGDF/src/labeling/ELabelPosSimple.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements simple labeling algorithm - * - * \author Joachim Kupke - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - - - ELabelPosSimple::ELabelPosSimple() : -m_absolut(true), - m_marginDistance(0.2), - m_edgeDistance(0.2), - m_midOnEdge(true) -{ } - - -ELabelPosSimple::~ELabelPosSimple() -{ } - - -// returns the segment of the polyline containing the point -// that is fraction*bends.length() away from the start -static DLine segment(DPolyline &bends, double fraction) -{ - double targetpos = bends.length()*fraction; - double pos = 0.0; - - ListConstIterator iter, next; - for (iter = next = bends.begin(), next++; next.valid(); iter++, next++) { - pos += (*iter).distance(*next); - if (pos >= targetpos) - return DLine(*iter, *next); - } - - return DLine(*--iter, bends.back()); -} - - -// liefert den Punkt neben dem Segment (links oder rechts, siehe 'left'), der orthogonal von -// 'p' die Entfernung 'newLen' von diesem Segment hat. -static DPoint leftOfSegment(const DLine &segment, const DPoint &p, double newLen, bool left = true) -{ - DVector v; - if (p == segment.start()) - v = segment.end() - p; - else - v = p - segment.start(); - - DVector newPos; - if (left) newPos = ++v; - else newPos = --v; - - // newPos hat immer L?nge != 0 - newPos = (newPos * newLen) / newPos.length(); - - return p + newPos; -} - - -void ELabelPosSimple::call(GraphAttributes &ug, ELabelInterface &eli) -{ - //ug.addNodeCenter2Bends(); - edge e; - forall_edges(e, ug.constGraph()) { - EdgeLabel &el = eli.getLabel(e); - DPolyline bends = ug.bends(e); - - bends.normalize(); - - if (bends.size() < 2) - OGDF_THROW_PARAM(AlgorithmFailureException, afcLabel); - - double frac; - - if (m_absolut) { - double len = bends.length(); - if (len == 0.0) - frac = 0.0; - else - frac = m_marginDistance / len; - - } - else { - frac = m_marginDistance; - } - - if (frac < 0.0) frac = 0.0; - if (frac > 0.4) frac = 0.4; - - double midFrac = 0.5; - double startFrac = frac; - double endFrac = 1.0 -frac; - - // hole Positionen auf der Kante - DPoint midPoint = bends.position(midFrac); - DPoint startPoint = bends.position(startFrac); - DPoint endPoint = bends.position(endFrac); - - // hole die beteiligten Segmente - DLine midLine = segment(bends, midFrac); - DLine startLine = segment(bends, startFrac); - DLine endLine = segment(bends, endFrac); - - // berechne die Labelpositionen - if (el.usedLabel(elEnd1)) { - DPoint np = leftOfSegment(startLine, startPoint, m_edgeDistance, true); - el.setX(elEnd1, np.m_x); - el.setY(elEnd1, np.m_y); - } - - if (el.usedLabel(elMult1)) { - DPoint np = leftOfSegment(startLine, startPoint, m_edgeDistance, false); - el.setX(elMult1, np.m_x); - el.setY(elMult1, np.m_y); - } - - if (el.usedLabel(elName)) { - DPoint np = m_midOnEdge ? midPoint : leftOfSegment(midLine, midPoint, m_edgeDistance, true); - el.setX(elName, np.m_x); - el.setY(elName, np.m_y); - } - - if (el.usedLabel(elEnd2)) { - DPoint np = leftOfSegment(endLine, endPoint, m_edgeDistance, true); - el.setX(elEnd2, np.m_x); - el.setY(elEnd2, np.m_y); - } - - if (el.usedLabel(elMult2)) { - DPoint np = leftOfSegment(endLine, endPoint, m_edgeDistance, false); - el.setX(elMult2, np.m_x); - el.setY(elMult2, np.m_y); - } - } -} - -} diff --git a/ext/OGDF/src/layered/CoffmanGrahamRanking.cpp b/ext/OGDF/src/layered/CoffmanGrahamRanking.cpp deleted file mode 100644 index 1e79d72ca..000000000 --- a/ext/OGDF/src/layered/CoffmanGrahamRanking.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definition of coffman graham ranking algorithm for Sugiyama - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - -namespace ogdf { - -CoffmanGrahamRanking::CoffmanGrahamRanking() : m_w(3) -{ - m_subgraph.set(new DfsAcyclicSubgraph()); -} - - -void CoffmanGrahamRanking::call (const Graph& G, NodeArray& rank) -{ - rank.init(G); - GraphCopy gc(G); - - m_subgraph.get().callAndReverse(gc); - removeTransitiveEdges(gc); - - List > ready_nodes; - NodeArray deg(gc); - NodeArray pi(gc); - m_s.init(gc); - - node v; - List edges; - - forall_nodes(v,gc) { - edges.clear(); - gc.inEdges(v, edges); - deg[v] = edges.size(); - if (deg[v] == 0) { - ready_nodes.pushBack(Tuple2(v,0)); - } - m_s[v].init(deg[v]); - } - - int i = 1; - while(!ready_nodes.empty()) { - v = ready_nodes.popFrontRet().x1(); - pi[v] = i++; - - adjEntry adj; - forall_adj(adj,v) { - if ((adj->theEdge()->source()) == v) { - node u = adj->twinNode(); - m_s[u].insert(pi[v]); - if (--deg[u] == 0) { - insert(u,ready_nodes); - } - } - } - } - - - List ready, waiting; - - forall_nodes(v,gc) { - edges.clear(); - gc.outEdges(v, edges); - deg[v] = edges.size(); - if (deg[v] == 0) { - insert(v,ready,pi); // ready.append(v); - } - } - - int k; - // for all ranks - for (k = 1; !ready.empty(); k++) { - - for (i = 1; i <= m_w && !ready.empty(); i++) { - node u = ready.popFrontRet(); - rank[gc.original(u)] = k; - - gc.inEdges >(u, edges); - for (ListIterator it = edges.begin(); it.valid() ; ++it){ - if (--deg[(*it)->source()] == 0){ - waiting.pushBack((*it)->source()); - } - } - } - - while (!waiting.empty()) { - insert(waiting.popFrontRet(), ready, pi); - } - } - - k--; - forall_nodes(v,G){ - rank[v] = k - rank[v]; - } - - m_s.init(); -} - - -void CoffmanGrahamRanking::insert (node u, List > &ready_nodes) -{ - int j = 0; - - for( ListIterator > it = ready_nodes.rbegin(); it.valid(); --it) { - node v = (*it).x1(); - int sigma = (*it).x2(); - - if (sigma < j) { - ready_nodes.insertAfter(Tuple2(u,j), it); - return; - } - - if (sigma > j) continue; - - const _int_set &x = m_s[u], &y = m_s[v]; - int k = min(x.length(), y.length()); - - while (j < k && x[j] == y[j]) { - j++; - } - - if (j == k) { - if (x.length() < y.length()) continue; - - (*it).x2() = k; - ready_nodes.insertAfter(Tuple2(u,sigma), it); - return; - } - - if (x[j] < y[j]) continue; - - (*it).x2() = j; - ready_nodes.insert(Tuple2(u,sigma), it); - return; - } - - ready_nodes.pushFront(Tuple2(u,j)); -} - - -void CoffmanGrahamRanking::insert (node v, List &ready, const NodeArray &pi) -{ - for( ListIterator it = ready.rbegin(); it.valid(); --it) { - if (pi[v] <= pi[*it]) { - ready.insertAfter(v, it); - return; - } - } - - ready.pushFront(v); -} - - -void CoffmanGrahamRanking::dfs(node v) -{ - visited->push(v); - mark[v] |= 1; - - node w; - adjEntry adj; - forall_adj(adj,v) { - if ((adj->theEdge()->source()) == v) { - w = adj->twinNode(); - if (mark[w] & 2) { - mark[w] |= 4; - } - - if ((mark[w] & 1) == 0) { - dfs(w); - } - } - } -} - -void CoffmanGrahamRanking::removeTransitiveEdges (Graph& G) -{ - node v, w; - List vout; - - mark.init(G,0); - visited = new StackPure(); - - forall_nodes(v,G) { - G.outEdges >(v, vout); - /* alternative: iterate over all adjELements (only out Edges) - * - * forall_adj(adj,v) { - * if ((adj->theEdge()->source()) == v) ... - * - * In this solution a List is generated, because we iterate three times - * over this subset of adjElements - */ - for (ListIterator it = vout.begin(); it.valid() ; ++it){ - w = (*it)-> target(); - mark[w] = 2; - } - - // forall out edges - for (ListIterator it = vout.begin(); it.valid() ; ++it){ - w = (*it)-> target(); - - // if (w != 1) - if ((mark[w] & 1) == 0) { - dfs(w); - } - } - - // forall out edges - for (ListIterator it = vout.begin(); it.valid() ; ++it){ - node u = (*it)->target(); - if (mark[u] & 4) { - G.delEdge(*it); - } - } - while (!visited->empty()) - mark[visited->pop()] = 0; - } - - mark.init(); - delete visited; -} - -} //namespace ogdf diff --git a/ext/OGDF/src/layered/CrossingsMatrix.cpp b/ext/OGDF/src/layered/CrossingsMatrix.cpp deleted file mode 100644 index db1438b6e..000000000 --- a/ext/OGDF/src/layered/CrossingsMatrix.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of crossings matrix. - * - * \author Andrea Wagner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf -{ -//------------------------------------------------------------------- -// CrossingMatrix -//------------------------------------------------------------------- - -CrossingsMatrix::CrossingsMatrix(const Hierarchy &H) -{ - int max_len = 0; - for (int i = 0; i < H.size(); i++) - { - int len = H[i].size(); - if (len > max_len) - max_len = len; - } - - map.init(max_len); - matrix.init(0, max_len - 1, 0, max_len - 1); - m_bigM = 10000; -} - - -void CrossingsMatrix::init(Level &L) -{ - const Hierarchy &H = L.hierarchy(); - - for (int i = 0; i < L.size(); i++) - { - map[i] = i; - for (int j = 0; j < L.size(); j++) - matrix(i,j) = 0; - } - - for (int i = 0; i < L.size(); i++) - { - node v = L[i]; - const Array &L_adj_i = L.adjNodes(v); - - for(int k = 0; k < L_adj_i.size(); k++) - { - int pos_adj_k = H.pos(L_adj_i[k]); - for (int j = i + 1; j < L.size(); j++) - { - const Array &L_adj_j = L.adjNodes(L[j]); - - for (int l = 0; l < L_adj_j.size(); l++) - { - int pos_adj_l = H.pos(L_adj_j[l]); - matrix(i,j) += (pos_adj_k > pos_adj_l); - matrix(j,i) += (pos_adj_l > pos_adj_k); - } - } - } - } -} - - -void CrossingsMatrix::init(Level &L, const EdgeArray *edgeSubGraph) -{ - OGDF_ASSERT(edgeSubGraph != 0); - init(L); - - const Hierarchy &H = L.hierarchy(); - const GraphCopy &HC(H); - - // calculate max number of graphs in edgeSubGraph - edge d; - int max = 0; - forall_edges(d, HC.original()) { - for (int i = 31; i > max; i--) - { - if((*edgeSubGraph)[d] & (1 << i)) - max = i; - } - } - - // calculation differs from ordinary init since we need the edges and not only the nodes - for (int k = 0; k <= max; k++) { - for (int i = 0; i < L.size(); i++) - { - node v = L[i]; - edge e; - // H.direction == 1 if direction == upward - if (H.direction()) { - forall_adj_edges(e,v) { - if ((e->source() == v) && ((*edgeSubGraph)[HC.original(e)] & (1 << k))) { - int pos_adj_e = H.pos(e->target()); - for (int j = i+1; j < L.size(); j++) { - node w = L[j]; - edge f; - forall_adj_edges(f,w) { - if ((f->source() == w) && ((*edgeSubGraph)[HC.original(f)] & (1 << k))) - { - int pos_adj_f = H.pos(f->target()); - matrix(i,j) += m_bigM * (pos_adj_e > pos_adj_f); - matrix(j,i) += m_bigM * (pos_adj_f > pos_adj_e); - } - } - } - } - } - } - else { - forall_adj_edges(e,v) { - if ((e->target() == v) && ((*edgeSubGraph)[HC.original(e)] & (1 << k))) { - int pos_adj_e = H.pos(e->source()); - for (int j = i+1; j < L.size(); j++) { - node w = L[j]; - edge f; - forall_adj_edges(f,w) { - if ((f->target() == w) && ((*edgeSubGraph)[HC.original(f)] & (1 << k))) - { - int pos_adj_f = H.pos(f->source()); - matrix(i,j) += m_bigM * (pos_adj_e > pos_adj_f); - matrix(j,i) += m_bigM * (pos_adj_f > pos_adj_e); - } - } - } - } - } - } - } - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/FastHierarchyLayout.cpp b/ext/OGDF/src/layered/FastHierarchyLayout.cpp deleted file mode 100644 index c36f02207..000000000 --- a/ext/OGDF/src/layered/FastHierarchyLayout.cpp +++ /dev/null @@ -1,1254 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the third phase of the Sugiyama - * algorithm - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - -#define forallnodes for(actNode=0;actNode>(istream& in,withKey& wk) { - in>>wk.element>>wk.key; - return in; - } -}; - - - -class cmpWithKey { -public: - static int compare(const withKey &wk1, const withKey &wk2) { - if(wk1.keywk2.key) return 1; - return 0; - } - OGDF_AUGMENT_STATICCOMPARER(withKey) -}; - - - -/** - * \brief Class kList extends the class List by functions needed in the FastHierarchLayout algorithm. - * - * Especially, it computes the median of a list and reduces it. - */ -class kList : public List { - -public: - - bool pop(int& e,double& k) { - if(empty()) return 0; - withKey wk=popFrontRet(); - e=wk.element; - k=wk.key; - return 1; - } - - double peek() { - return front().key; - } - - void add(int e,double k) { - withKey wK; - wK.element=e; - wK.key=k; - pushBack(wK); - } - - double median() const { - int sz = size(); - if(sz == 0) - return 0; - ListConstIterator it = get(sz/2); - double k = (*it).key; - if (sz == 2*(int) (sz/2)) - k = (k + (*it.pred()).key) / 2; - return k; - } - - - //! Scans the list for pairs of elements with the same double key. - /** - * Replaces them by one element. If integer key is 0, it removes element from list. - * Precondition : list is sorted. - */ - void reduce(kList& newList) { - if(empty()) return; - withKey oldWK,newWK; - newWK = oldWK = popFrontRet(); - - while(!empty()) { - oldWK = popFrontRet(); - if ((oldWK.key) > (newWK.key) + ALLOW || - (oldWK.key) < (newWK.key) - ALLOW) { - if(newWK.element) - newList.pushBack(newWK); - newWK = oldWK; - } - else - newWK.element += oldWK.element; - } - if(newWK.element) - newList.pushBack(newWK); - } -}; - - - -// ** Member functions of FastHierarchyLayout ** - -FastHierarchyLayout::FastHierarchyLayout() -{ - m_minNodeDist = 3; - m_minLayerDist = 3; - m_fixedLayerDist = 0; -} - - -FastHierarchyLayout::FastHierarchyLayout(const FastHierarchyLayout &fhl) -{ - m_minNodeDist = fhl.m_minNodeDist; - m_minLayerDist = fhl.m_minLayerDist; - m_fixedLayerDist = fhl.m_fixedLayerDist; -} - - -FastHierarchyLayout &FastHierarchyLayout::operator=(const FastHierarchyLayout &fhl) -{ - m_minNodeDist = fhl.m_minNodeDist; - m_minLayerDist = fhl.m_minLayerDist; - m_fixedLayerDist = fhl.m_fixedLayerDist; - - return *this; -} - - -void FastHierarchyLayout::doCall(const Hierarchy& H, - GraphCopyAttributes &AGC) -{ - const GraphCopy& GC = H; - int actLayer = 0; - int actNode = 0; - node v1,v2; - edge e1,e2; - int n1,n2; - List *newEdge; - - // initialize class variables - - n = GC.numberOfNodes(); - m = GC.numberOfEdges(); - k = H.size(); - x = new double[n]; - breadth = new double[n]; - layer = new int[n]; - adj[0] = new List[n]; - adj[1] = new List[n]; - virt = new bool[n]; - longEdge = new List*[n]; - height = new double[k]; - y = new double[k]; - first = new int[k+1]; - - // CG - forallnodes { - longEdge[actNode] = 0; - } - - // Compute first. - first[0] = 0; - foralllayers { - first[actLayer+1] = first[actLayer]+H[actLayer].size(); - height[actLayer] = 0; - } - - // Compute - // breadth, height, virt, longEdge for nonvirtual nodes - forall_nodes(v1,GC) { - n1 = first[H.rank(v1)] + H.pos(v1); // Number nodes top down and from left to right - virt[n1] = H.isLongEdgeDummy(v1); - breadth[n1] = 0; - layer[n1] = H.rank(v1); - if(!virt[n1]) { - breadth[n1] = AGC.getWidth(v1); - incrTo(height[layer[n1]],AGC.getHeight(v1)); - newEdge = OGDF_NEW List; - newEdge->pushBack(n1); - longEdge[n1] = newEdge; - } - } - - // compute long Edge for virtual nodes - //forall_edges(e1,GC.original()){ - edge e; - forall_edges(e,GC) - { - e1 = GC.original(e); - //if(GC.chain(e1).size() > 1) { - if(e1 && GC.chain(e1).size() > 1 && e == GC.chain(e1).front()) - { - newEdge = OGDF_NEW List; - ListConstIterator _it = 0; - for (_it = GC.chain(e1).begin(); _it.valid(); _it++){ - e2 = *_it; - v1 = e2->target(); - n1 = first[H.rank(v1)] + H.pos(v1); // Number nodes top down and from left to right - newEdge->pushBack(n1); - } - newEdge->popBack(); // last node is nonvirtual and must be removed from list. - - // CG: avoid assigning a redirected edge to a dummy node twice - if(newEdge->size() == 1 && longEdge[newEdge->front()] != 0) { - delete newEdge; - - } else { - // for every node in the the list, assign the longEdge (stored in - // newEdge) to the node. - ListConstIterator _it2 = 0; - for (_it2 = (*newEdge).begin(); _it2.valid(); _it2++){ - n1 = *_it2; - longEdge[n1] = newEdge; - } - } - } - } - - - // Compute adjacencylists adj[0] and adj[1] for every node. - forall_edges(e1,GC) { - v1 = e1->source(); - v2 = e1->target(); - n1 = first[H.rank(v1)] + H.pos(v1); - n2 = first[H.rank(v2)] + H.pos(v2); - adj[0][n2].pushBack(n1); - adj[1][n1].pushBack(n2); - } - - // Sort the adjacencylists adj[0] and adj[1] for every node according to - // the internal numbering. - forallnodes { - adj[0][actNode].quicksort(); - adj[1][actNode].quicksort(); - } - - - // Compute the layout - findPlacement(); - - // Copy coordinates into AGC - forall_nodes(v1,GC) { - n1 = first[H.rank(v1)] + H.pos(v1); - AGC.x(v1) = x[n1]; - if(GC.isDummy(v1) && !H.isLongEdgeDummy(v1)) - AGC.y(v1) = 0.5*(y[layer[n1]-1]+y[layer[n1]]); - else - AGC.y(v1) = y[layer[n1]]; - } - - // Cleanup - - List *toDelete; - forallnodes { - if(longEdge[actNode] != 0) { - toDelete = longEdge[actNode]; - ListConstIterator _it = 0; - for (_it = (*toDelete).begin(); _it.valid(); _it++){ - n1 = *_it; - longEdge[n1] = 0; - } - delete toDelete; - } - } - delete[] y; - delete[] first; - delete[] height; - delete[] x; - delete[] breadth; - delete[] layer; - delete[] adj[0]; - delete[] adj[1]; - delete[] virt; - delete[] longEdge; -} - - - -/************************************************************************* - sortLongEdges -************************************************************************** - -The function sortLongEdges places the node actNode as far as possible to the -left (if dir = 1) or to the right (if dir = -1) within a block. -A proper definition of blocks is given in Techreport zpr99-368, pp 5, where -blocks are named classes. If actNode is virtual (and thus belongs to a long -edge), the function sortLongEdges places the actNode as far as possible to -the left such that the corresponding long edge will be vertical. - -dir : Stores the direction of placement: 1 for placing long edges to the - left and -1 for placing them to the right. -pos : array for all nodes. Stores the computed position. -marked : array for all nodes. Stores for every node, whether sortLongEdges - has already been applied to it. -block : array for all nodes. Stores for every node the block it belongs to. -exD : is 1, if there exists a node w on the longEdge of actNode, - that has a direct right sibling (if moving to the left (depending on - the direction)) on the same layer which belongs to a different block. -dist : if exD is 1, it gives the minimal distance between any w of long - edge (see exD) and its direct right (left) sibling if the sibling - belongs to ANOTHER block. if exD is 0, dist is not relevant. -*/ - -void FastHierarchyLayout::sortLongEdges(int actNode, - int dir, - double *pos, - bool& exD, - double &dist, - int *block, - bool *marked) -{ - - ListConstIterator _it = 0; - - if(marked[actNode]) - // if node was already placed. - return; - - bool exB=0; - double best=0; - int next; - - // Mark the long edge. Thus all virtual nodes on the long edge will be - // regarded as placed. - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++){ - next = *_it; - marked[next] = 1; - } - - // Traverse the long Edge. - // If for a virtual node there exists a left direct sibling w and w belongs - // to the same block then call sortLongEdges recursively for w. Store - // leftmost (rightmost) position in best. - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++) { - next = *_it; - if( sameLayer(next - dir, next) && block[next - dir] == block[next]) { - sortLongEdges(next - dir, dir, pos, exD, dist, block, marked); - if(!exB || - dir * (best - pos[next - dir]) < - dir * (totalB[next] - totalB[next - dir])) - { - exB = 1; - best = pos[next - dir] + totalB[next] - totalB[next - dir]; - } - } - } - // Traverse long edge - // Set postion of every virtual node on edge to best. Test for every node - // if the direct left (right) sibling belongs to a different block. - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++){ - next = *_it; - pos[next]=best; - if( sameLayer(next + dir,next) && - block[next + dir] != block[next] && - (!exD || - dir*(totalB[next + dir] - totalB[next] - pos[next + dir] - + pos[next]) > dist)) - { - dist = dir*(totalB[next + dir] - totalB[next] - - pos[next + dir] + pos[next]); - exD = 1; - } - } - -} - - - -/************************************************************************* - placeSingleNode -************************************************************************** - -The function placeSingleNode places a sequence of nonvirtual nodes containing -exactly one node. - -actNode : is an nonvirtual node that has to be placed. -best : is the position that is computed for actNode by placeSingleNode. -d : is the direction of traversal. If d = 0 we traverse the graph top to - bottom. d = 1 otherwise. -leftBnd : contains the number of the next virtual sibling to the left of - actNode, if it exists. - -1 otherwise. Observe that between leftBnd - and actNode there may be other nonvirtual nodes. -rightBnd : contains the number of the next virtual sibling to the right of - actNode, if it exists. - -1 otherwise. Observe that between rightBnd - and actNode there may be other nonvirtual nodes. - -The total length of all edges of actnode to the previous layer (if d = 0) or -next layer (if d = 1) is minimized observing the bounds given by leftBnd and -rightBnd. The optimal position is the median of its neighbours adapted to -leftBnd and rightBnd. The position of the neighbours is given by the global -variable x. - -The funcion returns 0 if actNode does not have neighbours on the previous -(next) layer, 1 otherwise. - -*/ - -bool FastHierarchyLayout::placeSingleNode(int leftBnd, - int rightBnd, - int actNode, - double& best, - int d) -{ - int next; - kList neighbours; - ListConstIterator _it = 0; - - for (_it = adj[d][actNode].begin(); _it.valid(); _it++) { - next = *_it; - neighbours.add(0,x[next]); - } - if(neighbours.empty()) - return 0; - best = neighbours.median(); - - // if median outside boundaries, get free position as close as possible - // to boundary. - if(leftBnd != -1) - incrTo(best,x[leftBnd] + mDist[actNode] - mDist[leftBnd]); - if(rightBnd != -1) - decrTo(best,x[rightBnd] + mDist[actNode] - mDist[rightBnd]); - return 1; -} - - - -/************************************************************************* - placeNodes -************************************************************************** - -The function placeNode places a sequence of nonvirtual nodes. -The function partitions the sequence, applying a divide and conquer strategy -using recursive calls on the two subsequences. - -left : is the leftmost nonvirtual node of the sequence that has to be - placed. -right : is the rightmost nonvirtual node of the sequence that has to be - placed. -d : is the direction of traversal. If d = 0 we traverse the graph top to - bottom. d = 1 otherwise. -leftBnd : contains the number of the next virtual sibling to the left of the - sequence, if it exists. - -1 otherwise. Observe that between leftBnd and actNode there may be - other nonvirtual nodes. -rightBnd : contains the number of the next virtual sibling to the right of the - sequence, if it exists. - -1 otherwise. Observe that between rightBnd and actNode there may be - other nonvirtual nodes. - -The total length of all edges of the sequence to the previous layer (if d = 0) -or next layer (if d = 1) is minimized observing the bounds given by leftBnd -and rightBnd. - -The position that is computed for every node of the sequence is stored in the -global variable x. The position of the neighbours is given by the global -variable x. - -*/ - - -void FastHierarchyLayout::placeNodes(int leftBnd, - int rightBnd, - int left, - int right, - int d) -{ - ListConstIterator _it = 0; - - if(left == right) - // The sequence consists of a single node. - placeSingleNode(leftBnd,rightBnd,left,x[left],d); - - else if(left < right) { - // Introduce variables to handle the two subsequences analogously. - - int mdl[2]; - mdl[0] = (right + left)/2; // rightmost node of left subsequence. - mdl[1] = mdl[0] + 1; // leftmost node of right subsequence. - - int bnd[2]; // technically for left and right boundary. - bnd[0] = leftBnd; - bnd[1] = rightBnd; - - int res[2]; // res[0] startresistance to push mdl[0] to the left - // res[1] startresistance to push mdl[1] to the right - - int actNode, next; // auxiliary variables for nodes. - int resChange,resCh0,resCh1; // auxiliary variables for the resistance - - int dir; // variable to distinguish left and right subsequence. - // -1 for the left, 1 for the right subsequence. - - double mD; // minimal distance between mdl[0] and mdl[1] - mD = mDist[mdl[1]] - mDist[mdl[0]]; - - - kList bends[2]; // bends[0] stores the changes of resistance against - // pushing mdl[0] to the left - // bends[1] stores the changes of resistance against - // pushing mdl[1] to the right - // Change of resistance is of type withKey: containg - // the position in a double variable where the - // resitance changes and an integer storing the amount - // of incresing the resistance. - - kList bds; // auxiliary variable for constructing bends. - double newBend; // a position of a resistance change. - - double diff,diff1,diff2; // auxiliary variables - - - //recursive call for the left and the right subsequence - placeNodes(leftBnd,rightBnd,left,mdl[0],d); - placeNodes(leftBnd,rightBnd,mdl[1],right,d); - - - // Scan the left (i =0) and then the right subsequence (i = 1) to - // compute the bends[i]; for technical details see report. - for(int i = 0;i < 2;i++) { - dir = i ? 1: -1; // set direction - res[i]=0; - for(actNode = mdl[i];actNode >= left && actNode <= right;actNode +=dir) { - resChange = 0; - for (_it = adj[d][actNode].begin(); _it.valid(); _it++) { - next = *_it; - if(dir*(x[next] - x[actNode]) < ALLOW) - resChange++; - else { - resChange--; - newBend = x[next] + mDist[mdl[i]] - mDist[actNode]; - if(dir*(x[mdl[i]] - newBend) > -ALLOW) { - res[i]++; - } else if((bnd[i] == -1 || dir*(newBend - x[bnd[i]] - + mDist[bnd[i]] - mDist[mdl[i]]) - ALLOW) { - res[i] += resChange; - } else if((bnd[i] == -1 || - dir * - (newBend - x[bnd[i]] + mDist[bnd[i]] - mDist[mdl[i]]) - < ALLOW) && dir*(newBend - x[mdl[1 - i]]) < mD - ALLOW) - { - bds.add(resChange,newBend); - } - } - if(bnd[i] != -1) - bds.add(m,x[bnd[i]] - mDist[bnd[i]] + mDist[mdl[i]]); - cmpWithKey cmp; - bds.quicksort(cmp); - bds.reduce(bends[i]); - } - if(!bends[0].empty()) - bends[0].reverse(); - - - - // Move mdl[0] and mdl[1] such that the nodes respect the minimal node - // distance mD. - while(x[mdl[1]] - x[mdl[0]] < mD-ALLOW) { - // as long as distance too small - - resCh0=resCh1=0; - if(res[0] < res[1]) { // if smaller resistance to the left. - // Go to the next resistance change and update resCh0 and x[mdl[0]]. - if(!bends[0].pop(resCh0,x[mdl[0]]) || x[mdl[1]] - x[mdl[0]] > mD + ALLOW) - x[mdl[0]] = x[mdl[1]] - mD; - } - else if(res[1] < res[0]) { // if smaller resistance to the right. - // Go to the next resistance change and update resCh1 and x[mdl[1]]. - if(!bends[1].pop(resCh1,x[mdl[1]]) || x[mdl[1]] - x[mdl[0]] > mD + ALLOW) - x[mdl[1]] = x[mdl[0]] + mD; - } - else { // same resistance to the left and to the right. - // Update resCh0 resCh1 and x[mdl[0]] x[mdl[1]] by simultaneously - // moving mdl[0] and mdl[1]. - diff = (mD - x[mdl[1]] + x[mdl[0]])/2; - diff1 = bends[0].empty() ? diff + 1 : x[mdl[0]] - bends[0].peek(); - diff2 = bends[1].empty() ? diff + 1 : bends[1].peek()-x[mdl[1]]; - if(diff1 < diff + ALLOW && diff1 < diff2 + ALLOW) - bends[0].pop(resCh0,newBend); - if(diff2 < diff + ALLOW && diff2 < diff1 + ALLOW) - bends[1].pop(resCh1,newBend); - decrTo(diff,diff1); - decrTo(diff,diff2); - x[mdl[0]] -= diff; - x[mdl[1]] += diff; - } - res[0] += resCh0; // Update the resistance by the change of resistance - res[1] += resCh1; // Update the resistance by the change of resistance - } - - - // mdl[0] and mdl[1] respect minimal node distance mD. Place - // subsequences accordingly. - actNode = mdl[0]; - while(--actNode >= left && - x[mdl[0]] - x[actNode] < mDist[mdl[0]] - mDist[actNode]) - x[actNode] = x[mdl[0]] - mDist[mdl[0]] + mDist[actNode]; - actNode = mdl[1]; - while(++actNode <= right && - x[mdl[1]] - x[actNode] > mDist[mdl[1]] - mDist[actNode]) - x[actNode] = x[mdl[1]] - mDist[mdl[1]] + mDist[actNode]; - } -} - - - -/************************************************************************* - moveLongEdge -************************************************************************** - -The function moveLongEdge is used for postprocessing the layout. -If the two nonvirtual ndoes of the long edge are both to the left (right) of -the virtual nodes, the function moveLongEdge tries to reduce the length of the -two outermost segments by moving the virtual nodes simultaneously as far as -possible to the left (right). If both non virtual nodes are on different sides -of the virtual nodes, moveLongEdge tries to remove one of the edge bends by -moving the virtual nodes. - - -If there exists a conflict with another long edge on the left (right) side of -the current long edge, the function moveLongEdge is first applied recursively -to this long edge. - -actNode : a representative node of the long edge -dir : is -1 if it is preferred to move the long edge to the left, - 1 if it is preferred to move the long edge to the right, - 0 if there is no preference -marked : array for all nodes. Stores for every node, whether moveLongEdge - has already been applied to it. - -*/ - -void FastHierarchyLayout::moveLongEdge(int actNode, - int dir, - bool *marked) -{ - ListConstIterator _it = 0; - - if(!marked[actNode]&&virt[actNode]) { - // if actNode belongs to a long edge and has not been moved yet. - int next; - // mark all virtual nodes of the long edge - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++) { - next = *_it; - marked[(*_it)]=1; - } - - // first non virtual node of long edge - int fst=adj[0][longEdge[actNode]->front()].front(); - - // second non virtual node of long edge - int lst=adj[1][longEdge[actNode]->back()].front(); - - // Contains an order of the two positions of the nonvirtual nodes of - // the long edge. The function moveLongEdge first tries to place the - // long edge onto the first position If not successful, moveLongEdge - // tries to place the long edge onto the second position - List toTest; - - if(dir < 0) { - toTest.pushBack(x[fst] < x[lst] ? x[fst] : x[lst]); - toTest.pushBack(x[fst] < x[lst] ? x[lst] : x[fst]); - } - else if(dir > 0) { - toTest.pushBack(x[fst] < x[lst] ? x[lst] : x[fst]); - toTest.pushBack(x[fst] < x[lst] ? x[fst] : x[lst]); - } - else { - toTest.pushBack(x[fst]); - toTest.pushBack(x[lst]); - } - double xFirst; // stores the first and most preferred position - xFirst = toTest.front(); - - double xOpt; // stores the preferred position - - bool done = false; - while(!done && !toTest.empty()) { - xOpt = toTest.front(); // Best position that can be reached by moving - // the long edge - toTest.popFront(); - done = 1; - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++) { - // for all virtual nodes on the long edge - next = *_it; - - // Try moving to the left - if(!isFirst(next)) { - // next does have a left sibling - if(xOpt - x[next-1] < totalB[next] - totalB[next-1]) - // there is a conflict moving next to the position xOpt. - moveLongEdge(next - 1,-1,marked); - - // done = 0 if minimal distances cannot be repsected. - done = done && - xOpt - x[next-1] >= - totalB[next] - totalB[next-1] - ALLOW; - } - - // Try moving to the right - if(!isLast(next)) { - // next does have a right sibling - if(xOpt - x[next+1] > totalB[next] - totalB[next+1]) - // there is a conflict moving next to the position xOpt. - moveLongEdge(next + 1,1,marked); - - // done = 0 if minimal distances cannot be respected. - done = done && - xOpt - x[next+1] <= - totalB[next] - totalB[next+1] + ALLOW; - } - } - } - if(!done) { - // moveLongEdge was not able to move the virtual nodes to one of - // the two positions of the nonvirtual nodes. It now tries to - // approximate the most preferred position. - xOpt = xFirst; - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++) { - next = *_it; - if(!isFirst(next)) - incrTo(xOpt,x[next-1]+totalB[next]-totalB[next-1]); - if(!isLast(next)) - decrTo(xOpt,x[next+1]+totalB[next]-totalB[next+1]); - } - } - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++) { - next = *_it; - x[(*_it)] = xOpt; - } - } -} - - -/************************************************************************* - straightenEdge -************************************************************************** - -The function straightenEdge is applied to long edges with exactly one virtual -node and tries to remove a bend at the position of the virtual node, by -straightening the edge. - -actNode : the virtual representative node of the long edge -marked : array for all nodes. Stores for every node, whether straightenEdge - has already been applied to it. - -If there exists a conflict with a direct sibling to the left (right) side of -the current node, the function straightenEdge is first applied recursively to -this node. - -*/ - -void FastHierarchyLayout::straightenEdge(int actNode,bool *marked) -{ - if(!marked[actNode] && // breadth[actNode] < ALLOW && - adj[0][actNode].size() == 1 && - adj[1][actNode].size() == 1 && - longEdge[actNode]->size() < 2) - { - marked[actNode]=1; - - int fst=adj[0][actNode].front(); - int lst=adj[1][actNode].front(); - - // Get optimal position for actNode - double xOpt=x[fst] + (x[lst] - x[fst]) * - (y[layer[actNode]] - y[layer[fst]]) / - (y[layer[lst]] - y[layer[fst]]); - - - if(!isFirst(actNode)) { - // actNode does have a left sibling - if(xOpt - x[actNode-1] < totalB[actNode] - totalB[actNode-1] - ALLOW) - // there is a conflict with the position of the direct left sibling - // Recursively call straightenEdge. - straightenEdge(actNode - 1,marked); - if(xOpt - x[actNode - 1] _it = 0; - - // Replace all virtual nodes in an edge traversing only one layer by a - // nonvirtual node. - forallnodes if(virt[actNode] && - !virt[adj[0][actNode].front()] && - !virt[adj[1][actNode].front()]) - virt[actNode] = 0; - - // Compute minimal distances between nodes (totalB) - - totalB = new double[n]; - double toAdd; - forallnodes { - if (!actNode || - layer[actNode-1] < layer[actNode]) - totalB[actNode]=0; - else { - toAdd = breadth[actNode-1] / 2 + breadth[actNode] / 2; - // Enlarge the minimal Distance for nodes with a lot of neighbours. - incrTo(toAdd,m_minNodeDist / 3 * (double)(adj[0][actNode-1].size() + adj[0][actNode].size())); - incrTo(toAdd,m_minNodeDist / 3 * (double)(adj[1][actNode-1].size() + adj[1][actNode].size())); - // distances are computed such that they are placed on a grid based on minNodeDist. - toAdd = m_minNodeDist *(int)(toAdd/m_minNodeDist + 1 - ALLOW); - toAdd += m_minNodeDist; - totalB[actNode] = totalB[actNode-1] + toAdd; - } - } - - // Remove crossings of long edges - // Applied for long edges that cross each other in inner segments. - - List *newEdge,*oldEdge; - int down,spl; - - - // For every two consecutive layers l and l+1 , traverse the inner edge - // segments between the two layers according to the order of virtual nodes - // on layer l. We consider consecutive pairs of inner edges segments - // from left to right. If two inner edge segments cross, we split the - // right long edge between the two layers by parting the corresponding list - // into two sublists. - foralllayers { - last=-1; - forallnodesonlayer { - if(virt[actNode]) { - down=adj[1][actNode].front(); - if(virt[down]) { - if(last!=-1&&last>down) { - oldEdge = longEdge[actNode]; - spl = actLayer - layer[oldEdge->front()] + 1; - newEdge = OGDF_NEW List; - oldEdge->split(oldEdge->get(spl),(*newEdge), - (*oldEdge)); - for (_it = (*newEdge).begin(); _it.valid(); _it++) { - next = *_it; - longEdge[next] = newEdge; - } - } else - last = down; - } - } - } - } - - // Place long edges - - int blockCount; - bool exD; - int *block = new int[n]; - double *pos = new double[n]; - List *blockNodes; - kList neighbours; - double dist; - - forallnodes - x[actNode] = 0; - for(dir = 1; dir >= -1;dir -= 2) { - // for dir = 1, move long edges as far as possible to the left - // for dir = -1, move long edges as far as possible to the right - - - // Partition the graph into blocks according to the technical report. - blockCount = 0; - forallnodes - block[actNode] = marked[actNode] = 0; - foralllayers { - actNode = (dir == 1 ? first[actLayer] : first[actLayer+1] - 1); - if(!block[actNode]) { - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++){ - next = *_it; - block[next] = blockCount; - } - blockCount++; - } - actNode += dir; - while(actNode >= first[actLayer] && actNode < first[actLayer+1]) { - if(!block[actNode]) { - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++){ - next = *_it; - block[next] = block[actNode-dir]; - } - } - actNode += dir; - } - } - - // Store the nodes of every block in a separate list - blockNodes = new List[n]; - foralllayers { - for(actNode = (dir == 1 ? first[actLayer] : first[actLayer+1]-1); - actNode >= first[actLayer] && actNode < first[actLayer+1]; - actNode += dir) - { - blockNodes[block[actNode]].pushBack(actNode); - } - } - - for(int i = 0; i < blockCount;i++) { - // for every block - exD = 0; - dist = 0; - for (_it = blockNodes[i].begin(); _it.valid(); _it++) { - // for every node of the block apply sortLongEdges - actNode = *_it; - sortLongEdges(actNode,dir,pos,exD,dist,block,marked); - } - if(!exD) { - // The currently examined block does not share its layers with - // another block that has been placed before. Thus the block - // can be freely moved. We compute a position for the block by - // minimizing the total edge length to neighbours of blocks - // that have already been placed. dist has not been computed by - // sortLongEdges and is now set to the optimal value. - actLayer = layer[blockNodes[i].front()]; - forallnodesonlayer { - for (_it = adj[0][actNode].begin(); _it.valid(); _it++) { - next = *_it; - neighbours.add(0,pos[next] - pos[actNode]); - } - } - if(!neighbours.empty()) { - cmpWithKey cmp; - neighbours.quicksort(cmp); - dist =- dir*neighbours.median(); - neighbours.clear(); - } - } - // If exD is true, dist has been computed by sortLongEdges. - - // Move the nodes of the block to their positions. - for (_it = blockNodes[i].begin(); _it.valid(); _it++) { - actNode = *_it; - pos[actNode] -= dir * dist; - } - } - - // Compute for every node the average of the two positions of the left - // and right placement. - forallnodes - x[actNode] += pos[actNode] / 2; - - delete[] blockNodes; - } - - delete[] block; - delete[] pos; - - // Place nonvirtual nodes - - // Stores for every internal sequence of in - // wihch traversal the sequence has to be placed. - // An internal sequence is represeted by its left virtual sibling. Values: - // -1 : is not yet clear - // 0 : top down traversal - // 1 : bottom up traversal - int *nodeDir = new int[n]; - - forallnodes - nodeDir[actNode] = -1; - - - - // Initialization of marked. - // marked is used to indicate the placement of a sequence. - forallnodes { - if(virt[actNode]) { - next = actNode + 1; - while(sameLayer(next,actNode) && !virt[next]) - next++; - - // If actNode is representative of a fixed inner sequence, the - // sequence is already placed and marked is set - marked[actNode] = sameLayer(next,actNode) && - x[next] - x[actNode] < totalB[next] - totalB[actNode] + ALLOW; - - } else - marked[actNode] = 0; - } - - forallnodes { - if(marked[actNode] && nodeDir[actNode] == -1) { - // for every fixed sequence, traverse the long edge belonging to - // the representative actnode - for (_it = (*longEdge[actNode]).begin(); _it.valid(); _it++) { - // for every virtual node next of the long edge mark the - // corrsponding sequence as to be placed in the upward - // traversal if next is above of actnode and in the downward - // traversal if next is below actNode. - next = *_it; - if(next != actNode) - nodeDir[next] = next < actNode; - } - } - } - - // mDist is equal to totalB during the first traversal. After the first - // traversal it is set to the positions computed in the first traversal. - // It is only modified for external sequences. - mDist = new double[n]; - // Die folgende forallnodes Schleife wurde f?r den Vorschlag von - // Christoph (siehe unten) entfernt, da ?berfl?ssig - forallnodes - mDist[actNode] = totalB[actNode]; - - for(dir = 0;dir < 2;dir++) { - // for every traversal - - for(actLayer = dir ? k-1 : 0; 0 <= actLayer && actLayer < k; - actLayer += dir ? -1 : 1) - { - // for every layer (if dir = 0 top down) - -/* // NEU : ?nderungen vorgeschlagen von Christoph - // f?hren aber dazu, dass sich Knoten zu Nahe kommen - // k?nnen (n?her als minDist) (Carsten) - for(int i1 = first[actLayer]; i1 < first[actLayer+1]; i1++) - mDist[i1] = x[i1]; - - leftBnd=-1; - forallnodesonlayer { - if(virt[actNode] && virt[adj[dir][actNode].front()]) { - x[actNode] = x[adj[dir][actNode].front()]; - - if(leftBnd == -1) - placeNodes(-1,actNode,first[actLayer],actNode-1,dir); - else - placeNodes(leftBnd,actNode,leftBnd+1,actNode-1,dir); - - leftBnd = actNode; - } - } - - if(leftBnd == -1) - placeNodes(-1,-1,first[actLayer],first[actLayer+1]-1,dir); - else - placeNodes(leftBnd,-1,leftBnd+1,first[actLayer+1]-1,dir); - - for(int i1 = first[actLayer]; i1 < first[actLayer+1]; i1++) - mDist[i1] = totalB[i1]; - // ENDE NEU*/ - - leftBnd=-1; - forallnodesonlayer { - if(virt[actNode]) { - // For every sequence, bounded by leftBnd and actNode. - if(leftBnd == -1) { - // leftBnd is not a node. The sequence is external. Place it. - placeNodes(-1,actNode,first[actLayer],actNode - 1,dir); - for(next = first[actLayer]; next < actNode; next++) - mDist[next] = mDist[actNode] - x[actNode] + x[next]; - } - else if(nodeDir[leftBnd] != !dir) { // nodeDir[leftBnd] == dir || nodeDir[leftBnd] == -1 - // internal sequence - - if(!marked[leftBnd]) - // sequence has not been placed yet. Place it. - placeNodes(leftBnd,actNode,leftBnd + 1, - actNode - 1,dir); - - // Adjust nodeDir for the next layer. - leftNxt = adj[!dir][leftBnd].front(); - rightNxt = adj[!dir][actNode].front(); - if(virt[leftNxt] && virt[rightNxt]) - for(next = leftNxt + 1;next < rightNxt; next++) - nodeDir[next] = dir; - } - leftBnd = actNode; - } - } - if(leftBnd == -1) { - // No virtual node in the complete layer. Place it. - placeNodes(-1,-1,first[actLayer],first[actLayer+1] - 1,dir); - for (next = first[actLayer]; next < first[actLayer+1]; next++) - mDist[next] = x[next]; - } - else { - // External sequence to the right. Place it. - placeNodes(leftBnd,-1,leftBnd + 1,first[actLayer+1] - 1,dir); - for (next = first[actLayer+1] - 1;next > leftBnd; next--) - mDist[next] = mDist[leftBnd] - x[leftBnd] + x[next]; - } - } - } - delete[] nodeDir; - delete[] mDist; - - // Apply moveLongEdge to every long edge. - forallnodes - marked[actNode] = 0; - foralllayers { - for (actNode = (first[actLayer] + first[actLayer + 1]) / 2; - actNode < first[actLayer+1]; actNode++) - { - moveLongEdge(actNode,0,marked); - } - for (actNode = (first[actLayer] + first[actLayer+1]) / 2 - 1; - actNode >= first[actLayer]; actNode--) - { - moveLongEdge(actNode,0,marked); - } - } - - // Compute ordinates for the layers and boxY - - double boxY = k ? height[0] / 2 : 0; // y-value for the bounding box. - double minD; - - foralllayers { - y[actLayer] = boxY; - minD = m_minLayerDist; - if(!m_fixedLayerDist) { - forallnodesonlayer { - // adjust the distance of the layer to the longest edge - for (_it = adj[1][actNode].begin(); _it.valid(); _it++) { - next = *_it; - incrTo(minD,(x[next] - x[actNode]) / 3); - incrTo(minD,(x[actNode] - x[next]) / 3); - } - } - decrTo(minD,10 * m_minLayerDist); - } - boxY += height[actLayer] / 2; - if(actLayer < k - 1) - boxY += minD + height[actLayer+1] / 2; - } - - // Apply straightenEdge to every long edge with one virtual node. - - forallnodes - marked[actNode] = 0; - foralllayers { - for (actNode = (first[actLayer] + first[actLayer+1]) / 2; - actNode < first[actLayer+1]; actNode++) - { - straightenEdge(actNode,marked); - } - for (actNode = (first[actLayer] + first[actLayer+1]) / 2 - 1; - actNode >= first[actLayer]; actNode--) - { - straightenEdge(actNode,marked); - } - } - delete[] marked; - delete[] totalB; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/FastSimpleHierarchyLayout.cpp b/ext/OGDF/src/layered/FastSimpleHierarchyLayout.cpp deleted file mode 100644 index 9c5f51a80..000000000 --- a/ext/OGDF/src/layered/FastSimpleHierarchyLayout.cpp +++ /dev/null @@ -1,469 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the FastSimpleHierarchyLayout - * (third phase of sugiyama) - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - -FastSimpleHierarchyLayout::FastSimpleHierarchyLayout(int minXSep, int ySep) - : m_minXSep(minXSep), m_ySep(ySep) -{ - m_balanced = true; -} - -FastSimpleHierarchyLayout::FastSimpleHierarchyLayout(bool downward, bool leftToRight, int minXSep, int ySep) - : m_minXSep(minXSep), m_ySep(ySep), m_downward(downward), m_leftToRight(leftToRight) -{ - m_balanced = false; -} - -FastSimpleHierarchyLayout::FastSimpleHierarchyLayout(const FastSimpleHierarchyLayout &fshl) -{ - m_minXSep = fshl.m_minXSep; - m_ySep = fshl.m_ySep; - m_balanced = fshl.m_balanced; - m_downward = fshl.m_downward; - m_leftToRight = fshl.m_leftToRight; -} - - -FastSimpleHierarchyLayout::~FastSimpleHierarchyLayout() { } - - -FastSimpleHierarchyLayout &FastSimpleHierarchyLayout::operator=(const FastSimpleHierarchyLayout &fshl) -{ - m_minXSep = fshl.m_minXSep; - m_ySep = fshl.m_ySep; - m_balanced = fshl.m_balanced; - m_downward = fshl.m_downward; - m_leftToRight = fshl.m_leftToRight; - - return *this; -} - - -void FastSimpleHierarchyLayout::doCall(const Hierarchy& H, GraphCopyAttributes &AGC) -{ - const GraphCopy& GC = H; - node v; - NodeArray align(GC); - NodeArray root(GC); - - if (m_balanced) { - // the x positions; x=-1 <=> x is undefined - NodeArray x[4]; - int width[4]; - int min[4]; - int max[4]; - int minWidthLayout = 0; - - // initializing - for (int i = 0; i < 4; i++) { - min[i] = std::numeric_limits::max(); - max[i] = std::numeric_limits::min(); - } - - // calc the layout for down/up and leftToRight/rightToLeft - for (int downward = 0; downward <= 1; downward++) { - NodeArray > type1Conflicts = markType1Conflicts(H, downward == 0); - for (int leftToRight = 0; leftToRight <= 1; leftToRight++) { - verticalAlignment(H, root, align, type1Conflicts, downward == 0, leftToRight == 0); - horizontalCompactation(align, H, root, x[2 * downward + leftToRight], leftToRight == 0, downward == 0); - } - } - - /* - * - calc min/max x coordinate for each layout - * - calc x-width for each layout - * - find the layout with the minimal width - */ - for (int i = 0; i < 4; i++) { - forall_nodes(v, GC) { - if (min[i] > x[i][v]) { - min[i] = x[i][v]; - } - if (max[i] < x[i][v]) { - max[i] = x[i][v]; - } - } - width[i] = max[i] - min[i]; - if (width[minWidthLayout] > width[i]) { - minWidthLayout = i; - } - } - - /* - * shift the layout so that they align with the minimum width layout - * - leftToRight: align minimum coordinate - * - rightToLeft: align maximum coordinate - */ - int shift[4]; - for (int i = 0; i < 4; i++) { - if (i % 1 == 0) { - // for leftToRight layouts - shift[i] = min[minWidthLayout] - min[i]; - } else { - // for rightToLeft layouts - shift[i] = max[minWidthLayout] - max[i]; - } - } - - /* - * shift the layouts and use the - * median average coordinate for each node - */ - Array sorting(4); - forall_nodes(v, GC) { - for (int i = 0; i < 4; i++) { - sorting[i] = x[i][v] + shift[i]; - } - sorting.quicksort(); - AGC.x(v) = ((double)sorting[1] + (double)sorting[2]) / 2.0; - AGC.y(v) = H.rank(v) * m_ySep; - } - } else { - NodeArray x; - NodeArray > type1Conflicts = markType1Conflicts(H, m_downward); - verticalAlignment(H, root, align, type1Conflicts, m_downward, m_leftToRight); - horizontalCompactation(align, H, root, x, m_leftToRight, m_downward); - forall_nodes(v, GC) { - AGC.x(v) = x[v]; - AGC.y(v) = H.rank(v) * m_ySep; - } - } -} - -NodeArray > FastSimpleHierarchyLayout::markType1Conflicts(const Hierarchy &H, const bool downward) -{ - const GraphCopy& GC = H; - NodeArray > type1Conflicts(GC); - node v; - - forall_nodes(v, GC) { - NodeArray array(GC, false); - type1Conflicts[v] = array; - } - - if (H.size() >= 4) { - int upper, lower; // iteration bounds - int k0, k1; // node position boundaries of closest inner segments - int l; // node position on current level - Hierarchy::TraversingDir relupward; // upward relativ to the direction from downward - - if (downward) { - lower = 1; - upper = H.high() - 2; - - relupward = Hierarchy::downward; - } - else { - lower = H.high() - 1; - upper = 2; - - relupward = Hierarchy::upward; - } - - /* - * iterate level[2..h-2] in the given direction - * - * availible levels: 1 to h - */ - for (int i = lower; (downward && i <= upper) || (!downward && i >= upper); i = downward ? i + 1 : i - 1) { - k0 = 0; - l = 0; // index of first node on layer - Level currentLevel = H[i]; - Level nextLevel = downward ? H[i+1] : H[i-1]; - - // for all nodes on next level - for (int l1 = 0; l1 <= nextLevel.high(); l1++) { - const node virtualTwin = virtualTwinNode(H, nextLevel[l1], relupward); - - if (l1 == nextLevel.high() || virtualTwin != NULL) { - k1 = currentLevel.high(); - - if (virtualTwin != NULL) { - k1 = H.pos(virtualTwin); - } - - for (; l <= l1; l++) { - Array upperNeighbours = H.adjNodes(nextLevel[l1], relupward); - - for (int i = 0; i < upperNeighbours.size(); i++) { - node currentNeighbour = upperNeighbours[i]; - - /* - * XXX: < 0 in first iteration is still ok for indizes starting - * with 0 because no index can be smaller than 0 - */ - if (H.pos(currentNeighbour) < k0 || H.pos(currentNeighbour) > k1) { - (type1Conflicts[l1])[currentNeighbour] = true; - } - } - } - k0 = k1; - } - } - } - } - return type1Conflicts; -} - -void FastSimpleHierarchyLayout::verticalAlignment(const Hierarchy &H, NodeArray &root, - NodeArray &align, const NodeArray > &type1Conflicts, - bool downward, const bool leftToRight) -{ - const GraphCopy& GC = H; - node v, u; - int r; - int median; - Hierarchy::TraversingDir relupward; // upward relativ to the direction from downward - - int medianCount; - - relupward = downward ? Hierarchy::downward : Hierarchy::upward; - - // initialize root and align - forall_nodes(v, GC) { - root[v] = v; - align[v] = v; - } - - // for all Level - for (int i = downward ? 0 : H.high(); - (downward && i <= H.high()) || (!downward && i >= 0); i = downward ? i + 1 : i - 1) { - Level currentLevel = H[i]; - r = leftToRight ? -1 : std::numeric_limits::max(); - - // for all nodes on Level i (with direction leftToRight) - for (int j = leftToRight ? 0 : currentLevel.high(); - (leftToRight && j <= currentLevel.high()) || (!leftToRight && j >= 0); leftToRight ? j++ : j--) { - v = currentLevel[j]; - // the fist median - median = (int)floor((H.adjNodes(v, relupward).size() + 1) / 2.0); - - medianCount = (H.adjNodes(v, relupward).size() % 2 == 1) ? 1 : 2; - if (H.adjNodes(v, relupward).size() == 0) { - medianCount = 0; - } - - // for all median neighbours in direction of H - for (int count = 0; count < medianCount; count++) { - u = H.adjNodes(v, relupward)[median + count - 1]; - - if (align[v] == v) { - // if segment (u,v) not marked by type1 conflicts AND ... - if ((type1Conflicts[v])[u] == false && - ((leftToRight && r < H.pos(u)) || (!leftToRight && r > H.pos(u)))) { - align[u] = v; - root[v] = root[u]; - align[v] = root[v]; - r = H.pos(u); - } - } - } - } - } - -#ifdef DEBUG_OUTPUT - forall_nodes(v, GC) { - cout << "node: " << GC.original(v) << "/" << v << ", root: " << GC.original(root[v]) << "/" << root[v] << ", alignment: " << GC.original(align[v]) << "/" << align[v] << endl; - } -#endif -} - -void FastSimpleHierarchyLayout::horizontalCompactation(const NodeArray &align, - const Hierarchy &H, const NodeArray root, NodeArray &x, const bool leftToRight, bool downward) -{ -#ifdef DEBUG_OUTPUT - cout << "-------- Horizontal Compactation --------" << endl; -#endif - - const GraphCopy& GC = H; - node v; - NodeArray sink(GC); - NodeArray shift(GC, std::numeric_limits::max()); - - x.init(GC, -1); - - forall_nodes(v, GC) { - sink[v] = v; - } - - // calculate class relative coordinates for all roots - for (int i = downward ? 0 : H.high(); - (downward && i <= H.high()) || (!downward && i >= 0); i = downward ? i + 1 : i - 1) { - Level currentLevel = H[i]; - - for (int j = leftToRight ? 0 : currentLevel.high(); - (leftToRight && j <= currentLevel.high()) || (!leftToRight && j >= 0); leftToRight ? j++ : j--) { - v = currentLevel[j]; - if (root[v] == v) { - placeBlock(v, sink, shift, x, align, H, root, leftToRight); - } - } - } - -#ifdef DEBUG_OUTPUT - cout << "------- Sinks ----------" << endl; -#endif - // apply root coordinates for all aligned nodes - // (place block did this only for the roots) - forall_nodes(v, GC) { -#ifdef DEBUG_OUTPUT - if (sink[root[v]] == v) { - cout << "Topmost Root von Senke!: " << GC.original(v) << endl; - cout << "-> Shift: " << shift[v] << endl; - cout << "-> x: " << x[v] << endl; - } -#endif - x[v] = x[root[v]]; - } - - // apply shift for each class - forall_nodes(v, GC) { - if (shift[sink[root[v]]] < std::numeric_limits::max()) { - x[v] = x[v] + shift[sink[root[v]]]; - } - } -} - -void FastSimpleHierarchyLayout::placeBlock(node v, NodeArray &sink, - NodeArray &shift, NodeArray &x, const NodeArray &align, - const Hierarchy &H, const NodeArray &root, const bool leftToRight) -{ - node w; - node u; - -#ifdef DEBUG_OUTPUT - const GraphCopy& GC = H; -#endif - - if (x[v] == -1) { - x[v] = 0; - w = v; -#ifdef DEBUG_OUTPUT - cout << "---placeblock: " << GC.original(v) << " ---" << endl; -#endif - do { - // if not first node on layer - if ((leftToRight && H.pos(w) > 0) || (!leftToRight && H.pos(w) < H[H.rank(w)].high())) { - u = root[pred(w, H, leftToRight)]; - placeBlock(u, sink, shift, x, align, H, root, leftToRight); - if (sink[v] == v) { - sink[v] = sink[u]; - } - if (sink[v] != sink[u]) { -#ifdef DEBUG_OUTPUT - cout << "old shift " << GC.original(sink[u]) << ": " << shift[sink[u]] << "<>" << x[v] - x[u] - m_minXSep << endl; -#endif - if (leftToRight) { - shift[sink[u]] = min(shift[sink[u]], x[v] - x[u] - m_minXSep); - } else { - shift[sink[u]] = max(shift[sink[u]], x[v] - x[u] + m_minXSep); - } -#ifdef DEBUG_OUTPUT - cout << "-> new shift: " << shift[sink[u]] << endl; -#endif - } - else { - if (leftToRight) { - x[v] = max(x[v], x[u] + m_minXSep); - } else { - x[v] = min(x[v], x[u] - m_minXSep); - } - } -#ifdef DEBUG_OUTPUT - cout << "placing w: " << GC.original(w) << "; predecessor: " << GC.original(pred(w, H, leftToRight)) << - "; root(w)=v: " << GC.original(v) << "; root(pred(u)): " << GC.original(u) << - "; sink(v): " << GC.original(sink[v]) << "; sink(u): " << GC.original(sink[u]) << endl; - cout << "x(v): " << x[v] << endl; - } else { - cout << "not placing w: " << GC.original(w) << " because at beginning of layer" << endl; -#endif - } - w = align[w]; - } while (w != v); -#ifdef DEBUG_OUTPUT - cout << "---END placeblock: " << GC.original(v) << " ---" << endl; -#endif - } -} - -node FastSimpleHierarchyLayout::virtualTwinNode(const Hierarchy &H, const node v, const Hierarchy::TraversingDir dir) const -{ - if (!H.isLongEdgeDummy(v) || H.adjNodes(v, dir).size() == 0) { - return NULL; - } - - if (H.adjNodes(v, dir).size() > 1) { - // since v is a dummy there sould be only one upper neighbour - throw AlgorithmFailureException("FastSimpleHierarchyLayout.cpp"); - } - - return *H.adjNodes(v, dir).begin(); -} - -node FastSimpleHierarchyLayout::pred(const node v, const Hierarchy &H, const bool leftToRight) -{ - int pos = H.pos(v); - int rank = H.rank(v); - - Level level = H[rank]; - if ((leftToRight && pos != 0) || (!leftToRight && pos != level.high())) { - return level[leftToRight ? pos - 1 : pos + 1]; - } - else { - return NULL; - } -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/HierarchyLayoutModule.cpp b/ext/OGDF/src/layered/HierarchyLayoutModule.cpp deleted file mode 100644 index f5aa101b8..000000000 --- a/ext/OGDF/src/layered/HierarchyLayoutModule.cpp +++ /dev/null @@ -1,551 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the static functions. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -namespace ogdf { - -void HierarchyLayoutModule::addBends(GraphCopyAttributes &AGC, Hierarchy &H) { - - EdgeArray done(H, -1); - NodeArray dirty(H, false); - - for (int i = 0; i <= H.high(); i++) { // all level - const Level &lvl_cur = H[i]; - - /* - compute the max. height (y coord.) of the bounding boxex of lvl_cur - */ - // y coord. of the top - double y_h = AGC.y(lvl_cur[0]) + AGC.getHeight(lvl_cur[0])/2; - //y coord. of the bottom - double y_l = AGC.y(lvl_cur[0]) - AGC.getHeight(lvl_cur[0])/2; - - //iterate over all nodes and find the max. height - for(int j = 0; j <= lvl_cur.high(); j++) { - node v = lvl_cur[j]; - double a = AGC.y(v) - AGC.getHeight(v)/2; - double b = AGC.y(v) + AGC.getHeight(v)/2; - if (y_h < b ) - y_h = b; - if (y_l > a) - y_l = a; - } - - // list with edges, which muss be bended later - List bendMe; - - for(int j = 0; j <= lvl_cur.high(); j++) { - node v = lvl_cur[j]; - - adjEntry adj; - - /* - compute the edges, which overlap a node in lvl_cur - */ - forall_adj(adj, v) { - edge e = adj->theEdge(); - - if (done[e] == i) - continue; // already bended - - node w = e->target(); - if (w == v) - w = e->source(); - - node nodeLeft = v, nodeRight = w; - - if (AGC.x(v) == AGC.x(w)) - continue; // edge e cannot overlap a node - - if (AGC.x(v) > AGC.x(w)) - swap(nodeLeft, nodeRight); - - DLine line_v2w( DPoint(AGC.x(v), AGC.y(v)), DPoint(AGC.x(w), AGC.y(w)) ); - - //iterate over all node of lvl_cur and find out wether line_v2w overlap a node or not - for(int k = 0; k <= lvl_cur.high(); k++) { - node u = lvl_cur[k]; - - if (u == v) - continue; - - int ci = 0; - int cj = 0; - - overlap(AGC, H, e->source(), e->target(), i, ci, cj); - - if (ci > 0) - bendMe.pushBack(e); - - } // for k - - }// forall_adj - } - - NodeArray isNewNode(H.m_GC, false); - while (!bendMe.empty()) { - edge splitMe = bendMe.popFrontRet(); - - if (done[splitMe] == i) - continue; //already bended - - // coord of the new bend point - double bendX, bendY = y_h; - // represents a incomming edges, i.e. the target of splitMe is on current level i - bool incomming = false; - // v is the node of splitMe on current level i - node v; - v = splitMe->source(); - node t = splitMe->target(); - - if (H.rank(v) != i) { - v = t; - incomming = true; - } - - // compute coord. of the new bend - if (incomming) - bendY = y_l; - - // the x coord. of splitMe is smaler than of the x coord. of the source, i.e the segment is pointing upward from left to right - bool toRight = true; - if (AGC.x(splitMe->source()) > AGC.x(splitMe->target())) - toRight = false; - - if (H.isLongEdgeDummy(v)) - // long edge dummy v, just add a new bend point "above" v - bendX = AGC.x(v); - else { - // we have to compute the x coord. of the new bend point and ensure that other bend point do not have the same coord. assigned - - //the "neighbour" of node v, the bend points are placed between w and v if some edges of v are bended - node w = 0; - - if (toRight && incomming && H.pos(v) != 0) - w = lvl_cur[H.pos(v) - 1]; - - if (toRight && !incomming && H.pos(v) != lvl_cur.high()) - w = lvl_cur[H.pos(v) + 1]; - - if (!toRight && incomming && H.pos(v) != lvl_cur.high()) - w = lvl_cur[H.pos(v) + 1]; - - if (!toRight && !incomming && H.pos(v) != 0) - w = lvl_cur[H.pos(v) - 1]; - - //number of edges, which crossed the area between v und w - int num = 0; - int edgeNum = 1; - - adjEntry adj; - forall_adj(adj, v) { - edge eTmp = adj->theEdge(); - - if (incomming && eTmp->target() == v) { - node src = eTmp->source(); - if (isNewNode[src]) { - src = eTmp->adjSource()->cyclicSucc()->theEdge()->source(); - if (isNewNode[src]) - src = eTmp->adjSource()->cyclicSucc()->theEdge()->adjSource()->cyclicSucc()->theEdge()->source(); - } - - if (AGC.x(src) < AGC.x(v) && toRight) { - if (AGC.x(src) < AGC.x(splitMe->source())) - edgeNum++; - } - else { - if (AGC.x(src) > AGC.x(v) && !toRight) {//in-edges from right to left - if (AGC.x(src) < AGC.x(splitMe->source())) - edgeNum++; - } - } - } - else { - node tgt = eTmp->target(); - if (isNewNode[tgt]) { - tgt = eTmp->adjTarget()->cyclicSucc()->theEdge()->target(); - if (isNewNode[tgt]) - tgt = eTmp->adjTarget()->cyclicSucc()->theEdge()->adjTarget()->cyclicSucc()->theEdge()->target(); - } - - if (AGC.x(tgt) < AGC.x(v) && !toRight) {//out-edges from left to right - if (AGC.x(splitMe->target()) > AGC.x(tgt) ) - edgeNum++; - } - else { - if (AGC.x(tgt) > AGC.x(v) && toRight) { //in-edges from right to left - if (AGC.x(splitMe->target()) > AGC.x(tgt) ) - edgeNum++; - } - } - } - - if (incomming && toRight && eTmp->target() == v && AGC.x(eTmp->source()) > AGC.x(eTmp->target())) - num++; - - if (incomming && !toRight && eTmp->target() == v && AGC.x(eTmp->source()) < AGC.x(eTmp->target())) - num++; - - if (!incomming && toRight && eTmp->source() == v && AGC.x(eTmp->source()) < AGC.x(eTmp->target())) - num++; - - if (!incomming && !toRight && eTmp->source() == v && AGC.x(eTmp->source()) < AGC.x(eTmp->target())) - num++; - } - - // default value if w is null - double delta = 10; - double a = AGC.x(v) - AGC.getWidth(v)/2; - double b = a; - if (w != 0) { - b = AGC.x(w) + AGC.getWidth(w)/2; - if (AGC.x(v) < AGC.x(w)) { - a = AGC.x(v) + AGC.getWidth(v)/2; - b = AGC.x(w) - AGC.getWidth(w)/2; - } - forall_adj(adj, w) { - edge eTmp = adj->theEdge(); - if (incomming && toRight && eTmp->target() == w && AGC.x(eTmp->source()) < AGC.x(eTmp->target())) - num++; - - if (incomming && !toRight && eTmp->target() == w && AGC.x(eTmp->source()) > AGC.x(eTmp->target())) - num++; - - if (!incomming && toRight && eTmp->source() == w && AGC.x(eTmp->source()) < AGC.x(eTmp->target())) - num++; - - if (!incomming && !toRight && eTmp->source() == w && AGC.x(eTmp->source()) > AGC.x(eTmp->target())) - num++; - } - - delta = fabs(a - b)/(num+3); - if (AGC.x(v) < AGC.x(w)) - bendX = a + edgeNum * delta; - else - bendX = b + edgeNum * delta; - } - else { - if (H.pos(v)==0) - bendX = b + edgeNum * delta; - else - bendX = a + edgeNum * delta; - } - if (H.pos(v) % 2 != 0) - bendX = bendX + delta/2; - }// else x coord - - DLine segment1, segment2; - - //replace v if it is a bend point - double oldPosX = AGC.x(v); - double oldPosY = AGC.y(v); - bool ok = false; - - // replace v or add new bend if v is long edge dummy - if (H.isLongEdgeDummy(v)) { - AGC.y(v) = bendY; - AGC.x(v) = bendX; - int c_out = 0; - int c_in = 0; - - edge e_out = v->firstAdj()->theEdge(); - edge e_in = v->lastAdj()->theEdge(); - - if (e_out->source() != v) - swap(e_out, e_in); - - overlap(AGC, H, e_out->source(), e_out->target(), i, c_out, c_out); - - overlap(AGC, H, e_in->source(), e_in->target(), i, c_in, c_in); - - // add new bend point - if (c_in + c_out == 0) - ok = true; - } - - if (ok && !dirty[v]) { - - done[v->firstAdj()] = done[v->lastAdj()] = i; - - edge e1 = v->firstAdj()->theEdge(); - edge e2 = v->lastAdj()->theEdge(); - - segment1 = DLine( DPoint(AGC.x(e1->source()), AGC.y(e1->source())), - DPoint(AGC.x(e1->target()), AGC.y(e1->target())) ); - - segment2 = DLine( DPoint(AGC.x(e2->source()), AGC.y(e2->source())), - DPoint(AGC.x(e2->target()), AGC.y(e2->target())) ); - - dirty[v] = true; - } - else { - //retore old position - AGC.y(v) = oldPosY; - AGC.x(v) = oldPosX; - - // create a new bend point by splitting splitMe - node newNode = H.m_GC.split(splitMe)->source(); - isNewNode[newNode] = true; - AGC.y(newNode) = bendY; - AGC.x(newNode) = bendX; - done[newNode->firstAdj()] = done[newNode->lastAdj()] = i; - - edge e1 = newNode->firstAdj()->theEdge(); - edge e2 = newNode->lastAdj()->theEdge(); - - /* - compute edges which crossed the two new segment of the bended edge - */ - segment1 = DLine( DPoint(AGC.x(e1->source()), AGC.y(e1->source())), - DPoint(AGC.x(e1->target()), AGC.y(e1->target())) ); - - segment2 =DLine( DPoint(AGC.x(e2->source()), AGC.y(e2->source())), - DPoint(AGC.x(e2->target()), AGC.y(e2->target())) ); - } - - for(int z = 0; z <= lvl_cur.high(); z++) { - node uu = lvl_cur[z]; - - adjEntry adj; - forall_adj(adj, uu) { - edge ee = adj->theEdge(); - - DLine line_ee( DPoint(AGC.x(ee->source()), AGC.y(ee->source())), DPoint(AGC.x(ee->target()), AGC.y(ee->target()) ) ); - - DPoint dummy; - if (line_ee.intersection(segment1, dummy) && line_ee.intersection(segment2, dummy)) - bendMe.pushBack(ee); - } - } - } // while - - }//for i (all level) - -} - - - - -void HierarchyLayoutModule::dynLayerDistance(GraphCopyAttributes &AGC, Hierarchy &H) { - if (H.high() < 1) - return; - - // min. angle between horizon and an edge segment - double minAngle = 0.087266; //=5 degree - - double y_low = AGC.y(H[0][0]); - double maxH_low = 0; // the height of the node with maximal height on lvl i-1 - - const Level &lvl0 = H[0]; - for (int j = 0; j <= lvl0.high(); j++) { - node v = lvl0[j]; - if (maxH_low < AGC.getHeight(v)) - maxH_low = AGC.getHeight(v); - } - - for (int i = 1; i <= H.high(); i++) { // all level - const Level &lvl = H[i]; - const Level &lvl_low = H[i-1]; - double y_cur = AGC.y(lvl[0]); //current y-coord. of the lvl - double maxH_cur = 0; - int count = 0; //number of edges, which overlap a node - - for (int j = 0; j <= lvl.high(); j++) { - node v = lvl[j]; - - if (maxH_cur < AGC.getHeight(v)) - maxH_cur = AGC.getHeight(v); - - adjEntry adj; - int ci = 0; - int cj = 0; - forall_adj(adj, v) { - edge e = adj->theEdge(); - node w = e->source(); - - if (w == v) - continue; // only incoming edges - - if (AGC.x(v) == AGC.x(w)) - continue; // edge e cannot overlap a node - - overlap(AGC, H, e->source(), e->target(), i, ci, cj); - - DLine line_v2w( DPoint(AGC.x(v), AGC.y(v)), DPoint(AGC.x(w), AGC.y(w)) ); - count = count + ci + cj; - } - } - - - // node distance contrain; node on lvl should not overlap node of the lvl below - double diff = (y_cur - maxH_cur/2) - (y_low + maxH_low/2); - double newY = y_cur; - if ( diff < 0 ) { - newY = newY - diff; - } - - - //min. angle constrain - double delta_x = fabs(AGC.x(lvl[0]) - AGC.x(lvl_low[lvl_low.high()])); - double minH = tan(minAngle) * delta_x; - diff = (newY - maxH_cur/2) - (y_low + maxH_low/2); - if (diff < 0) { - newY = newY + fabs(diff - minH); - } - - // compute the number of long edges between lvl and lvl_low - double numEdge = 0; - for (int j = 0; j <= lvl.high(); j++) { - node v = lvl[j]; - - if (v->indeg() == 0) - continue; - - adjEntry adj; - forall_adj(adj, v) { - edge e = adj->theEdge(); - node w = e->source(); - if (w == v) - continue; // only incoming edges - - DLine line_v2w( DPoint(AGC.x(v), AGC.y(v)), DPoint(AGC.x(w), AGC.y(w)) ); - if (line_v2w.length()>3*(y_cur - y_low)) - numEdge++; - } - } - - //increase visibility, if there are a lot of edges overlap nodes - double factor = 0; - if (count >= 1 && 3 <= count) - factor = 0.4; - if ( count > 3) - factor = 0.8; - - // factor depends on the number of very long edges - if (numEdge <= 3 && numEdge>=1) - factor = 0.5; - if (numEdge >3 && numEdge<7) - factor = 1.5; - if (numEdge > 7) - factor = 2; - - newY = newY + (y_cur - y_low) * factor; - - //assign new y coord. - if (newY != y_cur) { - double b = fabs(newY - y_cur); - for (int ii = i; ii <= H.high(); ii++) { - const Level &lvlTmp = H[ii]; - for (int j = 0; j <= lvlTmp.high(); j++) { - node z = lvlTmp[j]; - AGC.y(z) = AGC.y(z) + b; - } - } - } - - y_low = newY; - } -} - - -void HierarchyLayoutModule::overlap(ogdf::GraphCopyAttributes &AGC, ogdf::Hierarchy &H, ogdf::node s, ogdf::node t, int i, int &ci, int &cj) { - const Level &lvl_cur = H[i]; - DLine line(DPoint(AGC.x(s), AGC.y(s)), DPoint(AGC.x(t), AGC.y(t))); - - //iterate over all node of level lvl_cur - for(int k = 0; k <= lvl_cur.high(); k++) { - node u = lvl_cur[k]; - - if (u == s || u== t || H.isLongEdgeDummy(u)) - continue; - - double h = AGC.getHeight(u); - double b = AGC.getWidth(u); - - //bounding box of the node u - DLine left(DPoint(AGC.x(u)-b/2, AGC.y(u)-h/2), DPoint(AGC.x(u)-b/2, AGC.y(u)+h/2)); - DLine right(DPoint(AGC.x(u)+b/2, AGC.y(u)-h/2), DPoint(AGC.x(u)+b/2, AGC.y(u)+h/2)); - DLine bottom(DPoint(AGC.x(u)-b/2, AGC.y(u)-h/2), DPoint(AGC.x(u)+b/2, AGC.y(u)-h/2)); - - DPoint ipoint; - bool intersecLeft = line.intersection(left, ipoint); - bool intersecRight = line.intersection(right, ipoint); - bool intersectBottom = line.intersection(bottom, ipoint); - - if (intersecLeft || intersecRight || intersectBottom) - ci++;; - - } - - if (i-1 >= 0) { - const Level &lvl_low = H[i-1]; - - //iterate over all node of lvl_low - for(int k = 0; k <= lvl_low.high(); k++) { - node u = lvl_low[k]; - - if (u == s || u == t || H.isLongEdgeDummy(u)) - continue; - - double h = AGC.getHeight(u); - double b = AGC.getWidth(u); - - //bounding box of the node u - DLine left(DPoint(AGC.x(u)-b/2, AGC.y(u)-h/2), DPoint(AGC.x(u)-b/2, AGC.y(u)+h/2)); - DLine right(DPoint(AGC.x(u)+b/2, AGC.y(u)-h/2), DPoint(AGC.x(u)+b/2, AGC.y(u)+h/2)); - DLine bottom(DPoint(AGC.x(u)-b/2, AGC.y(u)-h/2), DPoint(AGC.x(u)+b/2, AGC.y(u)-h/2)); - - DPoint ipoint; - bool intersecLeft = line.intersection(left, ipoint); - bool intersecRight = line.intersection(right, ipoint); - bool intersectBottom = line.intersection(bottom, ipoint); - - if (intersecLeft || intersecRight || intersectBottom) - cj++; - } - } -} - -} diff --git a/ext/OGDF/src/layered/OptimalHierarchyClusterLayout.cpp b/ext/OGDF/src/layered/OptimalHierarchyClusterLayout.cpp deleted file mode 100644 index b2bb3c4b2..000000000 --- a/ext/OGDF/src/layered/OptimalHierarchyClusterLayout.cpp +++ /dev/null @@ -1,897 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the optimal third phase of the - * sugiyama algorithm for cluster graphs - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -#ifdef OGDF_LP_SOLVER - -namespace ogdf { - -int checkSolution( - Array &matrixBegin, // matrixBegin[i] = begin of column i - Array &matrixCount, // matrixCount[i] = number of nonzeroes in column i - Array &matrixIndex, // matrixIndex[n] = index of matrixValue[n] in its column - Array &matrixValue, // matrixValue[n] = non-zero value in matrix - Array &rightHandSide, // right-hand side of LP constraints - Array &equationSense, // 'E' == 'G' >= 'L' <= - Array &lowerBound, // lower bound of x[i] - Array &upperBound, // upper bound of x[i] - Array &x) // x-vector of optimal solution (if result is lpOptimal) -{ - const double zeroeps = 1.0E-7; - - const int nCols = matrixBegin.size(); - const int nRows = rightHandSide.size(); - - Array2D M(0,nCols-1, 0,nRows-1, 0.0); - - int i; - for(i = 0; i < nCols; ++i) - { - for(int j = 0; j < matrixCount[i]; ++j) - { - int k = matrixBegin[i] + j; - M(i,matrixIndex[k]) = matrixValue[k]; - } - } - - // check inequations - for(i = 0; i < nRows; ++i) - { - double val = 0.0; - for(int j = 0; j < nCols; ++j) - val += M(j,i) * x[j]; - - switch(equationSense[i]) { - case 'E': - if(fabs(val - rightHandSide[i]) > zeroeps) - return i; - break; - case 'G': - if(!(val+zeroeps >= rightHandSide[i])) - return i; - break; - case 'L': - if(!(val-zeroeps <= rightHandSide[i])) - return i; - break; - default: - return -2; - } - } - - return -1; -} - - -//--------------------------------------------------------- -// Constructor -//--------------------------------------------------------- -OptimalHierarchyClusterLayout::OptimalHierarchyClusterLayout() -{ - m_nodeDistance = 3; - m_layerDistance = 3; - m_fixedLayerDistance = false; - m_weightSegments = 2.0; - m_weightBalancing = 0.1; - m_weightClusters = 0.05; -} - - -//--------------------------------------------------------- -// Copy Constructor -//--------------------------------------------------------- -OptimalHierarchyClusterLayout::OptimalHierarchyClusterLayout( - const OptimalHierarchyClusterLayout &ohl) -{ - m_nodeDistance = ohl.nodeDistance(); - m_layerDistance = ohl.layerDistance(); - m_fixedLayerDistance = ohl.fixedLayerDistance(); - m_weightSegments = ohl.weightSegments(); - m_weightBalancing = ohl.weightBalancing(); - m_weightClusters = ohl.weightClusters(); -} - - -//--------------------------------------------------------- -// Assignment Operator -//--------------------------------------------------------- -OptimalHierarchyClusterLayout &OptimalHierarchyClusterLayout::operator=( - const OptimalHierarchyClusterLayout &ohl) -{ - m_nodeDistance = ohl.nodeDistance(); - m_layerDistance = ohl.layerDistance(); - m_fixedLayerDistance = ohl.fixedLayerDistance(); - m_weightSegments = ohl.weightSegments(); - m_weightBalancing = ohl.weightBalancing(); - m_weightClusters = ohl.weightClusters(); - - return *this; -} - - -//--------------------------------------------------------- -// Call for Cluster Graphs -//--------------------------------------------------------- -void OptimalHierarchyClusterLayout::doCall( - const ExtendedNestingGraph &H, - ClusterGraphCopyAttributes &ACGC) -{ - // trivial cases - const int n = H.numberOfNodes(); - - if(n == 0) - return; // nothing to do - - if(n == 1) { - node v = H.firstNode(); - ACGC.x(v) = 0; - ACGC.y(v) = 0; - return; - } - - m_pH = &H; - m_pACGC = &ACGC; - - // actual computation - computeXCoordinates(H,ACGC); - computeYCoordinates(H,ACGC); -} - - -//--------------------------------------------------------- -// Compute x-coordinates (LP-based approach) (for cluster graphs) -//--------------------------------------------------------- -void OptimalHierarchyClusterLayout::computeXCoordinates( - const ExtendedNestingGraph& H, - ClusterGraphCopyAttributes &AGC) -{ - const ClusterGraphCopy &CG = H.getClusterGraph(); - - const int k = H.numberOfLayers(); - - // - // preprocessing: determine nodes that are considered as virtual - // - m_isVirtual.init(H); - - int i; - for(i = 0; i < k; ++i) - { - int last = -1; - - // Process nodes on layer i from left to right - Stack S; - S.push(H.layerHierarchyTree(i)); - while(!S.empty()) - { - const LHTreeNode *vNode = S.pop(); - - if(vNode->isCompound()) { - for(int j = vNode->numberOfChildren()-1; j >= 0; --j) - S.push(vNode->child(j)); - - } else { - node v = vNode->getNode(); - - if(H.isLongEdgeDummy(v) == true) { - m_isVirtual[v] = true; - - edge e = v->firstAdj()->theEdge(); - if(e->target() == v) - e = v->lastAdj()->theEdge(); - node u = e->target(); - - if(H.verticalSegment(e) == false) - continue; - - if(H.isLongEdgeDummy(u) == true) { - int down = H.pos(u); - if(last != -1 && last > down) { - m_isVirtual[v] = false; - } else { - last = down; - } - } - } else { - m_isVirtual[v] = false; - } - } - } - } - - // - // determine variables of LP - // - int nSegments = 0; // number of vertical segments - int nRealVertices = 0; // number of real vertices - int nEdges = 0; // number of edges not in vertical segments - int nBalanced = 0; // number of real vertices with deg > 1 for which balancing constraints may be applied - - m_vIndex.init(H,-1); // for real node: index of x[v] for dummy: index of corresponding segment - NodeArray bIndex(H,-1); // (relative) index of b[v] - EdgeArray eIndex(H,-1); // for edge not in vertical segment: its index - Array count(H.numberOfEdges()); // counts the number of dummy vertices - // in corresponding segment that are not at - // position 0 - - int nSpacingConstraints = 0; - for(i = 0; i < k; ++i) - { - Stack S; - S.push(H.layerHierarchyTree(i)); - while(!S.empty()) - { - const LHTreeNode *vNode = S.pop(); - - if(vNode->isCompound()) { - cluster c = vNode->originalCluster(); - - if(H.isVirtual(c) == false) - nSpacingConstraints += (c == CG.rootCluster()) ? 1 : 2; - - for(int j = vNode->numberOfChildren()-1; j >= 0; --j) - S.push(vNode->child(j)); - - } else { - node v = vNode->getNode(); - - // ignore dummy nodes and nodes representing cluster - // (top or bottom) border - if(H.type(v) == ExtendedNestingGraph::ntClusterBottom || H.type(v) == ExtendedNestingGraph::ntClusterTop) - continue; - - ++nSpacingConstraints; - - // ignore dummy nodes - if(m_isVirtual[v] == true) - continue; - - // we've found a real vertex - m_vIndex[v] = nRealVertices++; - if(v->degree() > 1) - bIndex[v] = nBalanced++; - - // consider all outgoing edges - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w == v) - continue; - - // we've found an edge not belonging to a vetical segment - eIndex[e] = nEdges++; - - if(m_isVirtual[w] == false) - continue; - - do { - // we've found a vertical segment - count[nSegments] = 0; - do { - m_vIndex[w] = nSegments; - count[nSegments] += 2; - - // next edge / dummy in segment - e = e->adjTarget()->cyclicSucc()->theEdge(); - w = e->target(); - } while(m_isVirtual[w] && H.verticalSegment(e)); - - ++nSegments; - - // edge following vertical segment - eIndex[e] = nEdges++; - - } while(m_isVirtual[w]); - } - } - } - } - - // Assign indices to clusters - int nClusters = 0; - m_cIndex.init(CG,-1); - - cluster c; - forall_clusters(c,CG) - if(H.isVirtual(c) == false) - m_cIndex[c] = nClusters++; - - - // assignment of variables to matrix columns - // d_e 0, ..., nEdges-1 - // x_v vertexOffset, ..., vertexOffset + nRealVertices-1 - // x_s segmentOffset, ..., segmentOffset + nSegments-1 - // b_v balancedOffset, ..., balancedOffset + nBalanced-1 - // l_c clusterLefOffset, ..., clusterLeftOffset + nClusters-1 - // r_c clusterRightOffset, ..., clusterRightOffset+ nClusters-1 - LPSolver solver; - - if(m_weightBalancing <= 0.0) - nBalanced = 0; // no balancing - - const int nCols = nEdges + nRealVertices + nSegments + nBalanced + 2*nClusters; - const int nRows = 2*nEdges + nSpacingConstraints + 2*nBalanced; - - m_vertexOffset = nEdges; - m_segmentOffset = nEdges + nRealVertices; - const int balancedOffset = m_segmentOffset + nSegments; - m_clusterLeftOffset = balancedOffset + nBalanced; - m_clusterRightOffset = m_clusterLeftOffset + nClusters; - - // allocation of matrix - Array matrixCount(0,nCols-1,0); - - for(i = 0; i < nEdges; ++i) { - matrixCount[i] = 2; - } - - for(int jj = 0; jj < k; ++jj) { - const LHTreeNode *layerRoot = H.layerHierarchyTree(jj); - - Stack S; - S.push(layerRoot); - while(!S.empty()) - { - const LHTreeNode *vNode = S.pop(); - - if(vNode->isCompound()) { - i = m_cIndex[vNode->originalCluster()]; - - if(i >= 0) { - int count = (vNode == layerRoot) ? 1 : 2; - - matrixCount[m_clusterLeftOffset + i] += count; - matrixCount[m_clusterRightOffset + i] += count; - } - - for(int j = vNode->numberOfChildren()-1; j >= 0; --j) - S.push(vNode->child(j)); - - } else { - node v = vNode->getNode(); - - // ignore nodes representing cluster (top or bottom) border - if(H.type(v) == ExtendedNestingGraph::ntClusterBottom || - H.type(v) == ExtendedNestingGraph::ntClusterTop) - continue; - - if(m_isVirtual[v] == false) { - i = m_vertexOffset + m_vIndex[v]; - - int count = 2 + 2*v->degree(); - if(nBalanced > 0) { - if(v->degree() > 1) - count += 2; - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(bIndex[w] != -1) - count += 2; - } - } - - matrixCount[i] = count; - - } else if (nBalanced > 0) { - i = m_vIndex[v]; - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(bIndex[w] != -1) - count[i] += 2; - } - } - } - } - } - - for(i = 0; i < nSegments; ++i) { - matrixCount[m_segmentOffset+i] = count[i] + 4; - } - - for(i = 0; i < nBalanced; ++i) { - matrixCount[balancedOffset+i] = 2; - } - - - // Computation of matrixBegin[i] from given matrixCount values - Array matrixBegin(nCols); - - int nNonZeroes = 0; - for(i = 0; i < nCols; ++i) { - matrixBegin[i] = nNonZeroes; - nNonZeroes += matrixCount[i]; - } - - - int debugNonZeroCount = 0; // for debugging only - - // - // constraints - // - Array matrixIndex(nNonZeroes); - Array matrixValue(nNonZeroes); - Array equationSense(nRows); - Array rightHandSide(nRows); - - int currentRow = 0; - Array currentCol(nCols); - for(i = 0; i < nCols; ++i) - currentCol[i] = matrixBegin[i]; - - // Constraints: - // d_(u,v) - x_u + x_v >= 0 - // d_(u,v) + x_u - x_v >= 0 - edge e; - forall_edges(e,H) - { - int dCol = eIndex[e]; - if(dCol >= 0) { - node u = e->source(); - int uCol = m_vIndex[u]; - uCol += (m_isVirtual[u]) ? m_segmentOffset : m_vertexOffset; - - node v = e->target(); - int vCol = m_vIndex[v]; - vCol += (m_isVirtual[v]) ? m_segmentOffset : m_vertexOffset; - - // d_(u,v) - x_u + x_v >= 0 - - matrixValue[currentCol[dCol]] = 1.0; - matrixIndex[currentCol[dCol]] = currentRow; - ++currentCol[dCol]; - debugNonZeroCount++; - - matrixValue[currentCol[uCol]] = -1.0; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = 1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - - // d_(u,v) + x_u - x_v >= 0 - - matrixValue[currentCol[dCol]] = 1.0; - matrixIndex[currentCol[dCol]] = currentRow; - ++currentCol[dCol]; - debugNonZeroCount++; - - matrixValue[currentCol[uCol]] = 1.0; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = -1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - } - } - - - // Constraints: - // x[v_i] - x[v_(i-1)] >= nodeDistance + 0.5*(width(v_i)+width(v_(i-1)) - for(i = 0; i < k; ++i) - { - List > L; - buildLayerList(H.layerHierarchyTree(i), L); - - if(L.size() < 2) - continue; - - ListConstIterator > it1 = L.begin(); - for(ListConstIterator > it2 = it1.succ(); - it2.valid(); it1 = it2, ++it2) - { - int uCol = (*it1).x1(); - double uWidth = (*it1).x2(); - - int vCol = (*it2).x1(); - double vWidth = (*it2).x2(); - - // x_v - x_u >= nodeDistance + 0.5*(width(v)+width(u)) - matrixValue[currentCol[uCol]] = -1.0; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = 1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = - m_nodeDistance + 0.5*(uWidth + vWidth); - - ++currentRow; - } - } - - // Constraints: - // b[v] - x[v] + 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - // b[v] + x[v] - 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - if(nBalanced > 0) { - node v; - forall_nodes(v,H) - { - int bCol = bIndex[v]; - if(bCol == -1) - continue; - bCol += balancedOffset; - - int vCol = m_vertexOffset+m_vIndex[v]; - - // b[v] - x[v] + 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - matrixValue[currentCol[bCol]] = 1.0; - matrixIndex[currentCol[bCol]] = currentRow; - ++currentCol[bCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = -1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - double f = 1.0 / v->degree(); - adjEntry adj; - forall_adj(adj,v) { - node u = adj->twinNode(); - int uCol = m_vIndex[u]; - uCol += (m_isVirtual[u]) ? m_segmentOffset : m_vertexOffset; - - matrixValue[currentCol[uCol]] = f; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - } - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - - // b[v] + x[v] - 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - matrixValue[currentCol[bCol]] = 1.0; - matrixIndex[currentCol[bCol]] = currentRow; - ++currentCol[bCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = 1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - f = -1.0 / v->degree(); - forall_adj(adj,v) { - node u = adj->twinNode(); - int uCol = m_vIndex[u]; - uCol += (m_isVirtual[u]) ? m_segmentOffset : m_vertexOffset; - - matrixValue[currentCol[uCol]] = f; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - } - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - } - } - - OGDF_ASSERT(nNonZeroes == debugNonZeroCount); - - // lower and upper bounds - Array lowerBound(nCols); - Array upperBound(nCols); - - for(i = 0; i < nCols; ++i) { - lowerBound[i] = 0.0; - upperBound[i] = solver.infinity(); - } - - - // objective function - Array obj(nCols); - forall_edges(e,H) { - i = eIndex[e]; - if(i >= 0) { - // edge segments connecting to a vertical segment - // (i.e. the original edge is represented by at least - // three edges in H) get a special weight; all others - // have weight 1.0 - int sz = H.chain(H.origEdge(e)).size(); - if(sz >= 2) { - node uOrig = H.origNode(e->source()); - node vOrig = H.origNode(e->target()); - if((uOrig && uOrig->outdeg() == 1) || (vOrig && vOrig->indeg() == 1)) - obj[i] = 1.2*m_weightSegments; - else - obj[i] = (sz >= 3) ? m_weightSegments : 1.0; - } else - obj[i] = 1.0; - - if(m_isVirtual[e->source()] == false && e->source()->degree() == 1) - obj[i] += m_weightBalancing; - if(m_isVirtual[e->target()] == false && e->target()->degree() == 1) - obj[i] += m_weightBalancing; - } - } - - for(i = nEdges; i < balancedOffset; ++i) - obj[i] = 0.0; // all x_v and x_s do not contribute - - for(; i < m_clusterLeftOffset; ++i) - obj[i] = m_weightBalancing; - - for(; i < m_clusterRightOffset; ++i) - obj[i] = -m_weightClusters; - - for(; i < nCols; ++i) - obj[i] = +m_weightClusters; - - // solve LP - double optimum; - Array x(nCols); - - LPSolver::Status status = - solver.optimize(LPSolver::lpMinimize, obj, - matrixBegin, matrixCount, matrixIndex, matrixValue, - rightHandSide, equationSense, - lowerBound, upperBound, - optimum, x); - - OGDF_ASSERT(status == LPSolver::lpOptimal); - int checkResult = checkSolution(matrixBegin, matrixCount, matrixIndex, matrixValue, - rightHandSide, equationSense, lowerBound, upperBound, x); - OGDF_ASSERT(checkResult == -1); - - // assign x coordinates - node v; - forall_nodes(v,H) - { - ExtendedNestingGraph::NodeType t = H.type(v); - if(t == ExtendedNestingGraph::ntNode || t == ExtendedNestingGraph::ntDummy) - { - if(m_isVirtual[v]) - AGC.x(v) = x[m_segmentOffset + m_vIndex[v]]; - else - AGC.x(v) = x[m_vertexOffset + m_vIndex[v]]; - } - } - - forall_clusters(c,CG.getOriginalClusterGraph()) - { - int i = m_cIndex[CG.copy(c)]; - OGDF_ASSERT(i >= 0); - - AGC.setClusterLeftRight(c, - x[m_clusterLeftOffset+i], x[m_clusterRightOffset+i]); - } - - - // clean-up - m_isVirtual.init(); - m_vIndex .init(); - m_cIndex .init(); -} - - -void OptimalHierarchyClusterLayout::buildLayerList( - const LHTreeNode *vNode, - List > &L) -{ - if(vNode->isCompound()) - { - int i = m_cIndex[vNode->originalCluster()]; - - if(i >= 0) - L.pushBack(Tuple2(m_clusterLeftOffset + i, 0)); - - for(int j = 0; j < vNode->numberOfChildren(); ++j) - buildLayerList(vNode->child(j), L); - - if(i >= 0) - L.pushBack(Tuple2(m_clusterRightOffset + i, 0)); - - } else { - node v = vNode->getNode(); - ExtendedNestingGraph::NodeType t = m_pH->type(v); - - if(t != ExtendedNestingGraph::ntClusterBottom && - t != ExtendedNestingGraph::ntClusterTop) - { - int i = m_vIndex[v]; - i += (m_isVirtual[v]) ? m_segmentOffset : m_vertexOffset; - - L.pushBack(Tuple2(i, m_pACGC->getWidth(v))); - } - } -} - - -//--------------------------------------------------------- -// Compute y-coordinates for cluster graphs -//--------------------------------------------------------- -void OptimalHierarchyClusterLayout::computeYCoordinates( - const ExtendedNestingGraph& H, - ClusterGraphCopyAttributes &AGC) -{ - const int k = H.numberOfLayers(); - - Array y(k); - - double prevHeight = 0; - for(int i = 0; i < k; ++i) - { - // Compute height of layer i and dy (if required) - double height = 0; // height[i] - double dy = m_layerDistance; // dy[i] - - Stack S; - S.push(H.layerHierarchyTree(i)); - while(!S.empty()) - { - const LHTreeNode *vNode = S.pop(); - - if(vNode->isCompound()) { - for(int j = vNode->numberOfChildren()-1; j >= 0; --j) - S.push(vNode->child(j)); - - } else { - node v = vNode->getNode(); - - if(H.type(v) == ExtendedNestingGraph::ntNode) { - double h = AGC.getHeight(v); - if(h > height) - height = h; - } - - if(m_fixedLayerDistance == false) { - edge e; - forall_adj_edges(e,v) { - node w = e->source(); - if(w != v) { - double dwv = fabs(AGC.x(w) - AGC.x(v)) / 3.0; - if(dwv > dy) - dy = dwv; - } - } - } - } - } - - if(dy > 10*m_layerDistance) - dy = 10*m_layerDistance; - - y[i] = (i > 0) ? y[i-1] + dy +0.5*(height+prevHeight) : 0.5*height; - - prevHeight = height; - } - - // set y-ccordinates of nodes - node v; - forall_nodes(v,H) { - ExtendedNestingGraph::NodeType t = H.type(v); - if(t == ExtendedNestingGraph::ntNode || t == ExtendedNestingGraph::ntDummy) - { - AGC.y(v) = y[H.rank(v)]; - } - } - - // set y-coordinates of clusters - const ClusterGraph &CG = H.getOriginalClusterGraph(); - - const double yUnit = m_layerDistance; - - cluster c; - forall_postOrderClusters(c,CG) - { - if(c == CG.rootCluster()) - continue; - - double contentMin = DBL_MAX; - double contentMax = DBL_MIN; - - ListConstIterator itV; - for(itV = c->nBegin(); itV.valid(); ++itV) { - node v = H.copy(*itV); - double t = AGC.y(v) - 0.5*AGC.getHeight(v); - double b = AGC.y(v) + 0.5*AGC.getHeight(v); - OGDF_ASSERT(t <= b); - - if(t < contentMin) contentMin = t; - if(b > contentMax) contentMax = b; - } - - ListConstIterator itC; - for(itC = c->cBegin(); itC.valid(); ++itC) { - double t = AGC.top(*itC); - double b = AGC.bottom(*itC); - OGDF_ASSERT(t <= b); - - if(t < contentMin) contentMin = t; - if(b > contentMax) contentMax = b; - } - - double currentTop = y[H.rank(H.top(c))]; - double currentBottom = y[H.rank(H.bottom(c))]; - - if(contentMin != DBL_MAX) - { - int kt = int(((contentMin-m_layerDistance) - currentTop) / yUnit); - if(kt >= 1) - currentTop += kt*yUnit; - - int kb = int((currentBottom - (contentMax+m_layerDistance)) / yUnit); - if(kb >= 1) - currentBottom -= kb*yUnit; - } - - AGC.setClusterTopBottom(c, currentTop, currentBottom); - } -} - -} - -#endif diff --git a/ext/OGDF/src/layered/OptimalHierarchyLayout.cpp b/ext/OGDF/src/layered/OptimalHierarchyLayout.cpp deleted file mode 100644 index ab9f408ba..000000000 --- a/ext/OGDF/src/layered/OptimalHierarchyLayout.cpp +++ /dev/null @@ -1,647 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration and implementation of the optimal -// third phase of the sugiyama algorithm - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -#ifdef OGDF_LP_SOLVER - -namespace ogdf { - - -//--------------------------------------------------------- -// Constructor -//--------------------------------------------------------- -OptimalHierarchyLayout::OptimalHierarchyLayout() -{ - m_nodeDistance = 3; - m_layerDistance = 3; - m_fixedLayerDistance = false; - m_weightSegments = 2.0; - m_weightBalancing = 0.1; -} - - -//--------------------------------------------------------- -// Copy Constructor -//--------------------------------------------------------- -OptimalHierarchyLayout::OptimalHierarchyLayout(const OptimalHierarchyLayout &ohl) -{ - m_nodeDistance = ohl.nodeDistance(); - m_layerDistance = ohl.layerDistance(); - m_fixedLayerDistance = ohl.fixedLayerDistance(); - m_weightSegments = ohl.weightSegments(); - m_weightBalancing = ohl.weightBalancing(); -} - - -//--------------------------------------------------------- -// Assignment Operator -//--------------------------------------------------------- -OptimalHierarchyLayout &OptimalHierarchyLayout::operator=(const OptimalHierarchyLayout &ohl) -{ - m_nodeDistance = ohl.nodeDistance(); - m_layerDistance = ohl.layerDistance(); - m_fixedLayerDistance = ohl.fixedLayerDistance(); - m_weightSegments = ohl.weightSegments(); - m_weightBalancing = ohl.weightBalancing(); - - return *this; -} - - -//--------------------------------------------------------- -// Call for Graphs -//--------------------------------------------------------- -void OptimalHierarchyLayout::doCall(const Hierarchy& H,GraphCopyAttributes &AGC) -{ - // trivial cases - const GraphCopy &GC = H; - const int n = GC.numberOfNodes(); - - if(n == 0) - return; // nothing to do - - if(n == 1) { - node v = GC.firstNode(); - AGC.x(v) = 0; - AGC.y(v) = 0; - return; - } - - // actual computation - computeXCoordinates(H,AGC); - computeYCoordinates(H,AGC); -} - - -//--------------------------------------------------------- -// Compute x-coordinates (LP-based approach) (for graphs) -//--------------------------------------------------------- -void OptimalHierarchyLayout::computeXCoordinates( - const Hierarchy& H, - GraphCopyAttributes &AGC) -{ - const GraphCopy &GC = H; - const int k = H.size(); - - // - // preprocessing: determine nodes that are considered as virtual - // - NodeArray isVirtual(GC); - - int i; - for(i = 0; i < k; ++i) - { - const Level &L = H[i]; - int last = -1; - for(int j = 0; j < L.size(); ++j) - { - node v = L[j]; - - if(H.isLongEdgeDummy(v) == true) { - isVirtual[v] = true; - - node u = v->firstAdj()->theEdge()->target(); - if(u == v) u = v->lastAdj()->theEdge()->target(); - - if(H.isLongEdgeDummy(u) == true) { - int down = H.pos(u); - if(last != -1 && last > down) { - isVirtual[v] = false; - } else { - last = down; - } - } - } else - isVirtual[v] = false; - } - } - - // - // determine variables of LP - // - int nSegments = 0; // number of vertical segments - int nRealVertices = 0; // number of real vertices - int nEdges = 0; // number of edges not in vertical segments - int nBalanced = 0; // number of real vertices with deg > 1 for which - // balancing constraints may be applied - - NodeArray vIndex(GC,-1); // for real node: index of x[v] - // for dummy: index of corresponding segment - NodeArray bIndex(GC,-1); // (relative) index of b[v] - EdgeArray eIndex(GC,-1); // for edge not in vertical segment: - // its index - Array count(GC.numberOfEdges()); // counts the number of dummy vertices - // in corresponding segment that are not at - // position 0 - - for(i = 0; i < k; ++i) - { - const Level &L = H[i]; - for(int j = 0; j < L.size(); ++j) { - node v = L[j]; - if(isVirtual[v] == true) - continue; - - // we've found a real vertex - vIndex[v] = nRealVertices++; - if(v->degree() > 1) - bIndex[v] = nBalanced++; - - // consider all outgoing edges - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w == v) - continue; - - // we've found an edge not belonging to a vetical segment - eIndex[e] = nEdges++; - - if(isVirtual[w] == false) - continue; - - // we've found a vertical segment - count[nSegments] = 0; - do { - vIndex[w] = nSegments; - const int high = H[H.rank(w)].high(); - if(high > 0) { - if (H.pos(w) == 0 || H.pos(w) == high) - ++count[nSegments]; - else - count[nSegments] += 2; - } - - // next edge / dummy in segment - e = e->adjTarget()->cyclicSucc()->theEdge(); - w = e->target(); - } while(isVirtual[w]); - - // edge following vertical segment - eIndex[e] = nEdges++; - - ++nSegments; - } - } - } - - // assignment of variables to matrix columns - // d_e 0, ..., nEdges-1 - // x_v vertexOffset, ..., vertexOffset+nRealVertices-1 - // x_s segmentOffset, ..., segmentOffset+nSegments-1 - // b_v balancedOffset, ..., balancedOffset+nBalanced-1 - LPSolver solver; - - if(m_weightBalancing <= 0.0) - nBalanced = 0; // no balancing - - const int nCols = nEdges + nRealVertices + nSegments + nBalanced; - const int nRows = 2*nEdges + GC.numberOfNodes() - k + 2*nBalanced; - - const int vertexOffset = nEdges; - const int segmentOffset = nEdges + nRealVertices; - const int balancedOffset = segmentOffset + nSegments; - - // allocation of matrix - Array matrixBegin(nCols); - Array matrixCount(nCols); - - int nNonZeroes = 0; - for(i = 0; i < nEdges; ++i) { - matrixBegin[i] = nNonZeroes; - nNonZeroes += (matrixCount[i] = 2); - } - - for(int jj = 0; jj < k; ++jj) { - const Level &L = H[jj]; - for(int j = 0; j < L.size(); ++j) { - node v = L[j]; - - if(isVirtual[v] == false) { - i = vertexOffset + vIndex[v]; - matrixBegin[i] = nNonZeroes; - - int high = H[H.rank(v)].high(); - int cstrSep; - if(high == 0) - cstrSep = 0; - else if (H.pos(v) == 0 || H.pos(v) == high) - cstrSep = 1; - else - cstrSep = 2; - - int count = cstrSep + 2*v->degree(); - if(nBalanced > 0) { - if(v->degree() > 1) - count += 2; - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(bIndex[w] != -1) - count += 2; - } - } - - matrixCount[i] = count; - nNonZeroes += matrixCount[i]; - - } else if (nBalanced > 0) { - i = vIndex[v]; - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(bIndex[w] != -1) - count[i] += 2; - } - } - } - } - - for(i = 0; i < nSegments; ++i) { - matrixBegin[segmentOffset+i] = nNonZeroes; - nNonZeroes += (matrixCount[segmentOffset+i] = count[i] + 4); - } - - for(i = 0; i < nBalanced; ++i) { - matrixBegin[balancedOffset+i] = nNonZeroes; - nNonZeroes += (matrixCount[balancedOffset+i] = 2); - } - - - int debugNonZeroCount = 0; // for debugging only - - // - // constraints - // - Array matrixIndex(nNonZeroes); - Array matrixValue(nNonZeroes); - Array equationSense(nRows); - Array rightHandSide(nRows); - - int currentRow = 0; - Array currentCol(nCols); - for(i = 0; i < nCols; ++i) - currentCol[i] = matrixBegin[i]; - - // Constraints: - // d_(u,v) - x_u + x_v >= 0 - // d_(u,v) + x_u - x_v >= 0 - edge e; - forall_edges(e,GC) - { - int dCol = eIndex[e]; - if(dCol >= 0) { - node u = e->source(); - int uCol = vIndex[u]; - uCol += (isVirtual[u]) ? segmentOffset : vertexOffset; - - node v = e->target(); - int vCol = vIndex[v]; - vCol += (isVirtual[v]) ? segmentOffset : vertexOffset; - - // d_(u,v) - x_u + x_v >= 0 - matrixValue[currentCol[dCol]] = 1.0; - matrixIndex[currentCol[dCol]] = currentRow; - ++currentCol[dCol]; - debugNonZeroCount++; - - matrixValue[currentCol[uCol]] = -1.0; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = 1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - - // d_(u,v) + x_u - x_v >= 0 - matrixValue[currentCol[dCol]] = 1.0; - matrixIndex[currentCol[dCol]] = currentRow; - ++currentCol[dCol]; - debugNonZeroCount++; - - matrixValue[currentCol[uCol]] = 1.0; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = -1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - } - } - - // Constraints: - // x[v_i] - x[v_(i-1)] >= nodeDistance + 0.5*(width(v_i)+width(v_(i-1)) - for(i = 0; i < k; ++i) - { - const Level &L = H[i]; - for(int j = 1; j < L.size(); ++j) - { - node u = L[j-1]; - int uCol = vIndex[u]; - uCol += (isVirtual[u]) ? segmentOffset : vertexOffset; - - node v = L[j]; - int vCol = vIndex[v]; - vCol += (isVirtual[v]) ? segmentOffset : vertexOffset; - - // x_v - x_u >= nodeDistance + 0.5*(width(v)+width(u)) - matrixValue[currentCol[uCol]] = -1.0; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = 1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = - m_nodeDistance + 0.5*(AGC.getWidth(v)+AGC.getWidth(u)); - - ++currentRow; - } - } - - // Constraints: - // b[v] - x[v] + 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - // b[v] + x[v] - 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - if(nBalanced > 0) { - for(i = 0; i < k; ++i) - { - const Level &L = H[i]; - for(int j = 0; j < L.size(); ++j) - { - node v = L[j]; - int bCol = bIndex[v]; - if(bCol == -1) - continue; - bCol += balancedOffset; - - int vCol = vertexOffset+vIndex[v]; - - // b[v] - x[v] + 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - matrixValue[currentCol[bCol]] = 1.0; - matrixIndex[currentCol[bCol]] = currentRow; - ++currentCol[bCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = -1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - double f = 1.0 / v->degree(); - adjEntry adj; - forall_adj(adj,v) { - node u = adj->twinNode(); - int uCol = vIndex[u]; - uCol += (isVirtual[u]) ? segmentOffset : vertexOffset; - - matrixValue[currentCol[uCol]] = f; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - } - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - - // b[v] + x[v] - 1/deg(v) * sum_{u in Adj(v)} x[u] >= 0 - matrixValue[currentCol[bCol]] = 1.0; - matrixIndex[currentCol[bCol]] = currentRow; - ++currentCol[bCol]; - debugNonZeroCount++; - - matrixValue[currentCol[vCol]] = 1.0; - matrixIndex[currentCol[vCol]] = currentRow; - ++currentCol[vCol]; - debugNonZeroCount++; - - f = -1.0 / v->degree(); - forall_adj(adj,v) { - node u = adj->twinNode(); - int uCol = vIndex[u]; - uCol += (isVirtual[u]) ? segmentOffset : vertexOffset; - - matrixValue[currentCol[uCol]] = f; - matrixIndex[currentCol[uCol]] = currentRow; - ++currentCol[uCol]; - debugNonZeroCount++; - } - - equationSense[currentRow] = 'G'; - rightHandSide[currentRow] = 0.0; - - ++currentRow; - } - } - } - - OGDF_ASSERT(nNonZeroes == debugNonZeroCount); - - // lower and upper bounds - Array lowerBound(nCols); - Array upperBound(nCols); - - for(i = 0; i < nCols; ++i) { - lowerBound[i] = 0.0; - upperBound[i] = solver.infinity(); - } - - // objective function - Array obj(nCols); - forall_edges(e,GC) { - i = eIndex[e]; - if(i >= 0) { - // edge segments connecting to a vertical segment - // (i.e. the original edge is represented by at least - // three edges in GC) get a special weight; all others - // have weight 1.0 - obj[i] = (GC.chain(GC.original(e)).size() >= 3) ? m_weightSegments : 1.0; - if(isVirtual[e->source()] == false && e->source()->degree() == 1) - obj[i] += m_weightBalancing; - if(isVirtual[e->target()] == false && e->target()->degree() == 1) - obj[i] += m_weightBalancing; - } - } - - for(i = nEdges; i < balancedOffset; ++i) - obj[i] = 0.0; // all x_v and x_s do not contribute - - for(; i < nCols; ++i) - obj[i] = m_weightBalancing; - - - // output problem - /*ofstream os("c:\\work\\GDE\\out.txt"); - os << "nRows = " << nRows << "\n"; - os << "nCols = " << nCols << "\n"; - os << "nNonZeroes = " << nNonZeroes << "\n"; - os << "\nmatrixBegin, matrixCount:\n"; - for(i = 0; i < nCols; ++i) - os << " [" << i << "] " << matrixBegin[i] << ", " << matrixCount[i] << "\n"; - os << "\nmatrixIndex, matrixValue:\n"; - for(i = 0; i < nNonZeroes; ++i) - os << " [" << i << "] " << matrixIndex[i] << ", " << matrixValue[i] << "\n"; - os << "\nequationSense, rightHandSide:\n"; - for(i = 0; i < nRows; ++i) - os << " [" << i << "] " << equationSense[i] << ", " << rightHandSide[i] << "\n"; - - os.flush();*/ - - - // solve LP - double optimum; - Array x(nCols); - - LPSolver::Status status = - solver.optimize(LPSolver::lpMinimize, obj, - matrixBegin, matrixCount, matrixIndex, matrixValue, - rightHandSide, equationSense, - lowerBound, upperBound, - optimum, x); - - OGDF_ASSERT(status == LPSolver::lpOptimal); - - /*os << "\nx\n"; - for(i = 0; i < nCols; ++i) - os << " [" << i << "] " << x[i] << "\n"; - - os.close();*/ - - // assign x coordinates - node v; - forall_nodes(v,GC) { - if(isVirtual[v]) - AGC.x(v) = x[segmentOffset+vIndex[v]]; - else - AGC.x(v) = x[vertexOffset+vIndex[v]]; - } -} - - -//--------------------------------------------------------- -// Compute y-coordinates (for graphs) -//--------------------------------------------------------- -void OptimalHierarchyLayout::computeYCoordinates( - const Hierarchy& H, - GraphCopyAttributes &AGC) -{ - const int k = H.size(); - int i; - - // compute height of each layer - Array height(0,k-1,0.0); - - for(i = 0; i < k; ++i) { - const Level &L = H[i]; - for(int j = 0; j < L.size(); ++j) { - double h = AGC.getHeight(L[j]); - if(h > height[i]) - height[i] = h; - } - } - - - // assign y-coordinates - double yPos = 0.5 * height[0]; - - for(i = 0; ; ++i) - { - const Level &L = H[i]; - for(int j = 0; j < L.size(); ++j) - AGC.y(L[j]) = yPos; - - if(i == k-1) - break; - - double dy = m_layerDistance; - - if(m_fixedLayerDistance == false) - { - for(int j = 0; j < L.size(); ++j) { - node v = L[j]; - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) { - double dvw = fabs(AGC.x(v)-AGC.x(w)) / 3.0; - if(dvw > dy) - dy = dvw; - } - } - } - - if(dy > 10*m_layerDistance) - dy = 10*m_layerDistance; - } - - yPos += dy + 0.5 * (height[i] + height[i+1]); - } -} - -} - -#endif diff --git a/ext/OGDF/src/layered/OptimalRanking.cpp b/ext/OGDF/src/layered/OptimalRanking.cpp deleted file mode 100644 index b76594520..000000000 --- a/ext/OGDF/src/layered/OptimalRanking.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of optimal node ranking algorithm - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// OptimalRanking -// optimal node ranking for hierarchical graphs using min-cost flow -//--------------------------------------------------------- - -OptimalRanking::OptimalRanking() -{ - m_subgraph.set(new DfsAcyclicSubgraph); - m_separateMultiEdges = true; -} - - -void OptimalRanking::call(const Graph &G, const EdgeArray &length, NodeArray &rank) -{ - EdgeArray cost(G,1); - call(G, length, cost, rank); -} - - -void OptimalRanking::call( - const Graph &G, - const EdgeArray &length, - const EdgeArray &cost, - NodeArray &rank) -{ - List R; - - m_subgraph.get().call(G,R); - - EdgeArray reversed(G,false); - for (ListConstIterator it = R.begin(); it.valid(); ++it) - reversed[*it] = true; - R.clear(); - - doCall(G, rank, reversed, length, cost); -} - - -void OptimalRanking::call (const Graph& G, NodeArray &rank) -{ - List R; - - m_subgraph.get().call(G,R); - - EdgeArray reversed(G,false); - for (ListConstIterator it = R.begin(); it.valid(); ++it) - reversed[*it] = true; - R.clear(); - - EdgeArray length(G,1); - - if(m_separateMultiEdges) { - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G, edges, minIndex, maxIndex); - - SListConstIterator it = edges.begin(); - if(it.valid()) - { - int prevSrc = minIndex[*it]; - int prevTgt = maxIndex[*it]; - - for(it = it.succ(); it.valid(); ++it) { - edge e = *it; - if (minIndex[e] == prevSrc && maxIndex[e] == prevTgt) - length[e] = 2; - else { - prevSrc = minIndex[e]; - prevTgt = maxIndex[e]; - } - } - } - } - - EdgeArray cost(G,1); - doCall(G, rank, reversed, length, cost); -} - - -void OptimalRanking::doCall( - const Graph& G, - NodeArray &rank, - EdgeArray &reversed, - const EdgeArray &length, - const EdgeArray &costOrig) -{ - MinCostFlowReinelt mcf; - - // construct min-cost flow problem - GraphCopy GC; - GC.createEmpty(G); - - // compute connected component of G - NodeArray component(G); - int numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - Array > nodesInCC(numCC); - - node v; - forall_nodes(v,G) - nodesInCC[component[v]].pushBack(v); - - EdgeArray auxCopy(G); - rank.init(G); - - for(int i = 0; i < numCC; ++i) - { - GC.initByNodes(nodesInCC[i], auxCopy); - makeLoopFree(GC); - - edge e; - forall_edges(e,GC) - if(reversed[GC.original(e)]) - GC.reverseEdge(e); - - // special cases: - if(GC.numberOfNodes() == 1) { - rank[GC.original(GC.firstNode())] = 0; - continue; - } else if(GC.numberOfEdges() == 1) { - e = GC.original(GC.firstEdge()); - rank[e->source()] = 0; - rank[e->target()] = length[e]; - continue; - } - - EdgeArray lowerBound(GC,0); - EdgeArray upperBound(GC,mcf.infinity()); - EdgeArray cost(GC); - NodeArray supply(GC); - - forall_edges(e,GC) - cost[e] = -length[GC.original(e)]; - - node v; - forall_nodes(v,GC) { - int s = 0; - forall_adj_edges(e,v) { - if(v == e->source()) - s += costOrig[GC.original(e)]; - else - s -= costOrig[GC.original(e)]; - } - supply[v] = s; - } - - OGDF_ASSERT(isAcyclic(GC) == true); - - // find min-cost flow - EdgeArray flow(GC); - NodeArray dual(GC); -#ifdef OGDF_DEBUG - bool feasible = -#endif - mcf.call(GC, lowerBound, upperBound, cost, supply, flow, dual); - OGDF_ASSERT(feasible); - - forall_nodes(v,GC) - rank[GC.original(v)] = dual[v]; - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/SplitHeuristic.cpp b/ext/OGDF/src/layered/SplitHeuristic.cpp deleted file mode 100644 index e50525447..000000000 --- a/ext/OGDF/src/layered/SplitHeuristic.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of split heuristic. - * - * \author Andrea Wagner - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - -namespace ogdf -{ -//------------------------------------------------------------------- -// SplitHeuristic -//------------------------------------------------------------------- - -void SplitHeuristic::init (const Hierarchy &H) -{ - m_cm = new CrossingsMatrix(H); -} - -void SplitHeuristic::cleanup() -{ - delete m_cm; -} - -// ordinary call -void SplitHeuristic::call(Level &L) -{ - m_cm->init(L); - buffer = Array(L.size()); - - recCall(L, 0, L.size() - 1); - - buffer = Array(-1); -} - -// SimDraw call -void SplitHeuristic::call(Level &L, const EdgeArray *edgeSubGraph) -{ - // only difference to call is the different calculation of the crossingsmatrix - m_cm->init(L, edgeSubGraph); - buffer = Array(L.size()); - - recCall(L, 0, L.size() - 1); - - buffer = Array(-1); -} - -void SplitHeuristic::recCall(Level &L, int low, int high) -{ - if (high <= low) return; - - const Hierarchy &H = L.hierarchy(); - CrossingsMatrix &crossings = *m_cm; - int up = high, down = low; - - // chooses L[low] as pivot - int i; - for (i = low+1; i <= high; i++) - { - if (crossings(i,low) < crossings(low,i)) - buffer[down++] = L[i]; - } - - // use two for-loops in order to keep the number of swaps low - for (i = high; i >= low+1; i--) - { - if (crossings(i,low) >= crossings(low,i)) - buffer[up--] = L[i]; - } - - buffer[down] = L[low]; - - for (i = low; i < high; i++) - { - int j = H.pos(buffer[i]); - if (i != j) - { - L.swap(i,j); - crossings.swap(i,j); - } - } - - recCall(L,low,down-1); - recCall(L,up+1,high); -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/acyclic_subgraph.cpp b/ext/OGDF/src/layered/acyclic_subgraph.cpp deleted file mode 100644 index cfc2e1816..000000000 --- a/ext/OGDF/src/layered/acyclic_subgraph.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of algorithms for computing an - * acyclic subgraph (DfsAcyclicSubgraph, GreedyCycleRemovel) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// DfsAcyclicSubgraph -// computes a maximal acyclic subgraph by deleting all DFS -// backedges (linear-time) -//--------------------------------------------------------- - -void DfsAcyclicSubgraph::call (const Graph &G, List &arcSet) -{ - isAcyclic(G,arcSet); -} - - -void DfsAcyclicSubgraph::callUML ( - const GraphAttributes &AG, - List &arcSet) -{ - const Graph &G = AG.constGraph(); - - // identify hierarchies - NodeArray hierarchy(G,-1); - int count = 0; - int treeNum = -1; - - node v; - forall_nodes(v,G) - { - if(hierarchy[v] == -1) { - int n = dfsFindHierarchies(AG,hierarchy,count,v); - if(n > 1) treeNum = count; - ++count; - } - } - - arcSet.clear(); - - // perform DFS on the directed graph formed by generalizations - NodeArray number(G,0), completion(G); - int nNumber = 0, nCompletion = 0; - - forall_nodes(v,G) { - if(number[v] == 0) - dfsBackedgesHierarchies(AG,v,number,completion,nNumber,nCompletion); - } - - // collect all backedges within a hierarchy - // and compute outdeg of each vertex within its hierarchy - EdgeArray reversed(G,false); - NodeArray outdeg(G,0); - - edge e; - forall_edges(e,G) { - if(AG.type(e) != Graph::generalization || e->isSelfLoop()) - continue; - - node src = e->source(), tgt = e->target(); - - outdeg[src]++; - - if (hierarchy[src] == hierarchy[tgt] && - number[src] >= number[tgt] && completion[src] <= completion[tgt]) - reversed[e] = true; - } - - // topologial numbering of nodes within a hierarchy (for each hierarchy) - NodeArray numV(G); - Queue Q; - int countV = 0; - - forall_nodes(v,G) - if(outdeg[v] == 0) - Q.append(v); - - while(!Q.empty()) { - v = Q.pop(); - - numV[v] = countV++; - - forall_adj_edges(e,v) { - node w = e->source(); - if(w != v) { - if(--outdeg[w] == 0) - Q.append(w); - } - } - } - - // "direct" associations - forall_edges(e,G) { - if(AG.type(e) == Graph::generalization || e->isSelfLoop()) - continue; - - node src = e->source(), tgt = e->target(); - - if(hierarchy[src] == hierarchy[tgt]) { - if (numV[src] < numV[tgt]) - reversed[e] = true; - } else { - if(hierarchy[src] == treeNum || (hierarchy[tgt] != treeNum && - hierarchy[src] > hierarchy[tgt])) - reversed[e] = true; - } - } - - // collect reversed edges - forall_edges(e,G) - if(reversed[e]) - arcSet.pushBack(e); -} - - -int DfsAcyclicSubgraph::dfsFindHierarchies( - const GraphAttributes &AG, - NodeArray &hierarchy, - int i, - node v) -{ - int count = 1; - hierarchy[v] = i; - - edge e; - forall_adj_edges(e,v) { - if(AG.type(e) != Graph::generalization) - continue; - - node w = e->opposite(v); - if(hierarchy[w] == -1) - count += dfsFindHierarchies(AG,hierarchy,i,w); - } - - return count; -} - - -void DfsAcyclicSubgraph::dfsBackedgesHierarchies( - const GraphAttributes &AG, - node v, - NodeArray &number, - NodeArray &completion, - int &nNumber, - int &nCompletion) -{ - number[v] = ++nNumber; - - edge e; - forall_adj_edges(e,v) - { - if(AG.type(e) != Graph::generalization) - continue; - - node w = e->target(); - - if (number[w] == 0) - dfsBackedgesHierarchies(AG,w,number,completion,nNumber,nCompletion); - } - - completion[v] = ++nCompletion; -} - - - - -//--------------------------------------------------------- -// GreedyCycleRemoval -// greedy heuristic for computing a maximal acyclic -// subgraph (linear-time) -//--------------------------------------------------------- - -void GreedyCycleRemoval::dfs (node v, const Graph &G) -{ - m_visited[v] = true; - - int i; - if (v->outdeg() == 0) i = m_min; - else if (v->indeg() == 0) i = m_max; - else i = v->outdeg() - v->indeg(); - - m_item[v] = m_B[m_index[v] = i].pushBack(v); - m_in [v] = v->indeg(); - m_out[v] = v->outdeg(); - m_counter++; - - edge e; - forall_adj_edges(e,v) { - node u = e->opposite(v); - if (!m_visited[u]) - dfs(u,G); - } -} - - -void GreedyCycleRemoval::call (const Graph &G, List &arcSet) -{ - arcSet.clear(); - - node u, v, w; - edge e; - - m_max = m_min = 0; - forall_nodes(v,G) { - if (-v->indeg () < m_min) m_min = -v->indeg (); - if ( v->outdeg() > m_max) m_max = v->outdeg(); - } - - if (G.numberOfEdges() == 0) return; - - m_visited.init(G,false); m_item.init(G); - m_in .init(G); m_out .init(G); - m_index .init(G); m_B .init(m_min,m_max); - - SListPure S_l, S_r; - NodeArray pos(G); - - m_counter = 0; - forall_nodes(v,G) { - if (m_visited[v]) continue; - dfs(v,G); - - int i, max_i = m_max-1, min_i = m_min+1; - - for ( ; m_counter > 0; m_counter--) { - if (!m_B[m_min].empty()) { - u = m_B[m_min].front(); m_B[m_min].popFront(); - S_r.pushFront(u); - - } else if (!m_B[m_max].empty()) { - u = m_B[m_max].front(); m_B[m_max].popFront(); - S_l.pushBack(u); - - } else { - while (m_B[max_i].empty()) - max_i--; - while (m_B[min_i].empty()) - min_i++; - - if (abs(max_i) > abs(min_i)) { - u = m_B[max_i].front(); m_B[max_i].popFront(); - S_l.pushBack(u); - } else { - u = m_B[min_i].front(); m_B[min_i].popFront(); - S_r.pushFront(u); - } - } - - m_item[u] = ListIterator(); - - forall_adj_edges(e,u) { - if (e->target() == u) { - w = e->source(); - if (m_item[w].valid()) { - m_out[w]--; i = m_index[w]; - m_B[i].del(m_item[w]); - if (m_out[w] == 0) i = m_min; - else if (m_in[w] == 0) i = m_max; - else i--; - m_item[w] = m_B[m_index[w] = i].pushBack(w); - - if (m_index[w] < min_i) - min_i = m_index[w]; - } - } else { - w = e->target(); - if (m_item[w].valid()) { - m_in[w]--; i = m_index[w]; - m_B[i].del(m_item[w]); - if (m_out[w] == 0) i = m_min; - else if (m_in[w] == 0) i = m_max; - else i++; - m_item[w] = m_B[m_index[w] = i].pushBack(w); - - if (m_index[w] > max_i) - max_i = m_index[w]; - } - } - } - } - - SListConstIterator it; - for(i = 0, it = S_l.begin(); it.valid(); ++it) - pos[*it] = i++; - for(it = S_r.begin(); it.valid(); ++it) - pos[*it] = i++; - - S_l.clear(); S_r.clear(); - } - - forall_edges(e,G) - if (pos[e->source()] >= pos[e->target()]) - arcSet.pushBack(e); - - m_visited.init(); m_item.init(); - m_in .init(); m_out .init(); - m_index .init(); m_B.init(); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/heuristics.cpp b/ext/OGDF/src/layered/heuristics.cpp deleted file mode 100644 index b801e02c4..000000000 --- a/ext/OGDF/src/layered/heuristics.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of heuristics for two-layer crossing - * minimization (BarycenterHeuristic, MedianHeuristic) - * - * \author Carsten Gutwenger, Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// BarycenterHeuristic -// implements the barycenter heuristic for 2-layer -// crossing minimization -//--------------------------------------------------------- - -void BarycenterHeuristic::call (Level &L) -{ - const Hierarchy& H = L.hierarchy(); - - for (int i = 0; i <= L.high(); ++i) { - node v = L[i]; - long sumpos = 0L; - - const Array &adjNodes = L.adjNodes(v); - for(int j = 0; j <= adjNodes.high(); ++j) - sumpos += H.pos(adjNodes[j]); - - m_weight[v] = (adjNodes.high() < 0) ? 0.0 : - double(sumpos) / double(adjNodes.size()); - } - - L.sort(m_weight); -} - - -//--------------------------------------------------------- -// MedianHeuristic -// implements the median heuristic for 2-layer -// crossing minimization -//--------------------------------------------------------- - -void MedianHeuristic::call (Level &L) -{ - const Hierarchy& H = L.hierarchy(); - - for (int i = 0; i <= L.high(); ++i) { - node v = L[i]; - - const Array &adjNodes = L.adjNodes(v); - const int high = adjNodes.high(); - - if (high < 0) m_weight[v] = 0; - else if (high & 1) - m_weight[v] = H.pos(adjNodes[high/2]) + H.pos(adjNodes[1+high/2]); - else - m_weight[v] = 2*H.pos(adjNodes[high/2]); - } - - L.sort(m_weight,0,2*H.adjLevel(L.index()).high()); -} - - -//--------------------------------------------------------- -// GreedySwitchHeuristic -// implements the greedy switch heuristic for 2-layer -// crossing minimization -//--------------------------------------------------------- - -void GreedySwitchHeuristic::init (const Hierarchy& H) -{ - m_crossingMatrix = new CrossingsMatrix(H); -} - -void GreedySwitchHeuristic::cleanup() -{ - delete m_crossingMatrix; -} - -void GreedySwitchHeuristic::call (Level &L) -{ - m_crossingMatrix->init(L); - int index; - bool nolocalmin; - - do { - nolocalmin = false; - - for (index = 0; index < L.size() - 1; index++) - if ((*m_crossingMatrix)(index,index+1) > (*m_crossingMatrix)(index+1,index)) { - - nolocalmin = true; - - L.swap(index,index+1); - m_crossingMatrix->swap(index,index+1); - } - } while (nolocalmin); -} - - -//--------------------------------------------------------- -// GreedyInsertHeuristic -// implements the greedy insert heuristic for 2-layer -// crossing minimization -//--------------------------------------------------------- - -void GreedyInsertHeuristic::init (const Hierarchy& H) -{ - m_weight.init(H); - m_crossingMatrix = new CrossingsMatrix(H); -} - -void GreedyInsertHeuristic::cleanup() -{ - m_weight.init(); - delete m_crossingMatrix; -} - -void GreedyInsertHeuristic::call(Level &L) -{ - m_crossingMatrix->init(L); - int index, i; - - // initialisation & priorisation - for (i = 0; i < L.size(); i++) { - double prio = 0; - for (index = 0; index < L.size(); index++) - prio += (*m_crossingMatrix)(i,index); - - // stable quicksort: no need for unique prio - m_weight[L[i]] = prio; - } - - L.sort(m_weight); -} - - -//--------------------------------------------------------- -// SiftingHeuristic -// implements the sifting heuristic for 2-layer -// crossing minimization -//--------------------------------------------------------- - -void SiftingHeuristic::init (const Hierarchy& H) -{ - m_crossingMatrix = new CrossingsMatrix(H); -} - -void SiftingHeuristic::cleanup() -{ - delete m_crossingMatrix; -} - -void SiftingHeuristic::call(Level &L) -{ - List vertices; - int i; - - const int n = L.size(); - - m_crossingMatrix->init(L); // initialize crossing matrix - - if (m_strategy == left_to_right || m_strategy == random) { - for (i = 0; i < n; i++) { - vertices.pushBack(L[i]); - } - - if (m_strategy == random) { - vertices.permute(); - } - - } else { // m_strategy == desc_degree - int max_deg = 0; - - for (i = 0; i < n; i++) { - int deg = L.adjNodes(L[i]).size(); - if (deg > max_deg) max_deg = deg; - } - - Array, int> bucket(0, max_deg); - for (i = 0; i < n; i++) { - bucket[L.adjNodes(L[i]).size()].pushBack(L[i]); - } - - for (i = max_deg; i >= 0; i--) { - while(!bucket[i].empty()) { - vertices.pushBack(bucket[i].popFrontRet()); - } - } - } - - for(i = 0; i< vertices.size(); i++) { - int dev = 0; - - // sifting left - for(; i > 0; --i) { - dev = dev - (*m_crossingMatrix)(i-1,i) + (*m_crossingMatrix)(i,i-1); - L.swap(i-1,i); - m_crossingMatrix->swap(i-1,i); - } - - // sifting right and searching optimal position - int opt = dev, opt_pos = 0; - for (; i < n-1; ++i) { - dev = dev - (*m_crossingMatrix)(i,i+1) + (*m_crossingMatrix)(i+1,i); - L.swap(i,i+1); - m_crossingMatrix->swap(i,i+1); - if (dev <= opt) { - opt = dev; opt_pos = i+1; - } - } - - // set optimal position - for (; i > opt_pos; --i) { - L.swap(i-1,i); - m_crossingMatrix->swap(i-1,i); - } - } -} - -} // namespace ogdf diff --git a/ext/OGDF/src/layered/ranking.cpp b/ext/OGDF/src/layered/ranking.cpp deleted file mode 100644 index 64639e70f..000000000 --- a/ext/OGDF/src/layered/ranking.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/* - * $Revision: 2552 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of node ranking algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// LongestPathRanking -// linear-time node ranking for hierarchical graphs -//--------------------------------------------------------- - -LongestPathRanking::LongestPathRanking() -{ - m_subgraph.set(new DfsAcyclicSubgraph); - m_sepDeg0 = true; - m_separateMultiEdges = true; - m_optimizeEdgeLength = true; - m_alignBaseClasses = false; - m_alignSiblings = false; -} - - -void LongestPathRanking::call(const Graph &G, const EdgeArray &length, NodeArray &rank) -{ - List R; - - m_subgraph.get().call(G,R); - - EdgeArray reversed(G,false); - for (ListConstIterator it = R.begin(); it.valid(); ++it) - reversed[*it] = true; - R.clear(); - - doCall(G, rank, reversed, length); -} - - -void LongestPathRanking::call (const Graph& G, NodeArray &rank) -{ - List R; - - m_subgraph.get().call(G,R); - - EdgeArray reversed(G,false); - for (ListConstIterator it = R.begin(); it.valid(); ++it) - reversed[*it] = true; - R.clear(); - - EdgeArray length(G,1); - - if(m_separateMultiEdges) { - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G, edges, minIndex, maxIndex); - - SListConstIterator it = edges.begin(); - if(it.valid()) - { - int prevSrc = minIndex[*it]; - int prevTgt = maxIndex[*it]; - - for(it = it.succ(); it.valid(); ++it) { - edge e = *it; - if (minIndex[e] == prevSrc && maxIndex[e] == prevTgt) - length[e] = 2; - else { - prevSrc = minIndex[e]; - prevTgt = maxIndex[e]; - } - } - } - } - - doCall(G, rank, reversed, length); -} - - -void LongestPathRanking::callUML(const GraphAttributes &AG, NodeArray &rank) -{ - const Graph &G = AG.constGraph(); - - // find base classes - List baseClasses; - node v; - forall_nodes(v,G) { - bool isBase = false; - edge e; - forall_adj_edges(e,v) { - if(AG.type(e) != Graph::generalization) - continue; - - if(e->target() == v) { - // incoming edge - isBase = true; // possible base of a hierarchy - } - if(e->source() == v) { - // outgoing edge - isBase = false; - break; - } - } - if(isBase) - baseClasses.pushBack(v); - } - - // insert a super sink - GraphCopySimple GC(G); - makeLoopFree(GC); - GraphAttributes AGC(GC,GraphAttributes::edgeType); - - node superSink = GC.newNode(); - - ListConstIterator it; - for(it = baseClasses.begin(); it.valid(); ++it) { - edge ec = GC.newEdge(GC.copy(*it), superSink); - AGC.type(ec) = Graph::generalization; - } - - edge e; - forall_edges(e,G) - AGC.type(GC.copy(e)) = AG.type(e); - - // compute length of edges - EdgeArray length(GC,1); - - if(m_separateMultiEdges) { - SListPure edges; - EdgeArray minIndex(G), maxIndex(G); - parallelFreeSortUndirected(G, edges, minIndex, maxIndex); - - SListConstIterator it = edges.begin(); - if(it.valid()) - { - int prevSrc = minIndex[*it]; - int prevTgt = maxIndex[*it]; - - for(it = it.succ(); it.valid(); ++it) { - edge e = *it; - if (minIndex[e] == prevSrc && maxIndex[e] == prevTgt) - length[GC.copy(e)] = 2; - else { - prevSrc = minIndex[e]; - prevTgt = maxIndex[e]; - } - } - } - } - - // compute spanning tree - // marked edges belong to tree - NodeArray outdeg(GC,0); - forall_nodes(v,GC) { - forall_adj_edges(e,v) - if(!e->isSelfLoop() && e->source() == v && - AGC.type(e) == Graph::generalization /*&& reversed[e] == true*/) - ++outdeg[v]; - } - - Queue Q; - Q.append(superSink); - EdgeArray marked(GC,false); - while(!Q.empty()) { - v = Q.pop(); - forall_adj_edges(e,v) { - node u = e->source(); - if(u == v || AGC.type(e) != Graph::generalization/* || reversed[e] == false*/) - continue; - - --outdeg[u]; - if(outdeg[u] == 0) { - marked[e] = true; - Q.append(u); - } - } - } - - outdeg.init(); - - // build super graph on which we will compute the ranking - // we join nodes that have to be placed on the same level to super nodes - NodeArray superNode(G,0); - NodeArray > joinedNodes(GC); - - // initially, there is a single node in GC for every node in G - forall_nodes(v,G) { - node vc = GC.copy(v); - superNode[v] = vc; - joinedNodes[vc].pushBack(v); - } - - if(m_alignBaseClasses && baseClasses.size() >= 2) { - ListConstIterator it = baseClasses.begin(); - node v1 = superNode[*it++]; - for(; it.valid(); ++it) - join(GC,superNode,joinedNodes,v1,superNode[*it]); - } - - // not needed anymore - GC.delNode(superSink); - baseClasses.clear(); - - if(m_alignSiblings) { - NodeArray > toJoin(GC); - - forall_nodes(v,GC) { - node v1 = 0; - forall_adj_edges(e,v) { - if(marked[e] == false || e->source() == v) - continue; - - node u = e->source(); - if(v1 == 0) - v1 = u; - else - toJoin[v1].pushBack(u); - } - } - - forall_nodes(v,GC) { - SListConstIterator it; - for(it = toJoin[v].begin(); it.valid(); ++it) - join(GC,superNode,joinedNodes,v,*it); - } - } - - marked.init(); - joinedNodes.init(); - - // don't want self-loops - makeLoopFree(GC); - - // determine reversed edges - DfsAcyclicSubgraph sub; - List R; - sub.callUML(AGC,R); - - EdgeArray reversed(GC,true); - for (ListConstIterator itE = R.begin(); itE.valid(); ++itE) - reversed[*itE] = false; - R.clear(); - - // compute ranking of GC - NodeArray rankGC; - doCall(GC, rankGC, reversed, length); - - // transfer to ranking of G - rank.init(G); - forall_nodes(v,G) - rank[v] = rankGC[superNode[v]]; -} - - -void LongestPathRanking::join( - GraphCopySimple &GC, - NodeArray &superNode, - NodeArray > &joinedNodes, - node v, node w) -{ - OGDF_ASSERT(v != w); - - SListConstIterator it; - for(it = joinedNodes[w].begin(); it.valid(); ++it) - superNode[*it] = v; - - joinedNodes[v].conc(joinedNodes[w]); - - SListPure edges; - GC.adjEdges(w,edges); - SListConstIterator itE; - for(itE = edges.begin(); itE.valid(); ++itE) { - edge e = *itE; - if(e->source() == w) - GC.moveSource(e, v); - else - GC.moveTarget(e, v); - } - - GC.delNode(w); -} - - -void LongestPathRanking::doCall( - const Graph& G, - NodeArray &rank, - EdgeArray &reversed, - const EdgeArray &length) -{ - rank.init(G,0); - - m_isSource.init(G,true); - m_adjacent.init(G); - - edge e; - forall_edges(e,G) { - if (e->isSelfLoop()) continue; - - if (!reversed[e]) { - m_adjacent[e->source()].pushBack(Tuple2(e->target(),length[e])); - m_isSource[e->target()] = false; - } else { - m_adjacent[e->target()].pushBack(Tuple2(e->source(),length[e])); - m_isSource[e->source()] = false; - } - } - - m_ingoing.init(G,0); - - if(m_optimizeEdgeLength) { - m_finished.init(G,false); - - int min = 0, max = 0; - m_maxN = G.numberOfNodes(); - - node v; - forall_nodes(v,G) - if (m_isSource[v]) { - dfs(v); - getTmpRank(v,rank); - dfsAdd(v,rank); - - if (rank[v] < min) min = rank[v]; - } - - forall_nodes(v,G) { - if ((rank[v] -= min) > max) max = rank[v]; - } - - if (max > 0 && separateDeg0Layer()) { - max++; - forall_nodes(v,G) - if (v->degree() == 0) rank[v] = max; - } - - m_finished.init(); - - } else { - SListPure sources; - SListConstIterator > it; - - node v; - forall_nodes(v,G) { - if(m_isSource[v]) - sources.pushBack(v); - for(it = m_adjacent[v].begin(); it.valid(); ++it) - ++m_ingoing[(*it).x1()]; - } - - while(!sources.empty()) { - v = sources.popFrontRet(); - - for(it = m_adjacent[v].begin(); it.valid(); ++it) { - node u = (*it).x1(); - int r = rank[v]+(*it).x2(); - if(r > rank[u]) - rank[u] = r; - - if (--m_ingoing[u] == 0) - sources.pushBack(u); - } - } - } - - m_isSource.init(); - m_adjacent.init(); - m_ingoing .init(); -} - - -void LongestPathRanking::dfs(node v) -{ - m_ingoing[v]++; - if (m_ingoing[v] == 1 && !m_finished[v]) { - SListConstIterator > it; - for(it = m_adjacent[v].begin(); it.valid(); ++it) - dfs((*it).x1()); - } -} - - -void LongestPathRanking::getTmpRank(node v, NodeArray &rank) -{ - List N; - - m_offset = m_maxN; - N.pushBack(v); - rank[v] = 0; - - while (!N.empty()) { - node w = N.front(); N.popFront(); - - SListConstIterator > it; - for(it = m_adjacent[w].begin(); it.valid(); ++it) { - node u = (*it).x1(); - - int r = max(rank[u],rank[w]+(*it).x2()); - - m_ingoing[u]--; - if (m_finished[u]) - m_offset = min(m_offset, rank[u] - rank[w]-(*it).x2()); - - else { - if (m_ingoing[u] == 0) { - N.pushBack(u); - } - rank[u] = r; - } - } - } - if (m_offset == m_maxN) m_offset = 0; -} - - -void LongestPathRanking::dfsAdd(node v, NodeArray &rank) -{ - if (!m_finished[v]) { - m_finished[v] = true; - rank[v] += m_offset; - - SListConstIterator > it; - for(it = m_adjacent[v].begin(); it.valid(); ++it) - dfsAdd((*it).x1(),rank); - } -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/sugiyama-cluster.cpp b/ext/OGDF/src/layered/sugiyama-cluster.cpp deleted file mode 100644 index 485bd0da2..000000000 --- a/ext/OGDF/src/layered/sugiyama-cluster.cpp +++ /dev/null @@ -1,1928 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Sugiyama algorithm (extension with - * clusters) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// RCCrossings -//--------------------------------------------------------- - -ostream& operator<<(ostream &os, const RCCrossings &cr) -{ - os << "(" << cr.m_cnClusters << "," << cr.m_cnEdges << ")"; - return os; -} - - -//--------------------------------------------------------- -// LHTreeNode -// represents a node in a layer hierarchy tree -//--------------------------------------------------------- - -void LHTreeNode::setPos() -{ - for(int i = 0; i <= m_child.high(); ++i) - m_child[i]->m_pos = i; -} - - -void LHTreeNode::removeAuxChildren() -{ - OGDF_ASSERT(isCompound() == true); - - int j = 0; - int i; - for(i = 0; i <= m_child.high(); ++i) - if(m_child[i]->m_type != AuxNode) - m_child[j++] = m_child[i]; - else - delete m_child[i]; - - int add = j-i; - if(add != 0) - m_child.grow(add, 0); -} - - -ostream &operator<<(ostream &os, const LHTreeNode *n) -{ - if(n->isCompound()) { - os << "C" << n->originalCluster(); - - os << " ["; - for(int i = 0; i < n->numberOfChildren(); ++i) - os << " " << n->child(i); - os << " ]"; - - } else { - os << "N" << n->getNode() << " "; - } - - return os; -} - - -//--------------------------------------------------------- -// AdjacencyComparer -// compares adjacency entries in an LHTreeNode -//--------------------------------------------------------- - -class AdjacencyComparer -{ - static int compare(const LHTreeNode::Adjacency &x, const LHTreeNode::Adjacency &y) - { - if(x.m_u->index() < y.m_u->index()) - return -1; - - else if(x.m_u == y.m_u) { - if(x.m_v->isCompound()) { - if(!y.m_v->isCompound()) return -1; - return (x.m_v->originalCluster()->index() < y.m_v->originalCluster()->index()) ? -1 : +1; - - } else if(y.m_v->isCompound()) - return +1; - - else - return (x.m_v->getNode()->index() < y.m_v->getNode()->index()) ? -1 : +1; - - } else - return +1; - } - - OGDF_AUGMENT_STATICCOMPARER(LHTreeNode::Adjacency) -}; - - -//--------------------------------------------------------- -// ENGLayer -// represents layer in an extended nesting graph -//--------------------------------------------------------- - -ENGLayer::~ENGLayer() -{ - Queue Q; - Q.append(m_root); - - while(!Q.empty()) { - LHTreeNode *p = Q.pop(); - - for(int i = 0; i < p->numberOfChildren(); ++i) - Q.append(p->child(i)); - - delete p; - } -} - - -void ENGLayer::store() { - Queue Q; - Q.append(m_root); - - while(!Q.empty()) { - LHTreeNode *p = Q.pop(); - - if(p->isCompound()) { - p->store(); - - for(int i = 0; i < p->numberOfChildren(); ++i) - Q.append(p->child(i)); - } - } -} - - -void ENGLayer::restore() { - Queue Q; - Q.append(m_root); - - while(!Q.empty()) { - LHTreeNode *p = Q.pop(); - - if(p->isCompound()) { - p->restore(); - - for(int i = 0; i < p->numberOfChildren(); ++i) - Q.append(p->child(i)); - } - } -} - - -void ENGLayer::permute() { - Queue Q; - Q.append(m_root); - - while(!Q.empty()) { - LHTreeNode *p = Q.pop(); - - if(p->isCompound()) { - p->permute(); - - for(int i = 0; i < p->numberOfChildren(); ++i) - Q.append(p->child(i)); - } - } -} - - -void ENGLayer::removeAuxNodes() { - Queue Q; - Q.append(m_root); - - while(!Q.empty()) { - LHTreeNode *p = Q.pop(); - - if(p->isCompound()) { - p->removeAuxChildren(); - - for(int i = 0; i < p->numberOfChildren(); ++i) - Q.append(p->child(i)); - } - } -} - - -void ENGLayer::simplifyAdjacencies(List &adjs) -{ - AdjacencyComparer cmp; - - if(!adjs.empty()) { - adjs.quicksort(cmp); - - ListIterator it = adjs.begin(); - ListIterator itNext = it.succ(); - - while(itNext.valid()) { - if((*it).m_u == (*itNext).m_u && (*it).m_v == (*itNext).m_v) { - (*it).m_weight += (*itNext).m_weight; - - adjs.del(itNext); - itNext = it.succ(); - - } else { - it = itNext; - ++itNext; - } - } - } -} - - -void ENGLayer::simplifyAdjacencies() -{ - Queue Q; - Q.append(m_root); - - while(!Q.empty()) { - LHTreeNode *p = Q.pop(); - - simplifyAdjacencies(p->m_upperAdj); - simplifyAdjacencies(p->m_lowerAdj); - - for(int i = 0; i < p->numberOfChildren(); ++i) - Q.append(p->child(i)); - } -} - - -//--------------------------------------------------------- -// ClusterGraphCopy -//--------------------------------------------------------- - -ClusterGraphCopy::ClusterGraphCopy() -{ - m_pCG = 0; - m_pH = 0; -} - -ClusterGraphCopy::ClusterGraphCopy(const ExtendedNestingGraph &H, const ClusterGraph &CG) -: ClusterGraph(H), m_pCG(&CG), m_pH(&H), m_copy(CG,0) -{ - m_original.init(*this,0); - m_copy [CG.rootCluster()] = rootCluster(); - m_original[rootCluster()] = CG.rootCluster(); - - createClusterTree(CG.rootCluster()); -} - - -void ClusterGraphCopy::init(const ExtendedNestingGraph &H, const ClusterGraph &CG) -{ - ClusterGraph::init(H); - m_pCG = &CG; - m_pH = &H; - m_copy .init(CG,0); - m_original.init(*this,0); - - m_copy [CG.rootCluster()] = rootCluster(); - m_original[rootCluster()] = CG.rootCluster(); - - createClusterTree(CG.rootCluster()); -} - - -void ClusterGraphCopy::createClusterTree(cluster cOrig) -{ - cluster c = m_copy[cOrig]; - - ListConstIterator itC; - for(itC = cOrig->cBegin(); itC.valid(); ++itC) { - cluster child = newCluster(c); - m_copy [*itC] = child; - m_original[child] = *itC; - - createClusterTree(*itC); - } - - ListConstIterator itV; - for(itV = cOrig->nBegin(); itV.valid(); ++itV) { - reassignNode(m_pH->copy(*itV), c); - } -} - - -void ClusterGraphCopy::setParent(node v, cluster c) -{ - reassignNode(v, c); -} - - -//--------------------------------------------------------- -// ExtendedNestingGraph -//--------------------------------------------------------- - -ExtendedNestingGraph::ExtendedNestingGraph(const ClusterGraph &CG) : - m_copy(CG), - m_topNode(CG), - m_bottomNode(CG), - m_copyEdge(CG), - m_mark(CG, 0) -{ - const Graph &G = CG; - - m_origNode.init(*this, 0); - m_type .init(*this, ntDummy); - m_origEdge.init(*this, 0); - - // Create nodes - node v; - forall_nodes(v,G) { - node vH = newNode(); - m_copy [v] = vH; - m_origNode[vH] = v; - m_type[vH] = ntNode; - } - - m_CGC.init(*this,CG); - - cluster c; - forall_clusters(c, CG) { - m_type[m_topNode [c] = newNode()] = ntClusterTop; - m_type[m_bottomNode[c] = newNode()] = ntClusterBottom; - - m_CGC.setParent(m_topNode [c], m_CGC.copy(c)); - m_CGC.setParent(m_bottomNode[c], m_CGC.copy(c)); - } - - // Create edges - forall_nodes(v,G) { - node vH = m_copy[v]; - cluster c = CG.clusterOf(v); - - newEdge(m_topNode[c], vH); - newEdge(vH, m_bottomNode[c]); - } - - forall_clusters(c,CG) { - if(c != CG.rootCluster()) { - cluster u = c->parent(); - - newEdge(m_topNode[u], m_topNode[c]); - newEdge(m_bottomNode[c], m_bottomNode[u]); - - newEdge(m_topNode[c], m_bottomNode[c]); - } - } - - OGDF_ASSERT(isAcyclic(*this)); - - - // preparation for improved test for cycles - m_aeLevel.init(*this, -1); - int count = 0; - assignAeLevel(CG.rootCluster(), count); - m_aeVisited.init(*this, false); - - - // Add adjacency edges - edge e; - forall_edges(e, G) { - edge eH = addEdge(m_copy[e->source()], m_copy[e->target()], true); - m_copyEdge[e].pushBack(eH); - m_origEdge[eH] = e; - } - - // Add additional edges between nodes and clusters to reflect adjacency hierarchy also - // with respect to clusters - forall_edges(e, G) { - node u = e->source(); - node v = e->target(); - - // e was reversed? - if(m_copyEdge[e].front()->source() != m_copy[e->source()]) - swap(u,v); - - if(CG.clusterOf(u) != CG.clusterOf(v)) { - cluster c = lca(u, v); - cluster cTo, cFrom; - - if(m_secondPathTo == v) { - cTo = m_secondPath; - cFrom = m_mark[c]; - } else { - cFrom = m_secondPath; - cTo = m_mark[c]; - } - - // Transfer adjacency relationship to a relationship between clusters - // "clusters shall be above each other" - edge eH = 0; - if(cFrom != c && cTo != c) - eH = addEdge(m_bottomNode[cFrom], m_topNode[cTo]); - - // if this is not possible, try to relax it to a relationship between node and cluster - if(eH == 0) { - addEdge(m_copy[u], m_topNode[cTo]); - addEdge(m_bottomNode[cFrom], m_copy[v]); - } - } - } - - OGDF_ASSERT(isAcyclic(*this)); - - // cleanup - m_aeVisited.init(); - m_aeLevel.init(); - - // compute ranking and proper hierarchy - computeRanking(); - createDummyNodes(); - //createVirtualClusters(); - buildLayers(); - - // assign positions on top layer - m_pos.init(*this); - count = 0; - assignPos(m_layer[0].root(), count); -} - -void ExtendedNestingGraph::computeRanking() -{ - // Compute ranking - OptimalRanking ranking; - ranking.separateMultiEdges(false); - - EdgeArray length(*this); - EdgeArray cost(*this); - edge e; - forall_edges(e,*this) { - NodeType typeSrc = type(e->source()); - NodeType typeTgt = type(e->target()); - - if(typeSrc == ntNode && typeTgt == ntNode) - length[e] = 2; // Node -> Node - else if (typeSrc != ntNode && typeTgt != ntNode) - length[e] = 2; // Cluster -> Cluster - else - length[e] = 1; // Node <-> Cluster - - cost[e] = (origEdge(e) != 0) ? 2 : 1; - } - - ranking.call(*this, length, cost, m_rank); - - // adjust ranks of top / bottom node - cluster c; - forall_postOrderClusters(c,m_CGC) - { - int t = INT_MAX; - int b = INT_MIN; - - ListConstIterator itV; - for(itV = c->nBegin(); itV.valid(); ++itV) { - if(type(*itV) != ntNode) - continue; - - int r = m_rank[*itV]; - if(r-1 < t) - t = r-1; - if(r+1 > b) - b = r+1; - } - - ListConstIterator itC; - for(itC = c->cBegin(); itC.valid(); ++itC) { - int rb = m_rank[bottom(m_CGC.original(*itC))]; - if(rb+2 > b) - b = rb+2; - int rt = m_rank[top(m_CGC.original(*itC))]; - if(rt-2 < t) - t = rt-2; - } - - cluster cOrig = m_CGC.original(c); - OGDF_ASSERT(m_rank[top(cOrig)] <= t && b <= m_rank[bottom(cOrig)]); - - if(t < INT_MAX) { - m_rank[top (cOrig)] = t; - m_rank[bottom(cOrig)] = b; - } - } - - // Remove all non-adjacency edges - edge eNext; - for(e = firstEdge(); e != 0; e = eNext) { - eNext = e->succ(); - if(m_origEdge[e] == 0) { - cluster c = originalCluster(e->source()); - // we do not remove edges from top(c)->bottom(c) - if(e->source() != top(c) || e->target() != bottom(c)) - delEdge(e); - } - } - - // Remove nodes for root cluster - cluster r = getOriginalClusterGraph().rootCluster(); - int high = m_rank[m_bottomNode[r]]; - int low = m_rank[m_topNode[r]]; - - delNode(m_topNode[r]); - delNode(m_bottomNode[r]); - m_topNode [r] = 0; - m_bottomNode[r] = 0; - - // Reassign ranks - Array > levels(low,high); - - node v; - forall_nodes(v, *this) - levels[m_rank[v]].pushBack(v); - - int currentRank = 0; - for(int i = low+1; i < high; ++i) - { - SListPure &L = levels[i]; - if(L.empty()) - continue; - - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) - m_rank[*it] = currentRank; - - ++currentRank; - } - - m_numLayers = currentRank; -} - - -void ExtendedNestingGraph::createDummyNodes() -{ - const ClusterGraph &CG = getOriginalClusterGraph(); - const Graph &G = CG; - - edge e; - forall_edges(e, G) - { - edge eH = m_copyEdge[e].front(); - node uH = eH->source(); - node vH = eH->target(); - - int span = m_rank[vH] - m_rank[uH]; - OGDF_ASSERT(span >= 1); - if(span < 2) - continue; - - // find cluster cTop containing both u and v - node u = m_origNode[uH]; - node v = m_origNode[vH]; - - cluster cTop = lca(u,v); - - // create split nodes - for(int i = m_rank[uH]+1; i < m_rank[vH]; ++i) { - eH = split(eH); - m_copyEdge[e].pushBack(eH); - m_origEdge[eH] = e; - m_rank[eH->source()] = i; - // assign preliminary cTop to all dummies since this is ok - // try to aesthetically improve this later - m_CGC.setParent(eH->source(), m_CGC.copy(cTop)); - } - - // improve cluster assignment - cluster c_1 = CG.clusterOf(u); - cluster c_2 = CG.clusterOf(v); - cluster root = CG.rootCluster(); - - if(c_1 == root || c_2 == root || m_rank[m_bottomNode[c_1]] >= m_rank[m_topNode[c_2]]) { - if(c_2 != root && m_rank[uH] < m_rank[m_topNode[c_2]]) - { - c_1 = 0; - while(c_2->parent() != root && m_rank[uH] < m_rank[m_topNode[c_2->parent()]]) - c_2 = c_2->parent(); - } - else if(c_1 != root && m_rank[vH] > m_rank[m_bottomNode[c_1]]) - { - c_2 = 0; - while(c_1->parent() != root && m_rank[vH] > m_rank[m_bottomNode[c_1->parent()]]) - c_1 = c_1->parent(); - - } else { - continue; // leave all dummies in cTop - } - - } else { - bool cont; - do { - cont = false; - - cluster parent = c_1->parent(); - if(parent != root && m_rank[m_bottomNode[parent]] < m_rank[m_topNode[c_2]]) { - c_1 = parent; - cont = true; - } - - parent = c_2->parent(); - if(parent != root && m_rank[m_bottomNode[c_1]] < m_rank[m_topNode[parent]]) { - c_2 = parent; - cont = true; - } - - } while(cont); - } - - if(c_1 != 0) { - ListConstIterator it = m_copyEdge[e].begin(); - for(cluster c = CG.clusterOf(u); c != c_1->parent(); c = c->parent()) { - while(m_rank[(*it)->target()] <= m_rank[m_bottomNode[c]]) { - m_CGC.setParent((*it)->target(), m_CGC.copy(c)); - ++it; - } - } - } - - if(c_2 != 0) { - ListConstIterator it = m_copyEdge[e].rbegin(); - for(cluster c = CG.clusterOf(v); c != c_2->parent(); c = c->parent()) { - while(m_rank[(*it)->source()] >= m_rank[m_topNode[c]]) { - m_CGC.setParent((*it)->source(), m_CGC.copy(c)); - --it; - } - } - } - } - - // create dummy nodes for edges top(c)->bottom(c) - cluster c; - forall_clusters(c,CG) - { - if(c == CG.rootCluster()) - continue; - - node vTop = top(c); - node vBottom = bottom(c); - - forall_adj_edges(e,vTop) - if(e->target() == vBottom) { - int span = m_rank[vBottom] - m_rank[vTop]; - OGDF_ASSERT(span >= 1); - if(span < 2) - continue; - - // create split nodes - edge eH = e; - for(int i = m_rank[vTop]+1; i < m_rank[vBottom]; ++i) { - eH = split(eH); - m_rank[eH->source()] = i; - m_type[eH->source()] = ntClusterTopBottom; - m_CGC.setParent(eH->source(), m_CGC.copy(c)); - } - break; - } - } -} - - -void ExtendedNestingGraph::createVirtualClusters() -{ - NodeArray vCopy(*this); - ClusterArray cCopy(m_CGC); - - createVirtualClusters(m_CGC.rootCluster(), vCopy, cCopy); - - // for each original edge, put the edge segments that are in the same cluster - // into a separate cluster - edge eOrig; - forall_edges(eOrig, m_CGC.getOriginalClusterGraph().getGraph()) - { - const List &L = m_copyEdge[eOrig]; - if(L.size() >= 3) { - ListConstIterator it = L.begin().succ(); - node v = (*it)->source(); - - cluster c = parent(v); - SList nextCluster; - nextCluster.pushBack(v); - - for(++it; it.valid(); ++it) { - node u = (*it)->source(); - cluster cu = parent(u); - - if(cu != c) { - if(nextCluster.size() > 1) - m_CGC.createCluster(nextCluster, c); - - nextCluster.clear(); - c = cu; - } - - nextCluster.pushBack(u); - } - - if(nextCluster.size() > 1) - m_CGC.createCluster(nextCluster, c); - } - } -} - - -void ExtendedNestingGraph::createVirtualClusters( - cluster c, - NodeArray &vCopy, - ClusterArray &cCopy) -{ - if(c->cCount() >= 1 && c->nCount() >= 1) - { - // build auxiliaray graph G - Graph G; - - ListConstIterator itV; - for(itV = c->nBegin(); itV.valid(); ++itV) { - vCopy[*itV] = G.newNode(); - } - - ListConstIterator itC; - for(itC = c->cBegin(); itC.valid(); ++itC) { - cCopy[*itC] = G.newNode(); - } - - for(itV = c->nBegin(); itV.valid(); ++itV) { - node v = *itV; - adjEntry adj; - forall_adj(adj,v) { - if(origEdge(adj->theEdge()) == 0) - continue; - - node w = adj->twinNode(); - cluster cw = parent(w); - if(cw == c) - G.newEdge(vCopy[v],vCopy[w]); - - else if(cw->parent() == c) { - cluster cwOrig = m_CGC.original(cw); - OGDF_ASSERT(cwOrig != 0); - if(rank(w) == rank(top(cwOrig)) || rank(w) == rank(bottom(cwOrig))) - G.newEdge(vCopy[v],cCopy[cw]); - } - } - } - - // find connect components in G - NodeArray component(G); - int k = connectedComponents(G, component); - - // create virtual clusters - if(k > 1) { - Array > nodes(k); - Array > clusters(k); - - for(itV = c->nBegin(); itV.valid(); ++itV) - nodes[component[vCopy[*itV]]].pushBack(*itV); - - for(itC = c->cBegin(); itC.valid(); ++itC) - clusters[component[cCopy[*itC]]].pushBack(*itC); - - for(int i = 0; i < k; ++i) { - if(nodes[i].size() + clusters[i].size() > 1) { - cluster cVirt = m_CGC.createCluster(nodes[i], c); - SListConstIterator it; - for(it = clusters[i].begin(); it.valid(); ++it) - m_CGC.moveCluster(*it,cVirt); - } - } - } - } - - // recurive call - for(ListConstIterator it = c->cBegin(); it.valid(); ++it) - createVirtualClusters(*it, vCopy, cCopy); -} - - -void ExtendedNestingGraph::buildLayers() -{ - m_layer.init(m_numLayers); - - Array > L(m_numLayers); - - node v; - forall_nodes(v,*this) { - L[rank(v)].pushBack(v); - } - - // compute minimum and maximum level of each cluster - m_topRank.init(m_CGC,m_numLayers); - m_bottomRank.init(m_CGC,0); - cluster c; - forall_postOrderClusters(c, m_CGC) { - ListConstIterator itV; - for(itV = c->nBegin(); itV.valid(); ++itV) { - int r = rank(*itV); - if(r > m_bottomRank[c]) - m_bottomRank[c] = r; - if(r < m_topRank[c]) - m_topRank[c] = r; - } - ListConstIterator itC; - for(itC = c->cBegin(); itC.valid(); ++itC) { - if(m_topRank[*itC] < m_topRank[c]) - m_topRank[c] = m_topRank[*itC]; - if(m_bottomRank[*itC] > m_bottomRank[c]) - m_bottomRank[c] = m_bottomRank[*itC]; - } - } - - Array > clusterBegin(m_numLayers); - Array > clusterEnd(m_numLayers); - - forall_clusters(c,m_CGC) { - clusterBegin[m_topRank [c]].pushBack(c); - clusterEnd [m_bottomRank[c]].pushBack(c); - } - - - ClusterSetPure activeClusters(m_CGC); - activeClusters.insert(m_CGC.rootCluster()); - - ClusterArray clusterToTreeNode(m_CGC, 0); - ClusterArray numChildren(m_CGC, 0); - NodeArray treeNode(*this, 0); - - int i; - for(i = 0; i < m_numLayers; ++i) { - // identify new clusters on this layer - ListConstIterator it; - for(it = L[i].begin(); it.valid(); ++it) { - ++numChildren[parent(*it)]; - } - - SListConstIterator itActive; - for(itActive = clusterBegin[i].begin(); itActive.valid(); ++itActive) - activeClusters.insert(*itActive); - - // create compound tree nodes - ListConstIterator itC; - for(itC = activeClusters.clusters().begin(); itC.valid(); ++itC) { - cluster c = *itC; - clusterToTreeNode[c] = OGDF_NEW LHTreeNode(c, clusterToTreeNode[c]); - if(c != m_CGC.rootCluster()) - ++numChildren[c->parent()]; - } - - // initialize child arrays - for(itC = activeClusters.clusters().begin(); itC.valid(); ++itC) { - clusterToTreeNode[*itC]->initChild(numChildren[*itC]); - } - - // set parent and children of compound tree nodes - for(itC = activeClusters.clusters().begin(); itC.valid(); ++itC) { - if(*itC != m_CGC.rootCluster()) { - LHTreeNode *cNode = clusterToTreeNode[*itC]; - LHTreeNode *pNode = clusterToTreeNode[(*itC)->parent()]; - - cNode->setParent(pNode); - pNode->setChild(--numChildren[(*itC)->parent()], cNode); - } - } - - // set root of layer - m_layer[i].setRoot(clusterToTreeNode[m_CGC.rootCluster()]); - - // create tree nodes for nodes on this layer - for(it = L[i].begin(); it.valid(); ++it) { - LHTreeNode *cNode = clusterToTreeNode[parent(*it)]; - LHTreeNode::Type type = (m_type[*it] == ntClusterTopBottom) ? - LHTreeNode::AuxNode : LHTreeNode::Node; - LHTreeNode *vNode = OGDF_NEW LHTreeNode(cNode, *it, type); - treeNode[*it] = vNode; - cNode->setChild(--numChildren[parent(*it)], vNode); - } - - // clean-up - for(itC = activeClusters.clusters().begin(); itC.valid(); ++itC) { - numChildren [*itC] = 0; - } - - // identify clusters that are not on next layer - for(itActive = clusterEnd[i].begin(); itActive.valid(); ++itActive) - activeClusters.remove(*itActive); - } - - // identify adjacencies between nodes and tree nodes - edge e; - forall_edges(e,*this) - { - node u = e->source(); - node v = e->target(); - bool isTopBottomEdge = (origEdge(e) == 0); - int weight = (isTopBottomEdge) ? 100 : 1; - - if(isTopBottomEdge) - continue; - - LHTreeNode *nd = treeNode[v]; - LHTreeNode *parent = nd->parent(); - if(isTopBottomEdge) { - nd = parent; - parent = parent->parent(); - } - - while(parent != 0) { - parent->m_upperAdj.pushBack(LHTreeNode::Adjacency(u,nd,weight)); - - nd = parent; - parent = parent->parent(); - } - - nd = treeNode[u]; - parent = nd->parent(); - if(isTopBottomEdge) { - nd = parent; - parent = parent->parent(); - } - - while(parent != 0) { - parent->m_lowerAdj.pushBack(LHTreeNode::Adjacency(v,nd,weight)); - - nd = parent; - parent = parent->parent(); - } - } - - for(i = 0; i < m_numLayers; ++i) - m_layer[i].simplifyAdjacencies(); - - - // identify relevant pairs for crossings between top->bottom edges - // and foreign edges - m_markTree.init(m_CGC,0); - ClusterArray > > edges(m_CGC); - ClusterSetSimple C(m_CGC); - for(i = 0; i < m_numLayers-1; ++i) - { - ListConstIterator it; - for(it = L[i].begin(); it.valid(); ++it) { - node u = *it; - - edge e; - forall_adj_edges(e,u) { - if(origEdge(e) == 0) - continue; - if(e->source() == u) { - node v = e->target(); - - LHTreeNode *uChild, *vChild; - cluster c = lca(treeNode[u], treeNode[v], &uChild, &vChild)->originalCluster(); - - edges[c].pushBack( - Tuple3(e,uChild,vChild)); - C.insert(c); - } - } - } - - for(it = L[i].begin(); it.valid(); ++it) { - node u = *it; - - edge e; - forall_adj_edges(e,u) { - if(e->source() == u && origEdge(e) == 0) { - LHTreeNode *aNode = treeNode[e->target()]; - cluster ca = aNode->parent()->originalCluster(); - LHTreeNode *aParent = aNode->parent()->parent(); - - for(; aParent != 0; aParent = aParent->parent()) { - ListConstIterator > itE; - for(itE = edges[aParent->originalCluster()].begin(); - itE.valid(); ++itE) - { - LHTreeNode *aChild, *vChild, *h1, *h2; - LHTreeNode *cNode = lca(aNode, treeNode[(*itE).x1()->target()], - &aChild, &vChild); - if(cNode != aNode->parent() && - lca(aNode,treeNode[(*itE).x1()->source()],&h1,&h2)->originalCluster() != ca) - cNode->m_upperClusterCrossing.pushBack( - LHTreeNode::ClusterCrossing(e->source(),aChild, - (*itE).x1()->source(),vChild, - (*itE).x1())); - } - } - - aNode = treeNode[e->source()]; - ca = aNode->parent()->originalCluster(); - aParent = aNode->parent()->parent(); - - for(; aParent != 0; aParent = aParent->parent()) { - ListConstIterator > itE; - for(itE = edges[aParent->originalCluster()].begin(); - itE.valid(); ++itE) - { - LHTreeNode *aChild, *vChild, *h1, *h2; - LHTreeNode *cNode = lca(aNode, treeNode[(*itE).x1()->source()], - &aChild, &vChild); - if(cNode != aNode->parent() && - lca(aNode,treeNode[(*itE).x1()->target()],&h1,&h2)->originalCluster() != ca) - cNode->m_lowerClusterCrossing.pushBack( - LHTreeNode::ClusterCrossing(e->target(),aChild, - (*itE).x1()->target(),vChild, - (*itE).x1())); - } - } - } - } - } - - // get rid of edges in edges[c] - SListConstIterator itC; - for(itC = C.clusters().begin(); itC.valid(); ++itC) - edges[*itC].clear(); - C.clear(); - } - - // clean-up - m_markTree.init(); -} - - -void ExtendedNestingGraph::storeCurrentPos() -{ - for(int i = 0; i < m_numLayers; ++i) - m_layer[i].store(); -} - - -void ExtendedNestingGraph::restorePos() -{ - int count; - for(int i = 0; i < m_numLayers; ++i) { - m_layer[i].restore(); - - count = 0; - assignPos(m_layer[i].root(), count); - } -} - - -void ExtendedNestingGraph::permute() -{ - for(int i = 0; i < m_numLayers; ++i) - m_layer[i].permute(); - - int count = 0; - assignPos(m_layer[0].root(), count); -} - - -RCCrossings ExtendedNestingGraph::reduceCrossings(int i, bool dirTopDown) -{ - //cout << "Layer " << i << ":\n"; - LHTreeNode *root = m_layer[i].root(); - - Stack S; - S.push(root); - - RCCrossings numCrossings; - while(!S.empty()) { - LHTreeNode *cNode = S.pop(); - numCrossings += reduceCrossings(cNode, dirTopDown); - - for(int j = 0; j < cNode->numberOfChildren(); ++j) { - if(cNode->child(j)->isCompound()) - S.push(cNode->child(j)); - } - } - - // set positions - int count = 0; - assignPos(root, count); - - return numCrossings; -} - - -struct RCEdge -{ - RCEdge() { } - RCEdge(node src, node tgt, RCCrossings cr, RCCrossings crReverse) { - m_src = src; - m_tgt = tgt; - m_cr = cr; - m_crReverse = crReverse; - } - - RCCrossings weight() const { return m_crReverse - m_cr; } - - node m_src; - node m_tgt; - RCCrossings m_cr; - RCCrossings m_crReverse; -}; - - -class LocationRelationshipComparer -{ -public: - static int compare(const RCEdge &x, const RCEdge &y) - { - return RCCrossings::compare(x.weight(), y.weight()); - } - OGDF_AUGMENT_STATICCOMPARER(RCEdge) -}; - - -bool ExtendedNestingGraph::tryEdge(node u, node v, Graph &G, NodeArray &level) -{ - const int n = G.numberOfNodes(); - - if(level[u] == -1) { - if(level[v] == -1) { - level[v] = n; - level[u] = n-1; - } else - level[u] = level[v]-1; - - } else if(level[v] == -1) - level[v] = level[u]+1; - - else if(level[u] >= level[v]) { - SListPure successors; - if(reachable(v, u, successors)) - return false; - else { - level[v] = level[u] + 1; - moveDown(v, successors, level); - } - } - - G.newEdge(u,v); - - return true; -} - - -RCCrossings ExtendedNestingGraph::reduceCrossings(LHTreeNode *cNode, bool dirTopDown) -{ - const int n = cNode->numberOfChildren(); - if(n < 2) - return RCCrossings(); // nothing to do - - cNode->setPos(); - - // Build - // crossings matrix - Array2D cn(0,n-1,0,n-1); - - // crossings between adjacency edges - Array > adj(n); - ListConstIterator it; - for(it = (dirTopDown) ? cNode->m_upperAdj.begin() : cNode->m_lowerAdj.begin(); it.valid(); ++it) - adj[(*it).m_v->pos()].pushBack(*it); - - int j; - for(j = 0; j < n; ++j) { - ListConstIterator itJ; - for(itJ = adj[j].begin(); itJ.valid(); ++itJ) { - int posJ = m_pos[(*itJ).m_u]; - - for(int k = j+1; k < n; ++k) { - ListConstIterator itK; - for(itK = adj[k].begin(); itK.valid(); ++itK) { - int posK = m_pos[(*itK).m_u]; - int weight = (*itJ).m_weight * (*itK).m_weight; - - if(posJ > posK) - cn(j,k).incEdges(weight); - if(posK > posJ) - cn(k,j).incEdges(weight); - } - } - } - } - - // crossings between clusters and foreign adjacency edges - ListConstIterator itCC; - for(itCC = (dirTopDown) ? - cNode->m_upperClusterCrossing.begin() : cNode->m_lowerClusterCrossing.begin(); - itCC.valid(); ++itCC) - { - /*cout << "crossing: C" << m_CGC.clusterOf((*itCC).m_edgeCluster->source()) << - " e=" << (*itCC).m_edgeCluster << " with edge " << (*itCC).m_edge << - " cluster: C" << m_CGC.clusterOf((*itCC).m_edge->source()) << - ", C" << m_CGC.clusterOf((*itCC).m_edge->target()) << "\n";*/ - - int j = (*itCC).m_cNode->pos(); - int k = (*itCC).m_uNode->pos(); - - int posJ = m_pos[(*itCC).m_uc]; - int posK = m_pos[(*itCC).m_u]; - - OGDF_ASSERT(j != k && posJ != posK); - - if(posJ > posK) - cn(j,k).incClusters(); - else - cn(k,j).incClusters(); - } - - - Graph G; // crossing reduction graph - NodeArray level(G,-1); - m_aeVisited.init(G,false); - m_auxDeg.init(G,0); - - // create nodes - NodeArray fromG(G); - Array toG(n); - - for(j = 0; j < n; ++j) - fromG[toG[j] = G.newNode()] = cNode->child(j); - - // create edges for l-r constraints - const LHTreeNode *neighbourParent = (dirTopDown) ? cNode->up() : cNode->down(); - if(neighbourParent != 0) { - node src = 0; - for(int i = 0; i < neighbourParent->numberOfChildren(); ++i) { - const LHTreeNode *vNode = - (dirTopDown) ? - neighbourParent->child(i)->down() : neighbourParent->child(i)->up(); - - if(vNode != 0) { - node tgt = toG[vNode->pos()]; - if(src != 0) { -#ifdef OGDF_DEBUG - bool result = -#endif - tryEdge(src, tgt, G, level); - OGDF_ASSERT(result); - } - src = tgt; - } - } - } - - // list of location relationships - List edges; - for(j = 0; j < n; ++j) - for(int k = j+1; k < n; ++k) { - if(cn(j,k) <= cn(k,j)) - edges.pushBack(RCEdge(toG[j], toG[k], cn(j,k), cn(k,j))); - else - edges.pushBack(RCEdge(toG[k], toG[j], cn(k,j), cn(j,k))); - } - - // sort list according to weights - LocationRelationshipComparer cmp; - edges.quicksort(cmp); - - // build acyclic graph - RCCrossings numCrossings; - ListConstIterator itE; - for(itE = edges.begin(); itE.valid(); ++itE) - { - node u = (*itE).m_src; - node v = (*itE).m_tgt; - - if(tryEdge(u, v, G, level)) { - numCrossings += (*itE).m_cr; - - } else { - numCrossings += (*itE).m_crReverse; - } - } - - OGDF_ASSERT(isAcyclic(G)); - - // sort nodes in G topological - topologicalNumbering(G,level); - - // sort children of cNode according to topological numbering - node v; - forall_nodes(v,G) - cNode->setChild(level[v], fromG[v]); - - //for(j = 0; j < n; ++j) { - // LHTreeNode *vNode = cNode->child(j); - //} - - return numCrossings; -} - -void ExtendedNestingGraph::assignPos(const LHTreeNode *vNode, int &count) -{ - if(vNode->isCompound()) { - for(int i = 0; i < vNode->numberOfChildren(); ++i) - assignPos(vNode->child(i), count); - - } else { - m_pos[vNode->getNode()] = count++; - } -} - - -void ExtendedNestingGraph::removeAuxNodes() -{ - for(int i = 0; i < m_numLayers; ++i) - m_layer[i].removeAuxNodes(); -} - - -void ExtendedNestingGraph::removeTopBottomEdges() -{ - // compute m_vertical - m_vertical.init(*this); - - //cluster rootOrig = getOriginalClusterGraph().rootCluster(); - edge e; - forall_edges(e,*this) - { - if(origEdge(e) == 0) - continue; - - bool vert = false; - node u = e->source(); - node v = e->target(); - - // if we do not use virtual clusters, cu and cv are simply the - // clusters containing u and v (=> no while-loop required) - cluster cu = parent(u); - while(isVirtual(cu)) - cu = cu->parent(); - cluster cv = parent(v); - while(isVirtual(cv)) - cv = cv->parent(); - - if(isLongEdgeDummy(u) && isLongEdgeDummy(v)) { - if(cu != cv) { - cluster cuOrig = m_CGC.original(cu); - cluster cvOrig = m_CGC.original(cv); - cluster cuOrigParent = cuOrig->parent(); - cluster cvOrigParent = cvOrig->parent(); - - if((cvOrig == cuOrigParent && rank(u) == rank(bottom(cuOrig))) || - (cuOrig == cvOrigParent && rank(v) == rank(top (cvOrig))) || - (cuOrigParent == cvOrigParent && - rank(u) == rank(bottom(cuOrig)) && - rank(v) == rank(top (cvOrig)) - )) - { - vert = true; - } - } else - vert = true; - } - - m_vertical[e] = vert; - } - - for(int i = 1; i < m_numLayers; ++i) - { - LHTreeNode *root = m_layer[i].root(); - - Stack S; - S.push(root); - - while(!S.empty()) { - LHTreeNode *cNode = S.pop(); - - cNode->setPos(); - ListConstIterator itCC; - for(itCC = cNode->m_upperClusterCrossing.begin(); itCC.valid(); ++itCC) { - int j = (*itCC).m_cNode->pos(); - int k = (*itCC).m_uNode->pos(); - - int posJ = m_pos[(*itCC).m_uc]; - int posK = m_pos[(*itCC).m_u]; - - OGDF_ASSERT(j != k && posJ != posK); - - // do we have a cluster-edge crossing? - if((j < k && posJ > posK) || (j > k && posJ < posK)) - m_vertical[(*itCC).m_edge] = false; - } - - - for(int j = 0; j < cNode->numberOfChildren(); ++j) { - if(cNode->child(j)->isCompound()) - S.push(cNode->child(j)); - } - } - } - - // delete nodes in hierarchy tree - removeAuxNodes(); - - // delete nodes in graph - node v, vNext; - for(v = firstNode(); v != 0; v = vNext) { - vNext = v->succ(); - if(type(v) == ntClusterTopBottom) - delNode(v); - } -} - - -cluster ExtendedNestingGraph::lca(node u, node v) const -{ - const ClusterGraph &CG = getOriginalClusterGraph(); - - SListConstIterator it; - for(it = m_markedClustersTree.begin(); it.valid(); ++it) - m_mark[*it] = 0; - m_markedClustersTree.clear(); - - cluster c1 = CG.clusterOf(u); - cluster pred1 = c1; - cluster c2 = CG.clusterOf(v); - cluster pred2 = c2; - - for( ; ; ) { - if(c1 != 0) { - if(m_mark[c1] != 0) { - m_secondPath = pred1; - m_secondPathTo = u; - return c1; - - } else { - m_mark[c1] = pred1; - pred1 = c1; - m_markedClustersTree.pushBack(c1); - c1 = c1->parent(); - } - } - if(c2 != 0) { - if(m_mark[c2] != 0) { - m_secondPath = pred2; - m_secondPathTo = v; - return c2; - - } else { - m_mark[c2] = pred2; - pred2 = c2; - m_markedClustersTree.pushBack(c2); - c2 = c2->parent(); - } - } - } -} - - -LHTreeNode *ExtendedNestingGraph::lca( - LHTreeNode *uNode, - LHTreeNode *vNode, - LHTreeNode **uChild, - LHTreeNode **vChild) const -{ - OGDF_ASSERT(uNode->isCompound() == false && vNode->isCompound() == false); - - SListConstIterator it; - for(it = m_markedClusters.begin(); it.valid(); ++it) - m_markTree[*it] = 0; - m_markedClusters.clear(); - - LHTreeNode *cuNode = uNode->parent(); - LHTreeNode *cvNode = vNode->parent(); - - LHTreeNode *uPred = uNode; - LHTreeNode *vPred = vNode; - - while(cuNode != 0 || cvNode != 0) { - if(cuNode != 0) { - if(m_markTree[cuNode->originalCluster()] != 0) { - *uChild = uPred; - *vChild = m_markTree[cuNode->originalCluster()]; - return cuNode; - - } else { - m_markTree[cuNode->originalCluster()] = uPred; - uPred = cuNode; - m_markedClusters.pushBack(cuNode->originalCluster()); - cuNode = cuNode->parent(); - } - } - if(cvNode != 0) { - if(m_markTree[cvNode->originalCluster()] != 0) { - *uChild = m_markTree[cvNode->originalCluster()]; - *vChild = vPred; - return cvNode; - - } else { - m_markTree[cvNode->originalCluster()] = vPred; - vPred = cvNode; - m_markedClusters.pushBack(cvNode->originalCluster()); - cvNode = cvNode->parent(); - } - } - } - - return 0; // error; not found! -} - - -void ExtendedNestingGraph::assignAeLevel(cluster c, int &count) -{ - m_aeLevel[m_topNode[c]] = count++; - - ListConstIterator itV; - for(itV = c->nBegin(); itV.valid(); ++itV) - m_aeLevel[m_copy[*itV]] = count++; - - ListConstIterator itC; - for(itC = c->cBegin(); itC.valid(); ++itC) - assignAeLevel(*itC, count); - - m_aeLevel[m_bottomNode[c]] = count++; -} - - -bool ExtendedNestingGraph::reachable(node v, node u, SListPure &successors) -{ - if(u == v) - return true; - - SListPure Q; - m_aeVisited[v] = true; - Q.pushBack(v); - - while(!Q.empty()) - { - node w = Q.popFrontRet(); - successors.pushBack(w); - - edge e; - forall_adj_edges(e, w) { - node t = e->target(); - - if(t == u) { - // we've found u, so we do not need the list of successors - Q.conc(successors); - - // reset all visited entries - SListConstIterator it; - for(it = Q.begin(); it.valid(); ++it) - m_aeVisited[*it] = false; - - return true; - } - - if(m_aeVisited[t] == false) { - m_aeVisited[t] = true; - Q.pushBack(t); - } - } - } - - // reset all visited entries - SListConstIterator it; - for(it = successors.begin(); it.valid(); ++it) - m_aeVisited[*it] = false; - - return false; -} - - -void ExtendedNestingGraph::moveDown(node v, const SListPure &successors, NodeArray &level) -{ - SListConstIterator it; - for(it = successors.begin(); it.valid(); ++it) { - m_aeVisited[*it] = true; - m_auxDeg[*it] = 0; - } - - for(it = successors.begin(); it.valid(); ++it) { - edge e; - forall_adj_edges(e,*it) { - node s = e->source(); - if(s != *it && m_aeVisited[s]) - ++m_auxDeg[*it]; - } - } - - SListPure Q; - edge e; - forall_adj_edges(e,v) { - node t = e->target(); - if(t != v) { - if( --m_auxDeg[t] == 0 ) - Q.pushBack(t); - } - } - - while(!Q.empty()) - { - node w = Q.popFrontRet(); - - int maxLevel = 0; - edge e; - forall_adj_edges(e, w) { - node s = e->source(); - node t = e->target(); - - if(s != w) - maxLevel = max(maxLevel, level[s]); - if(t != w) { - if(--m_auxDeg[t] == 0) - Q.pushBack(t); - } - } - - level[w] = maxLevel+1; - } - - for(it = successors.begin(); it.valid(); ++it) { - m_aeVisited[*it] = false; - } -} - - -edge ExtendedNestingGraph::addEdge(node u, node v, bool addAlways) -{ - if(m_aeLevel[u] < m_aeLevel[v]) - return newEdge(u,v); - - SListPure successors; - if(reachable(v, u, successors) == false) { - int d = m_aeLevel[u] - m_aeLevel[v] + 1; - OGDF_ASSERT(d > 0); - - SListConstIterator it; - for(it = successors.begin(); it.valid(); ++it) - m_aeLevel[*it] += d; - - return newEdge(u,v); - - } else if(addAlways) - return newEdge(v,u); - - return 0; -} - - -//--------------------------------------------------------- -// SugiyamaLayout -// implementations for extension with clusters -//--------------------------------------------------------- - -void SugiyamaLayout::call(ClusterGraphAttributes &AG) -{ -// ofstream os("C:\\temp\\sugi.txt"); - //freopen("c:\\work\\GDE\\cout.txt", "w", stdout); - - //const Graph &G = AG.constGraph(); - const ClusterGraph &CG = AG.constClusterGraph(); -/* if (G.numberOfNodes() == 0) { - os << "Empty graph." << endl; - return; - }*/ - - // 1. Phase: Edge Orientation and Layer Assignment - - // Build extended nesting hierarchy H - ExtendedNestingGraph H(CG); - - - /*os << "Cluster Hierarchy:\n"; - node v; - forall_nodes(v, G) - os << "V " << v << ": parent = " << CG.clusterOf(v)->index() << "\n"; - - cluster c; - forall_clusters(c, CG) - if(c != CG.rootCluster()) - os << "C " << c->index() << ": parent = " << c->parent()->index() << "\n"; - - os << "\nExtended Nesting Graph:\n"; - os << " nodes: " << H.numberOfNodes() << "\n"; - os << " edges: " << H.numberOfEdges() << "\n\n"; - - forall_nodes(v, H) { - os << v->index() << ": "; - switch(H.type(v)) { - case ExtendedNestingGraph::ntNode: - os << "[V " << H.origNode(v); - break; - case ExtendedNestingGraph::ntClusterTop: - os << "[CT " << H.originalCluster(v)->index(); - break; - case ExtendedNestingGraph::ntClusterBottom: - os << "[CB " << H.originalCluster(v)->index(); - break; - } - os << ", rank = " << H.rank(v) << "] "; - - edge e; - forall_adj_edges(e, v) - if(e->target() != v) - os << e->target() << " "; - os << "\n"; - } - - - os << "\nLong Edges:\n"; - edge e; - forall_edges(e, G) { - os << e << ": "; - ListConstIterator it; - for(it = H.chain(e).begin(); it.valid(); ++it) - os << " " << (*it); - os << "\n"; - } - - os << "\nLevel:\n"; - int maxLevel = 0; - forall_nodes(v,H) - if(H.rank(v) > maxLevel) - maxLevel = H.rank(v); -*/ - Array > level(H.numberOfLayers()); - node v; - forall_nodes(v,H) - level[H.rank(v)].pushBack(v); -/* - for(int i = 0; i <= maxLevel; ++i) { - os << i << ": "; - ListConstIterator it; - for(it = level[i].begin(); it.valid(); ++it) { - node v = *it; - switch(H.type(v)) { - case ExtendedNestingGraph::ntNode: - os << "(V" << H.origNode(v); - break; - case ExtendedNestingGraph::ntClusterTop: - os << "(CT" << H.originalCluster(v)->index(); - break; - case ExtendedNestingGraph::ntClusterBottom: - os << "(CB" << H.originalCluster(v)->index(); - break; - case ExtendedNestingGraph::ntDummy: - os << "(D" << v; - break; - } - - os << ",C" << H.originalCluster(v) << ") "; - } - os << "\n"; - } - - - os << "\nLayer Hierarchy Trees:\n"; - for(int i = 0; i <= maxLevel; ++i) { - os << i << ": " << H.layerHierarchyTree(i) << "\n"; - } - - os << "\nCompound Nodes Adjacencies:\n"; - for(int i = 0; i <= maxLevel; ++i) { - os << "Layer " << i << ":\n"; - - Queue Q; - Q.append(H.layerHierarchyTree(i)); - - while(!Q.empty()) { - const LHTreeNode *p = Q.pop(); - os << " C" << p->originalCluster() << ": "; - - ListConstIterator it; - for(it = p->m_upperAdj.begin(); it.valid(); ++it) { - node u = (*it).m_u; - LHTreeNode *vNode = (*it).m_v; - int weight = (*it).m_weight; - - os << " (" << u << ","; - if(vNode->isCompound()) - os << "C" << vNode->originalCluster(); - else - os << "N" << vNode->getNode(); - os << "," << weight << ") "; - } - os << "\n"; - - for(int i = 0; i < p->numberOfChildren(); ++i) - if(p->child(i)->isCompound()) - Q.append(p->child(i)); - } - }*/ - - // 2. Phase: Crossing Reduction - reduceCrossings(H); -/* - os << "\nLayers:\n"; - for(int i = 0; i < H.numberOfLayers(); ++i) { - os << i << ": "; - const List &L = level[i]; - Array order(0,L.size()-1,0); - ListConstIterator it; - for(it = L.begin(); it.valid(); ++it) - order[H.pos(*it)] = *it; - - for(int j = 0; j < L.size(); ++j) - os << " " << order[j]; - os << "\n"; - } - - os << "\nnumber of crossings: " << m_nCrossingsCluster << "\n"; -*/ - // 3. Phase: Coordinate Assignment - H.removeTopBottomEdges(); - m_clusterLayout.get().callCluster(H, AG); -} - - -RCCrossings SugiyamaLayout::traverseTopDown(ExtendedNestingGraph &H) -{ - RCCrossings numCrossings; - - for(int i = 1; i < H.numberOfLayers(); ++i) - numCrossings += H.reduceCrossings(i,true); - - return numCrossings; -} - - -RCCrossings SugiyamaLayout::traverseBottomUp(ExtendedNestingGraph &H) -{ - RCCrossings numCrossings; - - for(int i = H.numberOfLayers()-2; i >= 0; --i) - numCrossings += H.reduceCrossings(i,false); - - return numCrossings; -} - - -void SugiyamaLayout::reduceCrossings(ExtendedNestingGraph &H) -{ - RCCrossings nCrossingsOld, nCrossingsNew; - m_nCrossingsCluster = nCrossingsOld.setInfinity(); - - for(int i = 1; ; ++i) - { - int nFails = m_fails+1; - int counter = 0; - - do { - counter++; - // top-down traversal - nCrossingsNew = traverseTopDown(H); - - if(nCrossingsNew < nCrossingsOld) { - if(nCrossingsNew < m_nCrossingsCluster) { - H.storeCurrentPos(); - - if((m_nCrossingsCluster = nCrossingsNew).isZero()) - break; - } - nCrossingsOld = nCrossingsNew; - nFails = m_fails+1; - } else - --nFails; - - // bottom-up traversal - nCrossingsNew = traverseBottomUp(H); - - if(nCrossingsNew < nCrossingsOld) { - if(nCrossingsNew < m_nCrossingsCluster) { - H.storeCurrentPos(); - - if((m_nCrossingsCluster = nCrossingsNew).isZero()) - break; - } - nCrossingsOld = nCrossingsNew; - nFails = m_fails+1; - } else - --nFails; - - } while(nFails > 0); - - if(m_nCrossingsCluster.isZero() || i >= m_runs) - break; - - H.permute(); - nCrossingsOld.setInfinity(); - } - - H.restorePos(); - m_nCrossings = m_nCrossingsCluster.m_cnEdges; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/layered/sugiyama.cpp b/ext/OGDF/src/layered/sugiyama.cpp deleted file mode 100644 index 8298c0ce6..000000000 --- a/ext/OGDF/src/layered/sugiyama.cpp +++ /dev/null @@ -1,1293 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Sugiyama algorithm (classes Hierarchy, - * Level, SugiyamaLayout) - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// GraphCopyAttributes -// manages access on copy of an attributed graph -//--------------------------------------------------------- - -void GraphCopyAttributes::transform() -{ - node v; - forall_nodes(v,*m_pGC) - { - node vG = m_pGC->original(v); - if(vG) { - m_pAG->x(vG) = m_x[v]; - m_pAG->y(vG) = m_y[v]; - } - } - - edge e; - forall_edges(e,*m_pGC) - { - edge eG = m_pGC->original(e); - if(eG == 0 || e != m_pGC->chain(eG).front()) - continue; - // current implementation does not layout self-loops; - // they are simply ignored - //if (e->isSelfLoop()) continue; - - DPolyline &dpl = m_pAG->bends(eG); - dpl.clear(); - - ListConstIterator itE = m_pGC->chain(eG).begin(); - node v = (*itE)->source(); - node vAfter = (*itE)->target(); - - for (++itE; itE.valid(); ++itE) - { - node vBefore = v; - v = vAfter; - vAfter = (*itE)->target(); - - // filter real bend points - if((m_x[v] != m_x[vBefore] || m_x[v] != m_x[vAfter]) && - (m_y[v] != m_y[vBefore] || m_y[v] != m_y[vAfter])) - dpl.pushBack(DPoint(m_x[v],m_y[v])); - } - - if (m_pGC->isReversed(eG)) - dpl.reverse(); - } -} - - -//--------------------------------------------------------- -// ClusterGraphCopyAttributes -// manages access on copy of an attributed cluster graph -//--------------------------------------------------------- - -void ClusterGraphCopyAttributes::transform() -{ - node v; - forall_nodes(v,*m_pH) - { - node vG = m_pH->origNode(v); - if(vG) { - m_pACG->x(vG) = m_x[v]; - m_pACG->y(vG) = m_y[v]; - } - } - - edge e; - forall_edges(e,*m_pH) - { - edge eG = m_pH->origEdge(e); - if(eG == 0 || e != m_pH->chain(eG).front()) - continue; - // current implementation does not layout self-loops; - // they are simply ignored - //if (e->isSelfLoop()) continue; - - DPolyline &dpl = m_pACG->bends(eG); - dpl.clear(); - - ListConstIterator itE = m_pH->chain(eG).begin(); - node v = (*itE)->source(); - node vAfter = (*itE)->target(); - - for (++itE; itE.valid(); ++itE) - { - node vBefore = v; - v = vAfter; - vAfter = (*itE)->target(); - - // filter real bend points - if((m_x[v] != m_x[vBefore] || m_x[v] != m_x[vAfter]) && - (m_y[v] != m_y[vBefore] || m_y[v] != m_y[vAfter])) - dpl.pushBack(DPoint(m_x[v],m_y[v])); - } - - if (m_pH->isReversed(eG)) - dpl.reverse(); - } -} - - -//--------------------------------------------------------- -// Level -// representation of levels in hierarchies -//--------------------------------------------------------- - -const Array &Level::adjNodes(node v) -{ - return m_pHierarchy->adjNodes(v); -} - - -void Level::swap(int i, int j) -{ - m_nodes.swap(i,j); - m_pHierarchy->m_pos[m_nodes[i]] = i; - m_pHierarchy->m_pos[m_nodes[j]] = j; -} - - - -class WeightBucket : public BucketFunc { - const NodeArray *m_pWeight; - -public: - WeightBucket(const NodeArray *pWeight) : m_pWeight(pWeight) { } - - int getBucket(const node &v) { return (*m_pWeight)[v]; } -}; - - -void Level::recalcPos() -{ - NodeArray &pos = m_pHierarchy->m_pos; - - for(int i = 0; i <= high(); ++i) - pos[m_nodes[i]] = i; - - m_pHierarchy->buildAdjNodes(m_index); -} - - -void Level::getIsolatedNodes(SListPure > &isolated) -{ - for (int i = 0; i <= high(); ++i) - if (adjNodes(m_nodes[i]).high() < 0) - isolated.pushBack(Tuple2(m_nodes[i],i)); -} - - -void Level::setIsolatedNodes(SListPure > &isolated) -{ - const int sizeL = size(); - Array sortedNodes(sizeL); - isolated.pushBack(Tuple2(0,sizeL)); - SListConstIterator > itIsolated = isolated.begin(); - - int nextPos = (*itIsolated).x2(); - for( int iNodes = 0, iSortedNodes = 0; nextPos <= sizeL; ) { - if( iSortedNodes == nextPos ) { - if( iSortedNodes == sizeL ) - break; - sortedNodes[iSortedNodes++] = (*itIsolated).x1(); - nextPos = (*(++itIsolated)).x2(); - } else { - node v = m_nodes[iNodes++]; - if( adjNodes(v).size() > 0 ) - sortedNodes[iSortedNodes++] = v; - } - } - - for( int i = 0; i < sizeL; ++i) - m_nodes[i] = sortedNodes[i]; -} - - -void Level::sort(NodeArray &weight) -{ - SListPure > isolated; - getIsolatedNodes(isolated); - - WeightComparer<> cmp(&weight); - //m_nodes.quicksort(cmp); - std::stable_sort(&m_nodes[0], &m_nodes[0]+m_nodes.size(), cmp); - - if (!isolated.empty()) setIsolatedNodes(isolated); - recalcPos(); -} - - -void Level::sortByWeightOnly(NodeArray &weight) -{ - WeightComparer<> cmp(&weight); - std::stable_sort(&m_nodes[0], &m_nodes[0]+m_nodes.size(), cmp); - recalcPos(); -} - - -void Level::sort(NodeArray &weight, int minBucket, int maxBucket) -{ - SListPure > isolated; - getIsolatedNodes(isolated); - - WeightBucket bucketFunc(&weight); - bucketSort(m_nodes,minBucket,maxBucket,bucketFunc); - - if (!isolated.empty()) setIsolatedNodes(isolated); - recalcPos(); -} - - - -//--------------------------------------------------------- -// Hierarchy -// representation of proper hierarchies used by Sugiyama -//--------------------------------------------------------- - -Hierarchy::Hierarchy(const Graph &G, const NodeArray &rank) : - m_GC(G), m_rank(m_GC) -{ - doInit(rank); -} - - -void Hierarchy::doInit(const NodeArray &rank) -{ - makeLoopFree(m_GC); - - int maxRank = 0; - - node v; - forall_nodes(v,m_GC) { - int r = m_rank[v] = rank[m_GC.original(v)]; - OGDF_ASSERT(r >= 0) - if (r > maxRank) maxRank = r; - } - - SListPure edges; - m_GC.allEdges(edges); - SListConstIterator it; - for(it = edges.begin(); it.valid(); ++it) - { - edge e = *it; - - int rankSrc = m_rank[e->source()], rankTgt = m_rank[e->target()]; - - if (rankSrc > rankTgt) { - m_GC.reverseEdge(e); std::swap(rankSrc,rankTgt); - } - - if (rankSrc == rankTgt) { - e = m_GC.split(e); - m_GC.reverseEdge(e); - if ((m_rank[e->target()] = rankSrc+1) > maxRank) - maxRank = rankSrc+1; - - } else { - for(++rankSrc; rankSrc < rankTgt; ++rankSrc) - m_rank[(e = m_GC.split(e))->source()] = rankSrc; - } - } - - Array length(0,maxRank,0); - forall_nodes(v,m_GC) - length[m_rank[v]]++; - - int i; - for(i = 0; i <= m_pLevel.high(); ++i) - delete m_pLevel[i]; - m_pLevel.init(0,maxRank); - - for(i = 0; i <= maxRank; ++i) - m_pLevel[i] = new Level(this,i,length[i]); - - m_pos.init(m_GC); - m_lowerAdjNodes.init(m_GC); - m_upperAdjNodes.init(m_GC); - m_lastOcc.init(m_GC); // only used by calculateCrossingsPlaneSweep() - - forall_nodes(v,m_GC) { - int r = m_rank[v], pos = --length[r]; - m_pos[(*m_pLevel[r])[pos] = v] = pos; - - m_lowerAdjNodes[v].init(v->indeg()); - m_upperAdjNodes[v].init(v->outdeg()); - } - - m_nSet.init(m_GC,0); - buildAdjNodes(); -} - - -void Hierarchy::createEmpty(const Graph &G) -{ - m_GC.createEmpty(G); - m_rank.init(m_GC); -} - - -void Hierarchy::initByNodes(const List &nodes, - EdgeArray &eCopy, - const NodeArray &rank) -{ - m_GC.initByNodes(nodes,eCopy); - - doInit(rank); -} - - -Hierarchy::~Hierarchy() -{ - for(int i = 0; i <= high(); ++i) - delete m_pLevel[i]; -} - - -void Hierarchy::buildAdjNodes() -{ - for(int i = 0; i <= high(); ++i) - buildAdjNodes(i); -} - - -void Hierarchy::buildAdjNodes(int i) -{ - if (i > 0) { - const Level &lowerLevel = *m_pLevel[i-1]; - - for(int j = 0; j <= lowerLevel.high(); ++j) - m_nSet[lowerLevel[j]] = 0; - } - - if (i < high()) { - const Level &upperLevel = *m_pLevel[i+1]; - - for(int j = 0; j <= upperLevel.high(); ++j) - m_nSet[upperLevel[j]] = 0; - } - - const Level &level = *m_pLevel[i]; - - for(int j = 0; j <= level.high(); ++j) { - node v = level[j]; - edge e; - forall_adj_edges(e,v) { - if (e->source() == v) { - (m_lowerAdjNodes[e->target()])[m_nSet[e->target()]++] = v; - } else { - (m_upperAdjNodes[e->source()])[m_nSet[e->source()]++] = v; - } - } - } -} - - -void Hierarchy::storePos (NodeArray &oldPos) -{ - oldPos = m_pos; -} - - -void Hierarchy::restorePos (const NodeArray &newPos) -{ - m_pos = newPos; - - node v; - forall_nodes(v,m_GC) { - (*m_pLevel[m_rank[v]])[m_pos[v]] = v; - } - - //check(); - - buildAdjNodes(); -} - - -void Hierarchy::permute() -{ - for(int i = 0; i < m_pLevel.high(); ++i) { - Level &level = *m_pLevel[i]; - level.m_nodes.permute(); - for(int j = 0; j <= level.high(); ++j) - m_pos[level[j]] = j; - } - - //check(); - - buildAdjNodes(); -} - - -void Hierarchy::separateCCs(int numCC, NodeArray &component) -{ - Array > table(numCC); - - for(int i = 0; i < m_pLevel.high(); ++i) { - Level &level = *m_pLevel[i]; - for(int j = 0; j <= level.high(); ++j) { - node v = level[j]; - table[component[v]].pushBack(v); - } - } - - Array count(0, m_pLevel.high(), 0); - for(int c = 0; c < numCC; ++c) { - SListConstIterator it; - for(it = table[c].begin(); it.valid(); ++it) - m_pos[*it] = count[m_rank[*it]]++; - } - - node v; - forall_nodes(v,m_GC) { - (*m_pLevel[m_rank[v]])[m_pos[v]] = v; - } - - //check(); - - buildAdjNodes(); -} - - -int Hierarchy::calculateCrossings() -{ - int nCrossings = 0; - - for(int i = 0; i < m_pLevel.high(); ++i) { - nCrossings += calculateCrossings(i); - } - - return nCrossings; -} - - -// calculation of edge crossings between level i and i+1 -// implementation by Michael Juenger, Decembre 2000, adapted by Carsten Gutwenger -// implements the algorithm by Barth, Juenger, Mutzel - -int Hierarchy::calculateCrossings(int i) -{ - const Level &L = *m_pLevel[i]; // level i - const int nUpper = m_pLevel[i+1]->size(); // number of nodes on level i+1 - - int nc = 0; // number of crossings - - int fa = 1; - while (fa < nUpper) - fa *= 2; - - int nTreeNodes = 2*fa - 1; // number of tree nodes - fa -= 1; // "first address:" indexincrement in tree - - Array nin(0,nTreeNodes-1,0); - - for(int j = 0; j < L.size(); ++j) - { - const Array &adjNodes = m_upperAdjNodes[L[j]]; - for(int k = 0; k < adjNodes.size(); ++k) - { - // index of tree node for vertex adjNode[k] - int index = m_pos[adjNodes[k]] + fa; - nin[index]++; - - while (index>0) { - if (index % 2) - nc += nin[index+1]; // new crossing - index = (index - 1) / 2; - nin[index]++; - } - - } - } - - return nc; -} - - - -//----------------------------------------------- -// The following code -// calculateCrossingsPlaneSweep() and -// calculateCrossingsPlaneSweep(int i) -// is the old implementation of the crossing calculation using a -// plane sweep algorithm. We keep it in the library in order to -// test the new implementation against the old one. - -int Hierarchy::calculateCrossingsPlaneSweep() -{ - int nCrossings = 0; - - for(int i = 0; i < m_pLevel.high(); ++i) { - nCrossings += calculateCrossingsPlaneSweep(i); - } - - return nCrossings; -} - - -// The member node array m_lastOcc is only used by this function! - -int Hierarchy::calculateCrossingsPlaneSweep(int i) -{ - const Level *pLevel[2]; - pLevel[0] = m_pLevel[i]; pLevel[1] = m_pLevel[i+1]; - - if (pLevel[0]->high() <= 0 || pLevel[1] <= 0) return 0; - - int j, k; - for(j = 0; j <= 1; ++j) - for(k = 0; k <= pLevel[j]->high(); ++k) - m_lastOcc[(*pLevel[j])[k]] = 0; - - j = 0; - int index[2] = { 0, 0 }; - List endNodes[2]; - int nCrossings = 0; - - do { - int nOccW = 0, nCrossW = 0, nSumCrossW = 0; - node w = (*pLevel[j])[index[j]]; - - if (m_lastOcc[w].valid()) { - ListIterator it, itSucc; - for(it = endNodes[j].begin(); it.valid(); it = itSucc) { - itSucc = it.succ(); - if (*it == w) { - nOccW++; - nSumCrossW += nCrossW; - endNodes[j].del(it); - } else - nCrossW++; - if (m_lastOcc[w] == it) break; - } - nCrossings += nOccW * endNodes[1-j].size() + nSumCrossW; - } - - const Array &adjNodes = - (j == 0) ? m_upperAdjNodes[w] : m_lowerAdjNodes[w]; - - for(k = 0; k <= adjNodes.high(); ++k) { - node uk = adjNodes[k]; - if (m_pos[uk] > m_pos[w] || (m_pos[uk] == m_pos[w] && j == 0)) - m_lastOcc[uk] = endNodes[1-j].pushBack(uk); - } - - ++index[j]; - if (index[1-j] < pLevel[1-j]->size()) - j = 1-j; - - } while (index[j] < pLevel[j]->size()); - - return nCrossings; -} - -// end of old implementation -//----------------------------------------------- - - -int Hierarchy::calculateCrossingsSimDraw(const EdgeArray *edgeSubGraph) -{ - int nCrossings = 0; - - for(int i = 0; i < m_pLevel.high(); ++i) { - nCrossings += calculateCrossingsSimDraw(i, edgeSubGraph); - } - - return nCrossings; -} - - -// naive calculation of edge crossings between level i and i+1 -// for SimDraw-calculation by Michael Schulz - -int Hierarchy::calculateCrossingsSimDraw(int i, const EdgeArray *edgeSubGraph) -{ - const int maxGraphs = 32; - - const Level &L = *m_pLevel[i]; // level i - const GraphCopy &GC = L.hierarchy(); - - int nc = 0; // number of crossings - - for(int j = 0; j < L.size(); ++j) - { - node v = L[j]; - edge e; - forall_adj_edges(e,v) { - if (e->source() == v){ - int pos_adj_e = pos(e->target()); - for (int k = j+1; k < L.size(); k++) { - node w = L[k]; - edge f; - forall_adj_edges(f,w) { - if (f->source() == w) { - int pos_adj_f = pos(f->target()); - if(pos_adj_f < pos_adj_e) - { - int graphCounter = 0; - for(int numGraphs = 0; numGraphs < maxGraphs; numGraphs++) - if((1 << numGraphs) & (*edgeSubGraph)[GC.original(e)] & (*edgeSubGraph)[GC.original(f)]) - graphCounter++; - nc += graphCounter; - } - } - } - } - } - } - } - - return nc; -} - - -void Hierarchy::print(ostream &os) -{ - for(int i = 0; i <= m_pLevel.high(); ++i) { - os << i << ": "; - const Level &level = *m_pLevel[i]; - for(int j = 0; j < level.size(); ++j) - os << level[j] << " "; - os << endl; - } - - os << endl; - node v; - forall_nodes(v,m_GC) { - os << v << ": lower: " << (m_lowerAdjNodes[v]) << - ", upper: " << (m_upperAdjNodes[v]) << endl; - } - -} - -int Hierarchy::transposePart( - const Array &adjV, - const Array &adjW) -{ - const int vSize = adjV.size(); - int iW = 0, iV = 0, sum = 0; - - for(; iW <= adjW.high(); ++iW) { - int p = m_pos[adjW[iW]]; - while(iV < vSize && m_pos[adjV[iV]] <= p) ++iV; - sum += vSize - iV; - } - - return sum; -} - - -bool Hierarchy::transpose(node v) -{ - int rankV = m_rank[v], posV = m_pos[v]; - node w = (*m_pLevel[rankV])[posV+1]; - - int d = 0; - d += transposePart(m_upperAdjNodes[v],m_upperAdjNodes[w]); - d -= transposePart(m_upperAdjNodes[w],m_upperAdjNodes[v]); - d += transposePart(m_lowerAdjNodes[v],m_lowerAdjNodes[w]); - d -= transposePart(m_lowerAdjNodes[w],m_lowerAdjNodes[v]); - - if (d > 0) { - m_pLevel[rankV]->swap(posV,posV+1); - return true; - } - - return false; -} - - -void Hierarchy::check() -{ - int i, j; - for(i = 0; i <= high(); ++i) { - Level &L = *m_pLevel[i]; - for(j = 0; j <= L.high(); ++j) { - if (m_pos[L[j]] != j) { - cerr << "m_pos[" << L[j] << "] wrong!" << endl; - } - if (m_rank[L[j]] != i) { - cerr << "m_rank[" << L[j] << "] wrong!" << endl; - } - } - } - -/* node v; - forall_nodes(v,m_GC) { - const Array &upperNodes = m_upperAdjNodes[v]; - for(i = 0; i <= upperNodes.high(); ++i) { - if (i > 0 && m_pos[upperNodes[i-1]] > m_pos[upperNodes[i]]) { - cerr << "upperNodes[" << v << "] not sorted!" << endl; - } - } - const Array &lowerNodes = m_lowerAdjNodes[v]; - for(i = 0; i <= lowerNodes.high(); ++i) { - if (i > 0 && m_pos[lowerNodes[i-1]] > m_pos[lowerNodes[i]]) { - cerr << "lowerNodes[" << v << "] not sorted!" << endl; - } - } - }*/ -} - - - - -//--------------------------------------------------------- -// SugiyamaLayout -// Sugiyama drawing algorithm for hierarchical graphs -//--------------------------------------------------------- - -SugiyamaLayout::SugiyamaLayout() -{ - m_ranking .set(new LongestPathRanking); - m_crossMin .set(new BarycenterHeuristic); - m_crossMinSimDraw.set(new SplitHeuristic); - m_layout .set(new FastHierarchyLayout); - m_clusterLayout .set(new OptimalHierarchyClusterLayout); - m_packer .set(new TileToRowsCCPacker); - - m_fails = 4; - m_runs = 15; - m_transpose = true; - m_permuteFirst = false; - - m_arrangeCCs = true; - m_minDistCC = 20; - m_pageRatio = 1.0; - - m_alignBaseClasses = false; - m_alignSiblings = false; - m_subgraphs = 0; - - m_maxLevelSize = -1; - m_numLevels = -1; - m_timeReduceCrossings = 0.0; -} - - - - -void SugiyamaLayout::call(GraphAttributes &AG) -{ - doCall(AG,false); -} - - -void SugiyamaLayout::call(GraphAttributes &AG, NodeArray &rank) -{ - doCall(AG,false,rank); -} - - -void SugiyamaLayout::doCall(GraphAttributes &AG, bool umlCall) -{ - NodeArray rank; - doCall(AG, umlCall, rank); -} - - -void SugiyamaLayout::doCall(GraphAttributes &AG, bool umlCall, NodeArray &rank) -{ - const Graph &G = AG.constGraph(); - if (G.numberOfNodes() == 0) - return; - - // compute connected component of G - NodeArray component(G); - m_numCC = connectedComponents(G,component); - - const bool optimizeHorizEdges = (umlCall || rank.valid()); - if(!rank.valid()) - { - if(umlCall) - { - LongestPathRanking ranking; - ranking.alignBaseClasses(m_alignBaseClasses); - ranking.alignSiblings(m_alignSiblings); - - ranking.callUML(AG,rank); - - } else { - m_ranking.get().call(AG.constGraph(),rank); - } - } - - if(m_arrangeCCs) { - // intialize the array of lists of nodes contained in a CC - Array > nodesInCC(m_numCC); - - node v; - forall_nodes(v,G) - nodesInCC[component[v]].pushBack(v); - - Hierarchy H; - H.createEmpty(G); - const GraphCopy &GC = H; - - EdgeArray auxCopy(G); - Array boundingBox(m_numCC); - Array offset1(m_numCC); - NodeArray mark(GC); - - m_numLevels = m_maxLevelSize = 0; - - int totalCrossings = 0; - for(int i = 0; i < m_numCC; ++i) - { - // adjust ranks in cc to start with 0 - int minRank = INT_MAX; - ListConstIterator it; - for(it = nodesInCC[i].begin(); it.valid(); ++it) - if(rank[*it] < minRank) - minRank = rank[*it]; - - if(minRank != 0) { - for(it = nodesInCC[i].begin(); it.valid(); ++it) - rank[*it] -= minRank; - } - - H.initByNodes(nodesInCC[i],auxCopy,rank); - - reduceCrossings(H); - totalCrossings += m_nCrossings; - - m_layout.get().call(H,AG); - - double minX = DBL_MAX, maxX = -DBL_MAX, minY = DBL_MAX, maxY = -DBL_MAX; - - node vCopy; - forall_nodes(vCopy,GC) - { - mark[vCopy] = false; - node v = GC.original(vCopy); - if(v == 0) continue; - - if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; - if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; - if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; - if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; - } - - if(optimizeHorizEdges) - { - for(int i = 0; i < H.size(); ++i) { - const Level &L = H[i]; - for(int j = 0; j < L.size(); ++j) { - node v = L[j]; - if(!GC.isDummy(v)) continue; - edge e = GC.original(v->firstAdj()->theEdge()); - if(e == 0) continue; - node src = GC.copy(e->source()); - node tgt = GC.copy(e->target()); - - if(H.rank(src) == H.rank(tgt)) { - int minPos = H.pos(src), maxPos = H.pos(tgt); - if(minPos > maxPos) std::swap(minPos,maxPos); - - bool straight = true; - const Level &L_e = H[H.rank(src)]; - for(int p = minPos+1; p < maxPos; ++p) { - if(!H.isLongEdgeDummy(L_e[p]) && mark[L_e[p]] == false) { - straight = false; break; - } - } - if(straight) { - AG.bends(e).clear(); - mark[v] = true; - } - } - } - } - } - - edge eCopy; - forall_edges(eCopy,GC) - { - edge e = GC.original(eCopy); - if(e == 0 || eCopy != GC.chain(e).front()) continue; - - const DPolyline &dpl = AG.bends(e); - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - { - if((*it).m_x < minX) minX = (*it).m_x; - if((*it).m_x > maxX) maxX = (*it).m_x; - if((*it).m_y < minY) minY = (*it).m_y; - if((*it).m_y > maxY) maxY = (*it).m_y; - } - } - - minX -= m_minDistCC; - minY -= m_minDistCC; - - boundingBox[i] = DPoint(maxX - minX, maxY - minY); - offset1 [i] = DPoint(minX,minY); - - m_numLevels = max(m_numLevels, H.size()); - for(int i = 0; i <= H.high(); i++) { - Level &l = H[i]; - m_maxLevelSize = max(m_maxLevelSize, l.size()); - } - } - - m_nCrossings = totalCrossings; - - // call packer - Array offset(m_numCC); - m_packer.get().call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node and edge by the offset - // of its connected component. - - for(int i = 0; i < m_numCC; ++i) - { - const List &nodes = nodesInCC[i]; - - const double dx = offset[i].m_x - offset1[i].m_x; - const double dy = offset[i].m_y - offset1[i].m_y; - - // iterate over all nodes in ith CC - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - AG.x(v) += dx; - AG.y(v) += dy; - - edge e; - forall_adj_edges(e,v) - { - if(e->isSelfLoop() || e->source() != v) continue; - - DPolyline &dpl = AG.bends(e); - ListIterator it; - for(it = dpl.begin(); it.valid(); ++it) - { - (*it).m_x += dx; - (*it).m_y += dy; - } - } - } - } - - } else { - int minRank = INT_MAX; - node v; - forall_nodes(v,G) - if(rank[v] < minRank) - minRank = rank[v]; - - if(minRank != 0) { - forall_nodes(v,G) - rank[v] -= minRank; - } - - Hierarchy H(G,rank); - const GraphCopy &GC = H; - - m_compGC.init(GC); - forall_nodes(v,GC) { - node vOrig = GC.original(v); - if(vOrig == 0) - vOrig = GC.original(v->firstAdj()->theEdge())->source(); - - m_compGC[v] = component[vOrig]; - } - - reduceCrossings(H); - m_compGC.init(); - - m_layout.get().call(H,AG); - - if(optimizeHorizEdges) - { - NodeArray mark(GC,false); - for(int i = 0; i < H.size(); ++i) { - const Level &L = H[i]; - for(int j = 0; j < L.size(); ++j) { - node v = L[j]; - if(!GC.isDummy(v)) continue; - edge e = GC.original(v->firstAdj()->theEdge()); - if(e == 0) continue; - node src = GC.copy(e->source()); - node tgt = GC.copy(e->target()); - - if(H.rank(src) == H.rank(tgt)) { - int minPos = H.pos(src), maxPos = H.pos(tgt); - if(minPos > maxPos) std::swap(minPos,maxPos); - - bool straight = true; - const Level &L_e = H[H.rank(src)]; - for(int p = minPos+1; p < maxPos; ++p) { - if(!H.isLongEdgeDummy(L_e[p]) && mark[L_e[p]] == false) { - straight = false; break; - } - } - if(straight) { - AG.bends(e).clear(); - mark[v] = true; - } - } - } - } - } - - m_numLevels = H.size(); - m_maxLevelSize = 0; - for(int i = 0; i <= H.high(); i++) { - Level &l = H[i]; - if (l.size() > m_maxLevelSize) - m_maxLevelSize = l.size(); - } - - } - -} - - -void SugiyamaLayout::callUML(GraphAttributes &AG) -{ - doCall(AG,true); -} - - -bool SugiyamaLayout::transposeLevel(int i, Hierarchy &H) -{ - bool improved = false; - - if (m_levelChanged[i] || m_levelChanged[i-1] || m_levelChanged[i+1]) { - Level &L = H[i]; - - for (int j = 0; j < L.high(); j++) { - if (H.transpose(L[j])) improved = true; - } - } - - if (improved) H.buildAdjNodes(i); - return (m_levelChanged[i] = improved); -} - - -void SugiyamaLayout::doTranspose(Hierarchy &H) -{ - m_levelChanged.fill(true); - - bool improved; - do { - improved = false; - - for (int i = 0; i <= H.high(); ++i) - improved |= transposeLevel(i,H); - } while (improved); -} - - -void SugiyamaLayout::doTransposeRev(Hierarchy &H) -{ - m_levelChanged.fill(true); - - bool improved; - do { - improved = false; - - for (int i = H.high(); i >= 0 ; --i) - improved |= transposeLevel(i,H); - } while (improved); -} - - -int SugiyamaLayout::traverseTopDown(Hierarchy& H) -{ - H.direction(Hierarchy::downward); - - for (int i = 1; i <= H.high(); ++i) { - if(!useSubgraphs()) { - TwoLayerCrossMin &minimizer = m_crossMin.get(); - minimizer(H[i]); - } else { - TwoLayerCrossMinSimDraw &minimizer = m_crossMinSimDraw.get(); - minimizer.call(H[i],m_subgraphs); - } - } - - if (m_transpose) - doTranspose(H); - if(m_arrangeCCs == false) - H.separateCCs(m_numCC, m_compGC); - - if(!useSubgraphs()) - return H.calculateCrossings(); - else - return H.calculateCrossingsSimDraw(m_subgraphs); -} - - -int SugiyamaLayout::traverseBottomUp(Hierarchy& H) -{ - H.direction(Hierarchy::upward); - - for (int i = H.high()-1; i >= 0; i--) { - if(!useSubgraphs()) - { - TwoLayerCrossMin &minimizer = m_crossMin.get(); - minimizer(H[i]); - } - else - { - TwoLayerCrossMinSimDraw &minimizer = m_crossMinSimDraw.get(); - minimizer.call(H[i],m_subgraphs); - } - } - - if (m_transpose) - doTransposeRev(H); - if(m_arrangeCCs == false) - H.separateCCs(m_numCC, m_compGC); - - if(!useSubgraphs()) - return H.calculateCrossings(); - else - return H.calculateCrossingsSimDraw(m_subgraphs); -} - - -void SugiyamaLayout::reduceCrossings(Hierarchy &H) -{ - __int64 t; - System::usedRealTime(t); - - TwoLayerCrossMin &minimizer = m_crossMin.get(); - TwoLayerCrossMinSimDraw &sdminimizer = m_crossMinSimDraw.get(); - - if(m_permuteFirst) - H.permute(); - - int nCrossingsOld, nCrossingsNew; - NodeArray bestPos; - - if(!useSubgraphs()) - m_nCrossings = nCrossingsOld = H.calculateCrossings(); - else - m_nCrossings = nCrossingsOld = H.calculateCrossingsSimDraw(m_subgraphs); - H.storePos(bestPos); - - if (m_nCrossings == 0) { - t = System::usedRealTime(t); - m_timeReduceCrossings = double(t) / 1000; - return; - } - - if(!useSubgraphs()) - minimizer.init(H); - else - sdminimizer.init(H); - - if (m_transpose) { - m_levelChanged.init(-1,H.size()); - m_levelChanged[-1] = m_levelChanged[H.size()] = false; - } - - for (int i = 1; ;i++ ) { - int nFails = m_fails+1; - - do { - nCrossingsNew = traverseTopDown(H); - //cout << nCrossingsNew << endl; - - if (nCrossingsNew < nCrossingsOld) { - if (nCrossingsNew < m_nCrossings) { - H.storePos(bestPos); - - if ((m_nCrossings = nCrossingsNew) == 0) - break; - } - nCrossingsOld = nCrossingsNew; - nFails = m_fails+1; - } else - --nFails; - - nCrossingsNew = traverseBottomUp(H); - //cout << nCrossingsNew << endl; - - if (nCrossingsNew < nCrossingsOld) { - if (nCrossingsNew < m_nCrossings) { - H.storePos(bestPos); - - if ((m_nCrossings = nCrossingsNew) == 0) - break; - } - nCrossingsOld = nCrossingsNew; - nFails = m_fails+1; - } else - --nFails; - - } while (nFails > 0); - - if (m_nCrossings == 0 || i >= m_runs) - break; - - H.permute(); - - if(!useSubgraphs()) - nCrossingsOld = H.calculateCrossings(); - else - nCrossingsOld = H.calculateCrossings(); - if (nCrossingsOld < m_nCrossings) { - H.storePos(bestPos); - - m_nCrossings = nCrossingsOld; - } - } - - H.restorePos(bestPos); - - if(!useSubgraphs()) - minimizer.cleanup(); - else - sdminimizer.cleanup(); - m_levelChanged.init(); - - t = System::usedRealTime(t); - m_timeReduceCrossings = double(t) / 1000; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/lpsolver/LPSolver_coin.cpp b/ext/OGDF/src/lpsolver/LPSolver_coin.cpp deleted file mode 100644 index 7e204cb63..000000000 --- a/ext/OGDF/src/lpsolver/LPSolver_coin.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements front-end for LP solver - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#if defined(USE_COIN) && !defined(OGDF_OWN_LPSOLVER) - -#include - -namespace ogdf { - -LPSolver::LPSolver() -{ - osi = CoinManager::createCorrectOsiSolverInterface(); -} - - -double LPSolver::infinity() const -{ - return osi->getInfinity(); -} - -bool LPSolver::checkFeasibility( - const Array &matrixBegin, // matrixBegin[i] = begin of column i - const Array &matrixCount, // matrixCount[i] = number of nonzeroes in column i - const Array &matrixIndex, // matrixIndex[n] = index of matrixValue[n] in its column - const Array &matrixValue, // matrixValue[n] = non-zero value in matrix - const Array &rightHandSide, // right-hand side of LP constraints - const Array &equationSense, // 'E' == 'G' >= 'L' <= - const Array &lowerBound, // lower bound of x[i] - const Array &upperBound, // upper bound of x[i] - const Array &x // x-vector of optimal solution (if result is lpOptimal) -) -{ - const int numRows = rightHandSide.size(); - const int numCols = x.size(); - - double eps; - osi->getDblParam(OsiPrimalTolerance, eps); - - for(int i = 0; i < numCols; ++i) { - if(x[i]+eps < lowerBound[i] || x[i]-eps > upperBound[i]) { - cerr << "column " << i << " out of range" << endl; - return false; - } - } - - for(int i = 0; i < numRows; ++i) { - double leftHandSide = 0.0; - - for(int c = 0; c < numCols; ++c) { - for(int j = matrixBegin[c]; j < matrixBegin[c]+matrixCount[c]; ++j) - if(matrixIndex[j] == i) { - leftHandSide += matrixValue[j] * x[c]; - } - } - - switch(equationSense[i]) { - case 'G': - if(leftHandSide+eps < rightHandSide[i]) { - cerr << "row " << i << " violated " << endl; - cerr << leftHandSide << " > " << rightHandSide[i] << endl; - return false; - } - break; - case 'L': - if(leftHandSide-eps > rightHandSide[i]) { - cerr << "row " << i << " violated " << endl; - cerr << leftHandSide << " < " << rightHandSide[i] << endl; - return false; - } - break; - case 'E': - if(leftHandSide+eps < rightHandSide[i] || leftHandSide-eps > rightHandSide[i]) { - cerr << "row " << i << " violated " << endl; - cerr << leftHandSide << " = " << rightHandSide[i] << endl; - return false; - } - break; - default: - cerr << "unexpected equation sense " << equationSense[i] << endl; - return false; - } - } - return true; -} - -LPSolver::Status LPSolver::optimize( - OptimizationGoal goal, // goal of optimization (minimize or maximize) - Array &obj, // objective function vector - Array &matrixBegin, // matrixBegin[i] = begin of column i - Array &matrixCount, // matrixCount[i] = number of nonzeroes in column i - Array &matrixIndex, // matrixIndex[n] = index of matrixValue[n] in its column - Array &matrixValue, // matrixValue[n] = non-zero value in matrix - Array &rightHandSide, // right-hand side of LP constraints - Array &equationSense, // 'E' == 'G' >= 'L' <= - Array &lowerBound, // lower bound of x[i] - Array &upperBound, // upper bound of x[i] - double &optimum, // optimum value of objective function (if result is lpOptimal) - Array &x // x-vector of optimal solution (if result is lpOptimal) -) -{ - if(osi->getNumCols()>0) { // get a fresh one if necessary - delete osi; - osi = CoinManager::createCorrectOsiSolverInterface(); - } - - const int numRows = rightHandSide.size(); - const int numCols = obj.size(); -#ifdef OGDF_DEBUG - const int numNonzeroes = matrixIndex.size(); -#endif - - // assert correctness of array boundaries - OGDF_ASSERT(obj .low() == 0 && obj .size() == numCols); - OGDF_ASSERT(matrixBegin .low() == 0 && matrixBegin .size() == numCols); - OGDF_ASSERT(matrixCount .low() == 0 && matrixCount .size() == numCols); - OGDF_ASSERT(matrixIndex .low() == 0 && matrixIndex .size() == numNonzeroes); - OGDF_ASSERT(matrixValue .low() == 0 && matrixValue .size() == numNonzeroes); - OGDF_ASSERT(rightHandSide.low() == 0 && rightHandSide.size() == numRows); - OGDF_ASSERT(equationSense.low() == 0 && equationSense.size() == numRows); - OGDF_ASSERT(lowerBound .low() == 0 && lowerBound .size() == numCols); - OGDF_ASSERT(upperBound .low() == 0 && upperBound .size() == numCols); - OGDF_ASSERT(x .low() == 0 && x .size() == numCols); - - osi->setObjSense(goal==lpMinimize ? 1 : -1); - - int i; - - CoinPackedVector zero; - for(i = 0; i < numRows; ++i) { - osi->addRow(zero,equationSense[i],rightHandSide[i],0); - } - for(int colNo = 0; colNo < numCols; ++colNo) { - CoinPackedVector cpv; - for(i = matrixBegin[colNo]; iaddCol(cpv,lowerBound[colNo],upperBound[colNo],obj[colNo]); - } - - - osi->initialSolve(); - - Status status; - if(osi->isProvenOptimal()) { - optimum = osi->getObjValue(); - const double* sol = osi->getColSolution(); - for(i = numCols; i-->0;) - x[i]=sol[i]; - status = lpOptimal; - OGDF_ASSERT_IF(dlExtendedChecking, - checkFeasibility(matrixBegin,matrixCount,matrixIndex,matrixValue, - rightHandSide,equationSense,lowerBound,upperBound,x)); - - } else if(osi->isProvenPrimalInfeasible()) - status = lpInfeasible; - else if(osi->isProvenDualInfeasible()) - status = lpUnbounded; - else - OGDF_THROW_PARAM(AlgorithmFailureException,afcNoSolutionFound); - - return status; -} - -} // end namespace ogdf - -#endif diff --git a/ext/OGDF/src/misclayout/BalloonLayout.cpp b/ext/OGDF/src/misclayout/BalloonLayout.cpp deleted file mode 100644 index 7d7beeb34..000000000 --- a/ext/OGDF/src/misclayout/BalloonLayout.cpp +++ /dev/null @@ -1,738 +0,0 @@ -/* - * $Revision: 2573 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 18:48:33 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief BalloonLayout for trees that can also be applied to - * general graphs. - * - * Partially based on the papers by Lin/Yen and Carriere/Kazman - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//There are two radii at each node: The outer radius of the circle -//surrounding its subtree, and the inner radius of the circle -//on which the children of the node are placed -//For each angle assignment at a node p (parent), its own angle is -//used as offset, so that the children are correctly oriented - -#include - - -#include -#include -#include -#include - -#include - - -namespace ogdf { - - -BalloonLayout::BalloonLayout() : - m_rootSelection(BalloonLayout::rootCenter), //how to select the root - m_estimateFactor(1.2), //weight of radius addition value - m_childOrder(orderFixed), //how to arrange the children - m_treeComputation(BalloonLayout::treeBfs), //spanning tree by... - m_evenAngles(false) -{ - #ifdef OGDF_DEBUG - m_treeEdge = 0; - #endif -} - -BalloonLayout::~BalloonLayout() -{ -#ifdef OGDF_DEBUG -if (m_treeEdge != 0) delete m_treeEdge; -#endif -} - -BalloonLayout &BalloonLayout::operator=(const BalloonLayout &bl) -{ - m_treeComputation = bl.m_treeComputation; - m_childOrder = bl.m_childOrder; - m_rootSelection = bl.m_rootSelection; - m_estimateFactor = bl.m_estimateFactor; - m_evenAngles = bl.m_evenAngles; - - return *this; -} - - -void BalloonLayout::call(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - if(G.numberOfNodes() == 0) return; - - #ifdef OGDF_DEBUG - if (!isConnected(G)) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcConnected); - if (m_treeEdge != 0) delete m_treeEdge; - m_treeEdge = OGDF_NEW EdgeArray(); - m_treeEdge->init(G, false); - #endif - - m_rootSelection = rootCenter; - m_treeComputation = treeBfs; - m_childOrder = orderFixed; - - computeTree(G); - #ifdef OGDF_DEBUG - AG.colorNode(m_treeRoot) = "#0000CD"; - cout << "Treeroot is blue\n"; - #endif - - // determine root of tree (m_root) - m_root = m_treeRoot; - selectRoot(G); - #ifdef OGDF_DEBUG - AG.colorNode(m_root) = "#AA00AA"; - edge e; - forall_edges(e, G) - { - if ((*m_treeEdge)[e]) AG.colorEdge(e) = "#AA00AA"; - } - #endif - - computeRadii(AG); - - // computes m_angle[v] - computeAngles(G); - - // computes final coordinates of nodes - computeCoordinates(AG); -} - - -void BalloonLayout::selectRoot(const Graph &G) -//Todo: Vorgabewert durch user erlauben, firstNode? -{ - #ifdef OGDF_DEBUG - checkTree(G, true); - #endif - node v; - - switch(m_rootSelection) - { - - case BalloonLayout::rootHighestDegree: - { - int maxDeg = -1; - forall_nodes(v,G) - if(v->degree() > maxDeg) - { - m_root = v; - maxDeg = v->degree(); - } - } - break; - - case BalloonLayout::rootCenter: - { - NodeArray degree(G); - Queue leaves; - - if (G.numberOfNodes() == 1) - leaves.append(G.firstNode()); - else - forall_nodes(v,G) { - degree[v] = m_childCount[v]; - if (m_parent[v] != 0) degree[v]++; - if(degree[v] == 1) - leaves.append(v); - } - - while(!leaves.empty()) { - v = leaves.pop(); - - node p = m_parent[v]; - if (p != 0) - if (--degree[p] == 1) - leaves.append(p); - ListConstIterator it = m_childList[v].begin(); - while (it.valid()) - { - if (--degree[(*it)] == 1) - leaves.append((*it)); - it++; - } - }//while leaves - - - m_root = v; - //we swap the parent relationship on the path - //from m_treeRoot to m_root - - - //--------------- - node u = m_root; - v = 0; - while (u != 0) - { - node w = m_parent[u]; - m_parent[u] = v; - if (v != 0) - { - //may change the child order - m_childCount[v]++; - m_childList[v].pushBack(u); - }//if v - if (w != 0) - { - m_childCount[w]--; - ListIterator it = m_childList[w].begin(); - while (it.valid()) - { - if ((*it)==u) - { - m_childList[w].del(it); - break; - } - it++; - }//while children - }//if w - v = u; - u = w; - - }//while - - } - break; - default: {cout << BalloonLayout::rootCenter<<" "< level; - - switch (m_childOrder) - { - case orderOptimized: //todo - case orderFixed: - { - //compute radii in SNS model bottom up - //for leaves we use the smallest enclosing circle radius - //Using sqrt is quite slow, maybe an approximation will do - //r = 0.5*sqrt(w*w + h*h) - NodeArray children(G); - Queue leaves; - - if (G.numberOfNodes() > 1) - { - node v; - forall_nodes(v,G) { - if((children[v] = m_childCount[v]) == 0) - { - leaves.append(v); - m_oRadius[v] = m_size[v]; - } - }//forallnodes - //kann man wieder zusammenfassen mit unterer Schleife, - //da Berechnung geaendert - while(!leaves.empty()) { - v = leaves.pop(); - - node p = m_parent[v]; - - if (p != 0) - { - double t = m_oRadius[v]; - //we sum up the outer radius values here at - //the parent node to compute the estimate for - //the inner radius later - m_estimate[p] += t; - //set the value for the largest child radius - if (m_maxChildRadius[p] < t) - m_maxChildRadius[p] = t; - //if all children are processed, push p into queue - if (--children[p] == 0) - { - //we processed all children of p - //and can derive the radius value - level.append(p); - }//if children == 0 - }//if parent - //inner radius estimate - m_radius[v] = m_oRadius[v]; - //cout <<"Child-Radius: "<degree() <<" : "<degree() <<" : "< bfsqueue; - NodeArray marked(G, false); - - bfsqueue.pushBack(v); - - marked[v] = true; - - m_treeRoot = v; - - node w; - - while (!bfsqueue.empty()) - { - w = bfsqueue.popFrontRet(); - - edge e; - - forall_adj_edges(e, w) - { - node u = e->opposite(w); - if (!marked[u]) - { - m_parent[u] = w; - m_childCount[w]++; - bfsqueue.pushBack(u); - m_childList[w].pushBack(u); - - marked[u] = true; - #ifdef OGDF_DEBUG - (*m_treeEdge)[e] = true; - #endif - } - }//foralledges - }//while - #ifdef OGDF_DEBUG - checkTree(G, true); - #endif -}//computeBFSTree - -#ifdef OGDF_DEBUG -void BalloonLayout::checkTree(const Graph &G, bool treeRoot) -{ - //check the tree - //can each node be reached? - int testchecker = 0; - int listchecker = 0; - SListPure testqueue; - testqueue.pushBack((treeRoot ? m_treeRoot : m_root)); - while (!testqueue.empty()) - { - node z = testqueue.popFrontRet(); - testchecker++; - ListConstIterator it = m_childList[z].begin(); - while (it.valid() && (listchecker <= 2*G.numberOfNodes())) - { - listchecker++; - testqueue.pushBack((*it)); - it++; - }//while - }//while - if (G.numberOfNodes() != testchecker) - { - cout <<"Checktree: Nonodes"< queue; - queue.pushBack(v); - - while (!queue.empty()) - { - node p = queue.popFrontRet(); - - //process children - - if (m_childCount[p] > 0) - { - double anglesum = 0.0; - double pestimate = m_estimate[p]; //the circumference estimate of the parent - double fullAngle = 2.0*Math::pi; //angle that has to be shared by children - ListConstIterator it = m_childList[p].begin(); - if (m_childCount[p] == 1) - { - m_angle[(*it)] = Math::pi;//not used currently, fixed to parent angle - queue.pushBack((*it)); - #ifdef OGDF_DEBUG - checker++; - #endif - } - else - { - //The outer radius of ONE of the children may be larger - //than half of the estimate, but we never assign more than - //pi, therefore we have to make two runs to check and correct - //this. If the outer radius is more than half of the parent's - //estimate, we only assign pi - if (!m_evenAngles) - { - #ifdef OGDF_DEBUG - bool checkMulti = false; - #endif - ListConstIterator it2 = it; - while (it2.valid()) - { - if (m_oRadius[(*it2)]/m_estimate[p]>0.501) - { - #ifdef OGDF_DEBUG - if (checkMulti) - cout << "More than one large child vertex!\n"; - checkMulti = true; - #endif - pestimate = pestimate - m_oRadius[(*it2)]; - fullAngle = Math::pi; - #ifndef OGDF_DEBUG - break; - #endif - } - it2++; - } - } - while (it.valid()) - { - v = (*it); - it++; - - #ifdef OGDF_DEBUG - checker++; - #endif - - if (m_evenAngles) - { - m_angle[v] = Math::pi*2.0/m_childCount[p]; - queue.pushBack(v); - } - else - { - //erst alle Winkel aufaddieren und dann anteilig - //auf 2pi bzw. 100% - //m_angle[v] = anglesum; - - queue.pushBack(v); - - //Anteil an Plazierungsradius des Parent - //we use the diameter fraction of the estimate value - double ratio = m_oRadius[v]/m_estimate[p]; - //restrict vertices to at most half of the space, otherwise. - //there will be an overlap - if (ratio > 0.501) anglesum = Math::pi; - else anglesum = fullAngle*m_oRadius[v]/pestimate; - //cout<<"\nAnteil : "<Math::pi) cout << "Angle large than pi!!"<index()<<" "< queue; - queue.pushBack(v); - #ifdef OGDF_DEBUG - cout<<"Processing queue \n"; - //forall_nodes(v, G) - //{ - //cout<<"Angle "< 0) - { - //we start at the parent's angle and skip half of the angle - //of the last element - double anglesum = fmod(m_angle[p]-Math::pi+ - m_angle[*m_childList[p].begin()]/2.0, 2.0*Math::pi);//0.0; - //double sumchecker = 0.0;// debug value - //cout<<"Angle start offset: "< it = m_childList[p].begin(); - #ifdef OGDF_DEBUG - AG.colorNode(*it) = "#AB0007"; - #endif - //special case if only a single child: Same direction as parent - if (m_childCount[p] == 1) - { - node w = (*it); - queue.pushBack(w); - anglesum = m_angle[p]; - m_angle[w] = anglesum; - AG.x(w) = x+cos(anglesum)*m_radius[p]; - AG.y(w) = y+sin(anglesum)*m_radius[p]; -#ifdef OGDF_DEBUG - AG.colorNode(w) = "#00AB00"; -#endif - } - else - while (it.valid()) - { - //cout<<"Next child\n"; - node w = (*it); - queue.pushBack(w); - - it++; - - node z; - if (it.valid()) z = (*it); - else z = (*m_childList[p].begin()); - - //cout <degree()<<" Winkel: "< - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -//#define OUTPUT - -#include -#include -#include -#include -#include -#include -#include - - - -namespace ogdf { - -double angleNormalize(double alpha) -{ - while(alpha < 0) - alpha += 2*Math::pi; - - while(alpha >= 2*Math::pi) - alpha -= 2*Math::pi; - - return alpha; -} - -bool angleSmaller(double alpha, double beta) -{ - double alphaNorm = angleNormalize(alpha); - double betaNorm = angleNormalize(beta); - - double start = betaNorm-Math::pi; - - if(start >= 0) { - return start < alphaNorm && alphaNorm < betaNorm; - } else { - return alphaNorm < betaNorm || alphaNorm >= start+2*Math::pi; - } -} - -double angleDistance(double alpha, double beta) -{ - double alphaNorm = angleNormalize(alpha); - double betaNorm = angleNormalize(beta); - - double dist = alphaNorm - betaNorm; - if (dist < 0) dist += 2*Math::pi; - - return (dist <= Math::pi) ? dist : 2*Math::pi-dist; -} - - -void angleRangeAdapt(double sectorStart, double sectorEnd, double &start, double &length) -{ - double start1 = angleNormalize(sectorStart); - double end1 = angleNormalize(sectorEnd); - double start2 = angleNormalize(start); - double end2 = angleNormalize(start+length); - - if(end1 < start1) end1 += 2*Math::pi; - if(start2 < start1) start2 += 2*Math::pi; - if(end2 < start1) end2 += 2*Math::pi; - - if(start2 > end1) start = start1; - if(end2 > end1) start = angleNormalize(sectorEnd - length); -} - -struct ClusterStructure -{ - ClusterStructure(const Graph &G) : m_G(G), m_clusterOf(G) { } - - operator const Graph &() const { return m_G; } - - void initCluster(int nCluster, const Array &parent); - - void sortChildren(int i, - List &nodes, - Array > &posList, - Array &parentWeight, - Array &dirFromParent, - List > &mainSiteWeights); - - int numberOfCluster() const { return m_nodesIn.size(); } - - void resetNodes(int cluster, const List &nodes); - - const Graph &m_G; - Array > m_nodesIn; - NodeArray m_clusterOf; - List m_mainSiteCluster; - - Array m_parentCluster; - Array > m_childCluster; - - // undefined methods to avoid automatic creation - ClusterStructure(const ClusterStructure &); - ClusterStructure &operator=(const ClusterStructure &); -}; - - -void ClusterStructure::resetNodes(int cluster, const List &nodes) -{ - OGDF_ASSERT(m_nodesIn[cluster].size() == nodes.size()); - - SList &L = m_nodesIn[cluster]; - - L.clear(); - - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - L.pushBack(*it); -} - - -void ClusterStructure::initCluster(int nCluster, const Array &parent) -{ - m_nodesIn .init(nCluster); - m_parentCluster.init(nCluster); - m_childCluster .init(nCluster); - - node v; - forall_nodes(v,m_G) - m_nodesIn[m_clusterOf[v]].pushBack(v); - - int i; - for(i = 0; i < nCluster; ++i) { - m_parentCluster[i] = parent[i]; - if(parent[i] != -1) - m_childCluster[parent[i]].pushBack(i); - } -} - - -class WeightComparer -{ - typedef Tuple2 TheWeight; - static int compare(const TheWeight &x, const TheWeight &y) - { - if (x.x2() < y.x2()) return -1; - else if (x.x2() > y.x2()) return 1; - else return 0; - } - OGDF_AUGMENT_STATICCOMPARER(TheWeight) -}; - -void ClusterStructure::sortChildren( - int i, - List &nodes, - Array > &posList, - Array &parentWeight, - Array &dirFromParent, - List > &mainSiteWeights) -{ - const int n = nodes.size(); - const int parent = m_parentCluster[i]; - - if (parent != -1) - posList[parent].clear(); - - int pos = 0; - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - edge e; - forall_adj_edges(e,*it) { - node w = e->opposite(*it); - if (m_clusterOf[w] != i) - posList[m_clusterOf[w]].pushBack(pos); - } - pos++; - } - - List > weights; - - // build list of all adjacent clusters (children + parent) - List adjClusters = m_childCluster[i]; - if (parent != -1) - adjClusters.pushBack(parent); - - ListConstIterator itC; - for(itC = adjClusters.begin(); itC.valid(); ++itC) - { - int child = *itC; - - int size = posList[child].size(); - OGDF_ASSERT(size >= 1); - if(size == 1) { - weights.pushBack(Tuple2(child,posList[child].front())); - - } else { - // Achtung: Dieser Teil ist noch nicht richtig ausgetestet,da - // bei Bic.comp. immer nur ein Knoten benachbart ist - const List &L = posList[child]; - int gapEnd = L.front(); - int gapLength = L.front() - L.back() + n; - - int posPred = L.front(); - ListConstIterator it; - for(it = L.begin().succ(); it.valid(); ++it) { - if (*it - posPred > gapLength) { - gapEnd = *it; - gapLength = *it - posPred; - } - posPred = *it; - } - - int x = (n - gapEnd) % n; - - int sum = 0; - for(it = L.begin(); it.valid(); ++it) - sum += ((*it + x) % n); - - double w = double(sum)/double(size); - - w -= x; - if(w < 0) w += n; - - weights.pushBack(Tuple2(child,w)); - } - } - - WeightComparer weightComparer; - weights.quicksort(weightComparer); -#ifdef OUTPUT - cout << "weights after: " << weights << endl; -#endif - - m_childCluster[i].clear(); - ListConstIterator > itWeights; - - if(parent != -1) { - // find list element containing parent cluster - for(itWeights = weights.begin(); - (*itWeights).x1() != parent; - itWeights = weights.cyclicSucc(itWeights)) { } - - parentWeight[i] = (*itWeights).x2(); - for(itWeights = weights.cyclicSucc(itWeights); - (*itWeights).x1() != parent; - itWeights = weights.cyclicSucc(itWeights)) - { - m_childCluster[i].pushBack((*itWeights).x1()); - - if(m_nodesIn[i].size() == 1) - dirFromParent[(*itWeights).x1()] = Math::pi; - else { - double x = (*itWeights).x2() - parentWeight[i]; - if(x < 0) x += n; - dirFromParent[(*itWeights).x1()] = x/n*2*Math::pi; - } - } - - } else { - parentWeight[i] = 0; - for(itWeights = weights.begin(); itWeights.valid(); ++itWeights) - { - m_childCluster[i].pushBack((*itWeights).x1()); - - // not yet determined! - dirFromParent[(*itWeights).x1()] = -1; - } - mainSiteWeights = weights; - } -} - - -struct InfoAC -{ - node m_vBC, m_predCutBC, m_predCut; - int m_parentCluster; - - InfoAC(node vBC, node predCutBC, node predCut, int parentCluster) { - m_vBC = vBC; - m_predCutBC = predCutBC; - m_predCut = predCut; - m_parentCluster = parentCluster; - } -}; - - -class CircleGraph : public Graph -{ -public: - CircleGraph(const ClusterStructure &C, NodeArray &toCircle, int c); - - void order(List &nodes); - void swapping(List &nodes, int maxIterations); - - node fromCircle(node vCircle) const { return m_fromCircle[vCircle]; } - -private: - NodeArray m_fromCircle; - - void dfs( - NodeArray &depth, - NodeArray &father, - node v, - node f, - int d); -}; - - -CircleGraph::CircleGraph( - const ClusterStructure &C, - NodeArray &toCircle, - int c) -{ - m_fromCircle.init(*this); - - SListConstIterator it; - for(it = C.m_nodesIn[c].begin(); it.valid(); ++it) - { - node vCircle = newNode(); - toCircle [*it] = vCircle; - m_fromCircle[vCircle] = *it; - } - - for(it = C.m_nodesIn[c].begin(); it.valid(); ++it) - { - edge e; - forall_adj_edges(e,*it) { - node w = e->target(); - if (w == *it) continue; - - if(C.m_clusterOf[w] == c) - newEdge(toCircle[*it],toCircle[w]); - } - } -} - - -class DepthBucket : public BucketFunc -{ -public: - DepthBucket(const NodeArray &depth) : m_depth(depth) { } - - int getBucket(const node &v) - { - return -m_depth[v]; - } - - // undefined methods to avoid automatic creation - DepthBucket(const DepthBucket &); - DepthBucket &operator=(const DepthBucket &); - -private: - const NodeArray &m_depth; -}; - - -// Idee: Benutzung von outerplanarity (nachschlagen!) -void CircleGraph::order(List &nodes) -{ - NodeArray depth (*this,0); - NodeArray father (*this); - - dfs(depth, father, firstNode(), 0, 1); - - SListPure circleNodes; - allNodes(circleNodes); - - DepthBucket bucket(depth); - circleNodes.bucketSort(-numberOfNodes(),0,bucket); - - NodeArray visited(*this,false); - - ListIterator itCombined; - bool combinedAtRoot = false; - - SListConstIterator it; - for(it = circleNodes.begin(); it.valid(); ++it) - { - node v = *it; - List currentPath; - - ListIterator itInserted; - while(v != 0 && !visited[v]) - { - visited[v] = true; - itInserted = currentPath.pushBack(v); - v = father[v]; - } - - if(v && father[v] == 0 && !combinedAtRoot) { - combinedAtRoot = true; - - while(!currentPath.empty()) - currentPath.moveToSucc(currentPath.begin(),nodes,itCombined); - - } else { - if (v == 0) - itCombined = itInserted; - - nodes.conc(currentPath); - } - } -} - -void CircleGraph::dfs( - NodeArray &depth, - NodeArray &father, - node v, - node f, - int d) -{ - if (depth[v] != 0) - return; - - depth [v] = d; - father[v] = f; - - edge e; - forall_adj_edges(e,v) { - node w = e->opposite(v); - if(w == f) continue; - - dfs(depth,father,w,v,d+1); - } -} - - -void CircleGraph::swapping(List &nodes, int maxIterations) -{ - ListIterator it; - - if (nodes.size() >= 3) - { - NodeArray pos(*this); - const int n = numberOfNodes(); - - int currentPos = 0; - for(it = nodes.begin(); it.valid(); ++it) - pos[*it] = currentPos++; - - int iterations = 0; - bool improvement; - do { - improvement = false; - - for(it = nodes.begin(); it.valid(); ++it) - { - ListIterator itNext = nodes.cyclicSucc(it); - - node u = *it, v = *itNext; - // we fake a numbering around the circle starting with u at pos. 0 - // using the formula: (pos[t]-offset) % n - // and pos[u] + offset = n - int offset = n - pos[u]; - - // we count how many crossings we save when swapping u and v - int improvementCrosings = 0; - - edge ux; - forall_adj_edges(ux,u) { - node x = ux->opposite(u); - if(x == v) continue; - - int posX = (pos[x] + offset) % n; - - edge vy; - forall_adj_edges(vy,v) { - node y = vy->opposite(v); - if (y == u || y == x) continue; - - int posY = (pos[y] + offset) % n; - - if(posX > posY) - --improvementCrosings; - else - ++improvementCrosings; - } - } - - if(improvementCrosings > 0) { - improvement = true; - swap(*it,*itNext); - swap(pos[u],pos[v]); - } - } - } while(improvement && ++iterations <= maxIterations); - } - - for(it = nodes.begin(); it.valid(); ++it) - *it = m_fromCircle[*it]; -} - - - -//--------------------------------------------------------- -// Constructor -//--------------------------------------------------------- -CircularLayout::CircularLayout() -{ - // set options to defaults - m_minDistCircle = 20.0; - m_minDistLevel = 20.0; - m_minDistSibling = 10.0; - m_minDistCC = 20.0; - m_pageRatio = 1.0; -} - - -//--------------------------------------------------------- -// default call -// uses biconnected components as clusters -//--------------------------------------------------------- -void CircularLayout::call(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - if(G.empty()) - return; - - // all edges straight-line - AG.clearAllBends(); - - GraphCopy GC; - GC.createEmpty(G); - - // compute connected component of G - NodeArray component(G); - int numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - Array > nodesInCC(numCC); - - node v; - forall_nodes(v,G) - nodesInCC[component[v]].pushBack(v); - - EdgeArray auxCopy(G); - Array boundingBox(numCC); - - int i; - for(i = 0; i < numCC; ++i) - { - GC.initByNodes(nodesInCC[i],auxCopy); - - GraphCopyAttributes AGC(GC,AG); - - if(GC.numberOfNodes() == 1) - { - node v1 = GC.firstNode(); - AGC.x(v1) = AGC.y(v1) = 0; - - } else { - // partition nodes into clusters - // default uses biconnected components as cluster - ClusterStructure C(GC); - assignClustersByBiconnectedComponents(C); - - // call the actual layout algorithm with predefined clusters - doCall(AGC,C); - } - - node vFirst = GC.firstNode(); - double minX = AGC.x(vFirst), maxX = AGC.x(vFirst), - minY = AGC.y(vFirst), maxY = AGC.y(vFirst); - - node vCopy; - forall_nodes(vCopy,GC) { - node v = GC.original(vCopy); - AG.x(v) = AGC.x(vCopy); - AG.y(v) = AGC.y(vCopy); - - if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; - if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; - if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; - if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; - } - - minX -= m_minDistCC; - minY -= m_minDistCC; - - forall_nodes(vCopy,GC) { - node v = GC.original(vCopy); - AG.x(v) -= minX; - AG.y(v) -= minY; - } - - boundingBox[i] = DPoint(maxX - minX, maxY - minY); - } - - Array offset(numCC); - TileToRowsCCPacker packer; - packer.call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node and edge by the offset - // of its connected component. - - for(i = 0; i < numCC; ++i) - { - const List &nodes = nodesInCC[i]; - - const double dx = offset[i].m_x; - const double dy = offset[i].m_y; - - // iterate over all nodes in ith CC - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - AG.x(v) += dx; - AG.y(v) += dy; - } - } -} - - -struct QueuedCirclePosition -{ - int m_cluster; - double m_minDist; - double m_sectorStart, m_sectorEnd; - - QueuedCirclePosition(int cluster, - double minDist, - double sectorStart, - double sectorEnd) - { - m_cluster = cluster; - m_minDist = minDist; - m_sectorStart = sectorStart; - m_sectorEnd = sectorEnd; - } -}; - -struct ClusterRegion -{ - ClusterRegion(int c, double start, double length, double scaleFactor = 1.0) - { - m_start = start; - m_length = length; - m_scaleFactor = scaleFactor; - m_clusters.pushBack(c); - } - - double m_start, m_length, m_scaleFactor; - SList m_clusters; -}; - - -struct SuperCluster -{ - SuperCluster(SList &cluster, - double direction, - double length, - double scaleFactor = 1.0) - { - m_direction = direction; - m_length = length; - m_scaleFactor = scaleFactor; - m_cluster.conc(cluster); // cluster is emtpy afterwards! - } - - double m_direction, m_length, m_scaleFactor; - SList m_cluster; -}; - - -typedef SuperCluster *PtrSuperCluster; -ostream &operator<<(ostream &os, const PtrSuperCluster &sc) -{ - const double fac = 180 / Math::pi; - - os << "{" << fac*sc->m_direction << "," << fac*sc->m_length << "," << sc->m_scaleFactor << ":" << sc->m_cluster << "}"; - return os; -} - - -struct SCRegion -{ - SCRegion(SuperCluster &sc) { - m_length = sc.m_scaleFactor*sc.m_length; - m_start = angleNormalize(sc.m_direction - m_length/2); - m_superClusters.pushBack(&sc); - } - - double m_start, m_length; - SList m_superClusters; -}; - -void outputRegions(List ®ions) -{ - const double fac = 180 / Math::pi; - - cout << "regions:\n"; - ListIterator it; - for(it = regions.begin(); it.valid(); ++it) - { - cout << "[" << (*it).m_superClusters << ", " << - fac*(*it).m_start << ", " << fac*(*it).m_length << "]" << endl; - } -} - - -//--------------------------------------------------------- -// call for predefined clusters -// performs the actual layout algorithm -//--------------------------------------------------------- -void CircularLayout::doCall(GraphCopyAttributes &AG, ClusterStructure &C) -{ - // we consider currently only the case that we have a single main-site cluster - OGDF_ASSERT(C.m_mainSiteCluster.size() == 1); - - // compute radii of clusters - const int nCluster = C.numberOfCluster(); - Array radius (nCluster); - Array outerRadius(nCluster); - -#ifdef OUTPUT - const double fac = 360/(2*Math::pi); -#endif - - int i; - for(i = 0; i < nCluster; ++i) - { - const int n = C.m_nodesIn[i].size(); - - double sumDiameters = 0, maxR = 0; - SListConstIterator it; - for(it = C.m_nodesIn[i].begin(); it.valid(); ++it) { - double d = sqrt( - AG.getWidth(*it) * AG.getWidth(*it) + AG.getHeight(*it) * AG.getHeight(*it)); - sumDiameters += d; - if (d/2 > maxR) maxR = d/2; - } - - if(n == 1) { - radius [i] = 0; - outerRadius[i] = maxR; - - } else if (n == 2) { - radius [i] = 0.5*m_minDistCircle + sumDiameters / 4; - outerRadius[i] = 0.5*m_minDistCircle + sumDiameters / 2; - - } else { - radius [i] = (n*m_minDistCircle + sumDiameters) / (2*Math::pi); - outerRadius[i] = radius[i] + maxR; - } - -#ifdef OUTPUT - cout << "radius of " << i << " = " << radius[i] << endl; - cout << "outer radius of " << i << " = " << outerRadius[i] << endl; -#endif - } - - - int mainSite = C.m_mainSiteCluster.front(); - - NodeArray toCircle(C); - - Queue queue; - queue.append(mainSite); - - Array > posList (nCluster); - Array parentWeight (nCluster); - Array dirFromParent(nCluster); - List > mainSiteWeights; - - while(!queue.empty()) - { - int cluster = queue.pop(); - - CircleGraph GC(C, toCircle, cluster); - - // order nodes on circle - List nodes; - GC.order(nodes); - GC.swapping(nodes,50); - C.resetNodes(cluster, nodes); -#ifdef OUTPUT - cout << "after swapping of " << cluster << ": " << nodes << endl; -#endif - - C.sortChildren(cluster,nodes,posList,parentWeight,dirFromParent,mainSiteWeights); -#ifdef OUTPUT - cout << "child cluster of " << cluster << ": " << C.m_childCluster[cluster] << endl; -#endif - - // append all children of cluster to queue - ListConstIterator itC; - for(itC = C.m_childCluster[cluster].begin(); itC.valid(); ++itC) - queue.append(*itC); - } - - // compute positions of circles - Array preferedAngle(nCluster); - Array preferedDirection(nCluster); - computePreferedAngles(C,outerRadius,preferedAngle); - - Array circleDistance(nCluster); - Array circleAngle(nCluster); - - circleDistance[mainSite] = 0; - circleAngle[mainSite] = 0; - - Queue circleQueue; - // sectors are assigned to children weighted by the prefered angles - double sumPrefAngles = 0; - double sumChildrenLength = 0; - ListConstIterator itC; - for(itC = C.m_childCluster[mainSite].begin(); itC.valid(); ++itC) { - sumPrefAngles += preferedAngle[*itC]; - sumChildrenLength += 2*outerRadius[*itC]+m_minDistSibling; - } - - // estimation for distance of child cluster - double rFromMainSite = max(m_minDistLevel+outerRadius[mainSite], - sumChildrenLength / (2 * Math::pi)); - // estiamtion for maximal allowed angle (which is 2*maxHalfAngle) - double maxHalfAngle = acos(outerRadius[mainSite] / rFromMainSite); - - // assignment of angles around main-site with pendulum method ------- - - // initialisation - double minDist = outerRadius[mainSite] + m_minDistLevel; - List superClusters; - List regions; - //Array scaleFactor(nCluster); - ListConstIterator > it; - for(it = mainSiteWeights.begin(); it.valid(); ) - { - double currentWeight = (*it).x2(); - double currentDirection = currentWeight*2*Math::pi/C.m_nodesIn[mainSite].size(); - double sumLength = 0; - SList currentClusters; - - do { - int child = (*it).x1(); - //double weight = (*it).x2(); - - preferedDirection[child] = currentDirection; - currentClusters.pushBack(child); - sumLength += preferedAngle[child]; - - ++it; - } while (it.valid() && (*it).x2() == currentWeight); - - ListIterator itSC = superClusters.pushBack( - SuperCluster(currentClusters,currentDirection,sumLength, - (sumLength <= 2*maxHalfAngle) ? 1.0 : 2*maxHalfAngle/sumLength)); - - regions.pushBack(SCRegion(*itSC)); - } - -#ifdef OUTPUT - outputRegions(regions); -#endif - - // merging of regions - bool changed; - do { - changed = false; - - ListIterator itR1, itR2, itR3, itRNext; - for(itR1 = regions.begin(); itR1.valid() && regions.size() >= 2; itR1 = itRNext) - { - itRNext = itR1.succ(); - - itR2 = itR1.succ(); - bool finish = !itR2.valid(); - bool doMerge = false; - - if(!itR2.valid()) { - itR2 = regions.begin(); - double alpha = angleNormalize((*itR1).m_start + 2*Math::pi); - double beta = angleNormalize((*itR2).m_start); - double dist = beta - alpha; - if (dist < 0) dist += 2*Math::pi; - double dx = (*itR1).m_length - dist; - doMerge = dx > DBL_EPSILON; - //doMerge = dist < (*itR1).m_length; - - } else { - double alpha = angleNormalize((*itR1).m_start); - double beta = angleNormalize((*itR2).m_start); - double dist = beta - alpha; - if (dist < 0) dist += 2*Math::pi; - double dx = (*itR1).m_length - dist; - doMerge = dx > DBL_EPSILON; - //doMerge = dist < (*itR1).m_length; - } - - if(!doMerge) continue; - - do { - (*itR1).m_superClusters.conc((*itR2).m_superClusters); - - if(finish) { - regions.del(itR2); - break; - } - - itR3 = itR2.succ(); - finish = !itR3.valid(); - doMerge = false; - - if(!itR3.valid()) { - itR3 = regions.begin(); - double beta = angleNormalize((*itR3).m_start + 2*Math::pi); - double alpha = angleNormalize((*itR2).m_start); - double dist = beta - alpha; - if (dist < 0) dist += 2*Math::pi; - double dx = (*itR2).m_length - dist; - doMerge = dx > DBL_EPSILON; - //doMerge = dist < (*itR2).m_length; - - } else { - double beta = angleNormalize((*itR3).m_start); - double alpha = angleNormalize((*itR2).m_start); - double dist = beta - alpha; - if (dist < 0) dist += 2*Math::pi; - double dx = (*itR2).m_length - dist; - doMerge = dx > DBL_EPSILON; - //doMerge = dist < (*itR2).m_length; - } - - itRNext = itR2.succ(); - regions.del(itR2); - - itR2 = itR3; - - } while(regions.size() >= 2 && doMerge); - - double sectorStart = 0, sectorEnd, sectorLength = 0; - bool singleRegion = false; - if(regions.size() == 1) { - sectorLength = 2*Math::pi; - singleRegion = true; - } else { - sectorEnd = angleNormalize((*regions.cyclicSucc(itR1)).m_start); - ListIterator itPred = regions.cyclicPred(itR1); - sectorStart = angleNormalize((*itPred).m_start + (*itPred).m_length); - sectorLength = sectorEnd - sectorStart; - if(sectorLength < 0) sectorLength += 2*Math::pi; - } - - changed = true; - //compute deflection of R1 - double sumLength = 0, maxGap = -1; - SListConstIterator it, itStartRegion; - const SList &superClustersR1 = (*itR1).m_superClusters; - for(it = superClustersR1.begin(); it.valid(); ++it) - { - sumLength += (*it)->m_length; - - SListConstIterator itSucc = superClustersR1.cyclicSucc(it); - double gap = (*itSucc)->m_direction - (*it)->m_direction; - if (gap < 0) gap += 2*Math::pi; - if(gap > maxGap) { - maxGap = gap; itStartRegion = itSucc; - } - } - - // compute scaling - double scaleFactor = (sumLength <= sectorLength) ? 1 : sectorLength/sumLength; - - double sumWAngles = 0; - double sumDef = 0; - (*itR1).m_start = (*itStartRegion)->m_direction - scaleFactor * (*itStartRegion)->m_length/2; - double posStart = (*itR1).m_start; - it = itStartRegion; - do - { - double currentLength = scaleFactor * (*it)->m_length; - sumDef += angleDistance((*it)->m_direction, posStart + currentLength/2); - posStart += currentLength; - - double currentPos = (*it)->m_direction; - if (currentPos < (*itR1).m_start) - currentPos += 2*Math::pi; - sumWAngles += (*it)->m_length * currentPos; - - it = superClustersR1.cyclicSucc(it); - } while(it != itStartRegion); - - double deflection = sumDef / (*itR1).m_superClusters.size(); - while(deflection < -Math::pi) deflection += 2*Math::pi; - while(deflection > Math::pi) deflection -= 2*Math::pi; - - (*itR1).m_start += deflection; - - double center = sumWAngles / sumLength; - while(center < 0 ) center += 2*Math::pi; - while(center > 2*Math::pi) center -= 2*Math::pi; - - double tmpScaleFactor = scaleFactor; - double left = center - tmpScaleFactor*sumLength/2; - for(it = (*itR1).m_superClusters.begin(); it.valid(); ++it) - { - if(left < center) { - double minLeft = (*it)->m_direction-maxHalfAngle; - if(angleSmaller(left, minLeft)) { - scaleFactor = min(scaleFactor, - tmpScaleFactor * angleDistance(minLeft,center) / angleDistance(left,center)); - } - OGDF_ASSERT(scaleFactor > 0); - } - - double right = left + tmpScaleFactor*(*it)->m_length; - - if(right > center) { - double maxRight = (*it)->m_direction+maxHalfAngle; - if(angleSmaller(maxRight, right)) { - scaleFactor = min(scaleFactor, - tmpScaleFactor * angleDistance(maxRight,center) / angleDistance(right,center)); - } - OGDF_ASSERT(scaleFactor > 0); - } - - double currentLength = right-left; - if(currentLength < 0) currentLength += 2*Math::pi; - if(currentLength > 2*maxHalfAngle) - scaleFactor = min(scaleFactor, 2*maxHalfAngle/currentLength); - - left = right; - } - - OGDF_ASSERT(scaleFactor > 0); - - // set scale factor for all super clusters in region - if(!singleRegion) itStartRegion = superClustersR1.begin(); - ListIterator itFirst; - it = itStartRegion; - do - { - (*it)->m_scaleFactor = scaleFactor; - - // build new region for each super-cluster in R1 - ListIterator itInserted = - regions.insertBefore(SCRegion(*(*it)),itR1); - - if(!singleRegion) { - angleRangeAdapt(sectorStart, sectorEnd, - (*itInserted).m_start, (*itInserted).m_length); - } - - (*itInserted).m_start = angleNormalize((*itInserted).m_start); - - if(!itFirst.valid()) - itFirst = itInserted; - - it = superClustersR1.cyclicSucc(it); - } while(it != itStartRegion); - - // merge regions - bool changedInternal; - do { - changedInternal = false; - - ListIterator itA = (singleRegion) ? regions.begin() : itFirst,itB; - bool finished = false; - itB = itA.succ(); - for( ; ; ) - { - if(itB == itR1) { - if(singleRegion) { - itB = regions.begin(); - if (itA == itB) break; - finished = true; - } else break; - } - - if(angleSmaller((*itB).m_start, (*itA).m_start + (*itA).m_length)) - { - (*itA).m_superClusters.conc((*itB).m_superClusters); - (*itA).m_length += (*itB).m_length; - - //compute deflection of RA - double sumDef = 0; - double posStart = (*itA).m_start; - SListConstIterator it; - for(it = (*itA).m_superClusters.begin(); it.valid(); ++it) { - double currentDef = (*it)->m_direction - (posStart + (*it)->m_scaleFactor * (*it)->m_length/2); - if(currentDef > Math::pi) currentDef -= 2*Math::pi; - if(currentDef < -Math::pi) currentDef += 2*Math::pi; - sumDef += currentDef; //(*it)->m_direction - (posStart + (*it)->m_length/2); - posStart += (*it)->m_length * (*it)->m_scaleFactor; - } - double deflection = sumDef / (*itA).m_superClusters.size(); - (*itA).m_start += deflection; - (*itA).m_start = angleNormalize((*itA).m_start); - - if(!singleRegion) { - angleRangeAdapt(sectorStart, sectorEnd, - (*itA).m_start, (*itA).m_length); - } - - (*itA).m_start = angleNormalize((*itA).m_start); - - regions.del(itB); - changedInternal = true; - - } else { - itA = itB; - } - - if(finished) break; - - itB = itA.succ(); - } - } while(changedInternal); - - regions.del(itR1); - -#ifdef OUTPUT - outputRegions(regions); -#endif - } - } while(changed); - -/* ListIterator itR1 = regions.begin(),itR2; - for(itR2 = itR1.succ(); true; itR2 = itR1.succ()) - { - if(regions.size() == 1) - break; - - bool finish = !itR2.valid(); - bool doMerge = false; - - if(!itR2.valid()) { - itR2 = regions.begin(); - doMerge = (*itR2).m_start + 2*Math::pi < (*itR1).m_start + (*itR1).m_length; - } else - doMerge = (*itR2).m_start < (*itR1).m_start + (*itR1).m_length; - - if (doMerge) - { - (*itR1).m_clusters.conc((*itR2).m_clusters); - //(*itR1).m_length += (*itR2).m_length; // sp?ter bestimmen - - //compute deflection of R1 - double sumPrefAngles = 0; - double sumDef = 0; - double posStart = (*itR1).m_start; - SListConstIterator it; - for(it = (*itR1).m_clusters.begin(); it.valid(); ++it) - { - sumPrefAngles += preferedAngle[*it]; - sumDef += preferedDirection[*it] - (posStart + preferedAngle[*it]/2); - posStart += preferedAngle[*it]; - } - double deflection = sumDef / (*itR1).m_clusters.size(); - (*itR1).m_start += deflection; - - regions.del(itR2); - changed = true; - - // compute scaling - double scaleFactor = (sumPrefAngles <= 2*Math::pi) ? 1 : 2*Math::pi/sumPrefAngles; - double left = (*itR1).m_start; - double center = left + sumPrefAngles/2; - for(it = (*itR1).m_clusters.begin(); it.valid(); ++it) - { - double minLeft = preferedDirection[*it]-maxHalfAngle; - - if(left < minLeft) { - scaleFactor = - (preferedDirection[*it]-maxHalfAngle-center)/(left-center); - } - - left += preferedAngle[*it]; // "left" is now "right" for this cluster - - double maxRight = preferedDirection[*it]+maxHalfAngle; - if(maxRight < left) { - scaleFactor = - (preferedDirection[*it]+maxHalfAngle-center)/(left-center); - } - } - - (*itR1).m_length = scaleFactor * sumPrefAngles; - (*itR1).m_start = center - (*itR1).m_length / 2; - (*itR1).m_scaleFactor = scaleFactor; - if((*itR1).m_start > 2*Math::pi) - (*itR1).m_start -= 2*Math::pi; - -#ifdef OUTPUT - outputRegions(regions); -#endif - - - } else { - itR1 = itR2; - } - - if(finish) break; - } - } while(changed); -*/ - ListIterator itR; - //double minDist = outerRadius[mainSite] + m_minDistLevel; - //double sectorEnd = posStart+2*Math::pi; - for(itR = regions.begin(); itR.valid(); ++itR) - { - double posStart = (*itR).m_start; - - SListConstIterator itSC; - for(itSC = (*itR).m_superClusters.begin(); itSC.valid(); ++itSC) - { - double scaleFactor = (*itSC)->m_scaleFactor; - - SListConstIterator it; - for(it = (*itSC)->m_cluster.begin(); it.valid(); ++it) - { - double length = scaleFactor * preferedAngle[*it]; - - circleAngle[*it] = posStart + length/2; - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,posStart+length)); - - posStart += length; - } - } - } - -/* double posRegionEnd = R1.m_start; - - SListConstIterator it; - for(it = R1.m_clusters.begin(); it.valid(); ++it) - { - posRegionEnd += R1.m_scaleFactor*preferedAngle[*it]; - if(it != R1.m_clusters.rbegin()) - { - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,posRegionEnd)); - circleAngle[*it] = posRegionEnd - R1.m_scaleFactor*preferedAngle[*it]/2; - - posStart = posRegionEnd; - - } else { - itR2 = itR1.succ(); - circleAngle[*it] = posRegionEnd - R1.m_scaleFactor*preferedAngle[*it]/2; - - if(itR2.valid()) { - double gap = (*itR2).m_start - posRegionEnd; - posRegionEnd += gap * R1.m_scaleFactor*preferedAngle[*it] / - (R1.m_scaleFactor*preferedAngle[*it] + (*itR2).m_scaleFactor*preferedAngle[(*itR2).m_clusters.front()]); - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,posRegionEnd)); - posStart = posRegionEnd; - } else { - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,sectorEnd)); - } - } - } - }*/ - // end of pendulum method ------------------------------------------- - - - /*double completeAngle = 2 * Math::pi; - double angle = 0; - //double minDist = outerRadius[mainSite] + m_minDistLevel;// - //ListConstIterator > it;// - double sum = 0; - for(it = mainSiteWeights.begin(); it.valid(); ++it) - { - int child = (*it).x1(); - double weight = (*it).x2(); - - double delta = completeAngle * preferedAngle[child] / sumPrefAngles; - - //double gammaC = angle+delta/2 - weight*2*Math::pi/C.m_nodesIn[mainSite].size(); - double gammaC = circleAngle[child] - weight*2*Math::pi/C.m_nodesIn[mainSite].size(); - - sum += gammaC; - - //circleAngle[child] = angle + delta/2;// - //circleQueue.append(QueuedCirclePosition(child,minDist,angle,angle+delta));// - ////circleQueue.append(QueuedCirclePosition(child,minDist, - //// circleAngle[child]-realDelta/2,circleAngle[child]+realDelta/2)); - angle += delta; - } - - double gammaMainSite = (mainSiteWeights.size() == 0) ? 0 : sum / mainSiteWeights.size(); - if(gammaMainSite < 0) gammaMainSite += 2*Math::pi;*/ - double gammaMainSite = 0; - - while(!circleQueue.empty()) - { - QueuedCirclePosition qcp = circleQueue.pop(); - int cluster = qcp.m_cluster; - -#ifdef OUTPUT - cout << "cluster = " << cluster << ", start = " << fac*qcp.m_sectorStart << - ", end = " << fac*qcp.m_sectorEnd << endl; - cout << " minDist = " << qcp.m_minDist << - ", angle = " << fac*circleAngle[cluster] << endl; -#endif - - double delta = qcp.m_sectorEnd - qcp.m_sectorStart; - if (delta >= Math::pi) - //if (delta <= Math::pi) - { - circleDistance[cluster] = qcp.m_minDist + outerRadius[cluster]; - - } else { - double rMin = (outerRadius[cluster] + m_minDistSibling/2) / - (sin(delta/2)); - - circleDistance[cluster] = max(rMin,qcp.m_minDist+outerRadius[cluster]); - } - - if(C.m_childCluster[cluster].empty()) - continue; - - minDist = circleDistance[cluster] + outerRadius[cluster] + m_minDistLevel; - /*double alpha = acos((circleDistance[cluster]-outerRadius[cluster])/minDist); - - if(circleAngle[cluster]-alpha > qcp.m_sectorStart) - qcp.m_sectorStart = circleAngle[cluster]-alpha; - if(circleAngle[cluster]+alpha < qcp.m_sectorEnd) - qcp.m_sectorEnd = circleAngle[cluster]+alpha;*/ - delta = qcp.m_sectorEnd - qcp.m_sectorStart; - - sumPrefAngles = 0; - for(itC = C.m_childCluster[cluster].begin(); itC.valid(); ++itC) - { - sumPrefAngles += preferedAngle[*itC]; - - // computing prefered directions - double r = circleDistance[cluster]; - double a = minDist + outerRadius[*itC]; - double gamma = dirFromParent[*itC]; - -#ifdef OUTPUT - cout << " gamma of " << *itC << " = " << gamma/(2*Math::pi)*360 << endl; -#endif - if(gamma <= Math::pi/2) - preferedDirection[*itC] = qcp.m_sectorStart; - else if(gamma >= 3*Math::pi/2) - preferedDirection[*itC] = qcp.m_sectorEnd; - //else if(gamma == Math::pi) // Achtung! nicht Gleichheit ohne Toleranz testen! - else if(DIsEqual(gamma,Math::pi)) - preferedDirection[*itC] = circleAngle[cluster]; - else { - double gamma2 = (gamma < Math::pi) ? Math::pi - gamma : gamma - Math::pi; - double K = 1 + 1 /(tan(gamma2)*tan(gamma2)); - double C = r/(a*tan(gamma2))/K; - double C2 = sqrt((1-(r/a)*(r/a))/K + C*C); - - double beta = asin(C2-C); - if (gamma < Math::pi) - preferedDirection[*itC] = circleAngle[cluster]-beta; - else - preferedDirection[*itC] = circleAngle[cluster]+beta; - } -#ifdef OUTPUT - cout << " dir. of " << *itC << ": " << fac*preferedDirection[*itC] << endl; -#endif - } - - if(sumPrefAngles >= delta) - { - double angle = qcp.m_sectorStart; - for(itC = C.m_childCluster[cluster].begin(); itC.valid(); ++itC) - { - double deltaChild = delta * preferedAngle[*itC] / sumPrefAngles; - - circleAngle[*itC] = angle + deltaChild/2; - circleQueue.append(QueuedCirclePosition(*itC,minDist,angle,angle+deltaChild)); - angle += deltaChild; - } - - } else { - List regions; - for(itC = C.m_childCluster[cluster].begin(); itC.valid(); ++itC) - { - double start = preferedDirection[*itC]-preferedAngle[*itC]/2; - double length = preferedAngle[*itC]; - - if(start < qcp.m_sectorStart) - start = qcp.m_sectorStart; - if(start + length > qcp.m_sectorEnd) - start = qcp.m_sectorEnd - length; - - regions.pushBack(ClusterRegion(*itC,start,length)); - } - - bool changed; - do { - changed = false; - - ListIterator itR1 = regions.begin(),itR2; - for(itR2 = itR1.succ(); itR2.valid(); itR2 = itR1.succ()) - { - if((*itR2).m_start < (*itR1).m_start + (*itR1).m_length) - { - (*itR1).m_clusters.conc((*itR2).m_clusters); - (*itR1).m_length += (*itR2).m_length; - - //compute deflection of R1 - double sumDef = 0; - double posStart = (*itR1).m_start; - SListConstIterator it; - for(it = (*itR1).m_clusters.begin(); it.valid(); ++it) { - sumDef += preferedDirection[*it] - (posStart + preferedAngle[*it]/2); - posStart += preferedAngle[*it]; - } - double deflection = sumDef / (*itR1).m_clusters.size(); - (*itR1).m_start += deflection; - - if((*itR1).m_start < qcp.m_sectorStart) - (*itR1).m_start = qcp.m_sectorStart; - if((*itR1).m_start + (*itR1).m_length > qcp.m_sectorEnd) - (*itR1).m_start = qcp.m_sectorEnd - (*itR1).m_length; - - regions.del(itR2); - changed = true; - - } else { - itR1 = itR2; - } - } - } while(changed); - - double posStart = qcp.m_sectorStart; - ListIterator itR1, itR2; - for(itR1 = regions.begin(); itR1.valid(); itR1 = itR2) - { - const ClusterRegion &R1 = *itR1; - - double posRegionEnd = R1.m_start; - SListConstIterator it; - for(it = R1.m_clusters.begin(); it.valid(); ++it) - { - posRegionEnd += preferedAngle[*it]; - if(it != R1.m_clusters.rbegin()) - { - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,posRegionEnd)); - circleAngle[*it] = posRegionEnd - preferedAngle[*it]/2; - - posStart = posRegionEnd; - - } else { - itR2 = itR1.succ(); - circleAngle[*it] = posRegionEnd - preferedAngle[*it]/2; - if(itR2.valid()) { - double gap = (*itR2).m_start - posRegionEnd; - posRegionEnd += gap * preferedAngle[*it] / - (preferedAngle[*it] + preferedAngle[(*itR2).m_clusters.front()]); - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,posRegionEnd)); - posStart = posRegionEnd; - } else { - circleQueue.append(QueuedCirclePosition( - *it,minDist,posStart,qcp.m_sectorEnd)); - } - } - } - } - } - } - -#ifdef OUTPUT - cout << "\ncircle positions:\n"; -#endif - for(i = 0; i < nCluster; ++i) { -#ifdef OUTPUT - cout << i << ": dist \t" << circleDistance[i] << endl; - cout << " angle \t" << circleAngle[i] << endl; -#endif - - // determine gamma and M - double mX, mY, gamma; - - if(i == mainSite) - { - mX = 0; - mY = 0; - gamma = gammaMainSite; - - } else { - double alpha = circleAngle[i]; - if(alpha <= Math::pi/2) { - // upper left - double beta = Math::pi/2 - alpha; - mX = -circleDistance[i] * cos(beta); - mY = circleDistance[i] * sin(beta); - gamma = 1.5*Math::pi - beta; - - } else if(alpha <= Math::pi) { - // lower left - double beta = alpha - Math::pi/2; - mX = -circleDistance[i] * cos(beta); - mY = -circleDistance[i] * sin(beta); - gamma = 1.5*Math::pi + beta; - - } else if(alpha <= 1.5*Math::pi) { - // lower right - double beta = 1.5*Math::pi - alpha; - mX = circleDistance[i] * cos(beta); - mY = -circleDistance[i] * sin(beta); - gamma = Math::pi/2 - beta; - - } else { - // upper right - double beta = alpha - 1.5*Math::pi; - mX = circleDistance[i] * cos(beta); - mY = circleDistance[i] * sin(beta); - gamma = Math::pi/2 + beta; - } - } - - const int n = C.m_nodesIn[i].size(); - int pos = 0; - SListConstIterator itV; - for(itV = C.m_nodesIn[i].begin(); itV.valid(); ++itV, ++pos) - { - node v = *itV; - - double phi = pos - parentWeight[i]; - if(phi < 0) phi += n; - - phi = phi * 2*Math::pi/n + gamma; - if(phi >= 2*Math::pi) phi -= 2*Math::pi; - - double x, y; - if(phi <= Math::pi/2) { - // upper left - double beta = Math::pi/2 - phi; - x = -radius[i] * cos(beta); - y = radius[i] * sin(beta); - - } else if(phi <= Math::pi) { - // lower left - double beta = phi - Math::pi/2; - x = -radius[i] * cos(beta); - y = -radius[i] * sin(beta); - - } else if(phi <= 1.5*Math::pi) { - // lower right - double beta = 1.5*Math::pi - phi; - x = radius[i] * cos(beta); - y = -radius[i] * sin(beta); - - } else { - // upper right - double beta = phi - 1.5*Math::pi; - x = radius[i] * cos(beta); - y = radius[i] * sin(beta); - } - - AG.x(v) = x + mX; - // minus sign only for debugging! - AG.y(v) = -(y + mY); - } - } - -} - - -void CircularLayout::computePreferedAngles( - ClusterStructure &C, - const Array &outerRadius, - Array &preferedAngle) -{ - const int nCluster = C.numberOfCluster(); - const int mainSite = C.m_mainSiteCluster.front(); - - Array level(nCluster); - Queue Q; - - level[mainSite] = 0; - Q.append(mainSite); - - int nLevel = 0; - while(!Q.empty()) - { - int c = Q.pop(); - - nLevel = level[c]+1; - ListConstIterator it; - for(it = C.m_childCluster[c].begin(); it.valid(); ++it) { - level[*it] = nLevel; - Q.append(*it); - } - } - - ListConstIterator it; - for(it = C.m_childCluster[mainSite].begin(); it.valid(); ++it) - assignPrefAngle(C,outerRadius,preferedAngle, - *it,1,outerRadius[mainSite]+m_minDistLevel); - -#ifdef OUTPUT - cout << "\nprefered angles:" << endl; - for(int i = 0; i < nCluster; ++i) - cout << i << ": " << 360*preferedAngle[i]/(2*Math::pi) << endl; -#endif -} - -void CircularLayout::assignPrefAngle(ClusterStructure &C, - const Array &outerRadius, - Array &preferedAngle, - int c, - int l, - double r1) -{ - double maxPrefChild = 0; - - ListConstIterator it; - for(it = C.m_childCluster[c].begin(); it.valid(); ++it) { - assignPrefAngle(C,outerRadius,preferedAngle, - *it,l+1,r1 + m_minDistLevel + 2*outerRadius[c]); - /*if(preferedAngle[*it] > maxPrefChild) - maxPrefChild = preferedAngle[*it];*/ - maxPrefChild += preferedAngle[*it]; - } - - double rc = r1 + outerRadius[c]; - //preferedAngle[c] = max((2*outerRadius[c] + m_minDistSibling) / rc, maxPrefChild); - preferedAngle[c] = max(2*asin((outerRadius[c] + m_minDistSibling/2)/rc), maxPrefChild); -} - - -//--------------------------------------------------------- -// assigns the biconnected components of the graph as clusters -//--------------------------------------------------------- -void CircularLayout::assignClustersByBiconnectedComponents(ClusterStructure &C) -{ - const Graph &G = C; - - //--------------------------------------------------------- - // compute biconnected components - EdgeArray compnum(G); - int k = biconnectedComponents(G,compnum); - - - //--------------------------------------------------------- - // compute BC-tree - // - // better: proved a general class BCTree with the functionality - // - NodeArray > compV(G); - Array > nodeB(k); - - // edgeB[i] = list of edges in component i - Array > edgeB(k); - edge e; - forall_edges(e,G) - if(!e->isSelfLoop()) - edgeB[compnum[e]].pushBack(e); - - // construct arrays compV and nodeB such that - // compV[v] = list of components containing v - // nodeB[i] = list of vertices in component i - NodeArray mark(G,false); - - int i; - for(i = 0; i < k; ++i) { - SListConstIterator itEdge; - for(itEdge = edgeB[i].begin(); itEdge.valid(); ++itEdge) - { - edge e = *itEdge; - - if (!mark[e->source()]) { - mark[e->source()] = true; - nodeB[i].pushBack(e->source()); - } - if (!mark[e->target()]) { - mark[e->target()] = true; - nodeB[i].pushBack(e->target()); - } - } - - SListConstIterator itNode; - for(itNode = nodeB[i].begin(); itNode.valid(); ++itNode) - { - node v = *itNode; - compV[v].pushBack(i); - mark[v] = false; - } - } - mark.init(); - - Graph BCTree; - NodeArray componentOf(BCTree,-1); - NodeArray cutVertexOf(BCTree,0); - Array nodeOf(k); - - for(i = 0; i < k; ++i) { - node vBC = BCTree.newNode(); - componentOf[vBC] = i; - nodeOf[i] = vBC; - } - - node v; - forall_nodes(v,G) - { - if (compV[v].size() > 1) { - node vBC = BCTree.newNode(); - cutVertexOf[vBC] = v; - SListConstIterator it; - for(it = compV[v].begin(); it.valid(); ++it) - BCTree.newEdge(vBC,nodeOf[*it]); - } - } - - //--------------------------------------------------------- - // find center of BC-tree - // - // we currently use the center of the tree as main-site cluster - // alternatives are: "weighted" center (concerning size of BC's, - // largest component - // - node centerBC = 0; - - if(BCTree.numberOfNodes() == 1) - { - centerBC = BCTree.firstNode(); - - } else { - NodeArray deg(BCTree); - Queue leaves; - - node vBC; - forall_nodes(vBC,BCTree) { - deg[vBC] = vBC->degree(); - if(deg[vBC] == 1) - leaves.append(vBC); - } - - node current = 0; - while(!leaves.empty()) - { - current = leaves.pop(); - - edge e; - forall_adj_edges(e,current) { - node w = e->opposite(current); - if (--deg[w] == 1) - leaves.append(w); - } - } - - OGDF_ASSERT(current != 0); - centerBC = current; - - // if center node current of BC-Tree is a cut-vertex, we choose the - // maximal bic. comp. containing current as centerBC - if (componentOf[centerBC] == -1) { - int sizeCenter = 0; - node vCand = 0; - - edge e; - forall_adj_edges(e,current) { - node w = e->opposite(current); - int sizeW = sizeBC(w); - if(sizeW > sizeCenter) { - vCand = w; - sizeCenter = sizeW; - } - } - - // take maximal bic. comp only if not a a bridge - if(vCand && nodeB[componentOf[vCand]].size() > 2) - centerBC = vCand; - - // if a bridge is chosen as center, we take the closest non-bridge - } else if(nodeB[componentOf[centerBC]].size() == 2 && centerBC->degree() == 2) - { - //Queue Q; - SListPure currentCand, nextCand; - nextCand.pushBack(centerBC->firstAdj()); - nextCand.pushBack(centerBC->lastAdj()); - - bool found = false; - int bestSize = -1; - while(!nextCand.empty() && !found) - { - currentCand.conc(nextCand); - - while(!currentCand.empty()) - { - adjEntry adjParent = currentCand.popFrontRet()->twin(); - - for(adjEntry adj = adjParent->cyclicSucc(); adj != adjParent; adj = adj->cyclicSucc()) - { - adjEntry adjB = adj->twin(); - node vB = adjB->theNode(); - if(nodeB[componentOf[vB]].size() > 2) { - int candSize = sizeBC(vB); - if(!found || candSize > bestSize) { - centerBC = vB; - bestSize = candSize; - found = true; - } - } - adjEntry adjB2 = adjB->cyclicSucc(); - if(adjB2 != adjB) - nextCand.pushBack(adjB2); - } - } - } - } - } - -#ifdef OUTPUT - cout << "bic. comp.\n"; - for(i = 0; i < k; ++i) - cout << i << ": " << nodeB[i] << endl; - - cout << "\nBC-Tree:\n"; - forall_nodes(v,BCTree) { - cout << v << " [" << componentOf[v] << "," << cutVertexOf[v] << "]: "; - edge e; - forall_adj_edges(e,v) - cout << e->opposite(v) << " "; - cout << endl; - } - BCTree.writeGML("BC-Tree.gml"); -#endif - - - //--------------------------------------------------------- - // assign cluster - // - // we traverse the tree from the center to the outside - // cut-vertices are assigned to the inner cluster which contains them - // exception: bridges are no cluster at all if outer cut-vertex is only - // connected to one non-bridge [bridge -> c -> non bridge] - int currentCluster = 0; - Queue Q; - Array parentCluster(k+1); - - if(componentOf[centerBC] == -1) - { // case cut vertex as center - parentCluster[currentCluster] = -1; - C.m_clusterOf[cutVertexOf[centerBC]] = currentCluster; - - edge e; - forall_adj_edges(e,centerBC) { - node bBC = e->opposite(centerBC); - Q.append(InfoAC(bBC,centerBC,cutVertexOf[centerBC],currentCluster)); - } - - ++currentCluster; - - } else { // case bic. comp. as center - Q.append(InfoAC(centerBC,0,0,-1)); - } - - while(!Q.empty()) - { - InfoAC info = Q.pop(); - - // bridge? - if(nodeB[componentOf[info.m_vBC]].size() == 2 && - info.m_predCut != 0 && - info.m_vBC->degree() == 2) - { - node wBC = info.m_vBC->firstAdj()->twinNode(); - if(wBC == info.m_predCutBC) - wBC = info.m_vBC->lastAdj()->twinNode(); - - if(wBC->degree() == 2) - { - node bBC = wBC->firstAdj()->twinNode();; - if(bBC == info.m_vBC) - bBC = wBC->lastAdj()->twinNode(); - - if(nodeB[componentOf[bBC]].size() != 2) - { - Q.append(InfoAC(bBC,wBC,0,info.m_parentCluster)); - continue; // case already handled - } - } - } - - SListConstIterator itV; - for(itV = nodeB[componentOf[info.m_vBC]].begin(); itV.valid(); ++itV) - if (*itV != info.m_predCut) - C.m_clusterOf[*itV] = currentCluster; - - parentCluster[currentCluster] = info.m_parentCluster; - - edge e1; - forall_adj_edges(e1,info.m_vBC) - { - node wBC = e1->opposite(info.m_vBC); - if(wBC == info.m_predCutBC) continue; - - edge e2; - forall_adj_edges(e2,wBC) { - node bBC = e2->opposite(wBC); - if (bBC == info.m_vBC) continue; - - Q.append(InfoAC(bBC,wBC,cutVertexOf[wBC],currentCluster)); - } - } - - ++currentCluster; - } - - C.initCluster(currentCluster,parentCluster); - // in this case, the main-site cluster is always the first created - C.m_mainSiteCluster.pushBack(0); - -#ifdef OUTPUT - cout << "\ncluster:\n"; - for(i = 0; i < currentCluster; ++i) { - cout << i << ": " << C.m_nodesIn[i] << endl; - cout << " parent = " << C.m_parentCluster[i] << ", children " << C.m_childCluster[i] << endl; - } - cout << "main-site cluster: " << C.m_mainSiteCluster << endl; -#endif -} - - -int CircularLayout::sizeBC(node vB) -{ - int sum = 0; - adjEntry adj; - forall_adj(adj,vB) - sum += adj->twinNode()->degree() - 1; - return sum; -} - - - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/misclayout/ProcrustesSubLayout.cpp b/ext/OGDF/src/misclayout/ProcrustesSubLayout.cpp deleted file mode 100644 index 3ab0624c1..000000000 --- a/ext/OGDF/src/misclayout/ProcrustesSubLayout.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class ProcrustesSubLayout - * - * \author Martin Gronemann - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation - * and appearing in the files LICENSE_GPL_v2.txt and - * LICENSE_GPL_v3.txt included in the packaging of this file. - * - * \par - * In addition, as a special exception, you have permission to link - * this software with the libraries of the COIN-OR Osi project - * (http://www.coin-or.org/projects/Osi.xml), all libraries required - * by Osi, and all LP-solver libraries directly supported by the - * COIN-OR Osi project, and distribute executables, as long as - * you follow the requirements of the GNU General Public License - * in regard to all of the software in the executable aside from these - * third-party libraries. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -//! Creates an instance of circular layout. -ProcrustesSubLayout::ProcrustesSubLayout(LayoutModule* pSubLayout) : m_pSubLayout(pSubLayout), m_scaleToInitialLayout(true) -{ - // nothing -} - -void ProcrustesSubLayout::copyFromGraphAttributes(const GraphAttributes& graphAttributes, ProcrustesPointSet& pointSet) -{ - const Graph& graph = graphAttributes.constGraph(); - int i = 0; - for (node v = graph.firstNode(); v; v = v->succ()) - { - pointSet.set(i, graphAttributes.x(v), graphAttributes.y(v)); - i++; - } -} - -void ProcrustesSubLayout::translate(GraphAttributes& graphAttributes, double dx, double dy) -{ - const Graph& graph = graphAttributes.constGraph(); - for (node v = graph.firstNode(); v; v = v->succ()) - { - graphAttributes.x(v) += dx; - graphAttributes.y(v) += dy; - } -} - -void ProcrustesSubLayout::rotate(GraphAttributes& graphAttributes, double angle) -{ - const Graph& graph = graphAttributes.constGraph(); - for (node v = graph.firstNode(); v; v = v->succ()) - { - double x = cos(angle)*graphAttributes.x(v) - sin(angle)*graphAttributes.y(v); - double y = sin(angle)*graphAttributes.x(v) + cos(angle)*graphAttributes.y(v); - graphAttributes.x(v) = x; - graphAttributes.y(v) = y; - } -} - -void ProcrustesSubLayout::scale(GraphAttributes& graphAttributes, double scale) -{ - const Graph& graph = graphAttributes.constGraph(); - for (node v = graph.firstNode(); v; v = v->succ()) - { - graphAttributes.x(v) *= scale; - graphAttributes.y(v) *= scale; - } -} - -void ProcrustesSubLayout::flipY(GraphAttributes& graphAttributes) -{ - const Graph& graph = graphAttributes.constGraph(); - for (node v = graph.firstNode(); v; v = v->succ()) - { - graphAttributes.y(v) = -graphAttributes.y(v); - } -} - -//! Computes a circular layout for graph attributes \a GA. -void ProcrustesSubLayout::call(GraphAttributes& graphAttributes) -{ - // any layout? - if (!m_pSubLayout) - return; - - const Graph& graph = graphAttributes.constGraph(); - - // the nodes as points from the initial layout before - ProcrustesPointSet initialPointSet(graph.numberOfNodes()); - copyFromGraphAttributes(graphAttributes, initialPointSet); - initialPointSet.normalize(); - - // call the layout algorithm - m_pSubLayout->call(graphAttributes); - - // two new pointsets, one which holds the new layout - ProcrustesPointSet newPointSet(graph.numberOfNodes()); - copyFromGraphAttributes(graphAttributes, newPointSet); - newPointSet.normalize(); - newPointSet.rotateTo(initialPointSet); - - // and one which holds the new layout with flipped y coords - ProcrustesPointSet newFlippedPointSet(graph.numberOfNodes()); - copyFromGraphAttributes(graphAttributes, newFlippedPointSet); - newFlippedPointSet.normalize(true); - newFlippedPointSet.rotateTo(initialPointSet); - - // which layout is better - bool useFlippedLayout = initialPointSet.compare(newFlippedPointSet) < initialPointSet.compare(newPointSet); - double scaleFactor = initialPointSet.scale(); - if (useFlippedLayout) - { - reverseTransform(graphAttributes, newFlippedPointSet); - if (!m_scaleToInitialLayout) - scaleFactor = newFlippedPointSet.scale(); - } - else - { - reverseTransform(graphAttributes, newPointSet); - if (!m_scaleToInitialLayout) - scaleFactor = newFlippedPointSet.scale(); - } - - // everything is uniform and rotated. now get back to the initial layout - scale(graphAttributes, scaleFactor); - translate(graphAttributes, initialPointSet.originX(), initialPointSet.originY()); -} - -void ProcrustesSubLayout::reverseTransform(GraphAttributes& graphAttributes, const ProcrustesPointSet& pointSet) -{ - translate(graphAttributes, -pointSet.originX(), -pointSet.originY()); - if (pointSet.isFlipped()) - flipY(graphAttributes); - scale(graphAttributes, 1.0/pointSet.scale()); - rotate(graphAttributes, pointSet.angle()); -} - -ProcrustesPointSet::ProcrustesPointSet(int numPoints) : - m_numPoints(numPoints), - m_originX(0.0), - m_originY(0.0), - m_scale(1.0), - m_angle(0.0), - m_flipped(false) -{ - m_x = new double[m_numPoints]; - m_y = new double[m_numPoints]; -} - -ProcrustesPointSet::~ProcrustesPointSet() -{ - delete[] m_x; - delete[] m_y; -} - -void ProcrustesPointSet::normalize(bool flip) -{ - // upppppps - if (!m_numPoints) - return; - - // calculate the avg center - m_originX = 0.0; - m_originY = 0.0; - for (int i = 0; i < m_numPoints; ++i) - { - m_originX += m_x[i]; - m_originY += m_y[i]; - } - // average - m_originX /= (double)m_numPoints; - m_originY /= (double)m_numPoints; - - // center points and calculate root mean square distance (RMDS) - if (m_numPoints > 1) - { - m_scale = 0.0; - for (int i = 0; i < m_numPoints; ++i) - { - // translate - m_x[i] -= m_originX; - m_y[i] -= m_originY; - // while we are here: sum up for RMDS - m_scale += m_x[i]*m_x[i] + m_y[i]*m_y[i]; - } - // the ROOT MEAN in root mean square distance - m_scale = sqrt(m_scale / (double)m_numPoints); - } else { - m_scale = 1.0; - } - - // rescale all points to uniform scale - double scaleInv = 1.0 / m_scale; - for (int i = 0; i < m_numPoints; ++i) - { - // scaling - m_x[i] *= scaleInv; - m_y[i] *= scaleInv; - } - - m_flipped = flip; - if (m_flipped) - { - for (int i = 0; i < m_numPoints; ++i) - { - m_y[i] = -m_y[i]; - } - } -} - -void ProcrustesPointSet::rotateTo(const ProcrustesPointSet& other) -{ - // calculate angle between the two normalized point sets - double a = 0.0; - double b = 0.0; - for (int i = 0; i < m_numPoints; ++i) - { - a += m_x[i]*other.m_y[i] - m_y[i]*other.m_x[i]; - b += m_x[i]*other.m_x[i] + m_y[i]*other.m_y[i]; - } - - // note: atan and me never have been friends really. - // i hope i'm not missing anything here! - m_angle = atan2(a, b); - - // now rotate the points - for (int i = 0; i < m_numPoints; ++i) - { - double x = cos(m_angle)*m_x[i] - sin(m_angle)*m_y[i]; - double y = sin(m_angle)*m_x[i] + cos(m_angle)*m_y[i]; - m_x[i] = x; - m_y[i] = y; - } -} - -double ProcrustesPointSet::compare(const ProcrustesPointSet& other) const -{ - double result = 0.0; - // calculate the comparison value - for (int i = 0; i < m_numPoints; ++i) - { - double dx = other.m_x[i] - m_x[i]; - double dy = other.m_y[i] - m_y[i]; - result += dx*dx + dy*dy; - } - // somehow similiar to rmds, see wikipedia for further details - result = sqrt(result); - return result; -} - -} // end of namespace ogdf diff --git a/ext/OGDF/src/orthogonal/ClusterOrthoLayout.cpp b/ext/OGDF/src/orthogonal/ClusterOrthoLayout.cpp deleted file mode 100644 index d6a4cadb8..000000000 --- a/ext/OGDF/src/orthogonal/ClusterOrthoLayout.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements planar orthogonal drawing algorithm for -// cluster graphs. - * - * \author Carsten Gutwenger, Sebastian Leipert, Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -ClusterOrthoLayout::ClusterOrthoLayout() -{ - //drawing object distances - m_separation = 40.0; - m_cOverhang = 0.2; - m_margin = 40.0; - //preferred hierarchy direction is odNorth, but we use odSouth since gml's are flipped! - m_preferedDir = odSouth; - m_optionProfile = 0; - //edge costs - m_costAssoc = 1; - m_costGen = 4; - //align hierarchy nodes on same level - m_align = false; - //scale layout while improving it during compaction - m_useScalingCompaction = false; - m_scalingSteps = 6; - - m_orthoStyle = 0; //traditional 0, progressive 1 -} - - -/**-------------------------------------- -calling function without non-planar edges -*/ -void ClusterOrthoLayout::call(ClusterPlanRep &PG, - adjEntry adjExternal, - Layout &drawing) -{ - List npEdges; //is empty - List newEdges; //is empty - Graph G; - call(PG, adjExternal, drawing, npEdges, newEdges, G); -}//call c-planar - -/**--------------------------------------------------- -calling function taking the planar representation, the -external face (adjentry), the layout to be filled, -a list of non-planar edges, a list of inserted edges -and the original graph as input -*/ -void ClusterOrthoLayout::call(ClusterPlanRep &PG, - adjEntry adjExternal, - Layout &drawing, - List& npEdges, - List& newEdges, - Graph& originalGraph) -{ - // We don't care about UML hierarchies and therefore do not allow alignment - OGDF_ASSERT(!m_align); - - // if we have only one vertex in PG ... - if(PG.numberOfNodes() == 1) { - node v1 = PG.firstNode(); - node vOrig = PG.original(v1); - double w = PG.widthOrig(vOrig); - double h = PG.heightOrig(vOrig); - - drawing.x(v1) = m_margin + w/2; - drawing.y(v1) = m_margin + h/2; - m_boundingBox = DPoint(w + 2*m_margin, h + 2*m_margin); - return; - } - - OGDF_ASSERT(PG.representsCombEmbedding()) - //------------------------- - // insert cluster boundaries - PG.ModelBoundaries(); - OGDF_ASSERT(PG.representsCombEmbedding()) - - - //-------------------------- - // insert non-planar edges - CombinatorialEmbedding* CE = new CombinatorialEmbedding(PG); - if (!npEdges.empty()) - { - CPlanarEdgeInserter CEI; - CEI.call(PG, *CE, originalGraph, npEdges, newEdges); - }//if - - //------------------------------------------------------------ - // now we set the external face, currently to the largest face - adjEntry extAdj = 0; - int maximum = 0; - edge e, eSucc; - - for(e = PG.firstEdge(); e; e = eSucc) - { - eSucc = e->succ(); - if ( PG.clusterOfEdge(e) == PG.getClusterGraph().rootCluster() ) - { - int asSize = CE->rightFace(e->adjSource())->size(); - if ( asSize > maximum) - { - maximum = asSize; - extAdj = e->adjSource(); - } - int atSize = CE->rightFace(e->adjTarget())->size(); - if ( atSize > maximum) - { - maximum = atSize; - extAdj = e->adjTarget(); - } - - }//if root edge - - }//for - - delete CE; - - //returns adjEntry in rootcluster - adjExternal = extAdj; - OGDF_ASSERT(adjExternal != 0); - - - //---------------------------------------------------------- - //Compaction scaling: help node cages to pass by each other: - //First, the layout is blown up and then shrunk again in several steps - //We change the separation value and save the original value. - double l_orsep = m_separation; - if (m_useScalingCompaction) - { - double scaleFactor = double(int(1 << m_scalingSteps)); - m_separation = scaleFactor*m_separation; //reduce this step by step in compaction - }//if scaling - - //*********************************** - // PHASE 1: determine orthogonal shape - - //------------------------------------------------------- - // expand high-degree vertices and generalization mergers - PG.expand(); - - // get combinatorial embedding - CombinatorialEmbedding E(PG); - E.setExternalFace(E.rightFace(adjExternal)); - - // orthogonal shape representation - OrthoRep OR; - - ClusterOrthoShaper COF; - - //set some options - COF.align(false); //cannot be used yet with clusters - COF.traditional(m_orthoStyle > 0 ? false : true); //prefer 90/270 degree angles over 180/180 - //bend cost depends on cluster depths avoiding unnecessary "inner" bends - COF.bendCostTopDown(ClusterOrthoShaper::topDownCost); - - // New Call - //COF.call(PG,E,OR,2); - // Original call without bend bounds(still valid) - COF.call(PG, E, OR); - - String msg; - OGDF_ASSERT(OR.check(msg)) - - //****************************************************************** - // PHASE 2: construction of a feasible drawing of the expanded graph - - //--------------------------- - // expand low degree vertices - PG.expandLowDegreeVertices(OR); - - OGDF_ASSERT(PG.representsCombEmbedding()); - - //------------------ - // restore embedding - E.computeFaces(); - E.setExternalFace(E.rightFace(adjExternal)); - - OGDF_ASSERT(OR.check(msg)) - - //---------- - //COMPACTION - - //-------------------------- - // apply constructive compaction heuristics - OR.normalize(); - OR.dissect(); - - OR.orientate(PG,m_preferedDir); - - OGDF_ASSERT(OR.check(msg)) - - // compute cage information and routing channels - OR.computeCageInfoUML(PG); - //temporary grid layout - GridLayoutMapped gridDrawing(PG,OR,m_separation,m_cOverhang,4); - - RoutingChannel rcGrid(PG,gridDrawing.toGrid(m_separation),m_cOverhang); - rcGrid.computeRoutingChannels(OR, m_align); - - node v; - const OrthoRep::VertexInfoUML *pInfoExp; - forall_nodes(v,PG) { - pInfoExp = OR.cageInfo(v); - - if (pInfoExp) break; - } - - FlowCompaction fca(0,m_costGen,m_costAssoc); - fca.constructiveHeuristics(PG,OR,rcGrid,gridDrawing); - - OR.undissect(m_align); - - if (!m_align) {OGDF_ASSERT(OR.check(msg))} - - //-------------------------- - //apply improvement compaction heuristics - // call flow compaction on grid - FlowCompaction fc(0,m_costGen,m_costAssoc); - fc.align(m_align); - fc.scalingSteps(m_scalingSteps); - - fc.improvementHeuristics(PG,OR,rcGrid,gridDrawing); - - if (m_align) OR.undissect(false); - - //************************** - // PHASE 3: routing of edges - - OGDF_ASSERT(OR.check(msg) == true); - - EdgeRouter router; - MinimumEdgeDistances minDistGrid(PG, gridDrawing.toGrid(m_separation)); - //router.setOrSep(int(gridDrawing.toGrid(l_orsep))); //scaling test - router.call(PG,OR,gridDrawing,E,rcGrid,minDistGrid, gridDrawing.width(), - gridDrawing.height(), m_align); - - OGDF_ASSERT(OR.check(msg) == true); - - OR.orientate(pInfoExp->m_corner[odNorth],odNorth); - - //******************************************************* - // PHASE 4: apply improvement compaction heuristics again - - // call flow compaction on grid - fc.improvementHeuristics(PG, OR, minDistGrid, gridDrawing, int(gridDrawing.toGrid(l_orsep))); - - // re-map result - gridDrawing.remap(drawing); - - //postProcess(PG); - - //-------------------------- - // collapse all expanded vertices by introducing a new node in the center - // of each cage representing the original vertex - PG.collapseVertices(OR,drawing); - - // finally set the bounding box - computeBoundingBox(PG,drawing); - - //set the separation again to the input value - m_separation = l_orsep; -}//call - - - -// compute bounding box and move final drawing such that it is 0 aligned -// respecting margins -void ClusterOrthoLayout::computeBoundingBox( - const ClusterPlanRep &PG, - Layout &drawing) -{ - double minX, maxX, minY, maxY; - - minX = maxX = drawing.x(PG.firstNode()); - minY = maxY = drawing.y(PG.firstNode()); - - node v; - forall_nodes(v,PG) - { - double x = drawing.x(v); - if (x < minX) minX = x; - if (x > maxX) maxX = x; - - double y = drawing.y(v); - if (y < minY) minY = y; - if (y > maxY) maxY = y; - } - - double deltaX = m_margin - minX; - double deltaY = m_margin - minY; - - forall_nodes(v,PG) - { - drawing.x(v) += deltaX; - drawing.y(v) += deltaY; - } - - m_boundingBox = DPoint(maxX+deltaX+m_margin, maxY+deltaY+m_margin); -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/orthogonal/ClusterOrthoShaper.cpp b/ext/OGDF/src/orthogonal/ClusterOrthoShaper.cpp deleted file mode 100644 index 197d5d670..000000000 --- a/ext/OGDF/src/orthogonal/ClusterOrthoShaper.cpp +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes the Orthogonal Representation of a Planar - * Representation of a UML Graph. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - - -const int flowBound = 4; //No more than 4 bends in cage boundary, - //and no more than 360 degrees at vertices - -enum netArcType {defaultArc, angle, backAngle, bend}; - -namespace ogdf { - - -//************************************************************* -//call function: compute a flow in a dual network and interpret -//result as bends and angles (representation shape) -void ClusterOrthoShaper::call(ClusterPlanRep &PG, - CombinatorialEmbedding &E, - OrthoRep &OR, - int startBoundBendsPerEdge, - bool fourPlanar) - { - - if (PG.numberOfEdges() == 0) - return; - - m_fourPlanar = fourPlanar; - - // the min cost flow we use - MinCostFlowReinelt flowModule; - const int infinity = flowModule.infinity(); - - //************************************************************ - //fix some values depending on traditional or progressive mode - //************************************************************ - - //standard flow boundaries for traditional and progressive mode - const int upperAngleFlow = (m_traditional ? 4 : 1); //non zero - const int maxAngleFlow = (m_traditional ? 4 : 2); //use 2 for multialign zero degree - const int maxBackFlow = 2; //maximal flow on back arcs in progressive mode - const int upperBackAngleFlow = 2; // and 360 back (only progressive mode) - const int lowerAngleFlow = (m_traditional ? 1 : 0); - const int piAngleFlow = (m_traditional ? 2 : 0); - const int halfPiAngleFlow = 1; - //const int halfPiBackAngleFlow = 0; //(only progressive mode) - const int zeroAngleFlow = (m_traditional ? 0 : 2); - const int zeroBackAngleFlow = 0; //(only progressive mode) - - //in progressive mode, angles need cost to work out properly - //const int tradAngleCost = 0; - const int progAngleCost = 1; - const int tradBendCost = 1; - const int progBendCost = 3*PG.numberOfNodes(); //should use supply - PG.getClusterGraph().setUpdateDepth(true); - const int clusterTreeDepth = PG.getClusterGraph().treeDepth(); - - - OR.init(E); - FaceArray F(E); - - OGDF_ASSERT(PG.representsCombEmbedding()) - OGDF_ASSERT(F.valid()) - - - - //****************** - // NETWORK VARIABLES - //****************** - - Graph Network; //the dual network - EdgeArray lowerBound(Network,0); // lower bound for flow - EdgeArray upperBound(Network,0); // upper bound for flow - - EdgeArray cost(Network,0); // cost of an edge - NodeArray supply(Network,0); // supply of every node - - - //alignment helper - NodeArray fixedVal(Network, false); //already set somewhere - EdgeArray noBendEdge(Network, false); //for splitter, brother edges etc. - - //********************************* - //NETWORK TO PlanRep INFORMATION - - // stores for edges of the Network the corresponding adjEntries - // nodes, and faces of PG - EdgeArray adjCor(Network,0); - EdgeArray nodeCor(Network,0); - EdgeArray faceCor(Network,0); - - NodeArray nodeType(Network, low); - - //********************************* - //PlanRep TO NETWORK INFORMATION - - //Contains for every node of PG the corresponding node in the network - NodeArray networkNode(PG,0); - //Contains for every adjEntry of PG the corresponding edge in the network - AdjEntryArray backAdjCor(PG,0); //bends - //contains for every adjEntry of PG the corresponding angle arc in the network - //note: this doesn't need to correspond to resulting drawing angles - //bends on the boundary define angles at expanded nodes - AdjEntryArray angleArc(PG, 0); //angle - //contains the corresponding back arc face to node in progressive mode - AdjEntryArray angleBackArc(PG, 0); //angle - - //****************** - // OTHER INFORMATION - - // Contains for adjacency Entry of PG the face it belongs to in PG - AdjEntryArray adjF(PG,0); - - //Contains for angle network arc progressive mode backward arc - EdgeArray angleTwin(Network, 0); - - //types of network edges, to be used in flow to values - EdgeArray l_arcType(Network, angle); - - //contains the outer face - //face theOuterFace = E.externalFace(); - - //******************* - // STANDARD VARIABLES - - node v; - adjEntry adj; - edge e; - - - //********************************** - // GENERATE ALL NODES OF THE NETWORK - //********************************** - - //corresponding to the graphs nodes - int checksum = 0; - forall_nodes(v,PG) - { - OGDF_ASSERT((!m_fourPlanar) || (v->degree() < 5)); - - networkNode[v] = Network.newNode(); - //maybe install a shortcut here for degree 4 nodes if not expanded - - if (v->degree() > 4) nodeType[networkNode[v]] = high; - else nodeType[networkNode[v]] = low; - - //already set the supply - if (m_traditional) supply[networkNode[v]] = 4; - else supply[networkNode[v]] = 2*v->degree() - 4; - - checksum += supply[networkNode[v]]; - } - - //corresponding to the graphs faces - face f; - for (f = E.firstFace(); f; f = f->succ()) - { - F[f] = Network.newNode(); - - if (f == E.externalFace()) - { - nodeType[F[f]] = outer; - if (m_traditional) supply[F[f]] = - 2*f->size() - 4; - else supply[F[f]] = 4; - } - else { - nodeType[F[f]] = inner; - if (m_traditional) supply[F[f]] = - 2*f->size() + 4; - else supply[F[f]] = -4; - } - } - -#ifdef OGDF_DEBUG - //check the supply sum - checksum = 0; - forall_nodes(v, Network) - checksum += supply[v]; - OGDF_ASSERT(checksum == 0); -#endif - - -#ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)) { - forall_nodes(v,PG) - cout << " v = " << v << " corresponds to " - << networkNode[v] << endl; - for (f = E.firstFace(); f; f = f->succ()) { - cout << " face = " << f->index() << " corresponds to " << F[f]; - if (f == E.externalFace()) - cout<<" (Outer Face)"; - cout << endl; - } - } -#endif - - - - //********************************** - // GENERATE ALL EDGES OF THE NETWORK - //********************************** - - // OPTIMIZATION POTENTIAL: - // Do not insert edges with upper bound 0 into the network. - - // Locate for every adjacency entry its adjacent faces. - for (f = E.firstFace(); f; f = f->succ()) - { - forall_face_adj(adj,f) - adjF[adj] = f; - } - -#ifdef OGDF_DEBUG - if(int(ogdf::debugLevel) >= int(dlHeavyChecks)) { - for(f = E.firstFace(); f; f = f->succ()) { - cout << "Face " << f->index() << " : "; - forall_face_adj(adj,f) - cout << adj << "; "; - cout<adjSource()] && adjF[e->adjTarget()]) - if (F[adjF[e->adjSource()]] != F[adjF[e->adjTarget()]]) - { - // not a selfloop. - edge newE = Network.newEdge(F[adjF[e->adjSource()]],F[adjF[e->adjTarget()]]); - - l_arcType[newE] = bend; - - adjCor[newE] = e->adjSource(); - if ( (PG.typeOf(e) == Graph::generalization) || - (PG.isClusterBoundary(e) && (!m_traditional))) - upperBound[newE] = 0; - else - upperBound[newE] = infinity; - cost[newE] = (m_traditional ? - clusterTradBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, tradBendCost) : - clusterProgBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, progBendCost)); - - backAdjCor[e->adjSource()] = newE; - - newE = Network.newEdge(F[adjF[e->adjTarget()]],F[adjF[e->adjSource()]]); - - l_arcType[newE] = bend; - - adjCor[newE] = e->adjTarget(); - if ((PG.typeOf(e) == Graph::generalization) || - (PG.isClusterBoundary(e) && (m_traditional))) - upperBound[newE] = 0; - else - upperBound[newE] = infinity; - cost[newE] = (m_traditional ? - clusterTradBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, tradBendCost) : - clusterProgBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, progBendCost)); - backAdjCor[e->adjTarget()] = newE; - } - } - - - //***************************************************************** - // insert for every node edges to all appearances of adjacent faces - // flow defines angles at nodes - // progressive: and vice-versa - //***************************************************************** - - - //************************************************************ - // Observe that two generalizations are not allowed to bend on - // a node. There must be a 180 degree angle between them. - - // assure that there is enough flow between adjacent generalizations - NodeArray genshift(PG, false); - - //non-expanded vertex - forall_nodes(v,PG) - { - //***************************************** - // Locate possible adjacent generalizations - adjEntry gen1 = 0; - adjEntry gen2 = 0; - - if (PG.typeOf(v) != Graph::generalizationMerger - && PG.typeOf(v) != Graph::generalizationExpander) - { - forall_adj(adj,v) - { - if (PG.typeOf(adj->theEdge()) == Graph::generalization) - { - if (!gen1) gen1 = adj; - else gen2 = adj; - } - } - }// if not generalization - - - forall_adj(adj,v) - { - edge e2 = Network.newEdge(networkNode[v],F[adjF[adj]]); - - l_arcType[e2] = angle; - - //CHECK bounded edges? and upper == 2 for zero degree - //progressive and traditional - upperBound[e2] = upperAngleFlow; - nodeCor [e2] = v; - adjCor [e2] = adj; - faceCor [e2] = adjF[adj]; - angleArc [adj] = e2; - - //do not allow zero degree at non-expanded vertex - //&& !m_allowLowZero - - //progressive and traditional (compatible) - if (m_fourPlanar) lowerBound[e2] = lowerAngleFlow; //trad 1 = 90, prog 0 = 180 - - //insert opposite arcs face to node in progressive style - edge e3; - if (!m_traditional) - { - e3 = Network.newEdge(F[adjF[adj]], networkNode[v]); //flow for >180 degree - - l_arcType[e3] = backAngle; - - angleTwin[e2] = e3; - angleTwin[e3] = e2; - - cost[e2] = progAngleCost; - cost[e3] = progAngleCost; - - lowerBound[e3] = lowerAngleFlow; //180 degree,check highdegree drawings - upperBound[e3] = upperBackAngleFlow; //infinity; - //nodeCor [e3] = v; has no node, is face to node - adjCor [e3] = adj; - faceCor [e3] = adjF[adj]; - angleBackArc[adj] = e3; - - }//progressive - }//initialize - - //second run to have all angleArcs already initialized - //set the flow boundaries - forall_adj(adj,v) - { - edge e2 = angleArc[adj]; - edge e3 = 0; - if (!m_traditional) e3 = angleTwin[e2]; - - //allow low degree node zero degree angle for non-expanded vertices - //if (false) { - // if ((gen1 || gen2) && (PG.isVertex(v))) - // { - // lowerBound[e2] = 0; - // } - //} - //******************************************************************* - //******************************************************************* - - //hier muss man fuer die Kanten, die rechts ansetzen noch lowerbound 2 setzen - - if (gen2 == adj && gen1 == adj->cyclicSucc()) - { - upperBound[e2] = piAngleFlow; - lowerBound[e2] = piAngleFlow; - if (e3 && !m_traditional) - { - upperBound[e3] = 0; - lowerBound[e3] = 0; - } - genshift[v] = true; - } - else if (gen1 == adj && gen2 == adj->cyclicSucc()) - { - upperBound[e2] = piAngleFlow; - lowerBound[e2] = piAngleFlow; - if (e3 && !m_traditional) - { - upperBound[e3] = 0; - lowerBound[e3] = 0; - }//progressive - genshift[v] = true; - } - } - }//forall_nodes - - - //*************************************************** - // Reset upper and lower Bounds for network arcs that - // correspond to edges of generalizationmerger faces - // and edges of expanded nodes. - - - forall_nodes(v,PG) - { - if (PG.expandAdj(v)) - { - adj = PG.expandAdj(v); - // Get the corresponding face in the original embedding. - f = adjF[adj]; - - //***********************+ - //expanded merger cages - if (PG.typeOf(v) == Graph::generalizationMerger) - { - // Set upperBound to 0 for all edges. - forall_face_adj(adj,f) - { - //no bends on boundary (except special case following) - upperBound[backAdjCor[adj]] = 0; - upperBound[backAdjCor[adj->twin()]] = 0; - - // Node w is in Network - node w = networkNode[adj->twinNode()]; - forall_adj_edges(e,w) - { - if (e->target() == F[f]) - { - //is this: 180 degree? - lowerBound[e] = piAngleFlow; //traditional: 2 progressive: 0 - upperBound[e] = piAngleFlow; - if (!m_traditional) - { - edge aTwin = angleTwin[e]; - if (aTwin) - { - upperBound[aTwin] = 0; - lowerBound[aTwin] = 0; - } - }//if not traditional limit angle back arc - - } - } - - } - //special bend case - // Set the upper and lower bound for the first edge of - // the mergeexpander face to guarantee a 90 degree bend. - if (m_traditional) - { - upperBound[backAdjCor[PG.expandAdj(v)]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)]]= 1; - } - else - { - //progressive mode: bends are in opposite direction - upperBound[backAdjCor[PG.expandAdj(v)->twin()]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)->twin()]]= 1; - } - - // Set the upper and lower bound for the first node in - // clockwise order of the mergeexpander face to - // guaranty a 90 degree angle at the node in the interior - // and a 180 degree angle between the generalizations in the - // exterior. - node secFace; - - if (F[f] == backAdjCor[PG.expandAdj(v)]->target()) - secFace = backAdjCor[PG.expandAdj(v)]->source(); - else if (F[f] == backAdjCor[PG.expandAdj(v)]->source()) - secFace = backAdjCor[PG.expandAdj(v)]->target(); - else - { - OGDF_ASSERT(false); // Edges in Network mixed up. - } - node w = networkNode[PG.expandAdj(v)->twinNode()]; - - forall_adj(adj,w) - { - if (adj->theEdge()->target() == F[f]) - { - lowerBound[adj->theEdge()] = 1; - upperBound[adj->theEdge()] = 1; - if (!m_traditional) - { - edge aTwin = angleTwin[adj->theEdge()]; - if (aTwin) - { - upperBound[aTwin] = 0; - lowerBound[aTwin] = 0; - } - }//if not traditional limit angle back arc - break; - } - } - - if (m_traditional) - e = adj->cyclicSucc()->theEdge(); - else - { - //we have two edges instead of one per face - adjEntry ae = adj->cyclicSucc(); - e = ae->theEdge(); - if (e->target() != secFace) - //maybe we have to jump one step further - e = ae->cyclicSucc()->theEdge(); - - }//progressive mode - - if (e->target() == secFace) - { - lowerBound[e] = piAngleFlow; - upperBound[e] = piAngleFlow; - if (!m_traditional) - { - edge aTwin = angleTwin[e]; - if (aTwin) - { - upperBound[aTwin] = piAngleFlow; - lowerBound[aTwin] = piAngleFlow; - } - }//if not traditional limit angle back arc - } - - // Set the upper and lower bound for the last edge of - // the mergeexpander face to guarantee a 90 degree bend. - if (m_traditional) - { - upperBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()]] = 1; - } - else - { - //progressive mode: bends are in opposite direction - upperBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()->twin()]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()->twin()]] = 1; - }//progressive - - - // Set the upper and lower bound for the last node in - // clockwise order of the mergeexpander face to - // guaranty a 90 degree angle at the node in the interior - // and a 180 degree angle between the generalizations in the - // exterior. - if (F[f] == backAdjCor[PG.expandAdj(v)->faceCyclePred()]->target()) - secFace = backAdjCor[PG.expandAdj(v)->faceCyclePred()]->source(); - else if (F[f] == backAdjCor[PG.expandAdj(v)->faceCyclePred()]->source()) - secFace = backAdjCor[PG.expandAdj(v)->faceCyclePred()]->target(); - else - { - OGDF_ASSERT(false); // Edges in Network mixed up. - } - w = networkNode[PG.expandAdj(v)->faceCyclePred()->theNode()]; - - forall_adj(adj,w) - { - if (adj->theEdge()->target() == F[f]) - { - lowerBound[adj->theEdge()] = 1; - upperBound[adj->theEdge()] = 1; - if (!m_traditional) - { - edge aTwin = angleTwin[adj->theEdge()]; - if (aTwin) - { - upperBound[aTwin] = 0; - lowerBound[aTwin] = 0; - } - }//if not traditional limit angle back arc - break; - } - } - - if (m_traditional) - e = adj->cyclicPred()->theEdge(); - else - { - //we have two edges instead of one per face - adjEntry ae = adj->cyclicPred(); - e = ae->theEdge(); - if (e->target() != secFace) - //maybe we have to jump one step further - e = ae->cyclicPred()->theEdge(); - - }//progressive mode - - if (e->target() == secFace) - { - lowerBound[e] = piAngleFlow; - upperBound[e] = piAngleFlow; - if (!m_traditional) - { - edge aTwin = angleTwin[e]; - if (aTwin) - { - upperBound[aTwin] = piAngleFlow; - lowerBound[aTwin] = piAngleFlow; - } - }//if not traditional limit angle back arc - } - - - } - //************************** - //expanded high degree cages - else if (PG.typeOf(v) == Graph::highDegreeExpander ) - { - // Set upperBound to 1 for all edges, allowing maximal one - // 90 degree bend. - // Set upperBound to 0 for the corresponding entering edge - // allowing no 270 degree bend. - // Set upperbound to 1 for every edge corresponding to the - // angle of a vertex. This permitts 270 degree angles in - // the face - - adjEntry splitter = 0; - - - //assure that edges are only spread around the sides if not too - //many multi edges are aligned - - //************************ - //count multiedges at node - int multis = 0; - AdjEntryArray isMulti(PG, false); - if (m_multiAlign) - { - //if all edges are multi edges, find a 360 degree position - bool allMulti = true; - forall_face_adj(adj, f) //this double iteration slows the algorithm down - { - //no facesplitter in attributedgraph - //if (!PG.faceSplitter(adj->theEdge())) - { - adjEntry srcadj = adj->cyclicPred(); - adjEntry tgtadj = adj->twin()->cyclicSucc(); - //check if the nodes are expanded - node vt1, vt2; - if (PG.expandedNode(srcadj->twinNode())) - vt1 = PG.expandedNode(srcadj->twinNode()); - else vt1 = srcadj->twinNode(); - if (PG.expandedNode(tgtadj->twinNode())) - vt2 = PG.expandedNode(tgtadj->twinNode()); - else vt2 = tgtadj->twinNode(); - if (vt1 == vt2) - { - //we forbid bends between two incident multiedges - if (m_traditional) - { - lowerBound[backAdjCor[adj]] = upperBound[backAdjCor[adj]] = 0; - isMulti[adj] = true; - } - else - { - lowerBound[backAdjCor[adj->twin()]] = - lowerBound[backAdjCor[adj]] = - upperBound[backAdjCor[adj]] = - upperBound[backAdjCor[adj->twin()]] = 0; - isMulti[adj->twin()] = true; - } - multis++; - }//multi edge - else allMulti = false; - }//if outer boundary - - }//forallfaceadj count multis - //multi edge correction: only multi edges => one edge needs 360 degree - if (allMulti) - { - //find an edge that allows 360 degree without bends - bool twoNodeCC = true; //no foreign non-multi edge to check for - forall_face_adj(adj, f) - { - //now check for expanded nodes - adjEntry adjOut = adj->cyclicPred(); //outgoing edge entry - node vOpp = adjOut->twinNode(); - if (PG.expandedNode(vOpp)) - { - adjOut = adjOut->faceCycleSucc(); //on expanded boundary - //does not end on self loops - node vStop = vOpp; - if (PG.expandedNode(vStop)) vStop = PG.expandedNode(vStop); - while (PG.expandedNode(adjOut->twinNode()) == vStop) - //we are still on vOpps cage - adjOut = adjOut->faceCycleSucc(); - } - //now adjOut is either a "foreign" edge or one of the - //original multi edges if two-node-CC - //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin(); - adjEntry testAdj = adjOut->twin(); - node vBack = testAdj->theNode(); - if (PG.expandedNode(vBack)) - { - vBack = PG.expandedNode(vBack); - } - if (vBack != v) //v is expanded node - { - //dont use iteration result, set firstedge! - upperBound[backAdjCor[adj]] = 4; //4 bends for 360 - twoNodeCC = false; - break; - } - }//forall_adj_edges - //if only two nodes with multiedges are in current CC, - //assign 360 degree to first edge - if (twoNodeCC) - { - //it would be difficult to guarantee that the networkedge - //on the other side of the face would get the 360, so alllow - //360 for all edges or search for the outer face - - forall_face_adj(adj, f) - { - adjEntry ae = adj->cyclicPred(); - if (adjF[ae] == E.externalFace()) - { - upperBound[backAdjCor[adj]] = 4; //4 bends for 360 - break; - } - }//forall expansion adj - }//if - }//if allMulti - //End multi edge correction - }//if multialign - - - //********************** - //now set the upper Bounds - forall_face_adj(adj,f) - { - //should be: no 270 degrees - if (m_traditional) - upperBound[backAdjCor[adj->twin()]] = 0; - else - upperBound[backAdjCor[adj]] = 0; - - //if (false)//(PG.faceSplitter(adj->theEdge())) - //{ - // // No bends allowed on the face splitter - // upperBound[backAdjCor[adj]] = 0; - - // //CHECK - // //progressive??? sollte sein: - // upperBound[backAdjCor[adj->twin()]] = 0; - - // splitter = adj; - // continue; - //} - // else - // //should be: only one bend - { - - if (m_distributeEdges) - //CHECK - //maybe we should change this to setting the lower bound too, - //depending on the degree (<= 4 => deg 90) - { - //check the special case degree >=4 with 2 - // generalizations following each other if degree - // > 4, only 90 degree allowed, nodeType high - // bloed, da nicht original - //if (nodeType[ networkNode[adj->twinNode()] ] == high) - //hopefully size is original degree - if (m_traditional) - { - if (!isMulti[adj]) //m_multiAlign??? - { - //check if original node degree minus multi edges - //is high enough - //Attention: There are some lowerBounds > 1 -#ifdef OGDF_DEBUG - int oldBound = upperBound[backAdjCor[adj]]; -#endif - if ((!genshift[v]) && (f->size()-multis>3)) - upperBound[backAdjCor[adj]] = - //max(2, lowerBound[backAdjCor[adj]]); - //due to mincostflowreinelt errors, we are not - //allowed to set ub 1 - max(1, lowerBound[backAdjCor[adj]]); - else upperBound[backAdjCor[adj]] = - max(2, lowerBound[backAdjCor[adj]]); - //nur zum Testen der Faelle - OGDF_ASSERT(oldBound >= upperBound[backAdjCor[adj]]); - }// if not multi - }//traditional - else - { - //preliminary set the bound in all cases - - if (!isMulti[adj]) - { - //Attention: There are some lowerBounds > 1 - - if ((!genshift[v]) && (f->size()-multis>3)) - upperBound[backAdjCor[adj->twin()]] = - max(1, lowerBound[backAdjCor[adj->twin()]]); - else upperBound[backAdjCor[adj->twin()]] = - max(2, lowerBound[backAdjCor[adj->twin()]]); - - }// if not multi - }//progressive - }//distributeedges - - }// else no face splitter - - // Node w is in Network - node w = networkNode[adj->twinNode()]; - - // if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4))) - { - //should be: inner face angles set to 180 - forall_adj_edges(e,w) - { - if (e->target() == F[f]) - { - upperBound[e] = piAngleFlow; - lowerBound[e] = piAngleFlow; - if (!m_traditional) - { - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = piAngleFlow; - lowerBound[angleTwin[e]] = piAngleFlow; - }//if twin - }//if progressive mode - } - } - } - }// forallfaceadj - - //******************************************************** - // In case a face splitter was used, we need to update the - // second face of the cage. - if (splitter) - { - - adj = splitter->twin(); - // Get the corresponding face in the original embedding. - face f2 = adjF[adj]; - - forall_face_adj(adj,f2) - { - if (adj == splitter->twin()) - continue; - - if (m_traditional) - upperBound[backAdjCor[adj->twin()]] = 0; - else //progressive bends are in opposite direction - upperBound[backAdjCor[adj]] = 0; - - // Node w is in Network - node w = networkNode[adj->twinNode()]; - //if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4))) - { - forall_adj_edges(e,w) - { - if (e->target() == F[f2]) - { - upperBound[e] = piAngleFlow; - lowerBound[e] = piAngleFlow; - if (!m_traditional) - { - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = piAngleFlow; - lowerBound[angleTwin[e]] = piAngleFlow; - }//angleTwin - }//if progressive mode - } - }//forall adjacent edges - }//if not preset - } - } - } - }//if expanded - - else - { - - //********************************************* - //non-expanded (low degree) nodes - //check for alignment and for multi edges - //********************************************* - - //check for multi edges and decrease lowerbound if align - int lowerb = 0; - - if (PG.isVertex(v)) - { - node w = networkNode[v]; - if ((nodeType[w] != low) || (w->degree()<2)) continue; - - bool allMulti = true; - forall_adj_edges(e,w) - { - lowerb += max(lowerBound[e], 0); - - OGDF_ASSERT((!m_traditional) || (e->source() == w)); - if (m_traditional && (e->source() != w)) OGDF_THROW(AlgorithmFailureException); - if (e->source() != w) continue; //dont treat back angle edges - - if (m_multiAlign && (v->degree()>1)) - { - adjEntry srcAdj = adjCor[e]; - adjEntry tgtAdj = adjCor[e]->faceCyclePred(); - - //check if the nodes are expanded - node vt1, vt2; - if (PG.expandedNode(srcAdj->twinNode())) - vt1 = PG.expandedNode(srcAdj->twinNode()); - else vt1 = srcAdj->twinNode(); - - if (PG.expandedNode(tgtAdj->theNode())) - vt2 = PG.expandedNode(tgtAdj->theNode()); - else vt2 = tgtAdj->theNode(); - - if (vt1 == vt2) - { - - fixedVal[w] = true; - - //we forbid bends between incident multi edges - //or is it angle? - lowerBound[e] = upperBound[e] = zeroAngleFlow; - if (!m_traditional) - { - lowerBound[angleTwin[e]] = upperBound[angleTwin[e]] - = zeroBackAngleFlow; - }//if progressive mode - - }//multi edge - else - { - //CHECK - //to be done: only if multiedges - if (!genshift[v]) upperBound[e] = upperAngleFlow; - allMulti = false; - } - }//multiAlign - }//foralladjedges - - - if (m_multiAlign && allMulti && (v->degree()>1)) - { - - fixedVal[w] = true; - - //find an edge that allows 360 degree without bends - bool twoNodeCC = true; - forall_adj_edges(e, w) - { - //now check for expanded nodes - adjEntry runAdj = adjCor[e]; - node vOpp = runAdj->twinNode(); - node vStop; - vStop = vOpp; - runAdj = runAdj->faceCycleSucc(); - if (PG.expandedNode(vStop)) - { - - //does not end on self loops - vStop = PG.expandedNode(vStop); - while (PG.expandedNode(runAdj->twinNode()) == vStop) - //we are still on vOpps cage - runAdj = runAdj->faceCycleSucc(); - } - //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin(); - adjEntry testAdj = runAdj->twin(); - node vBack = testAdj->theNode(); - - if (vBack != v) //not same node - { - if (PG.expandedNode(vBack)) - { - vBack = PG.expandedNode(vBack); - } - if (vBack != vStop) //vstop !=0, not inner face in 2nodeCC - { - //CHECK: 4? upper - OGDF_ASSERT(!PG.expandedNode(v)); //otherwise not angle flow - if (m_traditional) - upperBound[e] = maxAngleFlow; //dont use iteration result, set firstedge! - else - { - upperBound[e] = lowerBound[e] = lowerAngleFlow; - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = maxBackFlow; - lowerBound[angleTwin[e]] = maxBackFlow; - } - } - twoNodeCC = false; - break; - }//if not 2nodeCC - }//if - }//forall_adj_edges - //if only two nodes with multiedges are in current CC, - //assign 360 degree to first edge - if (twoNodeCC) - { - //it would be difficult to guarantee that the networkedge - //on the other side of the face would get the 360, so alllow - //360 for all edges or search for external face - forall_adj_edges(e, w) - { - adjEntry adje = adjCor[e]; - if (adjF[adje] == E.externalFace()) - { - //CHECK: 4? upper - OGDF_ASSERT(!PG.expandedNode(v)); //otherwise not angle flow - if (m_traditional) - upperBound[e] = maxAngleFlow;//upperAngleFlow; - if (!m_traditional) - { - upperBound[e] = lowerAngleFlow;//upperAngleFlow; - lowerBound[e] = lowerAngleFlow; - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = maxBackFlow; - lowerBound[angleTwin[e]] = maxBackFlow; - } - } - break; - }//if - }//forall - }//if - }//if allMulti - }//replaces vertex - - } - }//forallnodes - - //********************************** - node tv; edge te; - //int flowSum = 0; - - //To Be done: hier multiedges testen - forall_nodes(tv, Network) - { - //flowSum += supply[tv]; - - //only check representants of original nodes, not faces - if (((nodeType[tv] == low) || (nodeType[tv] == high))) - { - //if node representant with degree 4, set angles preliminary - //degree four nodes with two gens are expanded in PlanRepUML - //all others are allowed to change the edge positions - if ( (m_traditional && (tv->degree() == 4)) || - ((tv->degree() == 8) && !m_traditional) ) - { - //three types: degree4 original nodes and facesplitter end nodes, - //maybe crossings - //fixassignment tells us that low degree nodes are not allowed to - //have zero degree and special nodes are already assigned - bool fixAssignment = true; - - //check if free assignment is possible for degree 4 - if (m_deg4free) - { - fixAssignment = false; - forall_adj_edges(te, tv) - { - if (te->source() == tv) - { - adjEntry pgEntry = adjCor[te]; - node pgNode = pgEntry->theNode(); - - if ((PG.expandedNode(pgNode)) - //|| (PG.faceSplitter(adjCor[te]->theEdge())) - || (PG.typeOf(pgNode) == Graph::dummy) //test crossings - ) - { - fixAssignment = true; - break; - } - }//if no angle back arc in progressive mode - }//forall_adj_edges - }//deg4free - - //CHECK - //now set the angles at degree 4 nodes to distribute edges - forall_adj_edges(te, tv) - { - - if (te->source() == tv) - { - if (fixedVal[tv]) continue; //if already special values set - - if (!fixAssignment) - { - lowerBound[te] = 0; //lowerAngleFlow maybe 1;//0; - upperBound[te] = upperAngleFlow;//4; - } - else - { - //only allow 90 degree arc value - lowerBound[te] = halfPiAngleFlow; - upperBound[te] = halfPiAngleFlow; - } - }//if no angle back arc in progressive mode - else - { - if (fixedVal[tv]) continue; //if already special values set - - if (!fixAssignment) - { - OGDF_ASSERT(lowerAngleFlow == 0); //should only be in progressive mode - lowerBound[te] = lowerAngleFlow; - upperBound[te] = upperBackAngleFlow; - } - else - { - //only allow 0-180 degree back arc value - lowerBound[te] = 0; //1 - upperBound[te] = 0; //halfPiAngleFlow; //1 - } - }//back angle arc - }//forall_adj_edges - }//degree 4 node - int lowsum = 0, upsum = 0; - forall_adj_edges(te, tv) - { - OGDF_ASSERT(lowerBound[te] <= upperBound[te]); - if (noBendEdge[te]) lowerBound[te] = 0; - lowsum += lowerBound[te]; - upsum += upperBound[te]; - }//forall_adj_edges - if (m_traditional) { - OGDF_ASSERT( (lowsum <= supply[tv]) && (upsum >= supply[tv])) - } - }//if node, no faces - }//forallnodes - //only for debugging: check faces - forall_nodes(tv, Network) - { - int lowsum = 0, upsum = 0; - forall_adj_edges(te, tv) - { - if (noBendEdge[te]) lowerBound[te] = 0; - lowsum += lowerBound[te]; - upsum += upperBound[te]; - }//forall_adj_edges - //OGDF_ASSERT( (lowsum <= supply[tv]) && (upsum >= supply[tv])); - } - //OGDF_ASSERT(flowSum == 0); - - - bool isFlow = false; - SList capacityBoundedEdges; - EdgeArray flow(Network,0); - - // Set upper Bound to current upper bound. - // Some edges are no longer capacitybounded, therefore save their status - EdgeArray isBounded(Network, false); - - forall_edges(e,Network) - - if (upperBound[e] == infinity) - { - capacityBoundedEdges.pushBack(e); - isBounded[e] = true; - }//if bounded - - int currentUpperBound; - if (startBoundBendsPerEdge > 0) - currentUpperBound = startBoundBendsPerEdge; - else - currentUpperBound = 4*PG.numberOfEdges(); - - - while ( (!isFlow) && (currentUpperBound <= 4*PG.numberOfEdges()) ) - { - - SListIterator it; - for (it = capacityBoundedEdges.begin(); it.valid(); it++) - upperBound[(*it)] = currentUpperBound; - - isFlow = flowModule.call(Network,lowerBound,upperBound,cost,supply,flow); - - - //#ifdef foutput - //if (isFlow) - // { - // forall_edges(e,Network) { - // fout << "e = " << e << " flow = " << flow[e]; - // if(nodeCor[e] == 0 && adjCor[e]) - // fout << " real edge = " << adjCor[e]->theEdge(); - // fout << endl; - // } - // forall_edges(e,Network) { - // if(nodeCor[e] == 0 && adjCor[e] != 0 && flow[e] > 0) { - // fout << "Bends " << flow[e] << " on edge " - // << adjCor[e]->theEdge() - // << " between faces " << adjF[adjCor[e]]->index() << " - " - // << adjF[adjCor[e]->twin()]->index() << endl; - // } - // } - // forall_edges(e,Network) { - // if(nodeCor[e] != 0 && faceCor[e] != 0) { - // fout << "Angle " << (flow[e])*90 << "\tdegree on node " - // << nodeCor[e] << " at face " << faceCor[e]->index() - // << "\tbetween edge " << adjCor[e]->faceCyclePred() - // << "\tand " << adjCor[e] << endl; - // } - // } - // if (startBoundBendsPerEdge> 0) { - // fout << "Minimizing edge bends for upper bound " - // << currentUpperBound; - // if(isFlow) - // fout << " ... Successful"; - // fout << endl; - // } - //} - //#endif - - OGDF_ASSERT(startBoundBendsPerEdge >= 1 || isFlow); - - currentUpperBound++; - - }// while (!isflow) - - - if (startBoundBendsPerEdge && !isFlow) - { - // couldn't compute reasonable shape - OGDF_THROW_PARAM(AlgorithmFailureException, afcNoFlow); - } - - - int totalNumBends = 0; - - - forall_edges(e,Network) - { - - if (nodeCor[e] == 0 && adjCor[e] != 0 && (flow[e] > 0) && - (angleTwin[e] == 0) ) //no angle edges - { - OGDF_ASSERT(OR.bend(adjCor[e]).size() == 0) - - char zeroChar = (m_traditional ? '0' : '1'); - char oneChar = (m_traditional ? '1' : '0'); - //we depend on the property that there is no flow - //in opposite direction due to the cost - OR.bend(adjCor[e]).set(zeroChar,flow[e]); - OR.bend(adjCor[e]->twin()).set(oneChar,flow[e]); - - totalNumBends += flow[e]; - - //check if bends fit bounds - if (isBounded[e]) - { - OGDF_ASSERT((int)OR.bend(adjCor[e]).size() <= currentUpperBound); - OGDF_ASSERT((int)OR.bend(adjCor[e]->twin()).size() <= currentUpperBound); - }//if bounded - } - else if (nodeCor[e] != 0 && faceCor[e] != 0) - { - if (m_traditional) OR.angle(adjCor[e]) = (flow[e]); - else - { - OGDF_ASSERT(angleTwin[e] != 0); - switch (flow[e]) - { - case 0: switch (flow[angleTwin[e]]) - { - case 0: OR.angle(adjCor[e]) = 2; break; - case 1: OR.angle(adjCor[e]) = 3; break; - case 2: OR.angle(adjCor[e]) = 4; break; - OGDF_NODEFAULT - }//switch - break; - case 1: switch (flow[angleTwin[e]]) - { - case 0: OR.angle(adjCor[e]) = 1; break; - OGDF_NODEFAULT - }//switch - break; - case 2: switch (flow[angleTwin[e]]) - { - case 0: OR.angle(adjCor[e]) = 0; break; - OGDF_NODEFAULT - }//switch - break; - OGDF_NODEFAULT - }//switch - }//progressive mode - }//if angle arc - } - - -#ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)) - cout << "\n\nTotal Number of Bends : "<< totalNumBends << endl << endl; -#endif - -#ifdef OGDF_DEBUG - String error; - if (OR.check(error) == false) { - cout << error << endl; - OGDF_ASSERT(false); - } -#endif - -}//call - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/orthogonal/CompactionConstraintGraph.cpp b/ext/OGDF/src/orthogonal/CompactionConstraintGraph.cpp deleted file mode 100644 index 1042034cb..000000000 --- a/ext/OGDF/src/orthogonal/CompactionConstraintGraph.cpp +++ /dev/null @@ -1,678 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class CompactionConstraintGraphBase. - * - * Represents base class for CompactionConstraintGraph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - -//#define foutput - -namespace ogdf { - - -// constructor for orthogonal representation -// builds constraint graph with basic arcs -CompactionConstraintGraphBase::CompactionConstraintGraphBase( - const OrthoRep &OR, - const PlanRep &PG, - OrthoDir arcDir, - int costGen, - int costAssoc, - bool align -) : - m_pathNode(OR), - m_edgeToBasicArc(OR,0) -{ - OGDF_ASSERT(&PG == &(const Graph &)OR); - - m_path .init(*this); - m_cost .init(*this,costAssoc); - m_type .init(*this,cetBasicArc); - m_verticalGen .init(PG, false); - m_verticalArc .init(*this, false); - m_border .init(*this, false); - m_alignmentArc.init(*this, false); - m_pathToEdge .init(*this, 0); - m_originalEdge.init(*this, 0); - - m_pPR = &PG;//only used in detecting cage visibility arcs - m_pOR = &OR; - m_align = align; - m_arcDir = arcDir; - m_oppArcDir = OR.oppDir(arcDir); - m_edgeCost[Graph::generalization] = costGen; - m_edgeCost[Graph::association ] = costAssoc; - - edge e; - forall_edges(e, PG) - { - if ((PG.typeOf(e) == Graph::generalization) && (!PG.isExpansionEdge(e))) - m_verticalGen[e] = true; - }//for - - insertPathVertices(PG); - insertBasicArcs(PG); -} - - -// insert vertex for each segment -void CompactionConstraintGraphBase::insertPathVertices(const PlanRep &PG) -{ - NodeArray genOpposite(PG,0); - - node v; - forall_nodes(v,PG) - { - const OrthoRep::VertexInfoUML *vi = m_pOR->cageInfo(v); - if (vi == 0 || PG.typeOf(v) == Graph::generalizationMerger) continue; - - adjEntry adjGen = vi->m_side[m_arcDir ].m_adjGen; - adjEntry adjOpp = vi->m_side[m_oppArcDir].m_adjGen; - if (adjGen != 0 && adjOpp != 0) - { - node v1 = adjGen->theNode(); - node v2 = adjOpp->theNode(); - genOpposite[genOpposite[v1] = v2] = v1; - } - } - - //TODO: hier abfragen, ob Kantensegment einer Originalkante - //und diese hat Multikantenstatus => man muss sich die Abstaende am Rand merken - //und auf alle Segmente anwenden - - NodeArray visited(PG,false); - - forall_nodes(v,PG) - { - if (!visited[v]) { - node pathVertex = newNode(); - - dfsInsertPathVertex(v, pathVertex, visited, genOpposite); - - //test for multi sep - //if exact two nodes in path, edge between is original edge segment, - //save this to recall the minsep for all segments later over original - //muss man hier originaledge als rueckgabe reintun??? - if ((m_path[pathVertex].size() == 2) && m_pathToEdge[pathVertex]) - { - - }//if original segment - else m_pathToEdge[pathVertex] = 0; - } - } -} - - -// insert all graph vertices into segment pathVertex -void CompactionConstraintGraphBase::dfsInsertPathVertex( - node v, - node pathVertex, - NodeArray &visited, - const NodeArray &genOpposite) -{ - visited[v] = true; - m_path[pathVertex].pushFront(v); - m_pathNode[v] = pathVertex; - - adjEntry adj; - forall_adj(adj,v) - { - OrthoDir dirAdj = m_pOR->direction(adj); - OGDF_ASSERT(dirAdj != odUndefined); - - if (dirAdj != m_arcDir && dirAdj != m_oppArcDir) { - //for multiedges, only useful if only one edge considered on path - //maybe zero if no original edge exists - if (!m_pathToEdge[pathVertex]) - { - //only reset later for multi edge segments - m_pathToEdge[pathVertex] = m_pPR->original(adj->theEdge()); - //used for all vertices - - } - - node w = adj->theEdge()->opposite(v); - if (!visited[w]) - dfsInsertPathVertex(w, pathVertex, visited, genOpposite); - } - } - - node w = genOpposite[v]; - if (w != 0 && !visited[w]) - dfsInsertPathVertex(w, pathVertex, visited, genOpposite); -} - - - -// -// insert an arc for each edge with direction m_arcDir -void CompactionConstraintGraphBase::insertBasicArcs(const PlanRep &PG) -{ - const Graph &G = *m_pOR; - - node v; - forall_nodes(v,G) - { - node start = m_pathNode[v]; - - adjEntry adj; - forall_adj(adj,v) { - if (m_pOR->direction(adj) == m_arcDir) { - edge e = newEdge(start, m_pathNode[adj->theEdge()->opposite(v)]); - m_edgeToBasicArc[adj] = e; - - m_cost[e] = m_edgeCost[PG.typeOf(adj->theEdge())]; - - //try to pull nodes up in hierarchies - if ( (PG.typeOf(adj->theEdge()) == Graph::generalization) && - (PG.typeOf(adj->theEdge()->target()) == Graph::generalizationExpander) && - !(PG.isExpansionEdge(adj->theEdge())) - ) - { - if (m_align) - { - //got to be higher than vertexarccost*doublebendfactor - m_cost[e] = 4000*m_cost[e]; //use parameter later corresponding - m_alignmentArc[e] = true; - }//if align - //to compconsgraph::doublebendfactor - else m_cost[e] = 2*m_cost[e]; - } - - //set generalization type - if (verticalGen(adj->theEdge())) m_verticalArc[e] = true; - //set onborder - if (PG.isDegreeExpansionEdge(adj->theEdge())) - { - edge borderE = adj->theEdge(); - node v1 = borderE->source(); - node v2 = borderE->target(); - m_border[e] = ((v1->degree()>2) && (v2->degree()>2) ? 2 : 1); - } - - } - } - } -} - - -// embeds constraint graph such that all sources and sinks lie in a common -// face -void CompactionConstraintGraphBase::embed() -{ - NodeArray onExternal(*this,false); - const CombinatorialEmbedding &E = *m_pOR; - face fExternal = E.externalFace(); - - adjEntry adj; - forall_face_adj(adj,fExternal) - onExternal[m_pathNode[adj->theNode()]] = true; - - // compute lists of sources and sinks - SList sources, sinks; - - node v; - forall_nodes(v,*this) { - if (onExternal[v]) { - if (v->indeg() == 0) - sources.pushBack(v); - if (v->outdeg() == 0) - sinks.pushBack(v); - } - } - -#ifdef foutput -writeGML("c:\\temp\\CCgraphbefore.gml", onExternal); -#endif - - // determine super source and super sink - node s,t; - if (sources.size() > 1) - { - s = newNode(); - SListIterator it; - for (it = sources.begin(); it.valid(); it++) - newEdge(s,*it); - } - else - s = sources.front(); - - if (sinks.size() > 1) - { - t = newNode(); - SListIterator it; - for (it = sinks.begin(); it.valid(); it++) - newEdge(*it,t); - } - else - t = sinks.front(); - - edge st = newEdge(s,t); - -#ifdef foutput -writeGML(String("c:\\temp\\CCgraph%d.gml"));//,randomNumber(0,20))); -writeGML("c:\\temp\\CClastgraph.gml"); -#endif - - bool isPlanar = planarEmbed(*this); - if (!isPlanar) OGDF_THROW(AlgorithmFailureException); - - - delEdge(st); - if (sources.size() > 1) - delNode(s); - if (sinks.size() > 1) - delNode(t); -} - - -// computes topological numbering on the segments of the constraint graph. -// Usage: If used on the basic (and vertex size) arcs, the numbering can be -// used in order to serve as sorting criteria for respecting the given -// embedding, e.g., when computing visibility arcs and allowing edges -// with length 0. -void CompactionConstraintGraphBase::computeTopologicalSegmentNum( - NodeArray &topNum) -{ - NodeArray indeg(*this); - StackPure sources; - - node v; - forall_nodes(v,*this) { - topNum[v] = 0; - indeg[v] = v->indeg(); - if(indeg[v] == 0) - sources.push(v); - } - - while(!sources.empty()) - { - node v = sources.pop(); - - edge e; - forall_adj_edges(e,v) { - if(e->source() != v) continue; - - node w = e->target(); - - if (topNum[w] < topNum[v] + 1) - topNum[w] = topNum[v] + 1; - - if (--indeg[w] == 0) - sources.push(w); - } - } -} - - - -class BucketFirstIndex : public BucketFunc > -{ -public: - int getBucket(const Tuple2 &t) { - return t.x1()->index(); - } -}; - -class BucketSecondIndex : public BucketFunc > -{ -public: - int getBucket(const Tuple2 &t) { - return t.x2()->index(); - } -}; - - -// remove "arcs" from visibArcs which we already have in the constraint graph -// (as basic arcs) -void CompactionConstraintGraphBase::removeRedundantVisibArcs( - SListPure > &visibArcs) -{ - // bucket sort list of all edges - SListPure all; - allEdges(all); - parallelFreeSort(*this,all); - - // bucket sort visibArcs - BucketFirstIndex bucketSrc; - visibArcs.bucketSort(0,maxNodeIndex(),bucketSrc); - - BucketSecondIndex bucketTgt; - visibArcs.bucketSort(0,maxNodeIndex(),bucketTgt); - - // now, in both lists, arcs are sorted by increasing target index, - // and arcs with the same target index by increasing source index. - SListConstIterator itAll = all.begin(); - SListIterator > it, itNext, itPrev; - - // for each arc in visibArcs, we check if it is also contained in list all - for(it = visibArcs.begin(); it.valid(); it = itNext) - { - // required since we delete from the list we traverse - itNext = it.succ(); - int i = (*it).x1()->index(); - int j = (*it).x2()->index(); - - // skip all arcs with smaller target index - while(itAll.valid() && (*itAll)->target()->index() < j) - ++itAll; - - // no more arcs => no more duplicates, so return - if (!itAll.valid()) break; - - // if target index is j, we also skip all arcs with target index i - // and source index smaller than i - while(itAll.valid() && (*itAll)->target()->index() == j && (*itAll)->source()->index() < i) - ++itAll; - - // no more arcs => no more duplicates, so return - if (!itAll.valid()) break; - - // if (i,j) is already present, we delete it from visibArcs - if ((*itAll)->source()->index() == i && - (*itAll)->target()->index() == j) - { - //visibArcs.del(it); - if (itPrev.valid()) - visibArcs.delSucc(itPrev); - else - visibArcs.popFront(); - } else - itPrev = it; - }//for visibArcs - - //****************************CHECK for - //special treatment for cage visibility - //two cases: input node cage: just compare arbitrary node - // merger cage: check first if there are mergers - itPrev = 0; - for(it = visibArcs.begin(); it.valid(); it = itNext) - { - - itNext = it.succ(); - - OGDF_ASSERT(!(m_path[(*it).x1()].empty()) && !(m_path[(*it).x1()].empty())); - - node boundRepresentant1 = m_path[(*it).x1()].front(); - node boundRepresentant2 = m_path[(*it).x2()].front(); - node en1 = m_pPR->expandedNode(boundRepresentant1); - node en2 = m_pPR->expandedNode(boundRepresentant2); - //do not allow visibility constraints in fixed cages - //due to non-planarity with middle position constraints - - if ( ( en1 && en2 ) && ( en1 == en2) ) - { - if (itPrev.valid()) visibArcs.delSucc(itPrev); - else visibArcs.popFront(); - } - else - { - //check if its a genmergerspanning vis arc, merge cases later - node firstn = 0, secondn = 0; - SListIterator< node > itn; - for (itn = m_path[(*it).x1()].begin(); itn.valid(); itn++) - { - node en = m_pPR->expandedNode(*itn); - if (!en) continue; - if (!(m_pPR->typeOf(*itn) == Graph::generalizationExpander)) continue; - else {firstn = en; break;} - }//for - for (itn = m_path[(*it).x2()].begin(); itn.valid(); itn++) - { - node en = m_pPR->expandedNode(*itn); - if (!en) continue; - if (!(m_pPR->typeOf(*itn) == Graph::generalizationExpander)) continue; - else {secondn = en; break;} - }//for - if ((firstn && secondn) && (firstn == secondn)) - { - if (itPrev.valid()) visibArcs.delSucc(itPrev); - else visibArcs.popFront(); - } - else itPrev = it; - } - }//for visibArcs - -} - - - -// output in gml-format with special edge colouring -// arcs with cost 0 are green, other arcs red -void CompactionConstraintGraphBase::writeGML(const char *filename) const -{ - ofstream os(filename); - writeGML(os); -} -void CompactionConstraintGraphBase::writeGML(const char *filename, NodeArray one) const -{ - ofstream os(filename); - writeGML(os, one); -} - -void CompactionConstraintGraphBase::writeGML(ostream &os) const -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " graphics [\n"; - os << " x 0.0\n"; - os << " y 0.0\n"; - os << " w 30.0\n"; - os << " h 30.0\n"; - - os << " fill \"#FFFF00\"\n"; - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - // nice idea to use the edge length as edge labels, but Graphwin- - // garbage is not able to show the graph (thinks it has to set - // the y-coordinates of all nodes to NAN) -#if 0 - os << " label \""; - writeLength(os,e); - os << "\"\n"; -#endif - - os << " graphics [\n"; - - os << " type \"line\"\n"; - os << " arrow \"last\"\n"; - switch(m_type[e]) - { - case cetBasicArc: // red - os << " fill \"#FF0000\"\n"; - break; - case cetVertexSizeArc: // blue - os << " fill \"#0000FF\"\n"; - break; - case cetVisibilityArc: // green - os << " fill \"#00FF00\"\n"; - break; - case cetReducibleArc: // rose - os << " fill \"#FF00FF\"\n"; - break; - case cetFixToZeroArc: //violett - os << " fill \"#3F00FF\"\n"; - break; - OGDF_NODEFAULT - } - - os << " ]\n"; // graphics - -#if 0 - os << " LabelGraphics [\n"; - os << " type \"text\"\n"; - os << " fill \"#000000\"\n"; - os << " anchor \"w\"\n"; - os << " ]\n"; -#endif - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -}//writegml - -void CompactionConstraintGraphBase::writeGML(ostream &os, NodeArray one) const -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::CompactionConstraintGraphBase::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " graphics [\n"; - os << " x 0.0\n"; - os << " y 0.0\n"; - os << " w 30.0\n"; - os << " h 30.0\n"; - if ((one[v])) { - os << " fill \"#FF0F0F\"\n"; - } else { - os << " fill \"#FFFF00\"\n"; - } - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - // nice idea to use the edge length as edge labels, but Graphwin- - // garbage is not able to show the graph (thinks it has to set - // the y-coordinates of all nodes to NAN) -#if 0 - os << " label \""; - writeLength(os,e); - os << "\"\n"; -#endif - - os << " graphics [\n"; - - os << " type \"line\"\n"; - os << " arrow \"last\"\n"; - switch(m_type[e]) - { - case cetBasicArc: // red - os << " fill \"#FF0000\"\n"; - break; - case cetVertexSizeArc: // blue - os << " fill \"#0000FF\"\n"; - break; - case cetVisibilityArc: // green - os << "fill \"#00FF00\"\n"; - break; - case cetReducibleArc: // rose - os << " fill \"#FF00FF\"\n"; - break; - case cetFixToZeroArc: //violett - os << " fill \"#3F00FF\"\n"; - break; - OGDF_NODEFAULT - } - - os << " ]\n"; // graphics - -#if 0 - os << " LabelGraphics [\n"; - os << " type \"text\"\n"; - os << " fill \"#000000\"\n"; - os << " anchor \"w\"\n"; - os << " ]\n"; -#endif - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/orthogonal/EdgeLabel-impl.h b/ext/OGDF/src/orthogonal/EdgeLabel-impl.h deleted file mode 100644 index 71f1baae3..000000000 --- a/ext/OGDF/src/orthogonal/EdgeLabel-impl.h +++ /dev/null @@ -1,2925 +0,0 @@ -/* - * $Archive: /ogdl/ogdf/EdgeLabel.cpp $ - * $Revision: 2572 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 17:32:30 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Class EdgeLabel handles edge label position computation. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -//#define foutput - -//#if !defined(_MSC_VER) && !defined(__BORLANDC__) -//#include -//#endif - - -const int coordBound = 1000000; - -//To be done: erzeuge fuer jeden Kandidaten einen Eintrag in m_candList, -//speichere Ueberlappungen durch Zeigerliste oder Listiterator? - - -namespace ogdf { - - //due to the visio interface we cant initialize all members - //here, aswe dont have a layout yet - template - ELabelPos::ELabelPos() - { - //initialize all members, check which labels are to be assigned - //m_assigned is set to false for all input labels and will be set - //to true if a position is assigned - - m_candStyle = 1; - m_placeHeuristic = 1; - m_posNum = 7; //(3) maybe for segment or whole length (4 candidates) - m_endInsertion = true; - - m_countFeatureIntersect = false; - - m_ug = 0; - m_prup = 0; - - m_segMargin = 0; - - }//eLabelPos - - - template - void ELabelPos::init(PlanRepUML& pru, - GridLayoutMapped& L, - ELabelInterface& eli) - { - - m_poly.init(pru.original()); - m_segInfo.init(pru.original()); - m_featureInfo.init(pru.original()); - m_edgeLength.init(pru.original()); - - m_eli = &eli; - m_gl = &L; - m_prup = &pru; - - m_ug = 0; - - m_defaultDistance = eli.distDefault(); - - m_segMargin = 1; - - int i; - for (i = 0; i < labelNum; i++) - { - m_assigned[i].init(pru.original(), false); - - m_candPosList[i].init(pru.original()); - m_candList[i].init(pru.original()); - - m_distance[i].init(pru.original(), m_defaultDistance); - m_intersect[i].init(pru.original()); - }//for - - - }//init - - template - void ELabelPos::call(PlanRepUML& pru, - GridLayoutMapped& L, - ELabelInterface& eli) //int - { - - init(pru, L, eli); - - OGDF_ASSERT(m_prup != 0); - - edge e; - - //initialize - initFeatureRectangles(); //grab the node size and position - initSegments(); //grab the segment position and number - - //start computation - computeCandidates(); - testFeatureIntersect(); - - //if there is only one candidate for an edge, - //we don't need to choose, but keep it for testing intersect. - - //build a data structure to decide feasible positioning - // initStructure(); - - //we don't need to delete in the list, only update match structure - testAllIntersect(); - - //now we know (in m_intersect) which labels intersect each other - //and have to choose the best candidates - //heuristic: first, cope with the labels having no candidates - //without intersection, for them choose a candidate - //having a) minimum intersection number - // b) intersection with labels having as many good - // candidates as possible - //should be collision-free! - //After that, check the remaining edges, choose a non-intersecting - //candidate (maybe having highest feature-distance) - - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - node v; - forall_nodes(v, *m_prup) - //forall_edges(e, m_prup->original()) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - - //run over all label positions, high constant... - int i; - for (i = 0; i < labelNum; i++) - { - bool intersectFree = false; - int minIntersect = coordBound; - int minIndex = 0; //index of minimum intersection numbers - for (int j=0; j < m_candPosList[i][e].size(); j++) - { - int intersections = (*m_intersect[i][e].get(j)).size(); - if (intersections > 0) - { - if (intersections < minIntersect) minIndex = j; - }//if problem - else intersectFree = true; - }//for candidates - //first round: only assign problematic labels - if ((m_candPosList[i][e].size() > 0) && !intersectFree) - { - eli.getLabel(e).setX((eLabelTyp)i, (*m_candPosList[i][e].get(minIndex)).m_x); - eli.getLabel(e).setY((eLabelTyp)i, (*m_candPosList[i][e].get(minIndex)).m_y); - - m_assigned[i][e] = true; - }//if - else //delete all intersecting candidates - { - ListIterator< GenericPoint > l_it = m_candPosList[i][e].begin(); - int k = 0; - - while (l_it.valid()) - { - int intersections = (*m_intersect[i][e].get(k)).size(); - - if (intersections > 0) - { - ListIterator< GenericPoint > l_dummy = l_it; - l_it++; - m_candPosList[i][e].del(l_dummy); - //l_it++; - }//if problem - - if (l_it.valid()) l_it++; - k++; - }//while - - }//else - }//for labeltypes - - } - }//forallnodes //edges - - //now we have to work on the labels without any good or - //bad candidates (all were intersecting original nodes) - - //after having assigned all problematic labels, - //we have to cope with the remaining labels / edges - //check all edges in current CC - //EdgeArray - checked.init(m_prup->original(), false); - - //node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - - if (checked[e]) continue; - - checked[e] = true; - - //run over all label positions, high constant... - int i; - for (i = 0; i < labelNum; i++) - { - //hier sollte man einen bestimmten (z.B. Mitte) aus allen intersectfree waehlen - if (!(m_assigned[i])[e]) //assign intersection free - { - //after preprocessing, all should have an entry, but preliminary - if (m_candPosList[i][e].size() > 0) - { - int preferredIndex = int(floor(double(m_candPosList[i][e].size())/2));//2.0 - //check: labelnum <4 => ln-2 <=1 should not happen - if ((i == 0) || (i == 1)) preferredIndex = 0; - if ( ((i == labelNum-2) || (i == labelNum-1)) && (m_candPosList[i][e].size() > 0) ) - preferredIndex = m_candPosList[i][e].size() - 1; - eli.getLabel(e).setX((eLabelTyp)i, - (*m_candPosList[i][e].get(preferredIndex)).m_x); - eli.getLabel(e).setY((eLabelTyp)i, - (*m_candPosList[i][e].get(preferredIndex)).m_y); - - m_assigned[i][e] = true; - }//if - }//if - }//for - - }//foralladjedges - }//forallnodes -#ifdef foutput - writeGML("result.gml", opResult); -#endif - - }//call - - - //forall edges and all label types, candidate placement positions - //are inserted in m_candPosList - template - void ELabelPos::computeCandidates() - { - -#ifdef foutput - //ofstream fout("candpos.txt",ios::app); -#endif - edge e; - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - - //different heuristics - switch (m_candStyle) - { - //standard method, just split edge length - case 1 : - { - int labelIndex; //the label index, 0 = end1,... - - //alle Endlabel (e1/m1, e2/m2) werden moeglichst paarweise gegenueberliegend - //angeordnet, dafuer wird der Platz dann ungleichmaessig verteilt (aber nach welchem Schluessel?) - //ausserdem koennen sich die Bereiche fuer Typen ueberlappen - - //hier muessen noch abstaende von original graph features hinzu - //its not clear yet if posNum is length or number - //labelNum is the OGDL-wide number of possible label types - //defined in ELabelInterface.h - //m_posNum is number of pos. cand. for candstyle 1, like ppinch - //distancestep defines the distance between consecutive label - //candidates - double distanceStep = m_edgeLength[e] / (labelNum*m_posNum); - int distance = 0; //running distance from start //+mindist - coordType standardDist = max(m_eli->minFeatDist(), - coordType(floor(double(distance))) ); - //int currentLengthPos = 0; //label pos. relative to edge length - int segIndex = 0; //segment index = index of starting point in m_poly - int currentPos = 1; //number of label positions - SegmentInfo si = (*m_segInfo[e].get(segIndex)); - int currentEnd = (int)si.length; - - int segStartX = (int)((*m_poly[e].get(segIndex)).m_x); - int segStartY = (int)((*m_poly[e].get(segIndex)).m_y); - //all labeltypes*the number of cand. per labeltype - while (currentPos <= labelNum*m_posNum) - { -#ifdef foutput - //fout<<" segment:\n"; - //fout<<" dir: "<getWidth(e, (eLabelTyp)labelIndex)); - int aktLabelHeight = (int)(m_eli->getHeight(e, (eLabelTyp)labelIndex)); - int alwHalf = int(ceil((double)(aktLabelWidth) / 2)); - int alhHalf = int(ceil((double)(aktLabelHeight) / 2)); - //derive symmetry label size - int symmLabel = 0; - int symmW = 0, symmH = 0; - switch (labelIndex) - { - case 0: symmLabel = 1; break; - case 1: symmLabel = 0; break; - case labelNum-2: symmLabel = labelNum-1; break; - case labelNum-1: symmLabel = labelNum-2; break; - }//switch - symmW = int(ceil( (double)(m_eli->getWidth(e, (eLabelTyp)symmLabel) ) / 2)); - symmH = int(ceil( (double)(m_eli->getHeight(e, (eLabelTyp)symmLabel) ) / 2)); -#ifdef foutput - //fout<<" labelIndex: "< candidate; - GenericPoint symmCandidate; //end label on the opposite edge side - //now assign positions according to segment direction - //endlabels are shifted depending on direction and type/distance - //in inner switch statement - //ausserdem einfache Tests - //necessary because left lower corner needs labelsize shift - //in some cases, but they are difficult to check later - //hier sollte man auch doppelpos. fuer Namen einfuehren und dabei m_distance zulassen - switch (si.direction) - { - case odWest: //horizontal west - { - candidate.m_x = segStartX - int(floor((double)((currentPos - segStartLabel))*distanceStep)); - //(currentPos - segStartLabel)*standardDist; - candidate.m_y = segStartY; - - switch (labelIndex) - { - case 0: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case 1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-2: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - }//switch - break; - }//odWest - case odNorth: - { - candidate.m_x = segStartX; - candidate.m_y = segStartY + int(floor((currentPos - segStartLabel)*distanceStep)); - // (currentPos - segStartLabel)*standardDist; - - switch (labelIndex) - { - case 0: symmCandidate.m_x = candidate.m_x + - m_distance[symmLabel][e] + symmW; - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case 1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-2: symmCandidate.m_x = candidate.m_x + - (m_distance[symmLabel][e] + symmW); - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - }//switch - break; - }//odNorth - case odEast: //horizontal - { - candidate.m_x = segStartX + int(floor((currentPos - segStartLabel)*distanceStep)); - //+ (currentPos - segStartLabel)*standardDist; - candidate.m_y = segStartY; - - switch (labelIndex) - { - case 0: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case 1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-2: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - }//switch - break; - }//odEast - case odSouth: - { - candidate.m_x = segStartX; - candidate.m_y = segStartY - int(floor((currentPos - segStartLabel)*distanceStep)); - //(currentPos - segStartLabel)*standardDist; - - switch (labelIndex) - { - case 0: symmCandidate.m_x = candidate.m_x + - m_distance[symmLabel][e] + symmW; - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case 1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-2: symmCandidate.m_x = candidate.m_x + - m_distance[symmLabel][e] + symmW; - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - }//switch - break; - }//odSouth - default: OGDF_THROW_PARAM(AlgorithmFailureException, afcLabel); - }//switch - - currentPos++; - distance = int(floor(currentPos*distanceStep)); - List l_dummy; - m_candPosList[labelIndex][e].pushBack(candidate); - //will be replaced by - m_candList[labelIndex][e].pushBack(PosInfo(e, (eLabelTyp)labelIndex, candidate)); - m_intersect[labelIndex][e].pushBack(l_dummy); - //end labels can be on opposite edge sides - if ( (labelIndex == 0) || - (labelIndex == 1) || - (labelIndex == labelNum-2) || - (labelIndex == labelNum-1) - ) - { - m_candPosList[symmLabel][e].pushBack(symmCandidate); - //will be replaced by - m_candList[symmLabel][e].pushBack(PosInfo(e, (eLabelTyp)symmLabel, symmCandidate)); - m_intersect[symmLabel][e].pushBack(l_dummy); - } - - }//while - - //jump to new segment - segIndex++; - - if (segIndex < m_segInfo[e].size()) - { - si = (*m_segInfo[e].get(segIndex)); - segStartX = (int)(*m_poly[e].get(segIndex)).m_x; - segStartY = (int)(*m_poly[e].get(segIndex)).m_y; - currentEnd += (int)si.length; - }//if - else break; - }//while - //for (labelIndex = 0; labelIndex < labelNum; labelIndex++) - //no we have processed all edge segments - - break; - }//case - default : break; - }//switch - int forI; - for(forI = 0; forI < labelNum; forI++) - { - OGDF_ASSERT(m_candPosList[forI][e].size() > 0); - }//For - }//foralladjedges - }//forallnodes -#ifdef foutput - writeGML(); -#endif - - }//computeCandidates - - - //build up intersection structure - template - void ELabelPos::initStructure() - { - //simple heuristic: - //pair (edge, labeltyp) has node with neighbours for all candidates - //intersecting candidates are connected - edge e; - node v; - - //back link graph nodes and positions - NodeArray l_labelInfo(m_intersectGraph); - //forward link - //link pair (edge, labeltyp) to node in intersectgraph - EdgeArray l_pairNode[labelNum]; - //use same order in candidate list to navigate in l_posNode - EdgeArray< List > l_posNode[labelNum]; - for (int i = 0; i < labelNum; i++) - { - l_pairNode[i].init(m_prup->original()); - l_posNode[i].init(m_prup->original()); - }//for - - //insert nodes in m_intersectGraph for all pairs - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - //node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - - // forall_edges(e, m_prup->original()) - // { - for (int i = 0; i < labelNum; i++) - { - v = m_intersectGraph.newNode(); - - LabelInfo li; - li.m_e = e; li.m_labelTyp = i; - l_labelInfo[v] = li; - - l_pairNode[i][e] = v; - - //insert nodes for the candidate positions for all pairs - //and connect them to the pairs representant - List< GenericPoint >& l_posList = posList(e,i); //all candidates for label Nr. i - - ListIterator< GenericPoint > it = l_posList.begin(); - //int candIndex = 0; - while (it.valid()) - { - node w = m_intersectGraph.newNode(); - l_posNode[i][e].pushBack(w); - - //candIndex++; - it++; - }//while - }//for - }//foralladjedges - }//forallnodes - - //now connect intersecting label representants - forall_edges(e, m_prup->original()) - { - for (int i = 0; i < labelNum; i++) - { - }//for - }//forall_edges - - }//initStructure - - - //check candidate positions for feature intersection - //intersecting cp are deleted from the list, but saved in a pool - //for possible assignment to left over edges - template - void ELabelPos::testFeatureIntersect() - { - - //labeltree not implemented yet, just check with all graph features - //initialize label structure - - //assure spare candidate - EdgeArray< GenericPoint > l_saveCandidate[labelNum]; - for (int k = 0; k < labelNum; k++) l_saveCandidate[k].init(m_prup->original()); - saveRecovery(l_saveCandidate); - - edge e; - //for all edge labels and their cand. pos., we check intersections - //with original graph features - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - - // forall_edges(e, m_prup->original()) - // { - int i; - for (i = 0; i < labelNum; i++) - { - //hier und beim berechnen der Kandidaten noch aendern: - //man braucht ja echte Labelposition und die Groesse, wichtig - //auch, da man die Richtung des Labels wissen muss - //insert labels into structure - List< GenericPoint >& l_posList = posList(e,i); //all candidates for label Nr. i - //will be replaced by - List& l_candList = candList(e, i); - - //check intersection with original graph nodes: - - //simple version one after another - ListIterator< GenericPoint > it = l_posList.begin(); - while (it.valid()) - { - - //label size and position - int minXLabel = (int)((*it).m_x - (m_eli->getWidth(e, (eLabelTyp)i) / 2)); - int maxXLabel = (int)((*it).m_x + (m_eli->getWidth(e, (eLabelTyp)i) / 2)); - int minYLabel = (int)((*it).m_y - (m_eli->getHeight(e, (eLabelTyp)i) / 2)); - int maxYLabel = (int)((*it).m_y + (m_eli->getHeight(e, (eLabelTyp)i) / 2)); - - node w; - //simple version: check with all original node rectangles - bool intersect = false; - forall_nodes(w, m_prup->original()) - { - FeatureInfo& fi = m_featureInfo[w]; - - intersect = ( (minXLabel <= fi.max_x) && - (maxXLabel >= fi.min_x) && - (minYLabel <= fi.max_y) && - (maxYLabel >= fi.min_y) ); - - if (intersect) break; - - }//forall_nodes - if (intersect) - { - ListIterator< GenericPoint > itX = it; - it++; - l_posList.del(itX); - - continue; - } - - it++; - }//while - - //now check if there is a proper candidate left - if (l_posList.empty()) - { - //assure proper label position assignment - //search a new position and give edge highest priority - l_posList.pushBack(l_saveCandidate[i][e]); - }//if - - //if there is only one cand, we don't need to decide, but there - //may be no intersection (test only for secu. testing) - - }//for - }//foralladjedges - }//forallnodes -#ifdef foutput - writeGML("label2.gml"); -#endif - }//testfeatureintersect - - - template - void ELabelPos::saveRecovery(EdgeArray< GenericPoint > (&saveCandidate)[labelNum]) - { - //a labeltype - dependant extra candidate for label positioning should - //be defined here to help in case of empty cand.list after featureintersect - - //simple version: use one (middle?) of the original candidates - - edge e; - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - //forall_edges(e, mapGraph) - //{ - int i; - for (i = 0; i < labelNum; i++) - { - List< GenericPoint >& l_posList = posList(e,i); //all candidates for label Nr. i - //hier: sichere, das Eintrag vorhanden - saveCandidate[i][e] = (*l_posList.get(int(floor((double)(l_posList.size())/2)))); - }//for labeltypes - }//foralladjedges - }//forallnodes - - }//saveRecovery - - - //check label positions for label/label intersection - //don't consider same edge label/label intersection - template - void ELabelPos::testAllIntersect() - { - List l_featureList; - //as long as labeltree is not implemented, use a worst case quadratic - //test better than round robin - edge e; - - //for all edge labels and their cand. pos., we check intersections - //with other label positions - //insert candidates in list - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - - // forall_edges(e, m_prup->original()) - // { - int i; - for (i = 0; i < labelNum; i++) - { - //insert labels into structure - List< GenericPoint >& l_posList = posList(e,i); //all candidates for label Nr. i - - //simple version one after another - int index = 0; - ListIterator< GenericPoint > it = l_posList.begin(); - while (it.valid()) - { - - //label size and position - FeatureInfo fi; - fi.size_x = m_eli->getWidth(e, (eLabelTyp)i); - fi.size_y = m_eli->getHeight(e, (eLabelTyp)i); - fi.min_x = (*it).m_x - int(ceil((fi.size_x / 2))); - fi.max_x = (*it).m_x + int(ceil((fi.size_x / 2))); - fi.min_y = (*it).m_y - int(ceil((fi.size_y / 2))); - fi.max_y = (*it).m_y + int(ceil((fi.size_y / 2))); - - //hier muss noch der Knoten hin - l_featureList.pushBack(FeatureLink(e, (eLabelTyp)i, 0, fi, index)); - - index++; - it++; - }//while - - - }//for - - }//foralladjedges - - }//forallnodes - //***************************************** - //now check - //********************************************* - - //Sort the label positions and perform sweepline run - FeatureComparer fc; - l_featureList.quicksort(fc); - - //run over all candidate positions and check intersections - //objects are active, if their y-intervall encloses the current - //sweepline position - - FeatureLink runFI; //next label position to be processed - ListIterator l_it = l_featureList.begin(); - - List sweepLine; - - int aktY = -coordBound - 1; //current y-coordinate of sweepline - - //run over all inserted label positions - while (l_it.valid()) - { - - OGDF_ASSERT((*l_it).m_fi.min_y > aktY); - - aktY = (int)((*l_it).m_fi.min_y); - - ListIterator itSweep = sweepLine.begin(); //sweepline iterator - - //loesche alle abgelaufenen events - while (itSweep.valid()) - { - if ((*itSweep).m_fi.max_y < aktY) - { - ListIterator itNext = itSweep.succ(); - sweepLine.del(itSweep); - itSweep = itNext; - continue; - } - itSweep++; - }//while - - itSweep = sweepLine.begin(); - //now we have only active events left, with y-intervall - //including current sweepline-position - - //run over all starting objects - while (l_it.valid() && (aktY == (*l_it).m_fi.min_y)) - { - itSweep = sweepLine.begin(); - //run over sweepline to find position and check intersection - //sort sweepline by increasing min_x-value - FeatureLink& fl = (*l_it); - - int aktX = (int)((*l_it).m_fi.min_x); - - //skip/test objects left of l_it - while (itSweep.valid() && (aktX > (*itSweep).m_fi.min_x) ) - { - //test on intersection - if (aktX <= (*itSweep).m_fi.max_x) - { - FeatureLink& fls = (*itSweep); - //intersecting another position for the same label is ok - if (!( (fl.m_elt == fls.m_elt) && (fl.m_edge == fls.m_edge) )) - (*m_intersect[fl.m_elt][fl.m_edge].get(fl.m_index)).pushBack( - LabelInfo(fls.m_edge, fls.m_elt, fls.m_index)); - } - itSweep++; - }//while left - //sweepline empty or object on same pos. / to the right found - //insert into sweepline: end or after last - if (!itSweep.valid()) - { - sweepLine.pushBack((*l_it)); - }//if rightmost entry - else - { - sweepLine.insertBefore((*l_it), itSweep); - /* - //now check for intersection until min_x > l_it.max_x - while ( itSweep.valid() && ((*itSweep).m_fi.min_x <= (*l_it).m_fi.max_x) ) - { - //hier muss man noch abfragen, ob es nicht die gleiche (e,typ) Sorte ist - FeatureLink& fls = (*itSweep); - (*m_intersect[fl.m_elt][fl.m_edge].get(fl.m_index)).pushBack( - LabelInfo(fls.m_edge, fls.m_elt, fls.m_index)); - itSweep++; - }//while*/ - }//else insert before - //now check for intersection until min_x > l_it.max_x - while ( itSweep.valid() && ((*itSweep).m_fi.min_x <= (*l_it).m_fi.max_x) ) - { - FeatureLink& fls = (*itSweep); - //intersecting another position for the same label is ok - if (!( (fl.m_elt == fls.m_elt) && (fl.m_edge == fls.m_edge) )) - (*m_intersect[fl.m_elt][fl.m_edge].get(fl.m_index)).pushBack( - LabelInfo(fls.m_edge, fls.m_elt, fls.m_index)); - itSweep++; - }//while - l_it++; - }//while starting - - //l_it++; - }//while l_it - - - //****************************************** - //now check if there is a proper candidate left - /* - if (l_posList.empty()) - { - //assure proper label position assignment - //search a new position and give edge highest priority - - }//if - */ - //if there is only one cand, we don't need to decide, but there - //may be no intersection (test only for secu. testing - //check end - //***************************************** - -#ifdef foutput - writeGML("label3.gml", opOmitIntersect); -#endif - - }//testAllIntersect - - - template - void ELabelPos::initSegments() - { - //we count the number of segments and their position/length - edge e; - //check all edges in current CC - EdgeArray checked(m_prup->original(), false); - - node v; - forall_nodes(v, *m_prup) - { - node w = m_prup->original(v); - if (!w) continue; - - forall_adj_edges(e, w) - { - //e = m_prup->original(e1); - //if (!e) continue; - if (checked[e]) continue; - - checked[e] = true; - - // forall_edges(e, m_prup->original()) - // { - edge ec; - int crossCount = 0; - int bendCount = 0; - int length = 0; - - if (m_prup->chain(e).size() < 1) continue; //dont count - //non-existing edges from other connected components - - edge et = m_prup->copy(e); //chain(e).front - - //fill the m_poly polyline for original e - m_poly[e].pushBack( GenericPoint(m_gl->x(et->source()), m_gl->y(et->source()))); - - //count all inner nodes as crossings or bends - ListConstIterator l_it; - - - int currNum = 1; - for(l_it = m_prup->chain(e).begin(); l_it.valid(); ++l_it) - { - SegmentInfo si; - - ec = *l_it; - GenericPoint ip1(m_gl->x(ec->source()), m_gl->y(ec->source())); - GenericPoint ip2(m_gl->x(ec->target()), m_gl->y(ec->target())); - m_poly[e].pushBack(ip2); - int len = max(abs(m_gl->x(ec->target()) - m_gl->x(ec->source()) ), - abs(m_gl->y(ec->target())- m_gl->y(ec->source()) ) ); - //set segmentinfo values - si.length = len; - si.number = currNum; - - OrthoDir od; - bool isHor = (ip1.m_y == ip2.m_y); //may still be same place - if (isHor) - { - if (ip1.m_x > ip2.m_x) od = odWest; - else od = odEast; - }//if isHor - else - { - //check m_x == m_x - if (ip1.m_y < ip2.m_y) od = odNorth; - else od = odSouth; - }//else - si.direction = od; - - m_segInfo[e].pushBack(si); - - //set overall edge length - length+= len; - - //dont count last edge - if ( l_it == m_prup->chain(e).rbegin() ) continue; - node nextV = ec->target();//depends on chain direction - if (nextV->degree()==4) crossCount++; - else bendCount++; - - currNum++; - }//forall copy edges in list - m_edgeLength[e] = length; - - }//foralladjedges - }//forall nodes //edges in pru - - }//initSegments - - - template - void ELabelPos::initFeatureRectangles() - { - node v; - //forall original nodes: get cage size and position - //if applied to result graph and layout, we dont need this - NodeArray checked(m_prup->original(), false); - forall_nodes(v, *m_prup) - { - node w = m_prup->expandedNode(v); - if (w != 0) - { - int aktX = m_gl->x(v); - int aktY = m_gl->y(v); - node wo = m_prup->original(w); - if (wo) - { - if (checked[wo]) //already processed node - { - if (aktX > m_featureInfo[wo].max_x) - m_featureInfo[wo].max_x = aktX; - if (aktY > m_featureInfo[wo].max_y) - m_featureInfo[wo].max_y = aktY; - if (aktX < m_featureInfo[wo].min_x) - m_featureInfo[wo].min_x = aktX; - if (aktY < m_featureInfo[wo].min_y) - m_featureInfo[wo].min_y = aktY; - m_featureInfo[wo].size_x = m_featureInfo[wo].max_x - m_featureInfo[wo].min_x; - m_featureInfo[wo].size_y = m_featureInfo[wo].max_y - m_featureInfo[wo].min_y; - }//if - else //new node - { - FeatureInfo fi; - fi.min_x = fi.max_x = aktX; - fi.min_y = fi.max_y = aktY; - fi.size_x = fi.size_y = 0; - - m_featureInfo[m_prup->original(w)] = fi; - - checked[m_prup->original(w)] = true; - - }//else - }//if original - }//if - }//forallnodes - - //now all expanded (original) nodes have a featureinfo - - }//initFeatureRectangles - - - - //************************************************************************* - //AttributedGraph-call section - template - void ELabelPos::call(GraphAttributes& ug, ELabelInterface& eli) //double - { - initUML(ug, eli); - - OGDF_ASSERT(m_ug != 0); - - edge e; - //initialize - initUMLFeatureRectangles(); //grab the node size and position - initUMLSegments(); //grab the segment position and number - - //start computation - computeUMLCandidates();//compute possible positions - - testUMLFeatureIntersect();//check for graph object intersection - - //if there is only one candidate for an edge, - //we don't need to choose, but keep it for testing intersect. - - //build a data structure to decide feasible positioning - //initStructure(); - - testUMLAllIntersect();//now check for label intersection - - //************************************************************ - //now we know (in m_intersect) which labels intersect each other - //and have to choose the best candidates - //heuristics: - //a) - //first, cope with the labels having no candidates - //without intersection, for them choose a candidate - //having a) minimum intersection number - // b) intersection with labels having as many good - // candidates as possible - //should be collision-free! - //After that, check the remaining edges, choose a non-intersecting - //candidate (maybe having highest feature-distance) - - //b) - //first assign intersection-free candidates and update the status - //of all other label candidates (possibly creating new intersection - //free candidates) - - //c) store all candidates in a heap with assigned costs and assign - //them in output order - - - //dynamically set m_active to csAssigned for all candidates of labels - //that get a position assignment which are not assigned themselves - - m_placeHeuristic = 2; - - //c) - if (m_placeHeuristic == 2) - { - int assignmentCount = 0; - edge e; - forall_edges(e, m_ug->constGraph()) - { - EdgeLabel& l_el = eli.getLabel(e); - //run over all label positions - int i; - for (i = 0; i < labelNum; i++) - { - if (!l_el.usedLabel((eLabelTyp)i)) continue; - - //run over all candidates and compare their intersection numbers - ListIterator< PosInfo > l_it = candList(e, i).begin(); - while (l_it.valid()) - { - double* cost = &((*l_it).m_cost); - PosInfo* myPos = &(*l_it); - int* update = &myPos->m_posIndex; - m_candidateHeap.insert(myPos, *cost, update); - - l_it++; - }//while candidates - }//for - }//foralledges - - //***************************************** - //now assign labels by extracting from heap - - while (!m_candidateHeap.empty()) - { - PosInfo* nextPos = m_candidateHeap.extractMin(); - while ( m_assigned[nextPos->m_typ][nextPos->m_edge] ) - { - if (m_candidateHeap.empty()) - { - nextPos = 0; - break; - }//if - nextPos = m_candidateHeap.extractMin(); - }//while - - //now nextPos holds the next unassigned PosInfo - if (nextPos == 0) break; - - edge e = nextPos->m_edge; - eLabelTyp elt = nextPos->m_typ; - //we use costs - //OGDF_ASSERT(nextPos->m_active == csActive); - - //assign the candidate - eli.getLabel(e).setX(elt, nextPos->m_coord.m_x); - eli.getLabel(e).setY(elt, nextPos->m_coord.m_y); - m_assigned[elt][e] = true; - - nextPos->m_active = csUsed; //is the only used candidate for this pair (e, elt) - assignmentCount++; - - //now update all unused candidates - //unused candidates get status csAssigned, - //their intersections are updated (priority) to find new minimal intersection candidates - List < PosInfo >& l_cands = candList(e, elt); - ListIterator< PosInfo > l_itCands = l_cands.begin(); - while (l_itCands.valid()) - { - if ( ((*l_itCands).m_active != csUsed) && - ((*l_itCands).m_active != csFIntersect) //they are not inserted in lists! - ) - { - //TODO: teste, ob fuer fintersect auch die anzahl korrigiert wird - (*l_itCands).m_active = csAssigned; - List & l_sects = (*l_itCands).m_intersect; - ListIterator l_itSects = l_sects.begin(); - while (l_itSects.valid()) - { - //ATTENTION: we only update the intersection number, not the list! - (*l_itSects)->m_numActive--; - OGDF_ASSERT((*l_itSects)->m_numActive >= 0); - double newCost = m_candidateHeap.getPriority((*l_itSects)->m_posIndex) - - costLI(); - (*l_itSects)->m_cost = newCost; - m_candidateHeap.decreaseKey((*l_itSects)->m_posIndex, - newCost - ); - - l_itSects++; - - }//while - - }//if - - l_itCands++; - }//while - - - }//while candidates - - }//placeheuristic c - - //store intersection free candidates for version a) - //preliminary till concept expanded - EdgeArray< List< PosInfo* > > l_freeCand[labelNum]; - for (int k=0; k < labelNum; k++) - { - l_freeCand[k].init(m_ug->constGraph()); - }//for - - - //a) - //******************************************************************* - if (m_placeHeuristic == 0) - { - forall_edges(e, m_ug->constGraph()) - { - EdgeLabel& l_el = eli.getLabel(e); - //run over all label positions - int i; - for (i = 0; i < labelNum; i++) - { - if (!l_el.usedLabel((eLabelTyp)i)) continue; - - bool intersectFree = false; - int minIntersect = coordBound; - PosInfo* minPointer; //PosInfo of cand. with minimum intersection numbers - - //run over all candidates and compare their intersection numbers - ListIterator< PosInfo > l_it = candList(e, i).begin(); - while (l_it.valid()) - { - //TODO: hier muss man zwischen csFIntersect und anderen unterscheiden - int intersections = (*l_it).m_intersect.size(); - if (intersections > 0) - { - //TODO: hier auf Anzahl testen ( b) ) - if (intersections < minIntersect) minPointer = &(*l_it); - }//if problem - else intersectFree = true; - l_it++; - }//while candidates - - //first round: only assign problematic labels - if ((candList(e, i).size() > 0) && !intersectFree) - { - eli.getLabel(e).setX((eLabelTyp)i, minPointer->m_coord.m_x); - eli.getLabel(e).setY((eLabelTyp)i, minPointer->m_coord.m_y); - - minPointer->m_active = csUsed; - - m_assigned[i][e] = true; - //TODO: forall other candidates, set status to csassigned - }//if - else //delete all intersecting candidates - { - ListIterator< PosInfo > l_it = candList(e, i).begin(); - - while (l_it.valid()) - { - int intersections = (*l_it).m_intersect.size(); - - if (intersections == 0) l_freeCand[i][e].pushBack(&(*l_it)); - - l_it++; - }//while - - }//else - }//for labeltypes - }//foralledges - }//if heuristics 0 - //********************************************************** - - //b) - //********************************************************** - if (m_placeHeuristic == 1) - { - - int assignmentCount = 0; - - //**************************************************** - //Assigning position candidates to labels - //m_numAssignment is the counted number of used labels - - while (assignmentCount < m_numAssignment) - { - //************************************************** - //assign intersection free label position candidates - while (!m_freeLabels.empty()) - { - PosInfo* l_front = m_freeLabels.popFrontRet(); - //remove already assigned leading candidates - //entweder m_assigned oder posinfostatus, da pointer - while (m_assigned[l_front->m_typ][l_front->m_edge]) - { - if (m_freeLabels.empty()) - { - l_front = 0; - break; - }//if - l_front = m_freeLabels.popFrontRet(); - }//while assigned - //look if there is still something to do - if (l_front != 0) - { - edge e = l_front->m_edge; - eLabelTyp elt = l_front->m_typ; - OGDF_ASSERT(l_front->m_active == csActive); - - //assign the candidate - eli.getLabel(e).setX(elt, l_front->m_coord.m_x); - eli.getLabel(e).setY(elt, l_front->m_coord.m_y); - m_assigned[elt][e] = true; - l_front->m_active = csUsed; //is the only used candidate for this pair (e, elt) - assignmentCount++; - - //now update all unused candidates - //unused candidates get status csAssigned, - //their intersections are updated to find new minimal intersection candidates - List < PosInfo >& l_cands = candList(e, elt); - ListIterator< PosInfo > l_itCands = l_cands.begin(); - while (l_itCands.valid()) - { - if ( ((*l_itCands).m_active != csUsed) && - ((*l_itCands).m_active != csFIntersect) //they are not inserted in lists! - ) - { - //TODO: teste, ob fuer fintersect auch die anzahl korrigiert wird - (*l_itCands).m_active = csAssigned; - List & l_sects = (*l_itCands).m_intersect; - ListIterator l_itSects = l_sects.begin(); - while (l_itSects.valid()) - { - //ATTENTION: we only update the intersection number, not the list!! - // (could use lis::pos(ListIterator)) - (*l_itSects)->m_numActive--; - //if the label is now free of intersections, insert it in list - if ( ((*l_itSects)->m_numActive == 0) && - ((*l_itSects)->m_active != csFIntersect) ) - m_freeLabels.pushBack((*l_itSects)); - l_itSects++; - - }//while - - }//if - - l_itCands++; - }//while - - }//if valid - - }//while free labels - - //*********************************************** - //assign intersecting candidates if necessary - //hier jetzt einen Kandidaten auswaehlen, der nicht intersectionfree ist, - //aber bestimmte Voraussetzungen mitbringt, etwa wenige oder viele - //Ueberschneidungen - //choose a good candidate among intersecting label positions - if (!m_sectLabels.empty()) - { - PosInfo* l_sect = m_sectLabels.popFrontRet(); - - while ( m_freeLabels.empty() && (l_sect != 0) ) - { - //************************************** - //check if we havent used this entry yet - //TODO: dont use csFIntersect - while ( (l_sect->m_active == csAssigned) || - (l_sect->m_active == csUsed) || - (l_sect->m_numActive == 0) - ) - { - if (m_sectLabels.empty()) - { - l_sect = 0; - break; - }//if - l_sect = m_sectLabels.popFrontRet(); - - }//while invalid entries - - //******************************** - //assign an intersecting candidate - //TODO: use priority queue and choose "good" entry - if (l_sect != 0) - { - edge e = l_sect->m_edge; - eLabelTyp elt = l_sect->m_typ; - OGDF_ASSERT((l_sect->m_active == csActive) - || (l_sect->m_active == csFIntersect) //preliminary - ); - - //assign the candidate - eli.getLabel(e).setX(elt, l_sect->m_coord.m_x); - eli.getLabel(e).setY(elt, l_sect->m_coord.m_y); - m_assigned[elt][e] = true; - l_sect->m_active = csUsed; //is the only used candidate for this pair (e, elt) - assignmentCount++; - - //now update all intersected candidates and all unused candidates - //unused candidates get status csAssigned, - //their intersections are updated to find new minimal intersection candidates - List < PosInfo >& l_cands = candList(e, elt); - ListIterator< PosInfo > l_itCands = l_cands.begin(); - while (l_itCands.valid()) - { - if ( ((*l_itCands).m_active != csUsed) && - ((*l_itCands).m_active != csFIntersect) - ) - { - //TODO: teste, ob fuer fintersect auch die anzahl korrigiert wird - (*l_itCands).m_active = csAssigned; - List & l_sects = (*l_itCands).m_intersect; - ListIterator l_itSects = l_sects.begin(); - while (l_itSects.valid()) - { - //ATTENTION: we only update the intersection number, not the list!! - // (could use lis::pos(ListIterator)) - (*l_itSects)->m_numActive--; - //if the label is now free of intersections, insert it in list - if ( ((*l_itSects)->m_numActive == 0) && - ((*l_itSects)->m_active != csFIntersect) ) - m_freeLabels.pushBack((*l_itSects)); - l_itSects++; - - }//while - - }//if - - l_itCands++; - }//while - }//if valid entry found - - }//while no other than intersecting labels - }//if - - //dann kontrollieren, ob es weder Ueberschneidungsfreie noch geeignete - //(!csFIntersect) Kandidaten gibt und danach einen mit Knotenueberschneidung - //waehlen - //we may have a problem: no more candidates without feature intersection - if ( m_freeLabels.empty() && - m_sectLabels.empty() && - (assignmentCount < m_numAssignment) - ) - { - //Probeweise: Nochmal durch alle laufen und testen - //TODO: loeschen - //************************************************ - edge e; - forall_edges(e, m_ug->constGraph()) - { - EdgeLabel& l_el = eli.getLabel(e); - - //run over all label positions, high constant... - int i; - for (i = 0; i < labelNum; i++) - { - if (m_assigned[i][e]) //already assigned - continue; - - if (!l_el.usedLabel((eLabelTyp)i)) //no input label - continue; - - List < PosInfo >& l_cands = candList(e, i); - - int preferredIndex = int(floor(l_cands.size()/2.0)); - - l_el.setX((eLabelTyp)i, - (*(l_cands.get(preferredIndex))).m_coord.m_x); - l_el.setY((eLabelTyp)i, - (*(l_cands.get(preferredIndex))).m_coord.m_y); - - m_assigned[i][e] = true; - assignmentCount++; - //TODO: check every time if intersection free labels are produced - - - //TODO: choose good candidate - /* - ListIterator< PosInfo > l_itCands = l_cands.begin(); - while (l_itCands.valid()) - { - OGDF_ASSERT( (*l_itCands).m_active == csFIntersect) ); - - //choose a "good" candidate - //if option m_countFI is set, use feature intersection number - - }//while - */ - }//for all types - - }//for all edges - - OGDF_ASSERT(assignmentCount == m_numAssignment); - - //************************************************ - - }//if nonFIntersecting label position candidates could be found - - - }//while not all - }//if heuristics 1 - - if (m_placeHeuristic == 0) - { - //a) - //now we have to work on the labels without any good or - //bad candidates (all were intersecting original nodes) - - //after having assigned all problematic labels, - //we have to cope with the remaining labels / edges - forall_edges(e, m_ug->constGraph()) - { - EdgeLabel& l_el = eli.getLabel(e); - - //run over all label positions, high constant... - int i; - for (i = 0; i < labelNum; i++) - { - - if (!l_el.usedLabel((eLabelTyp)i)) continue; - - //hier sollte man einen bestimmten (z.B. Mitte) aus allen intersectfree waehlen - if (!(m_assigned[i])[e]) //assign intersection free - { - //after preprocessing, all should have an entry, but preliminary - if (l_freeCand[i][e].size() > 0) - { - int preferredIndex = int(floor(double(l_freeCand[i][e].size())/2));//2.0 - //check: labelnum <4 => ln-2 <=1 should not happen - if ((i == 0) || (i == 1)) preferredIndex = 0; - if ( ((i == labelNum-2) || (i == labelNum-1)) && (l_freeCand[i][e].size() > 0) ) - preferredIndex = l_freeCand[i][e].size() - 1; - - eli.getLabel(e).setX((eLabelTyp)i, - (*l_freeCand[i][e].get(preferredIndex))->m_coord.m_x); - eli.getLabel(e).setY((eLabelTyp)i, - (*l_freeCand[i][e].get(preferredIndex))->m_coord.m_y); - - m_assigned[i][e] = true; - }//if - }//if - }//for - - //OGDF_ASSERT(m_assigned[e]); - }//foralledges - }//if heur 0 - - -#ifdef foutput - writeUMLGML("umlLabelCost.gml"); - writeUMLGML("umlresultUML.gml", opResult); -#endif - - }//call AttributedGraph - - - template - void ELabelPos::initUML(GraphAttributes& ug, - ELabelInterface& eli) - { - const Graph &G = ug.constGraph(); - - m_segInfo.init(G); - m_featureInfo.init(G); - m_edgeLength.init(G); - m_poly.init(G); - - m_eli = &eli; - m_ug = &ug; - - m_prup = 0; - m_gl = 0; - - m_defaultDistance = eli.distDefault(); - - m_segMargin = 0.001; - - int i; - for (i = 0; i < labelNum; i++) - { - m_assigned[i].init(G, false); - m_candList[i].init(G); //holds PosInfo for all candidates - m_distance[i].init(G, m_defaultDistance); - m_intersect[i].init(G); - }//for - - m_numAssignment = 0; - m_endInsertion = true; - m_endLabelPlacement = true; - - m_posCost = true; - m_symCost = false; - - }//initUML - - - template - void ELabelPos::computeUMLCandidates() - { - -#ifdef foutput - //ofstream fout("candposUML.txt",ios::app); -#endif - edge e; - forall_edges(e, m_ug->constGraph()) - { -#ifdef foutput - //fout<<"Kante: \n"; -#endif - //different heuristics - switch (m_candStyle) - { - //standard method, just split edge length - case 1 : - { - int labelIndex; //the label index, 0 = end1,... - - //Endlabel (e1/m1, e2/m2) placed pairwise - //TODO: overlapping regions - //TODO: distances to original graph features - - //set a distance for equal distribution on the edge length - coordType standardDist = //max(m_eli->minFeatDist(), //max/min!!?? - coordType((m_edgeLength[e] / (labelNum*m_posNum + 1))); - //range for "start" and "end" endlabel - coordType startRange = m_edgeLength[e] / 3.0; - coordType endRange = m_edgeLength[e] / 3.0; - //set a distance for endlabel to end placement - coordType startDist = (m_endLabelPlacement ? (standardDist / 3.0) : standardDist); - coordType endDist = (m_endLabelPlacement ? (standardDist / 3.0) : standardDist); - - int segIndex = 0; //segment index = index of starting point in m_poly - int currentPos = 1; //number of label positions - - //start and end point of current segment (position relative to edge length) - SegmentInfo si = (*m_segInfo[e].get(segIndex)); - coordType currentStart = 0.0; - coordType currentEnd = si.length; - - coordType segOfs = 0.0; //offset needed if new segment does not start at k*standardDist - - coordType range = currentPos*standardDist; //range on edge that is already used - - coordType segStartX = (*m_poly[e].get(segIndex)).m_x; - coordType segStartY = (*m_poly[e].get(segIndex)).m_y; - - //all labeltypes*the number of cand. per labeltype - while (currentPos <= labelNum*m_posNum) //todo: labelnumber sum - { - int segStartLabel = currentPos-1; - //stay within current segment - while ((range < currentEnd) - && (currentPos <= labelNum*m_posNum)) - { - //we process the first segment for end1/mult1 - //and the last for end2/mult2 - labelIndex = int(floor( (double)((currentPos-1)) / m_posNum )); - - int optPosDistance = 0; - if ( (labelIndex == 0) || (labelIndex == 1)) - optPosDistance = currentPos-1; - else if ( (labelIndex == labelNum-1) || (labelIndex == labelNum-2)) - optPosDistance = labelNum*m_posNum - currentPos; - - OGDF_ASSERT(optPosDistance >= 0); - - //derive info about current label - coordType aktLabelWidth = m_eli->getWidth(e, (eLabelTyp)labelIndex); - coordType aktLabelHeight = m_eli->getHeight(e, (eLabelTyp)labelIndex); - coordType alwHalf = (aktLabelWidth / 2.0); - coordType alhHalf = (aktLabelHeight / 2.0); - - //derive symmetry label size - int symmLabel = 0; - coordType symmW = 0, symmH = 0; - - switch (labelIndex) - { - case 0: symmLabel = 1; break; - case 1: symmLabel = 0; break; - case labelNum-2: symmLabel = labelNum-1; break; - case labelNum-1: symmLabel = labelNum-2; break; - }//switch - symmW = ( m_eli->getWidth(e, (eLabelTyp)symmLabel) / 2.0); - symmH = ( m_eli->getHeight(e, (eLabelTyp)symmLabel) / 2.0); -#ifdef foutput - //fout<<" labelIndex: "< candidate; - GenericPoint symmCandidate; //end label on the opposite edge side - //now assign positions according to segment direction - //endlabels are shifted depending on direction and type/distance - //in inner switch statement - //ausserdem einfache Tests - //necessary because left lower corner needs labelsize shift - //in some cases, but they are difficult to check later - //hier sollte man auch doppelpos. fuer Namen einfuehren und dabei m_distance zulassen - switch (si.direction) - { - case odWest: //horizontal west - { - candidate.m_x = segStartX - stepping + segOfs; - candidate.m_y = segStartY; - - switch (labelIndex) - { - case 0: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case 1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-2: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - }//switch - break; - }//odWest - case odNorth: - { - candidate.m_x = segStartX; - candidate.m_y = segStartY + stepping - segOfs; - - switch (labelIndex) - { - case 0: symmCandidate.m_x = candidate.m_x + - m_distance[symmLabel][e] + symmW; - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case 1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-2: symmCandidate.m_x = candidate.m_x + - (m_distance[symmLabel][e] + symmW); - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - }//switch - break; - }//odNorth - case odEast: //horizontal - { - candidate.m_x = segStartX + stepping - segOfs; - candidate.m_y = segStartY; - - switch (labelIndex) - { - case 0: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case 1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-2: symmCandidate.m_y = candidate.m_y - - (m_distance[symmLabel][e] + symmH); - candidate.m_y += (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - case labelNum-1: symmCandidate.m_y = candidate.m_y + - (m_distance[symmLabel][e] + symmH); - candidate.m_y -= (m_distance[labelIndex][e] + alhHalf); - symmCandidate.m_x = candidate.m_x; - break; - }//switch - break; - }//odEast - case odSouth: - { - candidate.m_x = segStartX; - candidate.m_y = segStartY - stepping + segOfs; - - switch (labelIndex) - { - case 0: symmCandidate.m_x = candidate.m_x + - m_distance[symmLabel][e] + symmW; - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case 1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-2: symmCandidate.m_x = candidate.m_x + - m_distance[symmLabel][e] + symmW; - candidate.m_x -= (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - case labelNum-1: symmCandidate.m_x = candidate.m_x - - (m_distance[symmLabel][e] + symmW); - candidate.m_x += (m_distance[labelIndex][e] + alwHalf); - symmCandidate.m_y = candidate.m_y; - break; - }//switch - break; - }//odSouth - default: OGDF_THROW_PARAM(AlgorithmFailureException, afcLabel); - }//switch - - currentPos++; - range = currentPos*standardDist; - - List l_dummy; - - m_candList[labelIndex][e].pushBack(PosInfo(e, - (eLabelTyp)labelIndex, - candidate, - currentPos-1)); - //add cost for distance to edge end - PosInfo& thePos = m_candList[labelIndex][e].back(); - if (usePosCost()) thePos.m_cost += optPosDistance*costPos(); - - m_intersect[labelIndex][e].pushBack(l_dummy); - //end labels can be on opposite edge sides - if ( (labelIndex == 0) || - (labelIndex == 1) || - (labelIndex == labelNum-2) || - (labelIndex == labelNum-1) - ) - { - m_candList[symmLabel][e].pushBack(PosInfo(e, - (eLabelTyp)symmLabel, - symmCandidate, - currentPos-1)); - - //add cost for distance to edge end - PosInfo& thePos = m_candList[symmLabel][e].back(); - if (usePosCost()) thePos.m_cost += optPosDistance*costPos(); - - m_intersect[symmLabel][e].pushBack(l_dummy); - } - - }//while - - //jump to new segment - segIndex++; - - if (segIndex < m_segInfo[e].size()) - { - si = (*m_segInfo[e].get(segIndex)); - segStartX = (*m_poly[e].get(segIndex)).m_x; - segStartY = (*m_poly[e].get(segIndex)).m_y; - currentStart = currentEnd; - currentEnd += si.length; - - segOfs = standardDist - (range - currentStart); - }//if - else break; - }//while - //for (labelIndex = 0; labelIndex < labelNum; labelIndex++) - //no we have processed all edge segments - - break; - } - default : break; - }//switch - }//forall -#ifdef foutput - writeUMLGML(); -#endif - - }//computeUMLCandidates - - - template - void ELabelPos::initUMLSegments() - { - //we count the number of segments and their position/length - edge e; -#ifdef foutput - //ofstream outf("labelpositionen.txt"); -#endif - forall_edges(e, m_ug->constGraph()) - { - DPoint dp1, dp2; -#ifdef foutput - //outf<<"\n\nKante: "<source()<<"->"<target()<<"\n"; -#endif - coordType length = 0; - - OGDF_ASSERT(m_poly[e].size() == 0); - - //bend points do (!!!not) include start and end node - - DPolyline& theBends = m_ug->bends(e); - - OGDF_ASSERT(theBends.size()>1); - - //count all inner nodes as crossings or bends - ListConstIterator l_it; - - l_it = theBends.begin(); - dp1 = *l_it; - GenericPoint ip2(dp1.m_x, dp1.m_y); - m_poly[e].pushBack(ip2); -#ifdef foutput - //outf<<"Startpunkt: "< ip2(dp2.m_x, dp2.m_y); - - //derive the segment direction - OrthoDir od; - bool isHor = DIsEqual(dp1.m_y, dp2.m_y, 1e-9); //may still be same place - if (isHor) - { - if (DIsGreater(dp1.m_x, dp2.m_x, 1e-9)) od = odWest; - else od = odEast; - }//if isHor - else - { - if (!DIsEqual(dp1.m_x, dp2.m_x, 1e-9)) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcOrthogonal); - //check m_x == m_x - if (DIsLess(dp1.m_y, dp2.m_y, 1e-9)) od = odNorth; - else od = odSouth; - }//else -#ifdef foutput - //outf<<"direction: "< - void ELabelPos::initUMLFeatureRectangles() - { - node v; - //forall original nodes: get cage size and position - //if applied to result graph and layout, we dont need this - - forall_nodes(v, m_ug->constGraph()) - { - - double aktX = m_ug->x(v); - double aktY = m_ug->y(v); - - FeatureInfo fi; - fi.max_x = aktX + m_ug->width(v)/2.0; - fi.min_x = aktX - m_ug->width(v)/2.0; - fi.max_y = aktY + m_ug->height(v)/2.0; - fi.min_y = aktY - m_ug->height(v)/2.0; - fi.size_x = m_ug->width(v); //fi.max_x - fi.min_x; - fi.size_y = m_ug->height(v); //fi.max_y - fi.min_y; - - m_featureInfo[v] = fi; - - }//forallnodes - - //now all expanded (original) nodes have a featureinfo - - }//initUMLFeatureRectangles - - - //***************************************************************** - //test intersection of label position candidates with graph objects - template - void ELabelPos::testUMLFeatureIntersect() - { - - //set m_active to 1 for all feature intersecting position candidates - //initialize label structure - - //assure spare candidate - EdgeArray< GenericPoint > l_saveCandidate[labelNum]; - //TODO: nur falls usedLabel - for (int k = 0; k < labelNum; k++) l_saveCandidate[k].init(m_ug->constGraph()); - saveUMLRecovery(l_saveCandidate); - - edge e; - //for all edge labels and their cand. pos., we check intersections - //with original graph features - - forall_edges(e, m_ug->constGraph()) - { - int i; - for (i = 0; i < labelNum; i++) - { - - //TODO: check if usedLabel - if (m_eli->getLabel(e).usedLabel((eLabelTyp)i)) m_numAssignment++; - - - //all PosInfos for candidates of label i - List& l_candList = candList(e, i); - - //check intersection with original graph nodes: - - ListIterator< PosInfo > itPos = l_candList.begin(); - - int numCand = l_candList.size(); - int numIS = 0; //number of intersecting candidates - - while (itPos.valid()) - { - //save intersection status if the number is to be counted - bool hasIntersection = false; - - GenericPoint& coord =(*itPos).m_coord; - - //label size and position - - coordType minXLabel = coord.m_x - (m_eli->getWidth(e, (eLabelTyp)i) / 2.0); - coordType maxXLabel = coord.m_x + (m_eli->getWidth(e, (eLabelTyp)i) / 2.0); - coordType minYLabel = coord.m_y - (m_eli->getHeight(e, (eLabelTyp)i) / 2.0); - coordType maxYLabel = coord.m_y + (m_eli->getHeight(e, (eLabelTyp)i) / 2.0); - - node w; - //simple version: check with all original node rectangles - bool intersect = false; - forall_nodes(w, m_ug->constGraph()) - { - FeatureInfo& fi = m_featureInfo[w]; - - intersect = ( (minXLabel <= fi.max_x) && - (maxXLabel >= fi.min_x) && - (minYLabel <= fi.max_y) && - (maxYLabel >= fi.min_y) ); - - hasIntersection = intersect || hasIntersection; //save positive result - //falls man eine Gewichtung nach Anzahl der Probleme vornehmen - //moechte - if (!m_countFeatureIntersect) - { if (intersect) break;} - else //count intersections - { - (*itPos).m_numFeatures++; - }//else - - - }//forall_nodes - - //now this is quadratic in |E| !!!, only test, change to sweepline - edge e2; - forall_edges(e2,m_ug->constGraph()) - { - if (e == e2) continue; //no costs for own edge - ListIterator l_sit = m_segInfo[e2].begin(); - while (l_sit.valid()) - { - bool eIntersect = ( (minXLabel <= ((*l_sit).max_x+segmentMargin())) && - (maxXLabel >= ((*l_sit).min_x-segmentMargin())) && - (minYLabel <= ((*l_sit).max_y+segmentMargin())) && - (maxYLabel >= ((*l_sit).min_y-segmentMargin())) ); - if (eIntersect) (*itPos).m_cost += costEI(); - l_sit++; - }//while - - }//foralledges - - - if (hasIntersection) - { - numIS++; - //change status of candidate instead of deletion - (*itPos).m_active = csFIntersect; - (*itPos).m_cost += costFI(); //todo: use multiple costs for multiple int. - itPos++; - - continue; - } - - itPos++; - }//while - - //TODO: hier stand einsetzung des savecandidate, man muesste hier - //oder in call dann einen "besten" Ersatzkandidaten einfuegen - if (numIS == l_candList.size()) - { - }//if - - //if there is only one cand, we don't need to decide, but there - //may be no intersection (test only for secu. testing) - - }//for - - }//forallnodes -#ifdef foutput - writeUMLGML("label2UML.gml", opOmitFIntersect); -#endif - }//testumlfeatureintersect - - - //test intersection among label position candidates - template - void ELabelPos::testUMLAllIntersect() - { - List l_featureList; - //as long as labeltree is not implemented, use a worst case quadratic - //test better than round robin - edge e; - - //for all edge labels and their cand. pos., we check intersections - //with other label positions - //insert candidates in list - //check all edges in current CC - - forall_edges(e, m_ug->constGraph()) - { - int i; - for (i = 0; i < labelNum; i++) - { - //insert labels into structure - - if (!m_eli->getLabel(e).usedLabel((eLabelTyp)i)) continue; - - List< PosInfo >& l_candList = candList(e,i); - - //simple version one after another - int index = 0; - - ListIterator< PosInfo > itPos = l_candList.begin(); - - while (itPos.valid()) - { - //label size and position - FeatureInfo fi; - fi.size_x = m_eli->getWidth(e, (eLabelTyp)i); - fi.size_y = m_eli->getHeight(e, (eLabelTyp)i); - fi.min_x = (*itPos).m_coord.m_x - (fi.size_x / 2.0); - fi.max_x = (*itPos).m_coord.m_x + (fi.size_x / 2.0); - fi.min_y = (*itPos).m_coord.m_y - (fi.size_y / 2.0); - fi.max_y = (*itPos).m_coord.m_y + (fi.size_y / 2.0); - - //hier muss noch der Knoten hin - l_featureList.pushBack(FeatureLink(e, (eLabelTyp)i, 0, fi, index, (*itPos) )); - - index++; - itPos++; - }//while - - - }//for - - }//foralledges - //***************************************** - //now check - //********************************************* - //if intersection found, insert an entry in the PosInfo-pointer List - //PosInfo::m_intersect - //and increment the active intersection counter - //PosInfo::m_numActive - //Sort the label positions and perform sweepline run - FeatureComparer fc; - l_featureList.quicksort(fc); - - //run over all candidate positions and check intersections - //objects are active, if their y-intervall encloses the current - //sweepline position - - FeatureLink runFI; //next label position to be processed - ListIterator l_it = l_featureList.begin(); - - List sweepLine; - - coordType aktY = -coordBound - 1; //current y-coordinate of sweepline - - //run over all inserted label positions - while (l_it.valid()) - { - - OGDF_ASSERT(DIsGreater((*l_it).m_fi.min_y, aktY)); - - aktY = (*l_it).m_fi.min_y; - - ListIterator itSweep = sweepLine.begin(); //sweepline iterator - - //******************************** - //delete old events - while (itSweep.valid()) - { - if (DIsLess((*itSweep).m_fi.max_y, aktY)) - { - ListIterator itNext = itSweep.succ(); - sweepLine.del(itSweep); - itSweep = itNext; - continue; - } - itSweep++; - }//while - - itSweep = sweepLine.begin(); - //now we have only active events left, with y-intervall - //including current sweepline-position - - //***************************** - //run over all starting objects - while ( l_it.valid() && (DIsEqual(aktY,(*l_it).m_fi.min_y)) ) - { - itSweep = sweepLine.begin(); - //run over sweepline to find position and check intersection - //sort sweepline by increasing min_x-value - FeatureLink& fl = (*l_it); - //get the corresponding PosInfo - //PosInfo& aktPosInfo = - - //int aktX = (int)((*l_it).m_fi.min_x); - coordType aktX = ((*l_it).m_fi.min_x); - - //skip/test objects left of l_it - while (itSweep.valid() && DIsGreater(aktX, (*itSweep).m_fi.min_x) ) - { - //test on intersection - if (DIsLessEqual(aktX, (*itSweep).m_fi.max_x)) - { - FeatureLink& fls = (*itSweep); - //intersecting another position for the same label is ok - if (!( (fl.m_elt == fls.m_elt) && (fl.m_edge == fls.m_edge) )) - { - //insert PosInfo pointer into PosInfo::m_intersect and increment m_numActive - //in both labels - PosInfo& pi1 = (*(fl.m_posInfo)); - PosInfo& pi2 = (*(fls.m_posInfo)); - - pi1.m_intersect.pushBack(fls.m_posInfo); - pi2.m_intersect.pushBack(fl.m_posInfo); - pi1.m_numActive++; - pi2.m_numActive++; - - pi1.m_cost += costLI(); - pi2.m_cost += costLI(); - - }//if intersection - } - itSweep++; - }//while left - - //sweepline empty or object on same pos. / to the right found - //insert into sweepline: end or after last - if (!itSweep.valid()) - { - sweepLine.pushBack((*l_it)); - }//if rightmost entry - else - { - sweepLine.insertBefore((*l_it), itSweep); - - }//else insert before - - //now check for intersection until min_x > l_it.max_x - while ( itSweep.valid() && (DIsLessEqual((*itSweep).m_fi.min_x, (*l_it).m_fi.max_x)) ) - { - FeatureLink& fls = (*itSweep); - - //intersecting another position for the same label is ok - if (!( (fl.m_elt == fls.m_elt) && (fl.m_edge == fls.m_edge) )) - { - //insert PosInfo pointer into PosInfo::m_intersect aund increment m_numActive - PosInfo& pi1 = (*(fl.m_posInfo)); - PosInfo& pi2 = (*(fls.m_posInfo)); - - pi1.m_intersect.pushBack(fls.m_posInfo); - pi2.m_intersect.pushBack(fl.m_posInfo); - pi1.m_numActive++; - pi2.m_numActive++; - - pi1.m_cost += costLI(); - pi2.m_cost += costLI(); - - - }//if intersection of other label candidate - itSweep++; - }//while - l_it++; - }//while starting - - //l_it++; - }//while l_it - - //now search for intersectionfree label candidates - - forall_edges(e, m_ug->constGraph()) - { - int i; - for (i = 0; i < labelNum; i++) - { - //insert labels into structure - - if (!m_eli->getLabel(e).usedLabel((eLabelTyp)i)) continue; - - List< PosInfo >& l_candList = candList(e,i); - - //simple version one after another - int index = 0; - - ListIterator< PosInfo > itPos = l_candList.begin(); - - while (itPos.valid()) - { - if (!((*itPos).m_active == csFIntersect) ) - { - if (!m_endInsertion) - { - if ((*itPos).m_intersect.empty()) - m_freeLabels.pushBack(&(*itPos)); - else m_sectLabels.pushBack(&(*itPos)); - }//if not endInsertion - else - { - switch (i) - { - case 0: - case 1: //start labels, changeable - if ((*itPos).m_intersect.empty()) - m_freeLabels.pushBack(&(*itPos)); - else m_sectLabels.pushBack(&(*itPos)); - break; - case labelNum-1: - case labelNum-2: //end labels - if ((*itPos).m_intersect.empty()) - m_freeLabels.pushFront(&(*itPos)); - else m_sectLabels.pushFront(&(*itPos)); - break; - default: - if ((*itPos).m_intersect.empty()) - m_freeLabels.pushBack(&(*itPos)); - else m_sectLabels.pushBack(&(*itPos)); - - break; - - }//switch - - }//else - }//if feature intersection - - itPos++; - }//while candidates - }//for label types - }//forall edges - /* - l_it = l_featureList.begin(); - - while (l_it.valid()) - { - //TODO: check csFIntersect status - if ( !(((*l_it).m_posInfo)->m_active == csFIntersect) ) - { - if ( ((*l_it).m_posInfo)->m_intersect.empty() ) - m_freeLabels.pushBack((*l_it).m_posInfo); - else m_sectLabels.pushBack((*l_it).m_posInfo); - }//if no feature intersection - - #ifdef foutput - ofstream ofs("Intersections.txt", ios::app); - ofs << "\nNeuer Kandidat\n" << ((*l_it).m_posInfo)->m_intersect.size() - << "Ueberschneidungen\n" << "Position: " - << ((*l_it).m_posInfo)->m_coord.m_x <<"/"<< ((*l_it).m_posInfo)->m_coord.m_y << "\n"; - #endif - l_it++; - }//while - #ifdef foutput - ofstream ofs("Intersections.txt", ios::app); - ofs << "\nENDE DER FEATURELISTE\n" < - void ELabelPos::saveUMLRecovery(EdgeArray< GenericPoint > - (&saveCandidate)[labelNum]) - { - - const Graph& mapGraph = m_ug->constGraph(); - //a labeltype - dependant extra candidate for label positioning should - //be defined here to help in case of empty cand.list after featureintersect - - //simple version: use one (middle?) of the original candidates - - edge e; - forall_edges(e, mapGraph) - { - int i; - for (i = 0; i < labelNum; i++) - { - //TODO: hier abfragen, ob label vorhanden =>etwas schneller - List< PosInfo >& l_posList = candList(e,i); //all candidates for label Nr. i - //hier: sichere, das Eintrag vorhanden - int savePos; - //am besten immer Mitte nehmen, da am wenigsten in Knoten - if ((i == 0) || (i ==1)) savePos = 0; - else if ((i == labelNum-1) || (i == labelNum-2)) - savePos = l_posList.size()-1; - else savePos = int(floor((double)(l_posList.size())/2)); - if (savePos < 0) savePos = 0; - saveCandidate[i][e] = (*l_posList.get(savePos)).m_coord; - }//for labeltypes - }//foralledges - - }//saveUMLRecovery - - - //************************************************************************* - //output section - template - void ELabelPos::writeGML(const char *filename, OutputParameter sectOmit) - { - OGDF_ASSERT(m_prup); - - const Graph& G = *m_prup; - - ofstream os(filename); - - NodeArray id(*m_prup); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::ELabelPos::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - os << " id " << (id[v] = nextId++) << "\n"; - os << " label \"" << v->index() << "\"\n"; - os << " graphics [\n"; - os << " x " << double(m_gl->x(v)) << "\n"; - os << " y " << double(m_gl->y(v)) << "\n"; - os << " w " << 3.0 << "\n"; - os << " h " << 3.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (m_prup->typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (m_prup->typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (m_prup->typeOf(v) == Graph::highDegreeExpander || - m_prup->typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (m_prup->typeOf(v) == Graph::dummy) - os << " type \"oval\"\n"; - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - - os << " ]\n"; // graphics - os << " ]\n"; // node - }//forallnodes - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << m_prup->typeOf(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (m_prup->typeOf(e) == Graph::generalization) - { - if (m_prup->typeOf(e->target()) == Graph::generalizationExpander) - os << " arrow \"none\"\n"; - else - os << " arrow \"last\"\n"; - os << " fill \"#FF0000\"\n"; - os << " width 2.0\n"; - } - else - { - if (m_prup->typeOf(e->source()) == Graph::generalizationExpander || - m_prup->typeOf(e->source()) == Graph::generalizationMerger || - m_prup->typeOf(e->target()) == Graph::generalizationExpander || - m_prup->typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - os << " fill \"#F0F00F\"\n"; - //os << " fill \"#FF0000\"\n"; - } - else if (m_prup->original(e) == 0) - { - os << " arrow \"none\"\n"; - os << " fill \"#AFAFAF\"\n"; - } - else - os << " arrow \"none\"\n"; - os << " width 1.0\n"; - }//else generalization - - os << " ]\n"; // graphics - - os << " ]\n"; // edge - }//foralledges - - forall_edges(e, m_prup->original()) - { - int i; - for (i=0; i < labelNum; i++) - { - for (int j=0; j < m_candPosList[i][e].size(); j++) - { - if ( (sectOmit == opOmitIntersect)&& - ((*m_intersect[i][e].get(j)).size() > 0) ) continue; - os << " node [\n"; - os << " id " << nextId++ << "\n"; - os << " label \"" << 999 << "\"\n"; - os << " graphics [\n"; - - if (sectOmit == opResult) - { - os << " x " << double(m_eli->getLabel(e).getX((eLabelTyp)i)) << "\n"; - os << " y " << double(m_eli->getLabel(e).getY((eLabelTyp)i)) << "\n"; - } - else - { - os << " x " << double((*m_candPosList[i][e].get(j)).m_x) << "\n"; - os << " y " << double((*m_candPosList[i][e].get(j)).m_y) << "\n"; - } - os << " w " << double(m_eli->getWidth(e, (eLabelTyp)i)) << "\n"; - os << " h " << double(m_eli->getHeight(e, (eLabelTyp)i)) << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - - //os << " type \"oval\"\n"; - switch (i) - { - case 0: os << " fill \"#2F2F0F\"\n"; break; - case 1: os << " fill \"#4F4F0F\"\n"; break; - case 2: os << " fill \"#6F6F0F\"\n"; break; - case 3: os << " fill \"#0F7F7F\"\n"; break; - case 4: os << " fill \"#0F9F9F\"\n"; break; - }//switch - - os << " ]\n"; // graphics - os << " ]\n"; // node - - if (sectOmit == opResult) break; - }//for j - }//for i - }//foralledges - - os << " ]\n"; // graph - - }//writegml - - - //UML version - template - void ELabelPos::writeUMLGML(const char *filename, OutputParameter sectOmit) - { - OGDF_ASSERT(m_ug); - - ofstream os(filename); - - const Graph& G = m_ug->constGraph(); - - NodeArray id(G); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::ELabelPos::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - os << " id " << (id[v] = nextId++) << "\n"; - os << " label \"" << v->index() << "\"\n"; - os << " graphics [\n"; - os << " x " << double(m_ug->x(v)) << "\n"; - os << " y " << double(m_ug->y(v)) << "\n"; - os << " w " << double(m_ug->width(v)) << "\n"; - os << " h " << double(m_ug->height(v)) << "\n"; - os << " type \"rectangle\"\n"; - os << " width 0.01\n"; - if (m_ug->type(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (m_ug->type(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (m_ug->type(v) == Graph::highDegreeExpander || - m_ug->type(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (m_ug->type(v) == Graph::dummy) - os << " type \"oval\"\n"; - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#FFFF00\"\n"; - //os << " fill \"#000000\"\n"; - - os << " ]\n"; // graphics - os << " ]\n"; // node - }//forallnodes - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << m_ug->type(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (m_ug->type(e) == Graph::generalization) - { - if (m_ug->type(e->target()) == Graph::generalizationExpander) - os << " arrow \"none\"\n"; - else - os << " arrow \"last\"\n"; - os << " fill \"#FF0000\"\n"; - os << " width 2.0\n"; - } - else - { - if (m_ug->type(e->source()) == Graph::generalizationExpander || - m_ug->type(e->source()) == Graph::generalizationMerger || - m_ug->type(e->target()) == Graph::generalizationExpander || - m_ug->type(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - os << " fill \"#F0F00F\"\n"; - //os << " fill \"#FF0000\"\n"; - } - else - os << " arrow \"none\"\n"; - os << " width 1.0\n"; - }//else generalization - //output bends - const DPolyline &dpl = m_ug->bends(e); - if (!dpl.empty()) { - os << " Line [\n"; - os << " point [ x " << m_ug->x(e->source()) << " y " << - m_ug->y(e->source()) << " ]\n"; - - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - os << " point [ x " << (*it).m_x << " y " << (*it).m_y << " ]\n"; - - os << " point [ x " << m_ug->x(e->target()) << " y " << - m_ug->y(e->target()) << " ]\n"; - - os << " ]\n"; // Line - } - //bends - - os << " ]\n"; // graphics - - os << " ]\n"; // edge - }//foralledges - - forall_edges(e, G) - { - int i; - for (i=0; i < labelNum; i++) - { - if (!m_eli->getLabel(e).usedLabel((eLabelTyp)i)) continue; - - ListIterator< PosInfo > l_it = candList(e, i).begin(); - - while (l_it.valid()) - { - if ( ( (sectOmit == opOmitIntersect)&& - (((*l_it).m_intersect.size() > 0) || - ((*l_it).m_active == csFIntersect) - ) - ) || - ( (sectOmit == opOmitFIntersect)&& - ((*l_it).m_active == csFIntersect) ) - ) - { - l_it++; - continue; - } - os << " node [\n"; - os << " id " << nextId++ << "\n"; - os << " label \"" << id[e->source()] <<"/"<target()]<<"/sects" - <<(*l_it).m_intersect.size()<< " /cost " << - double((*l_it).m_cost) <<"\"\n"; - os << " graphics [\n"; - - if (sectOmit == opResult) - { - os << " x " << double(m_eli->getLabel(e).getX((eLabelTyp)i)) << "\n"; - os << " y " << double(m_eli->getLabel(e).getY((eLabelTyp)i)) << "\n"; - } - else - { - os << " x " << double((*l_it).m_coord.m_x) << "\n"; - os << " y " << double((*l_it).m_coord.m_y) << "\n"; - } - os << " w " << double(m_eli->getWidth(e, (eLabelTyp)i)) << "\n"; - os << " h " << double(m_eli->getHeight(e, (eLabelTyp)i)) << "\n"; - os << " type \"rectangle\"\n"; - os << " width 0.01\n"; - - //os << " type \"oval\"\n"; - //Change background color of labels here - switch (i) - { - case 0: os << " line \"#00FF00\"\n"; break; - case 1: os << " line \"#00FF00\"\n"; break; - case 2: os << " line \"#FF0000\"\n"; break; - case 3: os << " line \"#0000FF\"\n"; break; - case 4: os << " line \"#0000FF\"\n"; break; - default: os << " line \"#FF00FF\"\n"; - /* case 0: os << " fill \"#2F2F0F\"\n"; break; - case 1: os << " fill \"#4F4F0F\"\n"; break; - case 2: os << " fill \"#6F6F0F\"\n"; break; - case 3: os << " fill \"#0F7F7F\"\n"; break; - case 4: os << " fill \"#0F9F9F\"\n"; break;*/ - }//switch - - os << " fill \"#FFFFFF\"\n"; - - os << " ]\n"; // graphics - os << " ]\n"; // node - - if (sectOmit == opResult) break; - l_it++; - }//while l_it - }//for i - }//foralledges - - os << "]\n"; // graph - - - }//writeumlgml - - -}//namespace ogdf diff --git a/ext/OGDF/src/orthogonal/EdgeRouter.cpp b/ext/OGDF/src/orthogonal/EdgeRouter.cpp deleted file mode 100644 index 2881ce378..000000000 --- a/ext/OGDF/src/orthogonal/EdgeRouter.cpp +++ /dev/null @@ -1,4145 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Edge routing and node placement implementation. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -//TODO: handle multiedges in a way that forbids assignment of different sides - - -#include -#include -#include - - -namespace ogdf { - -#define SETMULTIMINDELTA //set multidelta, - - -const double machineeps = 1.0e-10; -const int m_init = -1234567; //just to check initialization - - -//************************************************************************************************ -//edgerouter places original node boxes in preassigned cages, computes a number of -//bendfree edges minimizing placement and routes edges, thereby introducing bends, to -//achieve a correct layout -//************************************************************************************************ - -// routing channel and number of adjacent edges / generalization is supplied by previous -// compaction step in class routingchannel -// class NodeInfo holds the specific information for a single replaced node ( adjEntry != 0) - - -//constructor -EdgeRouter::EdgeRouter( - PlanRep& pru, - OrthoRep& H, - GridLayoutMapped& L, - CombinatorialEmbedding& E, - RoutingChannel& rou, - MinimumEdgeDistances& mid, - NodeArray& nodewidth, - NodeArray& nodeheight) -: - m_prup(&pru), - m_layoutp(&L), - m_orp(&H), - m_comb(&E), - m_rc(&rou), - m_med(&mid), - m_nodewidth(&nodewidth), - m_nodeheight(&nodeheight) -{ - init(pru, rou); -}//EdgeRouter - - -//initializes the members -void EdgeRouter::init( - PlanRep& pru, - RoutingChannel& rou, - bool align) -{ - //saves cage position left lower - m_newx.init(pru, m_init); - m_newy.init(pru, m_init); - //saves glue and connection point positions - m_agp_x.init(pru, m_init); - m_agp_y.init(pru, m_init); - m_acp_x.init(pru, m_init); - m_acp_y.init(pru, m_init); - m_abends.init(pru, bend_free); - m_oppositeBendType.init(pru, bend_free); - - m_minDelta = false; -#ifdef SETMULTIMINDELTA - m_minDelta = true; -#endif - - m_mergerSon.init(pru, false); - m_mergeDir.init(pru, odNorth); - m_align = align; - - m_fixed.init(pru, false); - m_processStatus.init(pru, unprocessed); - m_cage_point.init(pru); - - m_sep = rou.separation(); - m_overh = rou.overhang(); - Cconst = double(m_overh)/double(m_sep); -}//init - - -//call - function: placing nodes and routing edges -void EdgeRouter::call() -{ - //if no graph is given, you should stop or return 0,0 - OGDF_ASSERT( (m_prup != 0) && (m_layoutp != 0) && (m_orp != 0) && (m_comb != 0) && (m_nodewidth != 0)); - call(*m_prup, *m_orp, *m_layoutp, *m_comb, *m_rc, *m_med, *m_nodewidth, *m_nodeheight); -}//call - - -void EdgeRouter::call( - PlanRep& pru, - OrthoRep& H, - GridLayoutMapped& L, - CombinatorialEmbedding& E, - RoutingChannel& rou, - MinimumEdgeDistances& mid, - NodeArray& nodewidth, - NodeArray& nodeheight, - bool align) -{ - String msg; - OGDF_ASSERT(H.check(msg)); - - init(pru, rou, align); - m_prup = &pru; - m_layoutp = &L; - m_orp = &H; - m_comb = &E; - m_rc = &rou; - m_med = ∣ - m_nodewidth = &nodewidth; - m_nodeheight = &nodeheight; - //just input some stuff - infos.init(pru); - - node v; - int mysep = m_sep; - //set specific delta values automatically for all nodes - //preliminary: set to minimum value perimeter / degree of all nodes - //seems to cause problems with compaction - if (m_minDelta) - forall_nodes(v, pru) - { - if ( (pru.expandAdj(v) != 0) && - (pru.typeOf(v) != Graph::generalizationMerger)) - { - int perimeter = 2*nodewidth[v] + 2*nodeheight[v]; - OrthoDir debod = odNorth; - int vdeg = 0; - do { - OrthoRep::SideInfoUML sinfo = m_orp->cageInfo(v)->m_side[debod]; - if (sinfo.m_adjGen) - vdeg += (sinfo.m_nAttached[0] + 1 + sinfo.m_nAttached[1]); - else - vdeg += sinfo.m_nAttached[0]; - debod = OrthoRep::nextDir(debod); - } while (debod != odNorth); - if (vdeg != 0) mysep = min(mysep, int(floor((double)perimeter / vdeg))); - }//if expanded - }//forallnodes - - forall_nodes(v, pru) - { - if ( (pru.expandAdj(v) != 0) && - (pru.typeOf(v) != Graph::generalizationMerger)) //==Expander) ) - //adjEntry != nil, this cage node is a copy(original node) - { - OGDF_ASSERT(pru.widthOrig(pru.original(v)) > 0.0) - initialize_node_info(v, mysep); //delta, epsilon, cagesize, boxsize - } - }//forallnodes - - //the rerouting ********************************************************** - //simple rerouting version: maximize the number of bend free edges in the - //placement step, then try to minimize bends by changing attachment sides - //in the rerouting step - - //work on all expanded nodes / positioning info is kept in class NodeInfo - //and in layout previous compaction step guarantees routing channel - - //for every hor. edge e, lowe(e) denotes the biggest yvalue possible for - //the lower border of target(e)'s cage if e is routed bendfree (depending on pred edges) - //uppe(e) denotes the minimum yvalue for the upper border of v's cage if ... - lowe.init(*m_prup, m_init); - uppe.init(*m_prup, m_init); - alowe.init(*m_prup, m_init); - auppe.init(*m_prup, m_init); - //for each and every vert. edge e, lefte(e) denotes the biggest xvalue possible - //for the left border of v's cage if e is routed bendfree (depending on pred edges) - //righte(e) denotes the minimum xvalue for the right border of v's cage ... - lefte.init(*m_prup, m_init); - righte.init(*m_prup, m_init); - alefte.init(*m_prup, m_init); - arighte.init(*m_prup, m_init); - - //compute the lowe / uppe / lefte / righte values for every adjacent edge - //if generalization exists the node position is already fixed - node l_v; - - //********************************************************************* - //compute LOWER / UPPER / LEFTER / RIGHTER border values - //********************************************************************* - - //forall expanded nodes - forall_nodes(l_v, pru) - { - if ((pru.expandAdj(l_v) != 0) && (pru.typeOf(l_v) != Graph::generalizationMerger) )//check if replaced - { - NodeInfo& inf = infos[l_v]; - - //edges to the left side, pointing towards cage - const List& left_in_edges = inf.inList(odNorth); - ListConstIterator itE; - //LEFT EDGES - int pos_e = 1; - //for all edges incident to cage, we compute lower, upper, lefter, righter values from the paper - for (itE = left_in_edges.begin(); itE.valid(); ++itE) - { - edge inedge = *itE; - - int l_seps; //adjust multiples of delta for lower values - int u_seps; // -"- upper - int remaining_num = left_in_edges.size() - pos_e; //incident edges lying above ine - - l_seps = inf.delta(odNorth, odWest)*(pos_e-1); - u_seps = inf.delta(odNorth, odEast)*remaining_num; - - lowe[inedge] = L.y(inedge->target()) - l_seps - inf.eps(odNorth, odWest); - alowe[outEntry(inf, odNorth,pos_e-1)] = L.y(inedge->target()) - l_seps - inf.eps(odNorth, odWest); - uppe[inedge] = L.y(inedge->target()) + u_seps + inf.eps(odNorth, odEast); - auppe[outEntry(inf, odNorth, pos_e -1)] = L.y(inedge->target()) + u_seps + inf.eps(odNorth, odEast); - - arighte[outEntry(inf, odNorth, pos_e -1)] = righte[inedge] = 0; //unused for horizontal edges in twostep simple rerouting - alefte[outEntry(inf, odNorth, pos_e -1)] = lefte[inedge] = 0; //maybe initialize to -1 - pos_e++; - }//for - //RIGHT EDGES - //edges to the right side, pointing towards cage , check bottom -> top!!!!!!!!!! - const List& right_in_edges = inf.inList(odSouth); - pos_e = 1; - for (itE = right_in_edges.begin(); itE.valid(); ++itE) - { - edge inedge = *itE; - - int l_seps; //adjust multiples of delta to generalization/ no generalization for lower - int u_seps; // -"- upper - int remaining_num = right_in_edges.size() - pos_e; //incident edges lying above ine - - l_seps = inf.delta(odSouth, odWest)*(pos_e-1); - u_seps = inf.delta(odSouth, odEast)*remaining_num; - - lowe[inedge] = L.y(inedge->target()) - l_seps - inf.eps(odSouth, odWest); - alowe[outEntry(inf, odSouth, pos_e-1)] = L.y(inedge->target()) - l_seps - inf.eps(odSouth, odWest); - uppe[inedge] = L.y(inedge->target()) + u_seps + inf.eps(odSouth, odEast); - auppe[outEntry(inf, odSouth, pos_e-1)] = L.y(inedge->target()) + u_seps + inf.eps(odSouth, odEast); - //unused for horizontal edges in twostep simple rerouting - arighte[outEntry(inf, odSouth, pos_e-1)] = righte[inedge] = 0; - alefte[outEntry(inf, odSouth, pos_e-1)] = lefte[inedge] = 0; //maybe initialize to -1 - pos_e++; - }//for - - //TOP EDGES - //edges at the top side, pointing towards cage , check left -> right!!!!!!!!!! - const List& top_in_edges = inf.inList(odEast); //debug!!!!!!!!!!!! - pos_e = 1; - for (itE = top_in_edges.begin(); itE.valid(); ++itE) - { - edge inedge = *itE; - - int l_seps; //adjust multiples of delta for left - int r_seps; // -"- right - int remaining_num = top_in_edges.size() - pos_e; //incident edges lying above ine - - l_seps = inf.delta(odEast, odNorth)*(pos_e-1); - r_seps = inf.delta(odEast, odSouth)*remaining_num; - - lefte[inedge] = L.x(inedge->target()) - l_seps - inf.eps(odEast, odNorth); //eps are the same w/o gene - alefte[outEntry(inf, odEast, pos_e - 1)] = L.x(inedge->target()) - l_seps - inf.eps(odEast, odNorth); - righte[inedge] = L.x(inedge->target()) + r_seps + inf.eps(odEast, odSouth); - arighte[outEntry(inf,odEast, pos_e - 1)] = L.x(inedge->target()) + r_seps + inf.eps(odEast, odSouth); - - alowe[outEntry(inf,odEast, pos_e - 1)] = lowe[inedge] = 0; //unused for vertical edges in twostep simple rerouting - auppe[outEntry(inf,odEast, pos_e - 1)] = uppe[inedge] = 0; //maybe initialize to -1 - pos_e++; - }//for - //edges at the bottom side, pointing towards cage , check left -> right!!!!!!!!!! - const List& bottom_in_edges = inf.inList(odWest); //debug!!!!!!!!!!!! - pos_e = 1; - for (itE = bottom_in_edges.begin(); itE.valid(); ++itE) - { - edge inedge = *itE; - - int l_seps; //adjust multiples of delta for left - int r_seps; // -"- right - int remaining_num = bottom_in_edges.size() - pos_e; //incident edges lying above ine - - l_seps = inf.delta(odWest, odNorth)*(pos_e-1); - r_seps = inf.delta(odWest, odSouth)*remaining_num; - - lefte[inedge] = L.x(inedge->target()) - l_seps - inf.eps(odWest, odNorth); //eps are the same w/o gene - alefte[outEntry(inf, odWest, pos_e-1)] = L.x(inedge->target()) - l_seps - inf.eps(odWest, odNorth); - righte[inedge] = L.x(inedge->target()) + r_seps + inf.eps(odWest, odSouth); - arighte[outEntry(inf, odWest, pos_e-1)] = L.x(inedge->target()) + r_seps + inf.eps(odWest, odSouth); - - alowe[outEntry(inf, odWest, pos_e-1)] = lowe[inedge] = 0; //unused for vertical edges in twostep simple rerouting - auppe[outEntry(inf, odWest, pos_e-1)] = uppe[inedge] = 0; //maybe initialize to -1 - pos_e++; - }//for - }//if replaced - }//forallnodes - - //*********************************************************************************** - //now for all edges pointing towards cages representing nodes without generalization, - //we defined lowe/uppe values for horizontal and lefte/righte values for vertical edges - //*********************************************************************************** - - forall_nodes(v, pru) - { - if ( (pru.expandAdj(v) != 0) && (pru.typeOf(v) != Graph::generalizationMerger) )//== Graph::highDegreeExpander) ) //expanded high degree - { - compute_place(v, infos[v]/*, m_sep, m_overh*/); - //*************************************************************************** - //forall expanded nodes we computed a box placement and a preliminary routing - //now we can reroute some edges to avoid unnecessary bends (won't be optimal) - //simple approach: implement only local decision at corner between two - //neighboured nodebox sides - //*************************************************************************** - //classify_edges(v, infos[v]); //E sets from paper, reroutable - compute_routing(v); //maybe store result in structure and apply later - }//if expanded - }//forall_nodes - - ////try to place deg1 nodes - //forall_nodes(v, pru) - // { - // //there is an omission of placement here leading to errors - // if (false) //preliminary until umlex4 error checked - // { - // if ( (pru.expandAdj(v) != 0) && (pru.typeOf(v) != Graph::generalizationMerger) ) - // { - // //**************************************** - // //Re - Place degree one nodes if possible, to neighbour cage - // //mag sein, dass firstadj ein zeiger sein muss - // adjEntry fa = infos[v].firstAdj(); - // //step over possibly inserted bends - // while (pru.typeOf(fa->twinNode()) == Graph::dummy) - // fa = fa->faceCycleSucc(); - // if ((pru.typeOf(fa->twinNode()) != Graph::highDegreeExpander) && - // (pru.typeOf(fa->twinNode()) != Graph::lowDegreeExpander) ) - // { - // //place(v, m_sep, m_overh); - // continue; - // }//if expander - // //get neighbour node - // node v1 = fa->twinNode(); - // //get attachment side - // OrthoDir od = OrthoRep::prevDir(H.direction(fa)); - // - // node expandNode = pru.expandedNode(v1); - // //v is neighbour of expanded node and may fit in its cage - // //check if deg 1 can be placed near to node - // //problem: wenn nicht geflippt wird, ist meistens auch kein Platz auf der Seite - // if ( (infos[v].vDegree() == 1) && //can be placed freely - // //no edges to cross on neighbours side - // (infos[expandNode].num_edges(od) + infos[expandNode].flips(OrthoRep::prevDir(od), od) + - // infos[expandNode].flips(OrthoRep::nextDir(od), od) == 1) && - // //enough space to host trabant - // (infos[expandNode].coordDistance(od) > infos[v].nodeSize(OrthoRep::prevDir(od)) + m_sep) && - // (infos[expandNode].cageSize(od) > infos[v].nodeSize(od)) && - // //dumm gelaufen: der Knoten muss auch kleiner als der Nachbar sein, damit er nicht in - // //abgeknickte Kanten der Seite laeuft, deshalb hier spaeter deren Position testen, Bed. weg - // //das ist etwas doppelt, damit man spaeter nur diese entfernen muss, die oben bleibt - // (infos[expandNode].nodeSize(od) >= infos[v].nodeSize(od)) - // ) - // { - // //find new place, v must be cage node with out edge attached - // int npos, spos, epos, wpos, vxpos, vypos; - // switch (od) - // { - // case odNorth: - // npos = infos[expandNode].coord(odNorth) - m_sep - infos[v].node_xsize(); - // spos = infos[expandNode].coord(odNorth) - m_sep; - // wpos = infos[expandNode].cageCoord(odWest) - // + int(floor(infos[expandNode].cageSize(odNorth)/2.0) - // - floor(infos[v].nodeSize(odNorth)/2.0)); - // epos = wpos + infos[v].nodeSize(odNorth); - // vxpos = spos; - // vypos = wpos + int(floor(infos[v].nodeSize(odNorth)/2.0)); - // break; - // case odSouth: - // npos = infos[expandNode].coord(odSouth) + m_sep; - // spos = infos[expandNode].coord(odSouth) + m_sep + infos[v].node_xsize(); - // wpos = infos[expandNode].cageCoord(odWest) - // + int(floor(infos[expandNode].cageSize(odNorth)/2.0) - // - floor(infos[v].nodeSize(odNorth)/2.0)); - // epos = wpos + infos[v].nodeSize(odNorth); - // vxpos = npos; - // vypos = wpos + int(floor(infos[v].nodeSize(odNorth)/2.0)); - // break; - // case odEast: - // npos = infos[expandNode].cageCoord(odNorth) - // + int(floor(infos[expandNode].cageSize(odEast)/2.0) - // - floor(infos[v].nodeSize(odEast)/2.0)); - // spos = npos + infos[v].cageSize(odEast); - // wpos = infos[expandNode].coord(odEast) + m_sep; - // epos = wpos + infos[v].nodeSize(odEast); - // vypos = wpos; - // vxpos = npos + int(floor(infos[v].nodeSize(odEast)/2.0)); - // break; - // case odWest: - // npos = infos[expandNode].cageCoord(odNorth) - // + int(floor(infos[expandNode].cageSize(odEast)/2.0) - // - floor(infos[v].nodeSize(odEast)/2.0)); - // spos = npos + infos[v].cageSize(odEast); - // epos = infos[expandNode].coord(odWest) - m_sep; - // wpos = epos - infos[v].nodeSize(odNorth); - // vypos = epos; - // vxpos = npos + int(floor(infos[v].nodeSize(odEast)/2.0)); - // break; - // }//switch - // infos[v].set_coord(odNorth, npos); - // infos[v].set_coord(odSouth, spos); - // infos[v].set_coord(odWest, wpos); - // infos[v].set_coord(odEast, epos); - // infos[v].setCageCoord(odNorth, npos); - // infos[v].setCageCoord(odSouth, spos); - // infos[v].setCageCoord(odWest, wpos); - // infos[v].setCageCoord(odEast, epos); - // //set v coordinates - // m_layoutp->x(v) = vxpos; - // m_layoutp->y(v) = vypos; - // m_layoutp->x(v1) = vxpos; - // m_layoutp->y(v1) = vypos; - // //set corner coordinates after placing - // set_corners(v); - // m_processStatus[v] = processed; - // m_processStatus[v1] = used; - // //hier muss man auch die Kantenendpunkte setzen, sonst gibt es einen Fehler - // }//if - // }//if degreeexpander - // }//debug stop - //}//forall_nodes - - forall_nodes(v, pru) - { - if ( (pru.expandAdj(v) != 0) && (pru.typeOf(v) != Graph::generalizationMerger) ) - { - if (!(m_processStatus[v] == processed)) - place(v); - }//if expanded - }//forallnodes - - setDistances(); - - // PathFinder pf(pru, H, L, *m_comb); - // int routable = pf.analyse(); - //if (routable > 0) pf.route(false); - - OGDF_ASSERT(H.check(msg)); -}//call - - -//simple local placement decision based on incident edges attachment positions -//size of input original (replaced) node and original box - -void EdgeRouter::compute_gen_glue_points_y(node v) -//compute preliminary glue point positions based on placement -//and generalizations for horizontal edges and set bend type accordingly -{ - OGDF_ASSERT(infos[v].has_gen(odNorth) || infos[v].has_gen(odSouth)); - int ybase = 0; - int gen_y = infos[v].coord(odWest) + int(floor((double)(infos[v].node_ysize())/2)); //in the middle - //y coordinates - //check for left/right generalization - - //NORTH SIDE ************************************************* - ListIterator l_it = infos[v].inList(odNorth).begin(); - //NORTH GENERATOR ****************************************** - if (infos[v].has_gen(odNorth))//gen at left side - { - int pos = infos[v].gen_pos(odNorth)-1; //compare edge position to generalization position - if (pos > -1) l_it = infos[v].inList(odNorth).get(pos);//muss unter gen sein, -2??? - else {l_it = 0; pos = 0;} - bool firstcheck = true; - bool lastcheck = true; - //classify edges - //*************************************************** - //assign gp value for edges underneath generalization - ybase = gen_y - infos[v].delta(odNorth, odWest); - //bendfree edges underneath - while (l_it.valid() && - (pos*infos[v].delta(odNorth, odWest) + infos[v].eps(odNorth,odWest) <= - (cp_y(outEntry(infos[v], odNorth, pos)) - infos[v].coord(odWest)) )) //bendfree edges cage_coord??!!! - { - m_agp_y[outEntry(infos[v], odNorth, pos)] = cp_y(outEntry(infos[v], odNorth, pos)); - - if (firstcheck) {firstcheck = false; infos[v].set_l_upper(cp_y(outEntry(infos[v], odNorth, pos)));} - lastcheck = false; - infos[v].set_l_lower(cp_y(outEntry(infos[v], odNorth, pos))); - - m_abends[outEntry(infos[v], odNorth, pos)] = bend_free; - ybase = cp_y(outEntry(infos[v], odNorth, pos)) - infos[v].delta(odNorth, odWest); - l_it--; - pos--; - infos[v].nbf(odNorth)++; - }//while - - //still some lower edges to bend - while (l_it.valid()) - { - m_agp_y[outEntry(infos[v], odNorth, pos)] = infos[v].coord(odWest) - + infos[v].eps(odNorth, odWest) - + pos*infos[v].delta(odNorth, odWest); - if (cp_y(outEntry(infos[v], odNorth, pos)) < infos[v].coord(odWest) - m_sep) //paper E^ - { m_abends[outEntry(infos[v], odNorth, pos)] = prob_b1l; infos[v].inc_E_hook(odNorth, odWest);}//numr?? - else {m_abends[outEntry(infos[v], odNorth, pos)] = prob_b2l; infos[v].inc_E(odNorth, odWest);} - - ybase = ybase - infos[v].delta(odNorth, odWest); - pos--; - l_it--; - } - - //******************************************************* - //assign gp value for generalization - ybase = gen_y; //check == y(current edge)??? - l_it = infos[v].inList(odNorth).get(infos[v].gen_pos(odNorth)); - - infos[v].nbf(odNorth)++; - m_agp_y[outEntry(infos[v], odNorth, infos[v].gen_pos(odNorth))] = ybase; - m_abends[outEntry(infos[v], odNorth, infos[v].gen_pos(odNorth))] = bend_free; - - if (lastcheck) infos[v].set_l_lower(ybase); - infos[v].set_l_upper(ybase); - - //******************************************************* - //assign gp value for bendfree edges above generalization - l_it++; - pos = infos[v].gen_pos(odNorth) + 1; - while (l_it.valid() && - ((infos[v].inList(odNorth).size() - 1 - pos)*infos[v].delta(odNorth, odEast) - + infos[v].eps(odNorth,odEast) <= - (infos[v].coord(odEast) - cp_y(outEntry(infos[v], odNorth, pos))) )) - { - m_abends[outEntry(infos[v], odNorth, pos)] = bend_free; - ybase = cp_y(outEntry(infos[v], odNorth, pos));//+= infos[v].delta(odNorth, odEast); - - m_agp_y[outEntry(infos[v], odNorth, pos)] = ybase; - - infos[v].set_l_upper(ybase); - l_it++; pos++; - infos[v].nbf(odNorth)++; - } - - //******************************************************* - //assign gp value for bend edges on top of generalization - int bendnum = infos[v].inList(odNorth).size() - pos; - while (l_it.valid()) - { - //check for single/2 bend - //ybase += infos[v].delta(odNorth, odEast); //there is a generalization - ybase = infos[v].l_upper_unbend() + - (pos + 1 + bendnum - infos[v].inList(odNorth).size())*infos[v].delta(odNorth, odEast); - - if (m_acp_y[outEntry(infos[v], odNorth, pos)] < infos[v].coord(odEast) + m_sep) - { - m_abends[outEntry(infos[v],odNorth, pos)] = prob_b2r; infos[v].inc_E(odNorth, odEast); - } - else { - m_abends[outEntry(infos[v], odNorth, pos)] = prob_b1r; infos[v].inc_E_hook(odNorth, odEast); - } - m_agp_y[outEntry(infos[v], odNorth, pos)] = ybase; - - l_it++; - pos++; - }//while valid - }//if left gen - - //NO LEFT GENERATOR **************************************************** - else - { - int pos = 0; - OGDF_ASSERT(infos[v].has_gen(odSouth));//obs - //classify edges - //****************** - //edges bending down - //****************** - while (l_it.valid() && ( infos[v].coord(odWest) > - (cp_y(outEntry(infos[v], odNorth, pos)) - pos*infos[v].delta(odNorth, odWest) - infos[v].eps(odNorth,odWest)) )) - { - if (cp_y(outEntry(infos[v], odNorth, pos)) > infos[v].coord(odWest) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odNorth, pos)] = bend_2left; - infos[v].inc_E(odNorth, odWest); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odNorth, pos)] = prob_b1l; - infos[v].inc_E_hook(odNorth, odWest); - } - - m_agp_y[outEntry(infos[v], odNorth, pos)] = infos[v].coord(odWest) - + infos[v].eps(odNorth, odWest) - + pos*infos[v].delta(odNorth, odWest); - l_it++; - pos++; - }//while - //********************* - //bendfree edges - //********************* - bool check = true; - while (l_it.valid() && ( infos[v].coord(odEast) >= (cp_y(outEntry(infos[v], odNorth, pos)) - + (infos[v].inList(odNorth).size() - 1 - pos)*infos[v].delta(odNorth, odWest) - + infos[v].eps(odNorth,odWest)) )) - { - if (check) infos[v].set_l_lower(cp_y(outEntry(infos[v], odNorth, pos))); - infos[v].set_l_upper(cp_y(outEntry(infos[v], odNorth, pos))); - check = false; - m_abends[outEntry(infos[v], odNorth, pos)] = bend_free; - infos[v].nbf(odNorth)++; - m_agp_y[outEntry(infos[v], odNorth, pos)] = cp_y(outEntry(infos[v], odNorth, pos));//m_acp_y[outEntry(infos[v], odNorth, pos)]; - l_it++; - pos++; - } - //********************* - //edges bending upwards - //********************* - while (l_it.valid()) //&&???!!! - { - if (cp_y(outEntry(infos[v], odNorth, pos)) <= infos[v].coord(odEast) + m_sep) - { - m_abends[outEntry(infos[v], odNorth, pos)] = bend_2right; - infos[v].inc_E(odNorth, odEast); - } - else - { - m_abends[outEntry(infos[v], odNorth, pos)] = prob_b1r; infos[v].inc_E_hook(odNorth, odEast); - }//else - - m_agp_y[outEntry(infos[v], odNorth, pos)] = infos[v].coord(odEast) - - infos[v].eps(odNorth, odEast) - - (infos[v].inList(odNorth).size() - 1 - pos)*infos[v].delta(odNorth, odEast); - l_it++; - pos++; - }//while - - }//else left gen - - //RIGHT SIDE ************************************************************** - //RIGHT GENERATOR *********************************************** - if (infos[v].has_gen(odSouth)) - { - //left copy - int pos = infos[v].gen_pos(odSouth)-1; //compare edge position to generalization position - if (pos > -1) - l_it = infos[v].inList(odSouth).get(pos); - else l_it = 0; - //classify edges - //*************************************************** - //assign gp value for edges underneath generalization - ybase = gen_y - infos[v].delta(odSouth, odWest); - - //bendfree edges underneath - bool check = false; - bool lastcheck = true; - while (l_it.valid() && - (pos*infos[v].delta(odSouth, odWest) + infos[v].eps(odSouth,odWest) <= - (cp_y(outEntry(infos[v], odSouth, pos)) - infos[v].coord(odWest)) )) - { - m_agp_y[outEntry(infos[v], odSouth, pos)] = cp_y(outEntry(infos[v], odSouth, pos)); - - lastcheck = false; - infos[v].set_r_lower(m_agp_y[outEntry(infos[v], odSouth, pos)]); - if (!check) {infos[v].set_r_upper(m_agp_y[outEntry(infos[v], odSouth, pos)]); check = true;} - m_abends[outEntry(infos[v], odSouth, pos)] = bend_free; - ybase = cp_y(outEntry(infos[v], odSouth, pos)) - infos[v].delta(odSouth, odWest); - l_it--; - pos--; - infos[v].nbf(odSouth)++; - }//while - while (l_it.valid()) //still some lower edges to bend, ycoord+eps+delta - { - m_agp_y[outEntry(infos[v], odSouth, pos)] = ybase; - if (cp_y(outEntry(infos[v], odSouth, pos)) < infos[v].coord(odWest) - m_sep) - { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b1r; - infos[v].inc_E_hook(odSouth, odWest); - } - else { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b2r; - infos[v].inc_E(odSouth, odWest); - } - ybase = ybase - infos[v].delta(odSouth, odWest); - l_it--; - pos--; - } - //******************************************************* - //assign gp value for generalization - ybase = gen_y; //check == y(current edge)??? - l_it = infos[v].inList(odSouth).get(infos[v].gen_pos(odSouth)); - infos[v].nbf(odSouth)++; - m_agp_y[outEntry(infos[v], odSouth, infos[v].gen_pos(odSouth))] = ybase; - m_abends[outEntry(infos[v], odSouth, infos[v].gen_pos(odSouth))] = bend_free; - if (lastcheck) - { - infos[v].set_r_lower(m_agp_y[outEntry(infos[v], odSouth, infos[v].gen_pos(odSouth))]); - lastcheck = false; - } - infos[v].set_r_upper(ybase); - //******************************************************* - //assign gp value for bendfree edges above generalization - l_it++; - pos = infos[v].gen_pos(odSouth) + 1; - while (l_it.valid() && - ((infos[v].inList(odSouth).size() - 1 - pos)*infos[v].delta(odSouth, odEast) + infos[v].eps(odSouth,odEast) <= - (infos[v].coord(odEast) - cp_y(outEntry(infos[v], odSouth, pos))) )) - { - m_abends[outEntry(infos[v], odSouth, pos)] = bend_free; - ybase = cp_y(outEntry(infos[v], odSouth, pos));//+= infos[v].delta(odNorth, odEast); - m_agp_y[outEntry(infos[v], odSouth, pos)] = ybase; - infos[v].set_r_upper(ybase); - infos[v].nbf(odSouth)++; - l_it++; pos++; - } - //******************************************************* - //assign gp value for bend edges on top of generalization - while (l_it.valid()) - { - //check for single/2 bend - if (cp_y(outEntry(infos[v], odSouth, pos)) > infos[v].coord(odEast) + m_sep) - { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b1l; - infos[v].inc_E_hook(odSouth, odEast); - } - else { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b2l; - infos[v].inc_E(odSouth, odEast); - } - - ybase += infos[v].delta(odSouth, odEast); //there is a generalization - m_agp_y[outEntry(infos[v], odSouth, pos)] = ybase; - l_it++; - pos++; - }//while valid - }//if rightgen - //NO RIGHT GENERATOR **************************************************** - else - { - int pos = 0; - l_it = infos[v].inList(odSouth).begin(); - //classify edges - //****************** - //edges bending down - //****************** - while (l_it.valid() && ( infos[v].coord(odWest) > - (cp_y(outEntry(infos[v], odSouth, pos)) - pos*infos[v].delta(odSouth, odWest) - infos[v].eps(odSouth,odWest)) )) - { - if (cp_y(outEntry(infos[v], odSouth, pos)) > infos[v].coord(odWest) - m_sep)//must be intbend - { - m_abends[outEntry(infos[v], odSouth, pos)] = bend_2right; - infos[v].inc_E(odSouth, odWest); } - else //may be singlebend - { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b1r; - infos[v].inc_E_hook(odSouth, odWest); - } - //ab unterem Rand, oder ab gen, teile Abstand Anzahl Kanten??!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - m_agp_y[outEntry(infos[v], odSouth, pos)] = - infos[v].coord(odWest) - + infos[v].eps(odSouth, odWest) - + pos*infos[v].delta(odSouth, odWest); - l_it++; - pos++; - }//while - //********************* - //bendfree edges - //********************* - bool check = false; - while (l_it.valid() && ( infos[v].coord(odEast) >= - (cp_y(outEntry(infos[v], odSouth, pos)) - + (infos[v].inList(odSouth).size() - 1 - pos)*infos[v].delta(odSouth, odWest) - + infos[v].eps(odSouth,odWest)) )) - { - if (!check) { - infos[v].set_r_lower(cp_y(outEntry(infos[v], odSouth, pos))); - check = true; - } - infos[v].set_r_upper(cp_y(outEntry(infos[v], odSouth, pos))); - m_abends[outEntry(infos[v], odSouth,pos)] = bend_free; - infos[v].nbf(odSouth)++; - m_agp_y[outEntry(infos[v], odSouth, pos)] = cp_y(outEntry(infos[v], odSouth, pos)); - l_it++; - pos++; - }//while - //********************* - //edges bending upwards - //********************* - while (l_it.valid()) - { - if (cp_y(outEntry(infos[v], odSouth, pos)) <= infos[v].coord(odEast) + m_sep) - { - m_abends[outEntry(infos[v], odSouth, pos)] = bend_2left; - infos[v].inc_E(odSouth, odEast); - }//N/O?????!!!!! - else - { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b1l; - infos[v].inc_E_hook(odSouth, odEast); - }//else - m_agp_y[outEntry(infos[v], odSouth, pos)] = infos[v].coord(odEast) - - infos[v].eps(odSouth, odEast) - - (infos[v].inList(odSouth).size() - 1 - pos)*infos[v].delta(odSouth, odEast); - l_it++; - pos++; - }//while - }//else rightgen - //end set m_gy - - //x coordinates, just on the cage boundary - int l_pos = 0; - l_it = infos[v].inList(odNorth).begin(); - while (l_it.valid()) - { - m_agp_x[outEntry(infos[v], odNorth, l_pos)] = infos[v].coord(odNorth); - l_it++; - l_pos++; - } - l_it = infos[v].inList(odSouth).begin(); - l_pos = 0; - while (l_it.valid()) - { - m_agp_x[outEntry(infos[v], odSouth, l_pos)] = infos[v].coord(odSouth); - l_it++; - l_pos++; - } -}//gengluey - - -//todo: parameterize the different functions and delete the obsolete copies - -//compute preliminary glue point positions based on placement -//and generalizations for horizontal edges -void EdgeRouter::compute_gen_glue_points_x(node v) -{ - OGDF_ASSERT(infos[v].has_gen(odEast) || infos[v].has_gen(odWest)); - int xbase = 0; - - //position generalization in the middle of the node - int gen_x = infos[v].coord(odNorth) + infos[v].node_xsize()/2; //in the middle - //x coordinates in m_gp_x, set bend types for all edges - - //********************************************************** - //TOP SIDE ************************************************* - ListIterator l_it = infos[v].inList(odEast).begin(); - - //TOP GENERATOR ****************************************** - if (infos[v].has_gen(odEast))//gen at top side - { - int pos = infos[v].gen_pos(odEast)-1; //compare edge position to generalization position - if (pos > -1) - l_it = infos[v].inList(odEast).get(pos); - else { - l_it = 0; pos = 0; - } - //classify edges - //*************************************************** - //assign gp value for edges underneath generalization - xbase = gen_x - infos[v].delta(odEast, odNorth); - - //bendfree edges underneath - bool check = false; - while (l_it.valid() && - (pos*infos[v].delta(odEast, odNorth) + infos[v].eps(odEast,odNorth) <= - (cp_x(outEntry(infos[v], odEast, pos)) - infos[v].coord(odNorth)) )) - { - m_agp_x[outEntry(infos[v], odEast, pos)] = cp_x(outEntry(infos[v], odEast, pos)); - infos[v].set_t_right(m_agp_x[outEntry(infos[v], odEast, pos)]); - if (!check) { - check = true; - infos[v].set_t_left(m_agp_x[outEntry(infos[v], odEast, pos)]); - } - m_abends[outEntry(infos[v], odEast, pos)] = bend_free; - xbase = cp_x(outEntry(infos[v], odEast, pos)) - infos[v].delta(odEast, odNorth); - l_it--; - pos--; - infos[v].nbf(odEast)++; - }//while - - while (l_it.valid()) //still some lower edges to bend - { - m_agp_x[outEntry(infos[v], odEast, pos)] = xbase; - if (cp_x(outEntry(infos[v], odEast, pos)) < infos[v].coord(odNorth) - m_sep) - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b1l; - infos[v].inc_E_hook(odEast, odNorth); - } - else { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b2l; - infos[v].inc_E(odEast, odNorth); - } - xbase = xbase - infos[v].delta(odEast, odNorth); - l_it--; - pos--; - } - - //******************************************************* - //assign gp value for generalization - xbase = gen_x; //check == x(current edge)??? - l_it = infos[v].inList(odEast).get(infos[v].gen_pos(odEast)); - m_agp_x[outEntry(infos[v], odEast, infos[v].gen_pos(odEast))] = xbase; - m_abends[outEntry(infos[v], odEast, infos[v].gen_pos(odEast))] = bend_free; - infos[v].nbf(odEast)++; - if (!check) - infos[v].set_t_left(m_agp_x[outEntry(infos[v], odEast, infos[v].gen_pos(odEast))]); - infos[v].set_t_right(m_agp_x[outEntry(infos[v], odEast, infos[v].gen_pos(odEast))]); - - //******************************************************* - //assign gp value for bendfree edges above generalization - l_it++; - pos = infos[v].gen_pos(odEast) + 1; - while (l_it.valid() && - ((infos[v].inList(odEast).size() - 1 - pos)*infos[v].delta(odEast, odSouth) + infos[v].eps(odEast,odSouth) <= - (infos[v].coord(odSouth) - cp_x(outEntry(infos[v], odEast, pos))) )) - { - m_abends[outEntry(infos[v], odEast, pos)] = bend_free; - xbase = cp_x(outEntry(infos[v], odEast, pos));//+= infos[v].delta(odEast, odSouth); - m_agp_x[outEntry(infos[v], odEast, pos)] = xbase; - infos[v].set_t_right(m_agp_x[outEntry(infos[v], odEast, pos)]); - l_it++; pos++; - infos[v].nbf(odEast)++; - } - //******************************************************* - //assign gp value for bend edges on top of generalization - while (l_it.valid()) - { - //check for single/2 bend - if (m_acp_x[outEntry(infos[v], odEast, pos)] < infos[v].coord(odSouth) + m_sep) - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b2r; - infos[v].inc_E(odEast, odSouth); - } - else { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b1r; - infos[v].inc_E_hook(odEast, odSouth); - } - xbase += infos[v].delta(odEast, odSouth); //there is a generalization - m_agp_x[outEntry(infos[v], odEast, pos)] = xbase; - l_it++; - pos++; - }//while valid - }//if top gen - //NO TOPGENERATOR **************************************************** - else - { - int pos = 0; - int numbends = 0; //number of bend edges, used to correct position after assignment - OGDF_ASSERT(infos[v].has_gen(odWest));//obs - - //****************** - //edges bending down - //****************** - while (l_it.valid() && - ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odEast, pos)) - pos*infos[v].delta(odEast, odNorth) - - infos[v].eps(odEast,odNorth)) )) - { - if (cp_x(outEntry(infos[v], odEast, pos)) > infos[v].coord(odNorth) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odEast, pos)] = bend_2left; - infos[v].inc_E(odEast, odNorth); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b1l; - infos[v].inc_E_hook(odEast, odNorth); - } - - m_agp_x[outEntry(infos[v], odEast, pos)] = infos[v].coord(odNorth) - + infos[v].eps(odEast, odNorth) - + pos*infos[v].delta(odEast, odNorth); - l_it++; - pos++; - }//while - numbends = pos; - //********************* - //bendfree edges - //********************* - bool check = false; - int lastunbend = m_init; - int firstunbend = m_init; - while (l_it.valid() && ( infos[v].coord(odSouth) >= - (cp_x(outEntry(infos[v], odEast, pos)) - + (infos[v].inList(odEast).size() - 1 - pos)*infos[v].delta(odEast, odNorth) - + infos[v].eps(odEast,odNorth)) )) - { - m_abends[outEntry(infos[v], odEast, pos)] = bend_free; - infos[v].nbf(odEast)++; - lastunbend = m_agp_x[outEntry(infos[v], odEast, pos)] = cp_x(outEntry(infos[v], odEast, pos)); - if (firstunbend == m_init) firstunbend = lastunbend; - if (!check) { - check = true; - infos[v].set_t_left(m_agp_x[outEntry(infos[v], odEast, pos)] ); - } - infos[v].set_t_right(m_agp_x[outEntry(infos[v], odEast, pos)]); - l_it++; - pos++; - } - //********************************************************************* - //now we set all bending edges (left) as close as possible to the unbend edges - //to allow possible bend saving by edge flipping at the corner - - if (firstunbend != m_init) - { - ListIterator ll_it = infos[v].inList(odEast).begin(); - int llpos = 0; - while (ll_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odEast, llpos)) - - llpos*infos[v].delta(odEast, odNorth) - - infos[v].eps(odEast,odNorth)) )) - { - m_agp_x[outEntry(infos[v], odEast, llpos)] = firstunbend - - (numbends - llpos)*infos[v].delta(odEast, odNorth); - ll_it++; - llpos++; - }//while - }//if unbend edges - //********************************************************************* - //********************* - //edges bending upwards - //********************* - while (l_it.valid()) //&&???!!! - { - if (cp_x(outEntry(infos[v], odEast, pos)) <= infos[v].coord(odSouth) + m_sep) - { - m_abends[outEntry(infos[v], odEast, pos)] = bend_2right; - infos[v].inc_E(odEast, odSouth); - } - else { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b1r; - infos[v].inc_E_hook(odEast, odSouth); - }//else - m_agp_x[outEntry(infos[v], odEast, pos)] = infos[v].coord(odSouth) - - infos[v].eps(odEast, odSouth) - - (infos[v].inList(odEast).size() - 1 - pos)*infos[v].delta(odEast, odSouth); - l_it++; - pos++; - } - - }//else top gen - - //BOTTOM SIDE ************************************************************** - //BOTTOM GENERALIZATION *********************************************** - if (infos[v].has_gen(odWest)) - { - //left copy - int pos = infos[v].gen_pos(odWest)-1; //compare edge position to generalization position - if (pos > -1) - l_it = infos[v].inList(odWest).get(pos); - else { l_it = 0; pos = 0; } - //classify edges - //*************************************************** - //assign gp value for edges underneath generalization - xbase = gen_x - infos[v].delta(odWest, odNorth); - - //bendfree edges underneath - bool firstcheck = true; - while (l_it.valid() && - (pos*infos[v].delta(odWest, odNorth) + infos[v].eps(odWest,odNorth) <= - (cp_x(outEntry(infos[v], odWest, pos)) - infos[v].coord(odNorth)) )) - { - m_agp_x[outEntry(infos[v], odWest, pos)] = cp_x(outEntry(infos[v], odWest, pos)); - m_abends[outEntry(infos[v], odWest, pos)] = bend_free; - xbase = cp_x(outEntry(infos[v], odWest, pos)) - infos[v].delta(odWest, odNorth); - if (firstcheck) { - firstcheck = false; - infos[v].set_b_left(m_agp_x[outEntry(infos[v], odWest, pos)]); - } - infos[v].set_b_right(m_agp_x[outEntry(infos[v], odWest, pos)]); - l_it--; - pos--; - infos[v].nbf(odWest)++; - }//while - while (l_it.valid()) //still some lower edges to bend, xcoord+eps+delta - { - m_agp_x[outEntry(infos[v], odWest, pos)] = xbase; - if ( cp_x(outEntry(infos[v], odWest, pos)) < infos[v].coord(odNorth) - m_sep) //paper E^ - { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b1r; - infos[v].inc_E_hook(odWest, odNorth); - } - else { - m_abends[outEntry(infos[v], odWest, pos)] = bend_2right; - infos[v].inc_E(odWest, odNorth); - } - xbase = xbase - infos[v].delta(odWest, odNorth); - l_it--; - pos--; - } - //******************************************************* - //assign gp value for generalization - xbase = gen_x; //check == x(current edge)???cout - l_it = infos[v].inList(odWest).get(infos[v].gen_pos(odWest)); - m_agp_x[outEntry(infos[v], odWest, infos[v].gen_pos(odWest))] = xbase; - m_abends[outEntry(infos[v], odWest, infos[v].gen_pos(odWest))] = bend_free; - infos[v].nbf(odWest)++; - if (firstcheck) { - firstcheck = false; - infos[v].set_b_right(m_agp_x[outEntry(infos[v], odWest, infos[v].gen_pos(odWest))]); - } - infos[v].set_b_left(m_agp_x[outEntry(infos[v], odWest, infos[v].gen_pos(odWest))]); - //******************************************************* - //assign gp value for bendfree edges above generalization - l_it++; - pos = infos[v].gen_pos(odWest) + 1; - while (l_it.valid() && - ((infos[v].inList(odWest).size() - 1 - pos)*infos[v].delta(odWest, odSouth) + infos[v].eps(odWest,odSouth) <= - (infos[v].coord(odSouth) - cp_x(outEntry(infos[v], odWest, pos))) )) - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_free; - xbase = cp_x(outEntry(infos[v], odWest, pos));//+= infos[v].delta(odNorth, odEast); - m_agp_x[outEntry(infos[v], odWest, pos)] = xbase; - infos[v].nbf(odWest)++; - infos[v].set_b_left(m_agp_x[outEntry(infos[v], odWest, pos)]); - if (firstcheck) - { - infos[v].set_b_right(m_agp_x[outEntry(infos[v], odWest, pos)]); - firstcheck = false; - } - l_it++; pos++; - }//while - //******************************************************* - //assign gp value for bend edges on top of generalization - while (l_it.valid()) - { - //check for single/2 bend - if (m_acp_x[outEntry(infos[v], odWest, pos)] > infos[v].coord(odSouth) + m_sep) - { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b1l; - infos[v].inc_E_hook(odWest, odSouth); - } - else { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b2l; - infos[v].inc_E(odWest, odSouth); - } - xbase += infos[v].delta(odWest, odSouth); //there is a generalization - m_agp_x[outEntry(infos[v], odWest, pos)] = xbase; - l_it++; - pos++; - }//while valid - }//if bottomgen - //************************************************************************ - //NO BOTTOM GENERATOR **************************************************** - else - { - int pos = 0; - int rightbend = 0; //save number of actually bend edges to correct their position later - l_it = infos[v].inList(odWest).begin(); - //classify edges - //****************** - //edges bending down - //****************** - while (l_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odWest, pos)) - pos*infos[v].delta(odWest, odNorth) - infos[v].eps(odWest,odNorth)) )) - { - if (cp_x(outEntry(infos[v], odWest, pos)) > infos[v].coord(odNorth) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_2right; - infos[v].inc_E(odWest, odNorth); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b1r; - infos[v].inc_E_hook(odWest, odNorth); - } - - m_agp_x[outEntry(infos[v], odWest, pos)] = infos[v].coord(odNorth) - + infos[v].eps(odWest, odNorth) - + pos*infos[v].delta(odWest, odNorth); - l_it++; - pos++; - }//while - rightbend = pos; - //********************* - //bendfree edges - //********************* - bool firstcheck = true; - int lastunbend = m_init; - int firstunbend = m_init; - while (l_it.valid() && ( infos[v].coord(odSouth) >= - (cp_x(outEntry(infos[v], odWest, pos)) - + (infos[v].inList(odWest).size() - 1 - pos)*infos[v].delta(odWest, odNorth) - + infos[v].eps(odWest,odNorth)) )) - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_free; - infos[v].nbf(odWest)++; - lastunbend = m_agp_x[outEntry(infos[v], odWest, pos)] = cp_x(outEntry(infos[v], odWest, pos)); - - if (firstunbend == m_init) firstunbend = lastunbend; - - if (firstcheck) - { - infos[v].set_b_right(lastunbend); - firstcheck = false; - } - infos[v].set_b_left(lastunbend); - l_it++; - pos++; - } - //********************************************************************* - //no assign bend edges as close as possible - - if (firstunbend != m_init) - { - ListIterator ll_it = infos[v].inList(odWest).begin(); - int llpos = 0; - while (ll_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odWest, llpos)) - llpos*infos[v].delta(odWest, odNorth) - infos[v].eps(odWest,odNorth)) )) - { - m_agp_x[outEntry(infos[v], odWest, llpos)] = firstunbend - - (rightbend - llpos)*infos[v].delta(odWest, odNorth); - ll_it++; - llpos++; - }//while - }//if - //********************************************************************* - //********************* - //edges bending upwards - //********************* - - while (l_it.valid()) //&&???!!! - { - if (cp_x(outEntry(infos[v], odWest, pos)) <= infos[v].coord(odSouth) + m_sep) - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_2left; - infos[v].inc_E(odWest, odSouth); - }//if - else - { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b1l; - infos[v].inc_E_hook(odWest, odSouth); - }//else - - if (lastunbend != m_init) - { - m_agp_x[outEntry(infos[v], odWest, pos)] = lastunbend + infos[v].delta(odWest, odSouth); - lastunbend = lastunbend + infos[v].delta(odWest, odSouth); - }//if - else - m_agp_x[outEntry(infos[v], odWest, pos)] = infos[v].coord(odSouth) - - infos[v].eps(odWest, odSouth) - - (infos[v].inList(odWest).size() - 1 - pos)*infos[v].delta(odWest, odSouth); - l_it++; - pos++; - }//while - - }//else leftgen - //end set m_gx - - //y coordinates, just on the cage boundary - l_it = infos[v].inList(odEast).begin(); - int l_pos = 0; - while (l_it.valid()) - { - m_agp_y[outEntry(infos[v], odEast, l_pos)] = infos[v].coord(odEast); - l_it++; - l_pos++; - } - l_it = infos[v].inList(odWest).begin(); - l_pos = 0; - while (l_it.valid()) - { - m_agp_y[outEntry(infos[v], odWest, l_pos)] = infos[v].coord(odWest); - l_it++; - l_pos++; - } -}//gengluex - - -//compute preliminary glue point positions based on placement -//maybe: use earlier classification of edges: bendfree? -void EdgeRouter::compute_glue_points_y(node v) -{ - //forall edges in horizontal lists, we set the glue point y coordinate - ListIterator l_it = infos[v].inList(odNorth).begin(); - int pos = 0; - int bendDownCounter = 0; - //left edges - //classify edges - //****************** - //edges bending down - //****************** - while (l_it.valid() && ( infos[v].coord(odWest) > - (cp_y(outEntry(infos[v], odNorth, pos)) - pos*infos[v].delta(odNorth, odWest) - infos[v].eps(odNorth,odWest)) )) - { - if (cp_y(outEntry(infos[v], odNorth, pos)) > infos[v].coord(odWest) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odNorth, pos)] = bend_2left; - infos[v].inc_E(odNorth, odWest); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odNorth, pos)] = prob_b1l; - infos[v].inc_E_hook(odNorth, odWest); - } - m_agp_y[outEntry(infos[v], odNorth, pos)] = infos[v].coord(odWest) - + infos[v].eps(odNorth, odWest) - + pos*infos[v].delta(odNorth, odWest); - bendDownCounter++; - l_it++; - pos++; - }//while - //********************* - //bendfree edges - //********************* - int lastunbend = m_init; - int firstunbend = m_init; - bool firstcheck = true; - while (l_it.valid() && ( infos[v].coord(odEast) >= - (cp_y(outEntry(infos[v], odNorth, pos)) - + (infos[v].inList(odNorth).size() - 1 - pos)*infos[v].delta(odNorth, odWest) - + infos[v].eps(odNorth,odWest)) )) - { - m_abends[outEntry(infos[v], odNorth, pos)] = bend_free; - infos[v].nbf(odNorth)++; - lastunbend = m_agp_y[outEntry(infos[v], odNorth, pos)] = cp_y(outEntry(infos[v], odNorth, pos)); - if (firstcheck) - { - infos[v].set_l_lower(m_agp_y[outEntry(infos[v], odNorth, pos)]); - firstunbend = lastunbend; - firstcheck = false; - } - infos[v].set_l_upper(m_agp_y[outEntry(infos[v], odNorth, pos)]); - l_it++; - pos++; - } - //********************************************************************* - //correct left edges - if (firstunbend != m_init) - { - ListIterator ll_it = infos[v].inList(odNorth).begin(); - int llpos = 0; - while (ll_it.valid() && ( infos[v].coord(odWest) > - (cp_y(outEntry(infos[v], odNorth, llpos)) - llpos*infos[v].delta(odNorth, odWest) - infos[v].eps(odNorth, odWest)) )) - { - m_agp_y[outEntry(infos[v], odNorth, llpos)] = firstunbend - - (bendDownCounter - llpos)*infos[v].delta(odNorth, odWest); - ll_it++; - llpos++; - }//while - }//if - //********************************************************************* - //********************* - //edges bending upwards - //********************* - while (l_it.valid()) //&&???!!! - { - if (cp_y(outEntry(infos[v], odNorth, pos)) <= infos[v].coord(odEast) + m_sep) - { - m_abends[outEntry(infos[v], odNorth, pos)] = bend_2right; - infos[v].inc_E(odNorth, odEast); - } - else - { - m_abends[outEntry(infos[v], odNorth, pos)] = prob_b1r; - infos[v].inc_E_hook(odNorth, odEast); - } - //leave space to reroute - if (lastunbend != m_init) - { - m_agp_y[outEntry(infos[v], odNorth, pos)] = lastunbend + infos[v].delta(odNorth, odEast); - lastunbend = lastunbend + infos[v].delta(odNorth, odEast); - }//if - else - m_agp_y[outEntry(infos[v], odNorth, pos)] = infos[v].coord(odEast) - - infos[v].eps(odNorth, odEast) - - (infos[v].inList(odNorth).size() - 1 - pos)*infos[v].delta(odNorth, odEast); - l_it++; - pos++; - }//while - //South edges - pos = 0; - bendDownCounter = 0; - l_it = infos[v].inList(odSouth).begin(); - - //classify edges - //****************** - //edges bending down - //****************** - while (l_it.valid() && ( infos[v].coord(odWest) > - (cp_y(outEntry(infos[v], odSouth, pos)) - pos*infos[v].delta(odSouth, odWest) - infos[v].eps(odSouth,odWest)) )) - { - if (cp_y(outEntry(infos[v], odSouth, pos)) > infos[v].coord(odWest) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odSouth, pos)] = bend_2right; //was left - infos[v].inc_E(odSouth, odWest); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b1r; - infos[v].inc_E_hook(odSouth, odWest); - } - m_agp_y[outEntry(infos[v], odSouth, pos)] = infos[v].coord(odWest) - + infos[v].eps(odSouth, odWest) - + pos*infos[v].delta(odSouth, odWest); - l_it++; - bendDownCounter++; - pos++; - }//while - //********************* - //bendfree edges - //********************* - firstcheck = true; - lastunbend = m_init; - firstunbend = m_init; - while (l_it.valid() && ( infos[v].coord(odEast) >= - (cp_y(outEntry(infos[v], odSouth, pos)) - + (infos[v].inList(odSouth).size() - 1 - pos)*infos[v].delta(odSouth, odWest) - + infos[v].eps(odSouth,odWest)) )) - { - m_abends[outEntry(infos[v], odSouth, pos)] = bend_free; - infos[v].nbf(odSouth)++; - lastunbend = m_agp_y[outEntry(infos[v], odSouth, pos)] = cp_y(outEntry(infos[v], odSouth, pos)); - if (firstcheck) - { - firstcheck = false; - infos[v].set_r_lower(m_agp_y[outEntry(infos[v], odSouth, pos)]); - firstunbend = lastunbend; - } - infos[v].set_r_upper(m_agp_y[outEntry(infos[v], odSouth, pos)]); - l_it++; - pos++; - }//while - - //*************************** - //correct right bending edges - if (firstunbend != m_init) - { - ListIterator ll_it = infos[v].inList(odSouth).begin(); - int llpos = 0; - while (ll_it.valid() && ( infos[v].coord(odWest) > - (cp_y(outEntry(infos[v], odSouth, llpos)) - llpos*infos[v].delta(odSouth, odWest) - - infos[v].eps(odSouth, odWest)) )) - { - m_agp_y[outEntry(infos[v], odSouth, llpos)] = firstunbend - - (bendDownCounter - llpos)*infos[v].delta(odSouth, odWest); - ll_it++; - llpos++; - }//while - }//if - //********************************************************************* - //********************* - //edges bending upwards - //********************* - while (l_it.valid()) //&&???!!! - { - if (cp_y(outEntry(infos[v], odSouth, pos)) <= infos[v].coord(odEast) + m_sep) - { - m_abends[outEntry(infos[v], odSouth, pos)] = bend_2left; - infos[v].inc_E(odSouth, odEast); - }//was right - else - { - m_abends[outEntry(infos[v], odSouth, pos)] = prob_b1l; - infos[v].inc_E_hook(odSouth, odEast); - }//else - //leave as much space as possible for rerouters - if (lastunbend != m_init) - { - m_agp_y[outEntry(infos[v], odSouth, pos)] = lastunbend + infos[v].delta(odSouth, odEast); - lastunbend = lastunbend + infos[v].delta(odSouth, odEast); - }//if - else - m_agp_y[outEntry(infos[v], odSouth, pos)] = - infos[v].coord(odEast) - infos[v].eps(odSouth, odEast) - (infos[v].inList(odSouth).size() - 1 - pos)*infos[v].delta(odSouth, odEast); - l_it++; - pos++; - }//while - - //x coordinates, just on the cage boundary - l_it = infos[v].inList(odNorth).begin(); - int l_pos = 0; - while (l_it.valid()) - { - m_agp_x[outEntry(infos[v], odNorth, l_pos)] = infos[v].coord(odNorth); - l_it++; - l_pos++; - } - l_it = infos[v].inList(odSouth).begin(); - l_pos = 0; - while (l_it.valid()) - { - m_agp_x[outEntry(infos[v], odSouth, l_pos)] = infos[v].coord(odSouth); - l_it++; - l_pos++; - } -} - - -void EdgeRouter::compute_glue_points_x(node& v) -//compute preliminary glue point positions based on placement -//maybe: use earlier classification of edges: bendfree? -{ - //forall edges in vertical lists, we set the glue point x coordinate - //TOP SIDE ************************************************* - ListIterator l_it = infos[v].inList(odEast).begin(); - int pos = 0; - int numbends = 0; - //classify edges - //****************** - //edges bending down - //****************** - while (l_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odEast, pos)) - pos*infos[v].delta(odEast, odNorth) - infos[v].eps(odEast,odNorth)) )) - { - if (cp_x(outEntry(infos[v], odEast, pos)) > infos[v].coord(odNorth) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odEast, pos)] = bend_2left; - infos[v].inc_E(odEast, odNorth); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b1l; - infos[v].inc_E_hook(odEast, odNorth); - } - m_agp_x[outEntry(infos[v], odEast, pos)] = infos[v].coord(odNorth) - + infos[v].eps(odEast, odNorth) + pos*infos[v].delta(odEast, odNorth); - l_it++; - pos++; - }//while - numbends = pos; - int lastunbend = m_init; - int firstunbend = m_init; - //********************* - //bendfree edges - //********************* - bool firstcheck = true; - while (l_it.valid() && ( infos[v].coord(odSouth) >= - (cp_x(outEntry(infos[v], odEast, pos)) - + (infos[v].inList(odEast).size() - 1 - pos)*infos[v].delta(odEast, odNorth) - + infos[v].eps(odEast,odNorth)) )) - { - m_abends[outEntry(infos[v], odEast, pos)] = bend_free; - infos[v].nbf(odEast)++; - lastunbend = m_agp_x[outEntry(infos[v], odEast, pos)] = cp_x(outEntry(infos[v], odEast, pos)); - if (firstunbend == m_init) firstunbend = lastunbend; - if (firstcheck) - { - firstcheck = false; - infos[v].set_t_left(lastunbend); - }//if - infos[v].set_t_right(lastunbend); - l_it++; - pos++; - } - //********************************************************************* - //temporary sol, correct left edges - - if (firstunbend != m_init) - { - ListIterator ll_it = infos[v].inList(odEast).begin(); - int llpos = 0; - while (ll_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odEast, llpos)) - - llpos*infos[v].delta(odEast, odNorth) - - infos[v].eps(odEast,odNorth)) )) - { - m_agp_x[outEntry(infos[v], odEast, llpos)] = firstunbend - - (numbends - llpos)*infos[v].delta(odEast, odNorth); - ll_it++; - llpos++; - }//while - }//if - //********************************************************************* - //********************* - //edges bending to the right side - //********************* - while (l_it.valid()) //&&???!!! - { - if (cp_x(outEntry(infos[v], odEast, pos)) <= infos[v].coord(odSouth) + m_sep) - { - if (cp_x(outEntry(infos[v], odEast, pos)) > infos[v].coord(odSouth) - infos[v].eps(odEast, odSouth)) - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b2r; - infos[v].inc_E(odEast, odSouth); - }//if - else - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b2r;//use prob_bf; - infos[v].inc_E(odEast, odSouth); - }//else - }//if - else - { - m_abends[outEntry(infos[v], odEast, pos)] = prob_b1r; - infos[v].inc_E_hook(odEast, odSouth); - }//else - if (lastunbend != m_init) - { - m_agp_x[outEntry(infos[v], odEast, pos)] = lastunbend + infos[v].delta(odEast, odSouth); - lastunbend = lastunbend + infos[v].delta(odEast, odSouth); - }//if - else m_agp_x[outEntry(infos[v], odEast, pos)] = infos[v].coord(odSouth) - - infos[v].eps(odEast, odSouth) - - (infos[v].inList(odEast).size() - 1 - pos)*infos[v].delta(odEast, odSouth); - l_it++; - pos++; - }//while - - //bottom********************************************************** - pos = 0; - l_it = infos[v].inList(odWest).begin(); - int rightbend = 0; //save number of atually bend edge to correct their position later - //classify edges - //****************** - //edges bending to north dir / westright - //****************** - while (l_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odWest, pos)) - pos*infos[v].delta(odWest, odNorth) - infos[v].eps(odWest,odNorth)) )) - { - if (cp_x(outEntry(infos[v], odWest, pos)) > infos[v].coord(odNorth) - m_sep)//must be doublebend - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_2right; - infos[v].inc_E(odWest, odNorth); - } - else //may be singlebend - { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b1r; - infos[v].inc_E_hook(odWest, odNorth); - } - m_agp_x[outEntry(infos[v], odWest, pos)] = infos[v].coord(odNorth) - + infos[v].eps(odWest, odNorth) - + pos*infos[v].delta(odWest, odNorth); - l_it++; - pos++; - }//while - rightbend = pos; //NUMBER of bend edges - //********************* - //bendfree edges - //********************* - firstunbend = true; - firstcheck = true; - lastunbend = m_init; - firstunbend = m_init; - while (l_it.valid() && ( infos[v].coord(odSouth) >= - (cp_x(outEntry(infos[v], odWest, pos)) - + (infos[v].inList(odWest).size() - 1 - pos)*infos[v].delta(odWest, odNorth) - + infos[v].eps(odWest,odNorth)) )) - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_free; - infos[v].nbf(odWest)++; - lastunbend = m_agp_x[outEntry(infos[v], odWest, pos)] = cp_x(outEntry(infos[v], odWest, pos)); - if (firstunbend == m_init) firstunbend = lastunbend; - if (firstcheck) - { - firstcheck = false; - infos[v].set_b_right(lastunbend); - } - infos[v].set_b_left(lastunbend); - l_it++; - pos++; - } - //********************************************************************* - //temporary sol, correct left edges - - if (firstunbend != m_init) - { - ListIterator ll_it = infos[v].inList(odWest).begin(); - int llpos = 0; - while (ll_it.valid() && ( infos[v].coord(odNorth) > - (cp_x(outEntry(infos[v], odWest, llpos)) - llpos*infos[v].delta(odWest, odNorth) - infos[v].eps(odWest,odNorth)) )) - { - //ab unterem Rand, oder ab gen, teile Abstand Anzahl Kanten??!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - m_agp_x[outEntry(infos[v], odWest, llpos)] = firstunbend - - (rightbend - llpos)*infos[v].delta(odWest, odNorth); - ll_it++; - llpos++; - }//while - OGDF_ASSERT(rightbend == llpos); - }//if - //********************************************************************* - //********************* - //edges bending upwards - //********************* - while (l_it.valid()) //&&???!!! - { - if (cp_x(outEntry(infos[v], odWest, pos)) <= infos[v].coord(odSouth) + m_sep) - { - m_abends[outEntry(infos[v], odWest, pos)] = bend_2left; - infos[v].inc_E(odWest, odSouth); - } - else - { - m_abends[outEntry(infos[v], odWest, pos)] = prob_b1l; - infos[v].inc_E_hook(odWest, odSouth); - }//else - - if (lastunbend != m_init) - { - m_agp_x[outEntry(infos[v], odWest, pos)] = lastunbend + infos[v].delta(odWest, odSouth); - lastunbend = lastunbend + infos[v].delta(odWest, odSouth); - } - else - m_agp_x[outEntry(infos[v], odWest, pos)] = infos[v].coord(odSouth) - - infos[v].eps(odWest, odSouth) - - (infos[v].inList(odWest).size() - 1 - pos)*infos[v].delta(odWest, odSouth); - l_it++; - pos++; - }//while - //y values - //y coordinates, just on the cage boundary - l_it = infos[v].inList(odEast).begin(); - int l_pos = 0; - while (l_it.valid()) - { - m_agp_y[outEntry(infos[v], odEast, l_pos)] = infos[v].coord(odEast); - l_it++; - l_pos++; - } - l_it = infos[v].inList(odWest).begin(); - l_pos = 0; - while (l_it.valid()) - { - m_agp_y[outEntry(infos[v], odWest, l_pos)] = infos[v].coord(odWest); - l_it++; - l_pos++; - } -}//compute gpx - - -void EdgeRouter::set_corners(node v) -{ - //set the layout position - //set the expandedNode entries for the corners, should be where they are inserted - edge e; - node w; - const OrthoRep::VertexInfoUML* vinfo = m_orp->cageInfo(v); - adjEntry ae = vinfo->m_corner[0]; - e = *ae; - w = e->source();//pointing towards north, on left side - m_prup->setExpandedNode(w, v); - - m_layoutp->x(w) = infos[v].coord(odNorth); - m_layoutp->y(w) = infos[v].coord(odWest); - ae = vinfo->m_corner[1]; - e = *ae; - w = e->source(); - m_prup->setExpandedNode(w, v); - - m_layoutp->x(w) = infos[v].coord(odNorth); - m_layoutp->y(w) = infos[v].coord(odEast); - ae = vinfo->m_corner[2]; - e = *ae; - w = e->source(); - m_prup->setExpandedNode(w, v); - - m_layoutp->x(w) = infos[v].coord(odSouth); - m_layoutp->y(w) = infos[v].coord(odEast); - ae = vinfo->m_corner[3]; - e = *ae; - w = e->source(); - m_prup->setExpandedNode(w, v); - - m_layoutp->x(w) = infos[v].coord(odSouth); - m_layoutp->y(w) = infos[v].coord(odWest); -}//setcorners - - - -//***************************************************************************** -//locally decide where to place the node in the computed cage area -//allow individual separation and overhang distance, input original node v -//classify edges with preliminary bend_types prob_xxx -//choose bendfree edges, bend edges may be rerouted to save bends -//***************************************************************************** - -void EdgeRouter::compute_place(node v, NodeInfo& inf/*, int l_sep, int l_overh*/) -{ - int l_directvalue = 10; //value of edges connecting two cages bendfree, with bends: value = 1 - - //gen at left or right cage side - bool horizontal_merger = (inf.has_gen(odNorth) || inf.has_gen(odSouth)); - //gen at top or bottom side - bool vertical_merger = (inf.has_gen(odWest) || inf.has_gen(odEast)); - - List l_horz; //contains horizontal incoming edges at v's cage, sorted increasing uppe, paper L - List l_horzl; //by increasing lowe - - List edgevalue; //saves value for direct / bend edges in lhorz - - //for every element of list l_horzl, we store its iterator in l_horz, ist Wahnsinn, spaeter global - EdgeArray< ListIterator > horz_entry(*m_prup); - EdgeArray< ListIterator > vert_entry(*m_prup); - EdgeArray< ListIterator > value_entry(*m_prup); - EdgeArray valueCounted(*m_prup, false); //did we consider edge in numunbend sum? - List l_vert; // vertical - List l_vertl; //by increasing lefte - //attachment side, maybe check the direction instead - EdgeArray at_left(*m_prup, false); - EdgeArray at_top(*m_prup, false); - - //Fill edge lists ****************************************************** - int lhorz_size = inf.inList(odNorth).size() + inf.inList(odSouth).size(); - if (lhorz_size && (!horizontal_merger)) - { - edge e; - //fill l_horz sorting by uppe, remember entry for edges sorted by lowe - //all inf.inList[odNorth] and [odSouth], sorted by lower - - //check: each side is already sorted by lowe/uppe definition!!!!!!!!!!!!!!!!!!! - ListIterator li_l = inf.inList(odNorth).begin(); - ListIterator li_r = inf.inList(odSouth).begin(); - //iterators for increasing lower value - ListIterator li_ll = inf.inList(odNorth).begin(); - ListIterator li_lr = inf.inList(odSouth).begin(); - - int uppe_l, uppe_r, lowe_l, lowe_r; - - uppe_l = (li_l.valid() ? auppe[outEntry(inf, odNorth, 0)] : INT_MAX);//only both 10000.0 if both empty!!! - uppe_r = (li_r.valid() ? auppe[outEntry(inf, odSouth, 0)] : INT_MAX);//never in for - loop - lowe_l = (li_ll.valid() ? alowe[outEntry(inf, odNorth, 0)] : INT_MAX);//only both 10000.0 if both empty!!! - lowe_r = (li_lr.valid() ? alowe[outEntry(inf, odSouth, 0)] : INT_MAX);//never in for - loop - - int lcount, rcount, llcount, rlcount;//zaehle fuer outEntry in Listen - lcount = rcount = llcount = rlcount = 0; - //forall horizontal edges, sort - for (int k = 0; k < lhorz_size; k++) - { - node nextNeighbour; - //run in parallel over opposite side lists - //upper value - if (uppe_l <= uppe_r) //favour left edges, maybe we should prefer them - { - e = *li_l; - at_left[e] = true; - nextNeighbour = (inf.is_in_edge(odNorth, lcount) ? e->source() : e->target()); - li_l++; - lcount++; - uppe_l = (lcount < inf.inList(odNorth).size() ? auppe[outEntry(inf, odNorth, lcount)] : INT_MAX); - } - else - { - e = *li_r; - nextNeighbour = (inf.is_in_edge(odSouth, rcount) ? e->source() : e->target()); - li_r++; - rcount++; - uppe_r = (rcount < inf.inList(odSouth).size() ? auppe[outEntry(inf, odSouth, rcount)] : INT_MAX); - } - horz_entry[e] = l_horz.pushBack(e);//fill edge in L - - value_entry[e] = edgevalue.pushBack((m_prup->expandedNode(nextNeighbour) ? l_directvalue : 1)); - - //lower value - if (lowe_l <= lowe_r) //favour left edges, maybe we should prefer them - { - e = *li_ll; - //at_left[e] = true; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - li_ll++; - llcount++; - lowe_l = (llcount < inf.inList(odNorth).size() ? alowe[outEntry(inf, odNorth, llcount)] : INT_MAX); - } - else - { - e = *li_lr; - li_lr++; - rlcount++; - //lowe_r = (li_lr.valid() ? lowe[*li_lr] : 10000.0); - lowe_r = (rlcount < inf.inList(odSouth).size() ? alowe[outEntry(inf, odSouth, rlcount)] : INT_MAX); - } - l_horzl.pushBack(e); //fill edge in e_0,...e_k - - }//for - }//if horz - //vertical edges ******************************************************* - int lvert_size = inf.inList(odEast).size() + inf.inList(odWest).size(); - if (lvert_size && !vertical_merger) - { - //fill l_vert - edge e; - //fill l_vert sorting by righte, remember entry for edges sorted by lefte - //all inf.inList[odEast] and [odWest], sorted by lefte - - //check: each side is already sorted by lefte/righte definition!!!!!!!!!!!!!!!!!!! - ListIterator li_t = inf.inList(odEast).begin(); - ListIterator li_b = inf.inList(odWest).begin(); - //iterators for increasing lefte value - ListIterator li_lt = inf.inList(odEast).begin(); - ListIterator li_lb = inf.inList(odWest).begin(); - - int righte_t, righte_b, lefte_t, lefte_b; - righte_t = (li_t.valid() ? arighte[outEntry(inf, odEast, 0)] : INT_MAX);//only both 10000.0 if both empty!!! - righte_b = (li_b.valid() ? arighte[outEntry(inf, odWest, 0)] : INT_MAX);//never in for - loop - lefte_t = (li_lt.valid() ? alefte[outEntry(inf, odEast, 0)] : INT_MAX);//only both 10000.0 if both empty!!! - lefte_b = (li_lb.valid() ? alefte[outEntry(inf, odWest, 0)] : INT_MAX);//never in for - loop - - //forall horizontal edges, sort - int tcount, bcount, tlcount, blcount;//zaehle fuer outEntry in Listen - tcount = bcount = tlcount = blcount = 0; - for (int k = 0; k < lvert_size; k++) - { - if (li_t.valid() || li_b.valid()) - { - //righter value - if (righte_t <= righte_b) //favour top edges, maybe we should prefer them - { - if (li_t.valid()) - { - e = *li_t; - at_top[e] = true; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - li_t++; - tcount++; - }//if - righte_t = (tcount < inf.inList(odEast).size() ? arighte[outEntry(inf, odEast, tcount)] : INT_MAX); - } - else - { - if (li_b.valid()) - { - e = *li_b; - li_b++; - bcount++; - }//if - righte_b = (bcount < inf.inList(odWest).size() ? arighte[outEntry(inf, odWest, bcount)] : INT_MAX); - } - vert_entry[e] = l_vert.pushBack(e);//fill edge in L - } - //lefter value - if (lefte_t <= lefte_b) //favour top edges, maybe we should prefer them - { - e = *li_lt; - //at_left[e] = true; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - li_lt++; - tlcount++; - //lefte_t = (li_lt.valid() ? lefte[*li_lt] : 100000.0); - lefte_t = (tlcount < inf.inList(odEast).size() ? alefte[outEntry(inf, odEast, tlcount)] : INT_MAX); - //if (lefte_t != (tlcount < inf.inList(odEast).size() ? alefte[outEntry(inf, odEast, tlcount)] : 100000.0)) exit; - } - else - { - e = *li_lb; - li_lb++; - blcount++; - //lefte_b = (li_lb.valid() ? lefte[*li_lb] : 100000.0); - lefte_b = (blcount < inf.inList(odWest).size() ? alefte[outEntry(inf, odWest, blcount)] : INT_MAX); - } - l_vertl.pushBack(e); - }//for - }//if vert - - //we inserted the edges incident to v int the list l_horz (horizontal edges sorted - //by upper) / l_horzl (horizontal edges sorted by lower) and l_vert (vertical edges - //sorted by righter / l_vertl (vertical edges sorted by lefter) - int boxx = inf.node_xsize(); - int boxy = inf.node_ysize(); - - //now two iterations are executed to compute the best starting index - //in the list of horizontal/vertical edges to maximise unbend edges - - //some variables for the placement iteration - int num_unbend = 0; //current number of unbend edges(paper: size) - int best_unbend = -1;//best number of unbend edges so far (paper: best) - int i; - - //vertical position paper ALGORITHM1****************************************************************** - //check e_i sorted by lowe, l_horz sorted by uppe !!!!!!!!!!!!!! - //we need to have an listentry for all edges sorted by lowe to - //delete them in l_horz - - if (!l_horz.empty()) - { - //starting from the lowest horizontal edge, we move the virtual node box up and count the number of potentially - //unbend edges to find the best starting unbend edge additionally, we set the values for the connection/glue point position - int stop = l_horz.size(); - int bestvalue; - - if (l_horz.size() == 1) - { - best_unbend = 1; - if (at_left[*(l_horz.begin())]) - bestvalue = alowe[outEntry(inf, odNorth, 0)]; - else bestvalue = alowe[outEntry(inf, odSouth, 0)]; - } - else - { - ListIterator p = l_horz.begin(); - ListIterator valp = edgevalue.begin();// run over edgevalue in parallel to p - - int leftcount = 0, rightcount = 0; - for (i = 1; i < stop+1; i++) //in der Regel laenger als noetig?? - { - if (!valueCounted[l_horzl.front()]) - { - num_unbend += *value_entry[l_horzl.front()]; - valueCounted[l_horzl.front()] = true; - } - while (p.valid()) - { - //the edge indicated by p fits in the box started with l_horzl.front lower value - if (uppe[(*p)]<= (lowe[l_horzl.front()]+boxy)) //+machineeps)) //||(p == horz_entry[l_horzl.front()])) - //assert first edge int horzl is edge i? - //p's entry needs no bend => increase num_unbend (edges) - { - //num_unbend++; - num_unbend += *valp; - valueCounted[*p] = true; - //only to be set if new best_unbend - p++; - valp++; - }//if - else - { - break; - } - }//while unbend - - if (num_unbend > best_unbend) - { - best_unbend = num_unbend; - bestvalue = (at_left[l_horzl.front()] ? alowe[outEntry(inf,odNorth, leftcount)] : alowe[outEntry(inf, odSouth, rightcount)]); - }//if new best - - if (at_left[l_horzl.front()]) leftcount++; - else rightcount++; - - if ( p == horz_entry[l_horzl.front()]) p++; - if ( valp == value_entry[l_horzl.front()]) valp++; - - l_horz.del(horz_entry[l_horzl.front()]); - - if (num_unbend) num_unbend -= *value_entry[l_horzl.front()]; - - OGDF_ASSERT(num_unbend >= 0); - - edgevalue.del(value_entry[l_horzl.front()]); - - valueCounted[l_horzl.front()] = false; - - l_horzl.popFront(); - }//for, l_horz list entries - - }//else bugfix size 1 - - m_newy[v] = min((inf.cage_coord(odEast) - inf.node_ysize() - inf.rc(odEast)), bestvalue); - inf.set_coord(odWest, m_newy[v]); - inf.set_coord(odEast, m_newy[v] + inf.node_ysize()); - }//if horz - else - { - if (horizontal_merger) - { - //position is fixed //odNorth was odNorth - edge e; - //note that get starts indexing with zero, whereas gen_pos starts with one - if (inf.has_gen(odNorth)) e = *(inf.inList(odNorth).get(inf.gen_pos(odNorth))); - else e = *(inf.inList(odSouth).get(inf.gen_pos(odSouth))); //check e !!!!!!!!!!!!! - int gen_y = m_layoutp->y( e->target()); //koennte man auch in inf schreiben !!!!!!!!! - m_newy[v] = gen_y - int(floor((double)(inf.node_ysize())/2)); - inf.set_coord(odWest, m_newy[v]); - inf.set_coord(odEast, m_newy[v] + inf.node_ysize()); - }//if - else - { - //new heuristics: look for vertical generalization and shift towards it - if (vertical_merger) - { - //find out direction of generalization - bool wg = inf.has_gen(odWest); - bool eg = inf.has_gen(odEast); - int mynewy = 0; - if (wg) - { - if (eg) - { - if (inf.is_in_edge(odWest, inf.gen_pos(odWest))) //position to odEast - { - mynewy = inf.cage_coord(odEast) - inf.rc(odEast) - inf.node_ysize(); - } - else - { - mynewy = inf.cage_coord(odWest) + inf.rc(odWest); - } - }//both - else - { - mynewy = inf.cage_coord(odWest) + inf.rc(odWest); - }//only west - } - else - { - mynewy = inf.cage_coord(odEast) - inf.rc(odEast) - inf.node_ysize(); - }//else no west - m_newy[v] = mynewy; - inf.set_coord(odWest, m_newy[v]); - inf.set_coord(odEast, m_newy[v] + inf.node_ysize()); - }//if verticalmerger - else - { - //we place the node at the position cage_lower_border(v)+routing_channel_bottom(v) - m_newy[v] = inf.cage_coord(odEast) - inf.rc(odEast) - inf.node_ysize(); - inf.set_coord(odWest, m_newy[v]); - inf.set_coord(odEast, m_newy[v] + inf.node_ysize()); - //forall horizontal edges set their glue point y coordinate - }//else verticalmerger - }//else merger - }//else horz - - - //forall horizontal edges we computed the y-coordinate of their glue point in m_gp_y - //and we computed the y-coordinate of the lower box segment in m_newy - //horizontal position**************************** - if (!l_vert.empty()) - { - //starting from the leftmost vertical edge, we move the virtual - //node box rightwards and count the number of potentially unbend edges - //to find the best starting unbend edge - num_unbend = 0; - best_unbend = -1; - //edge bestedge; - int bestvalue; - int stop = l_vert.size(); - //bugfix - if (l_vert.size() == 1) - { - best_unbend = 1; - //bestedge = l_vert.front(); - if (at_top[*(l_vert.begin())]) - bestvalue = alefte[outEntry(inf, odEast, 0)]; - else bestvalue = alefte[outEntry(inf, odWest, 0)]; - } - else - { - //ALGORITHM 1 - int topcount = 0, lowcount = 0; - ListIterator p = l_vert.begin(); //pointer on paper list L - for (i = 1; i < stop+1; i++) - { - while (p.valid()) - { - if (righte[(*p)] <= lefte[l_vertl.front()]+boxx+machineeps) //assert first edge is edge i? - //(p == vert_entry[l_vertl.front()])) - //p's entry needs no bend => increase num_unbend (edges) - { - num_unbend++; - ++p; - }//while unbend - else break; - } - if (num_unbend > best_unbend) - { - best_unbend = num_unbend; - //bestedge = l_vertl.front(); - bestvalue = (at_top[l_vertl.front()] ? alefte[outEntry(inf,odEast, topcount)] : alefte[outEntry(inf, odWest, lowcount)]); - }//if new best - if (at_top[l_vertl.front()]) topcount++; - else lowcount++; - - if (p == vert_entry[l_vertl.front()]) p++; //may be -- if valid - - OGDF_ASSERT(p != vert_entry[l_vertl.front()]) - - l_vert.del(vert_entry[l_vertl.front()]); - l_vertl.popFront(); - - if (num_unbend) num_unbend--; //the next index will bend current start edge - }//for, l_vert list entries - }//else bugfix - - //assign computed value - m_newx[v] = min( (inf.cage_coord(odSouth) - inf.node_xsize() - inf.rc(odSouth)), - (bestvalue)); - // (lefte[bestedge])); - inf.set_coord(odNorth, m_newx[v]); - inf.set_coord(odSouth, m_newx[v] + inf.node_xsize()); - //check: do we need this here !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - //- (at_left[bestedge] ? - // inf.eps(odNorth, odWest) : inf.eps(odSouth, odWest))));//maybe top / down epsilon - }//if vert - else - { - if (vertical_merger) - { - //position is fixed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 - //position is fixed //odNorth was odNorth - edge e; - //note that get starts indexing with zero, whereas gen_pos starts with one - if (inf.has_gen(odEast)) e = *(inf.inList(odEast).get(inf.gen_pos(odEast))); - else e = *(inf.inList(odWest).get(inf.gen_pos(odWest))); //check e !!!!!!!!!!!!! - int gen_x = m_layoutp->x( e->target()); - m_newx[v] = gen_x - int(inf.node_xsize()/2.0);//abziehen => aufrunden !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - inf.set_coord(odNorth, m_newx[v]); - inf.set_coord(odSouth, m_newx[v] + inf.node_xsize()); - }//if - else - { - if (horizontal_merger) - { - //find out direction of generalization - bool sg = inf.has_gen(odSouth); - bool ng = inf.has_gen(odNorth); - - int mynewx = 0; - if (sg) - { - if (ng) - { - if (inf.is_in_edge(odSouth, inf.gen_pos(odSouth))) //position to odNorth - { - mynewx = inf.cage_coord(odNorth) + inf.rc(odNorth); - } - else - { - mynewx = inf.cage_coord(odSouth) - inf.rc(odSouth) - inf.node_xsize(); - } - }//both - else - { - mynewx = inf.cage_coord(odSouth) - inf.rc(odSouth) - inf.node_xsize(); - }//only south - } - else - { - mynewx = inf.cage_coord(odNorth) + inf.rc(odNorth); - }//else no south - m_newx[v] = mynewx; - inf.set_coord(odNorth, mynewx); - inf.set_coord(odSouth, mynewx + inf.node_xsize()); - }//if horizontalmerger - //we place the node at the position cage_left_border(v)+routing_channel_left(v) - //should be handled by value assign - else - { - m_newx[v] = inf.cage_coord(odSouth) - inf.rc(odSouth) - inf.node_xsize(); - inf.set_coord(odNorth, m_newx[v]); - inf.set_coord(odSouth, m_newx[v] + inf.node_xsize()); - } - }//else merger - }//else vert - - if (m_mergerSon[v]) - { - if (vertical_merger) //change vertical position - { - //test incons. - OGDF_ASSERT(!horizontal_merger); - //we have to know the exact direction of the edge to the merger - OGDF_ASSERT( (m_mergeDir[v] == odNorth) || (m_mergeDir[v] == odSouth)); - if (m_mergeDir[v] == odNorth) - m_newy[v] = (inf.cage_coord(odEast) - inf.node_ysize() - inf.rc(odEast)); - else - m_newy[v] = (inf.cage_coord(odWest) + inf.rc(odWest)); - inf.set_coord(odWest, m_newy[v]); - inf.set_coord(odEast, m_newy[v] + inf.node_ysize()); - } - if (horizontal_merger) - { - //test inconsistency - OGDF_ASSERT(!vertical_merger); - //we have to know the exact direction of the edge to the merger - OGDF_ASSERT( (m_mergeDir[v] == odEast) || (m_mergeDir[v] == odWest)); - if (m_mergeDir[v] == odWest) - m_newx[v] = inf.cage_coord(odNorth) + inf.rc(odNorth); - else - m_newx[v] = inf.cage_coord(odSouth) - inf.rc(odSouth) - inf.node_xsize(); - inf.set_coord(odNorth, m_newx[v]); - inf.set_coord(odSouth, m_newx[v] + inf.node_xsize()); - } - }//if genmergeson - //ende test - - //now we have vertical as well as horizontal position and can assign both values - if (horizontal_merger) - compute_gen_glue_points_y(v); - else compute_glue_points_y(v); - if (vertical_merger) - compute_gen_glue_points_x(v); - else compute_glue_points_x(v); - set_corners(v); - //we computed the new placement position for original node box v and stored it in m_new as well as in inf (debug) - //assert some assigment - //{ - // if ( (m_prup->expandAdj(v) != 0) && (m_prup->typeOf(v) != Graph::generalizationMerger) ) - // { - // OGDF_ASSERT( (m_newx[v] >= inf.cage_coord(odNorth)) && (m_newy[v] >= inf.cage_coord(odWest)) ); - // OGDF_ASSERT( (m_newx[v] + inf.node_xsize()<= inf.cage_coord(odSouth)) && - // (m_newy[v] + inf.node_ysize()<= inf.cage_coord(odEast))); - // } - //} - - //now assign boolean values for reroutability: is edge to box distance large enough to allow rerouting - //{} is done in call function in classify_edges() - - //we computed the new placement position for original node box v - //and stored it in m_newxy as well as in inf (debug) -}//compute_place - - -//************************************************************************ -//REAL PLACEMENT Change graph based on placement/rerouting -void EdgeRouter::place(node l_v) -{ - //two steps: first, introduce the bends on the incoming edges, - // normalise, then adjust the layout information for the cage nodes and bend nodes - String m; - String msg; - OrthoRep::VertexInfoUML* vinfo = m_orp->cageInfo(l_v); - edge e; - bool inedge; - bool corn, acorn; //test on last and first corner transition after rerouting - //forall four sides check the edges - - //NORTH SIDE *************************************************** - //integrate offset for double bend edges without bendfree edges because of rerouting - int leftofs = (infos[l_v].num_bend_free(odNorth) ? 0 : - infos[l_v].delta(odNorth, odWest)*infos[l_v].flips(odWest, odNorth)); - int rightofs = (infos[l_v].num_bend_free(odNorth) ? 0 : - infos[l_v].delta(odNorth, odEast)*infos[l_v].flips(odEast, odNorth)); - - List& inlist = infos[l_v].inList(odNorth); //left side - ListIterator it = inlist.begin(); - int ipos = 0; - corn = false; //check if end corner changed after necessary rerouting - acorn = false; //check if start corner changed after necessary re - - while (it.valid()) - { - e = *it; - node v; - adjEntry ae; //"outgoing" from cage - inedge = infos[l_v].is_in_edge(odNorth, ipos); - if (inedge) - { - ae = e->adjTarget(); - } - else - { - ae = e->adjSource(); - } - v = m_cage_point[ae]; - - if (m_processStatus[v] == used) - { - it++;//should be enough to break - continue; - }//if degree1 preprocessing on opposite side - adjEntry cornersucc = ae->cyclicSucc(); - adjEntry saveadj = ae; - //correct possible shift by bends from other cage - if (!((inedge && (v == e->target())) - || ((v == e->source()) && !inedge) )) - { - edge run = e; - if (inedge) - { - adjEntry runadj = run->adjSource(); - while (v != runadj->theEdge()->target()) { - runadj = runadj->faceCycleSucc(); - } - e = runadj->theEdge(); - cornersucc = runadj->twin()->cyclicSucc(); - OGDF_ASSERT(v == cornersucc->theNode()); - saveadj = runadj->twin(); - } - OGDF_ASSERT(((v == e->target()) && (inedge)) ||(v == e->source())); - }//if buggy - //position - if ((m_agp_x[ae] != m_init) && (m_agp_y[ae] != m_init)) - set_position(v, m_agp_x[ae], m_agp_y[ae]); - OGDF_ASSERT((m_agp_y[ae] != m_init) && (m_agp_x[ae] != m_init)); - - //bends - if (abendType(ae) != bend_free) - { - edge newe; - node newbend, newglue; - int xtacy; - switch (abendType(ae)) - { - //case prob_b1l: - case bend_1left: //rerouted single bend - //delete old corner - if (ipos == 0) - { - OGDF_ASSERT(infos[l_v].flips(odNorth, odWest) > 0); - adjEntry ae2 = saveadj->cyclicPred();//ae->cyclicPred(); //aussen an cage - adjEntry ae3 = ae2->faceCycleSucc(); - //as long as unsplit does not work, transition - //node oldcorner; - if (ae2 == (ae2->theEdge()->adjSource())) - { - //oldcorner = ae2->theEdge()->target(); - unsplit(ae2->theEdge(), ae3->theEdge()); - } - else - { - unsplit(ae3->theEdge(), ae2->theEdge()); - //oldcorner = ae2->theEdge()->source(); - } - }//if pos==0 - //delete corner after last rerouting - if ((!acorn) && (ipos == infos[l_v].flips(odNorth, odWest) - 1)) - { - acorn = true; - edge newe2; - adjEntry ae2 = saveadj->cyclicSucc();//cornersucc;//ae->cyclicSucc();//next to the right in cage - edge savedge = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[0] = newe2->adjSource(); - } - else { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[0] = savedge->adjTarget(); - } - fix_position(newe2->source(), infos[l_v].coord(odNorth), infos[l_v].coord(odWest)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - - xtacy = infos[l_v].coord(odNorth) - + infos[l_v].delta(odWest, odNorth) - *(infos[l_v].flips(odNorth, odWest) - 1 - ipos) - + infos[l_v].eps(odWest, odNorth); - if (inedge) newe = addLeftBend(e); - else newe = addRightBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - fix_position(newglue, xtacy, infos[l_v].coord(odWest)); - fix_position(newbend, xtacy, cp_y(ae)); - break; - case prob_b1l: - case prob_b2l: - case bend_2left: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae], m_agp_y[ae]+leftofs); - xtacy = infos[l_v].cage_coord(odNorth) - + (infos[l_v].num_bend_edges(odNorth, odWest) -ipos)*m_sep; - newe = addLeftBend(e); - fix_position(newe->source(), xtacy, (inedge ? cp_y(ae) : (gp_y(ae)+leftofs))); - newe = addRightBend(newe); - fix_position(newe->source(), xtacy, (inedge ? (gp_y(ae)+leftofs) : cp_y(ae))); - break;//int bend downwards - case bend_1right: - if (!corn) - { - corn = true; - edge newe2; - adjEntry ae2 = saveadj->cyclicPred();//ae->cyclicPred(); - edge savedge = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[1] = savedge->adjTarget(); - } - else { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[1] = newe2->adjSource(); - } - fix_position(newe2->source(), infos[l_v].coord(odNorth), infos[l_v].coord(odEast)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - //delete corner after last rerouting - if (corn && (ipos == infos[l_v].inList(odNorth).size()-1)) - { - adjEntry ae2 = saveadj->cyclicSucc();//ae->cyclicSucc(); - adjEntry ae3 = ae2->faceCycleSucc(); - if (ae2 == (ae2->theEdge()->adjSource())) - unsplit(ae2->theEdge(), ae3->theEdge()); - else - unsplit(ae3->theEdge(), ae2->theEdge()); - }//if last - xtacy = infos[l_v].coord(odNorth) - + (ipos + infos[l_v].flips(odNorth, odEast) - infos[l_v].inList(odNorth).size()) - * infos[l_v].delta(odEast, odNorth) + infos[l_v].eps(odEast, odNorth); - if (inedge) newe = addRightBend(e); - else newe = addLeftBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - fix_position(newbend, xtacy, cp_y(ae)); - fix_position(newglue, xtacy, infos[l_v].coord(odEast)); - break;//rerouted single bend - case prob_b1r: - case prob_b2r: - case bend_2right: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae], m_agp_y[ae]-rightofs); - xtacy = infos[l_v].cage_coord(odNorth) - + (1 + ipos + infos[l_v].num_bend_edges(odNorth, odEast) - infos[l_v].inList(odNorth).size()) - * m_sep; - //* infos[l_v].delta(odNorth, odEast); - newe = addRightBend(e); - fix_position(newe->source(), xtacy, (inedge ? cp_y(ae) : (gp_y(ae)-rightofs))); - newe = addLeftBend(newe); - fix_position(newe->source(), xtacy, (inedge ? (gp_y(ae)-rightofs) : cp_y(ae))); - break; //double bend upwards - default: break; - }//switch - m_orp->normalize(); - }//if not bendfree - ipos++; - it++; - }//while - - //********************************************* - //EAST SIDE (bottom)************************************ - leftofs = (infos[l_v].num_bend_free(odEast) ? 0 : - infos[l_v].delta(odEast, odNorth)*infos[l_v].flips(odNorth, odEast)); - //temp - //leftofs = infos[l_v].delta(odEast, odNorth)*infos[l_v].flips(odNorth, odEast); - //temp end - rightofs = (infos[l_v].num_bend_free(odEast) ? 0 : - infos[l_v].delta(odEast, odSouth)*infos[l_v].flips(odSouth, odEast)); - //temp - //rightofs = infos[l_v].delta(odEast, odSouth)*infos[l_v].flips(odSouth, odEast); - //tempend - - it = infos[l_v].inList(odEast).begin(); - ipos = 0; - corn = false; //check if end corner changed after necessary rerouting - acorn = false; //check if start corner changed after necessary re - while (it.valid()) - { - e = *it; - node v; - adjEntry ae; //"outgoing" from cage - inedge = infos[l_v].is_in_edge(odEast, ipos); - if (inedge) - { - ae = e->adjTarget(); - } - else - { - ae = e->adjSource(); - } - v = m_cage_point[ae]; - if (m_processStatus[v] == used) - { - it++;//should be enough to break - continue; - }//if degree1 preprocessing on opposite side - adjEntry cornersucc = ae->cyclicSucc(); - adjEntry adjsave = ae; - //correct possible shift by bends from other cage - if (!((inedge && (v == e->target())) - || ((v == e->source()) && !inedge) )) - { - edge run = e; - if (inedge) - { - adjEntry runadj = run->adjSource(); - while (v != runadj->theEdge()->target()) {runadj = runadj->faceCycleSucc(); } - e = runadj->theEdge(); - cornersucc = runadj->twin()->cyclicSucc(); - OGDF_ASSERT(v == cornersucc->theNode()); - adjsave = runadj->twin(); - } - OGDF_ASSERT((v == e->target()) ||(v == e->source())); - }//if buggy - OGDF_ASSERT((v == e->target()) ||(v == e->source())); - //position - if ((m_agp_x[ae] != m_init) && (m_agp_y[ae] != m_init)) set_position(v, m_agp_x[ae], m_agp_y[ae]); - OGDF_ASSERT((m_agp_y[ae] != m_init) && (m_agp_x[ae] != m_init)) - //bends - if (abendType(ae) != bend_free) - { - switch (abendType(ae)) - { - edge newe; - node newbend, newglue; - int ypsiqueen; - //case prob_b1l: - case bend_1left: - //set new corner before first rerouting - //delete corner before starting - if (ipos == 0) - { - adjEntry ae2 = adjsave->cyclicPred(); //ae->cyclicPred(); //aussen an cage - adjEntry ae3 = ae2->faceCycleSucc(); - - if (ae2 == (ae2->theEdge()->adjSource())) - unsplit(ae2->theEdge(), ae3->theEdge()); - else - unsplit(ae3->theEdge(), ae2->theEdge()); - } - if ((!acorn) && (ipos == infos[l_v].flips(odEast, odNorth) - 1)) - { - - acorn = true; - edge newe2; - adjEntry ae2 = adjsave->cyclicSucc();//next to the right in cage - edge savedge = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[1] = newe2->adjSource(); - } - else { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[1] = savedge->adjTarget(); - } - fix_position(newe2->source(), infos[l_v].coord(odNorth), infos[l_v].coord(odEast)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - if (inedge) newe = addLeftBend(e); //abhaengig von inedge, ?? - else newe = addRightBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - ypsiqueen = infos[l_v].coord(odEast) - (infos[l_v].flips(odEast, odNorth) - ipos - 1) - * infos[l_v].delta(odNorth, odEast) - infos[l_v].eps(odNorth, odEast); - fix_position(newbend, cp_x(ae), ypsiqueen); - fix_position(newglue, infos[l_v].coord(odNorth), ypsiqueen); - //target oder source von newe coord - break; //rerouted single bend - case prob_b1l: - case prob_b2l: - case bend_2left: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae]+leftofs, m_agp_y[ae]); - ypsiqueen = infos[l_v].cage_coord(odEast) - - (infos[l_v].num_bend_edges(odEast, odNorth) - ipos)*m_sep; - newe = addLeftBend(e); - fix_position(newe->source(),(inedge ? cp_x(ae) : m_agp_x[ae]+leftofs) ,ypsiqueen); - newe = addRightBend(newe); - fix_position(newe->source(),(inedge ? m_agp_x[ae] + leftofs : cp_x(ae)) ,ypsiqueen); - break;//double bend downwards - //case prob_b1r: - case bend_1right: - //set new corner before first rerouting - if (!corn) - { - corn = true; - edge newe2; - adjEntry ae2 = adjsave->cyclicPred(); - edge le = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[2] = le->adjTarget(); - } - else { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[2] = newe2->adjSource(); - } - fix_position(newe2->source(),infos[l_v].coord(odSouth), infos[l_v].coord(odEast)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - ypsiqueen = infos[l_v].coord(odEast) - (ipos + infos[l_v].flips(odEast, odSouth) - infos[l_v].inList(odEast).size()) - * infos[l_v].delta(odSouth, odEast) - infos[l_v].eps(odSouth, odEast); - //delete corner after last rerouting - if (corn && (ipos == infos[l_v].inList(odEast).size() - 1)) - { - adjEntry ae2 = adjsave->cyclicSucc();//ae->cyclicSucc(); - adjEntry ae3 = ae2->faceCycleSucc(); - //as long as unsplit does not work, transition - //node oldcorner; - if (ae2 == (ae2->theEdge()->adjSource())) - { - //oldcorner = ae2->theEdge()->target(); - unsplit(ae2->theEdge(), ae3->theEdge()); - } - else - { - unsplit(ae3->theEdge(), ae2->theEdge()); - //oldcorner = ae2->theEdge()->source(); - } - } - if (inedge) newe = addRightBend(e); - else newe = addLeftBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - - fix_position(newbend, cp_x(ae), ypsiqueen); - fix_position(newglue, infos[l_v].coord(odSouth), ypsiqueen); - break;//rerouted single bend - case prob_b1r: - case prob_b2r: - case bend_2right: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae]-rightofs, m_agp_y[ae]); - ypsiqueen = infos[l_v].cage_coord(odEast) - - (ipos - infos[l_v].inList(odEast).size() + infos[l_v].num_bend_edges(odEast, odSouth))*m_sep; - //(infos[l_v].inList(odEast).size() + infos[l_v].flips(odEast, odSouth) - ipos)*m_sep; - newe = addRightBend(e); - fix_position(newe->source(), (inedge ? cp_x(ae) : m_agp_x[ae]-rightofs), ypsiqueen); - newe = addLeftBend(newe); - fix_position(newe->source(), (inedge ? m_agp_x[ae]-rightofs : cp_x(ae)), ypsiqueen); - break; //double bend upwards - default: break; - }//switch - m_orp->normalize(); - }//if - ipos++; - it++; - }//while - - //***************************************************** - //SOUTH SIDE******************************************* - leftofs = (infos[l_v].num_bend_free(odSouth) ? 0 : - infos[l_v].delta(odSouth, odEast)*infos[l_v].flips(odEast, odSouth)); - rightofs = (infos[l_v].num_bend_free(odSouth) ? 0 : - infos[l_v].delta(odSouth, odWest)*infos[l_v].flips(odWest, odSouth)); - it = infos[l_v].inList(odSouth).begin(); - ipos = 0; - corn = false; //check if end corner changed after necessary rerouting - acorn = false; //check if start corner changed after necessary re - while (it.valid() && (infos[l_v].inList(odSouth).size() > 0)) - { - e = *it; - node v;//test - adjEntry ae; //"outgoing" from cage - inedge = infos[l_v].is_in_edge(odSouth, ipos); - if (inedge) - { - ae = e->adjTarget(); - } - else - { - ae = e->adjSource(); - } - v = m_cage_point[ae]; - if (m_processStatus[v] == used) - { - it++;//should be enough to break - continue; - }//if degree1 preprocessing on opposite side - adjEntry cornersucc = ae->cyclicSucc(); - adjEntry saveadj = ae; - //correct possible shift by bends from other cage - if (!((inedge && (v == e->target())) - || ((v == e->source()) && !inedge) )) - { - edge run = e; - if (inedge) - { - adjEntry runadj = run->adjSource(); - while (v != runadj->theEdge()->target()) {runadj = runadj->faceCycleSucc();} - e = runadj->theEdge(); - cornersucc = runadj->twin()->cyclicSucc(); - OGDF_ASSERT(v == cornersucc->theNode()); - saveadj = runadj->twin(); - } - OGDF_ASSERT((v == e->target()) ||(v == e->source())); - }//if buggy - //position - if ((m_agp_x[ae] != m_init) && (m_agp_y[ae] != m_init)) set_position(v, m_agp_x[ae], m_agp_y[ae]); - OGDF_ASSERT((m_agp_x[ae] != m_init) && (m_agp_y[ae] != m_init)) - //bends - if (abendType(ae) != bend_free) - { - edge newe; - node newbend, newglue; - int xtacy; - switch (abendType(ae)) - { - case bend_1left: - if ((!corn)) - { - corn = true; - edge newe2; - adjEntry ae2 = saveadj->cyclicSucc();//next to the right in cage - edge savedge = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[2] = newe2->adjSource(); - } - else { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[2] = savedge->adjTarget(); - } - fix_position(newe2->source(), infos[l_v].coord(odSouth), infos[l_v].coord(odEast)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - //delete corner after last rerouting - if (ipos == infos[l_v].inList(odSouth).size()-1) - { - adjEntry ae2 = saveadj->cyclicPred();//ae->cyclicPred(); - adjEntry ae3 = ae2->faceCycleSucc(); - if (ae2 == (ae2->theEdge()->adjSource())) - unsplit(ae2->theEdge(), ae3->theEdge()); - else - unsplit(ae3->theEdge(), ae2->theEdge()); - }//if last - xtacy = infos[l_v].coord(odSouth) - - infos[l_v].delta(odEast, odSouth) - *(infos[l_v].flips(odSouth, odEast) + ipos - infos[l_v].inList(odSouth).size()) - -infos[l_v].eps(odEast, odSouth); - if (inedge) newe = addLeftBend(e); - else newe = addRightBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - fix_position(newglue, xtacy, infos[l_v].coord(odEast)); - fix_position(newbend, xtacy, cp_y(ae)); - break; //rerouted single bend - case prob_b1l: - case prob_b2l: - case bend_2left: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae], m_agp_y[ae]-leftofs); - xtacy = infos[l_v].cage_coord(odSouth) - - (ipos + 1 + infos[l_v].num_bend_edges(odSouth, odEast) - - infos[l_v].inList(odSouth).size())*m_sep; - newe = addLeftBend(e); - - //gy = gp_y(ae) - infos[l_v].flips(odEast, odSouth)*infos[l_v].delta(odSouth, odEast); - //if (inedge) fix_position(e->target(), m_agp_x[ae], gy); - //else fix_position(e->source(), m_agp_x[ae], gy); - fix_position(newe->source(), xtacy, (inedge ? cp_y(ae) : gp_y(ae)-leftofs)); - newe = addRightBend(newe); - fix_position(newe->source(), xtacy, (inedge ? gp_y(ae)-leftofs : cp_y(ae))); - break;//double bend downwards - //case prob_b1r: - case bend_1right: - //delete corner before rerouting - if (ipos == 0) - { - adjEntry ae2 = saveadj->cyclicSucc();//cornersucc; - adjEntry ae3 = ae2->faceCycleSucc(); - - //node oldcorner; - if (ae2 == (ae2->theEdge()->adjSource())) - { - //oldcorner = ae2->theEdge()->target(); - unsplit(ae2->theEdge(), ae3->theEdge()); - } - else - { - unsplit(ae3->theEdge(), ae2->theEdge()); - //oldcorner = ae2->theEdge()->source(); - } - }//if - //last flipped edge, insert sw - corner node - if ((!acorn) && (ipos == infos[l_v].flips(odSouth, odWest) - 1)) - { - acorn = true; - edge newe2; - adjEntry ae2 = saveadj->cyclicPred(); - edge le = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[3] = le->adjTarget(); - } - else { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[3] = newe2->adjSource(); - } - fix_position(newe2->source(), infos[l_v].coord(odSouth), infos[l_v].coord(odWest)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - - if (inedge) newe = addRightBend(e); - else newe = addLeftBend(e); - newbend = newe->source(); - //source ist immer neuer Knick, aber target haengt von der Richtung ab... - if (inedge) newglue = newe->target(); - else newglue = e->source(); - xtacy = infos[l_v].coord(odSouth) - (infos[l_v].flips(odSouth, odWest) - ipos - 1) - * infos[l_v].delta(odWest, odSouth) - infos[l_v].eps(odWest, odSouth); - fix_position(newbend, xtacy, cp_y(ae)); - fix_position(newglue, xtacy, infos[l_v].coord(odWest)); - break;//rerouted single bend - case prob_b1r: - case prob_b2r: - case bend_2right: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae], m_agp_y[ae]+rightofs); - xtacy = infos[l_v].cage_coord(odSouth) - - (infos[l_v].num_bend_edges(odSouth, odWest) - ipos) * m_sep; - newe = addRightBend(e); - fix_position(newe->source(), xtacy,(inedge ? cp_y(ae) : m_agp_y[ae]+rightofs )); - newe = addLeftBend(newe); - fix_position(newe->source(), xtacy, (inedge ? m_agp_y[ae]+rightofs : cp_y(ae))); - break; //double bend downwards - default: break; - }//switch - m_orp->normalize(); - }//if - ipos++; - it++; - }//while - - //***************************************************** - //WEST SIDE****************************************** - leftofs = (infos[l_v].num_bend_free(odWest) ? 0 : - infos[l_v].delta(odWest, odSouth)*infos[l_v].flips(odSouth, odWest)); - rightofs = (infos[l_v].num_bend_free(odWest) ? 0 : - infos[l_v].delta(odWest, odNorth)*infos[l_v].flips(odNorth, odWest)); - it = infos[l_v].inList(odWest).begin(); - ipos = 0; - corn = acorn = false; - while (it.valid()) - { - e = *it; - node v; - adjEntry ae; //"outgoing" from cage - inedge = infos[l_v].is_in_edge(odWest, ipos); - if (inedge) - { - ae = e->adjTarget(); - } - else - { - ae = e->adjSource(); - } - v = m_cage_point[ae]; - if (m_processStatus[v] == used) - { - it++;//should be enough to break - continue; - }//if degree1 preprocessing on opposite side - //position - adjEntry cornersucc = ae->cyclicSucc(); - adjEntry saveadj = ae; - //correct possible shift by bends from other cage - if (!((inedge && (v == e->target())) - || ((v == e->source()) && !inedge) )) - { - edge run = e; - if (inedge) - { - adjEntry runadj = run->adjSource(); - while (v != runadj->theEdge()->target()) {runadj = runadj->faceCycleSucc(); } - e = runadj->theEdge(); - cornersucc = runadj->twin()->cyclicSucc(); - OGDF_ASSERT(v == cornersucc->theNode()); - saveadj = runadj->twin(); - } - OGDF_ASSERT((v == e->target()) ||(v == e->source())); - }//if buggy - //position - if ((m_agp_x[ae] != m_init) && (m_agp_y[ae] != m_init)) set_position(v, m_agp_x[ae], m_agp_y[ae]); - OGDF_ASSERT((m_agp_x[ae] != m_init) && (m_agp_y[ae] != m_init)); - //bends - if (abendType(ae) != bend_free) - { - edge newe; - node newbend, newglue; - int ypsiqueen; - switch (abendType(ae)) - { - case bend_1left: - //node right side - //set new corner before first rerouting - if (!acorn) - { - acorn = true; - edge newe2; - adjEntry ae2 = saveadj->cyclicSucc(); // cornersucc;//next to the right in cage - edge savedge = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[3] = newe2->adjSource(); - } - else { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[3] = savedge->adjTarget(); - } - fix_position(newe2->source(), infos[l_v].coord(odSouth), infos[l_v].coord(odWest)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - //delete corner after last rerouting - if (acorn && (ipos == infos[l_v].inList(odWest).size()-1)) - { - adjEntry ae2 = saveadj->cyclicPred(); //ae->cyclicPred(); //aussen an cage - adjEntry ae3 = ae2->faceCycleSucc(); - if (ae2 == (ae2->theEdge()->adjSource())) - unsplit(ae2->theEdge(), ae3->theEdge()); - else - unsplit(ae3->theEdge(), ae2->theEdge()); - }//if - // - if (inedge) newe = addLeftBend(e); - else newe = addRightBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - ypsiqueen = infos[l_v].coord(odWest) - + (infos[l_v].flips(odWest, odSouth) + ipos - infos[l_v].inList(odWest).size()) - *infos[l_v].delta(odSouth, odWest) - +infos[l_v].eps(odSouth, odWest); - fix_position(newbend, cp_x(ae), ypsiqueen); - fix_position(newglue, infos[l_v].coord(odSouth), ypsiqueen); - break; //rerouted single bend - case prob_b1l: - case prob_b2l: - case bend_2left: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae]-leftofs, m_agp_y[ae]); - ypsiqueen = infos[l_v].cage_coord(odWest) - + (ipos + 1 + infos[l_v].num_bend_edges(odWest, odSouth) - - infos[l_v].inList(odWest).size())*m_sep; - //coord - (-infos[l_v].flips(odWest, odSouth) - ipos + infos[l_v].inList(odWest).size())*m_sep; - newe = addLeftBend(e); - fix_position(newe->source(), (inedge ? cp_x(ae) : m_agp_x[ae]-leftofs), ypsiqueen); - newe = addRightBend(newe); - fix_position(newe->source(), (inedge ? m_agp_x[ae]-leftofs : cp_x(ae)), ypsiqueen); - break;//double bend downwards - //case prob_b1r: - case bend_1right: - //set new corner before first rerouting - - //delete corner after last rerouting - if (ipos == 0)//(corn && (ipos == infos[l_v].inList(odWest).size()-1)) - { - adjEntry ae2 = saveadj->cyclicSucc(); //cornersucc;//ae->cyclicSucc(); - adjEntry ae3 = ae2->faceCycleSucc(); - //as long as unsplit does not work, transition - //node oldcorner; - if (ae2 == (ae2->theEdge()->adjSource())) - { - //oldcorner = ae2->theEdge()->target(); - unsplit(ae2->theEdge(), ae3->theEdge()); - } - else { - unsplit(ae3->theEdge(), ae2->theEdge()); - //oldcorner = ae2->theEdge()->source(); - } - } - if ((!corn) && (ipos == infos[l_v].flips(odWest, odNorth) - 1)) - { - corn = true; - edge newe2; - adjEntry ae2 = saveadj->cyclicPred();//ae->cyclicPred(); - edge savedge = ae2->theEdge(); - if (ae2 == (ae2->theEdge()->adjSource())) - { - newe2 = addLeftBend(ae2->theEdge()); - vinfo->m_corner[0] = savedge->adjTarget(); - } - else { - newe2 = addRightBend(ae2->theEdge()); - vinfo->m_corner[0] = newe2->adjSource(); - } - fix_position(newe2->source(), infos[l_v].coord(odNorth), infos[l_v].coord(odWest)); - m_prup->setExpandedNode(newe2->source(), l_v); - } - if (inedge) newe = addRightBend(e); - else newe = addLeftBend(e); - newbend = newe->source(); - - if (inedge) newglue = newe->target(); - else newglue = e->source(); - ypsiqueen = infos[l_v].coord(odWest) + (infos[l_v].flips(odWest, odNorth) - ipos - 1) - * infos[l_v].delta(odNorth, odWest) + infos[l_v].eps(odNorth, odWest); - fix_position(newbend, cp_x(ae), ypsiqueen); - fix_position(newglue, infos[l_v].coord(odNorth), ypsiqueen); - break;//rerouted single bend - case prob_b1r: - case prob_b2r: - case bend_2right: - //adjust glue point to rerouted edges - fix_position(v, m_agp_x[ae]+rightofs, m_agp_y[ae]); - ypsiqueen = infos[l_v].cage_coord(odWest) - + (infos[l_v].num_bend_edges(odWest, odNorth) - ipos)*m_sep; - //infos[l_v].coord(odWest) - ((ipos + 1) - infos[l_v].flips(odNorth, odWest)) * m_sep; - newe = addRightBend(e); - fix_position(newe->source(), (inedge ? cp_x(ae) : m_agp_x[ae]+rightofs), ypsiqueen); - newe = addLeftBend(newe); - - fix_position(newe->source(), (inedge ? m_agp_x[ae]+rightofs : cp_x(ae)), ypsiqueen); - break; //double bend upwards - default: break; - }//switch - m_orp->normalize(); - }//if - - ipos++; - it++; - - }//while - - //m_prup->writeGML(String("placeInput%d.gml",l_v->index()), *m_orp, *m_layoutp); - //OGDF_ASSERT(m_orp->check(msg)); - //*********************************** -}//place - - -//given a replacement cage (defining routing channels??) -//and a box placement, compute a bend-minimising routing -//box placement is in m_newx[v], m_newy[v] for left lower corner -//now it is in NodeInfo, m_new may be obs -//check rounding !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -void EdgeRouter::compute_routing(node v) //reroute(face f) -{ - //compute for each box corner the possible reroutings - - //first, define some values - //find the uppermost/lowest unbend edge on the left and right side - //and the rightmost/leftmost unbend edge on the top and bottom side - //use values stored in inf - //****************************************************************** - //alpha used in move - functions, variable al_12 means: - //max. number of edges to be moved from side 2 to side 1 - //eight cases, two for ev corner - //1space left for edges moved from top to left side - int al_lt = alpha_move(odNorth, odEast, v); - //2space left for edges moved from left to top side - int al_tl = alpha_move(odEast, odNorth, v); - //3space left for edges moved from left to bottom side - //int al_bl = alpha_move(odWest, odNorth, v); - //4Space left for edges moved from bottom side to left side - //int al_lb = alpha_move(odNorth, odWest, v); - //5space left for edges moved from right to top side - //int al_tr = alpha_move(odEast, odSouth, v); - //6space left for edges moved from top to right side - int al_rt = alpha_move(odSouth, odEast, v); - //7space left for edges moved from right to bottom side - int al_br = alpha_move(odWest, odSouth, v); - //8space left for edges moved from bottom to right side - //int al_rb = alpha_move(odSouth, odWest, v); - - //******************************************************************* - - //******************************************************************* - //beta used in move functions - //be_12k defines the number of edges with preliminary bends - //but connection point in the glue point area, so that - //they could be routed bendfree if k (enough) edges are moved from - //side 1 to side 2 - //k is computed as the minimum of al_21 and card(E^12) (rerouteable edges) - //beta is only used internally to compute bend save - //save_12 holds the number of saved bends by moving edges from 1 to 2 - - //flip_12 contains the number of edges flipped from - //side 1 to 2 and flip_21 ~ - //from side 2 to 1 (only one case is possible) - - //algorithm 3 in the paper - - //This means that for two sides with equal value, our algorithm always - //prefers one (the same) above the other - - //top-left - int flip_tl, flip_lt; - if (compute_move(odEast, odNorth, flip_tl, v) < compute_move(odNorth, odEast, flip_lt, v)) - flip_tl = 0; - else flip_lt = 0; - //left-bottom - int flip_lb, flip_bl; - if (compute_move(odNorth, odWest, flip_lb, v) < compute_move(odWest, odNorth, flip_bl, v)) - flip_lb = 0; - else flip_bl = 0; - //top-right - int flip_tr, flip_rt; - if (compute_move(odEast, odSouth, flip_tr, v) < compute_move(odSouth, odEast, flip_rt, v)) - flip_tr = 0; - else flip_rt = 0; - //bottom-right - int flip_br, flip_rb; - if (compute_move(odWest, odSouth, flip_br, v) < compute_move(odSouth, odWest, flip_rb, v)) - flip_br = 0; - else flip_rb = 0; - //cout<<"resulting flip numbers: "< 0) - { - flip_lt -= int(floor(surplus/2.0)); - flip_rt -= int(ceil(surplus/2.0)); - }//if surplus - }//if - if (infos[v].num_bend_free(odWest) == 0)//bottom - { - surplus = flip_rb + flip_lb - al_br; - if (surplus > 0) - { - flip_lb -= int(floor(surplus/2.0)); - flip_rb -= int(ceil(surplus/2.0)); - } - }//if - if (infos[v].num_bend_free(odSouth) == 0) - { - surplus = flip_br + flip_tr - al_rt; - if (surplus > 0) - { - flip_br -= int(floor(surplus/2.0)); - flip_tr -= int(ceil(surplus/2.0)); - } - - }//if - if (infos[v].num_bend_free(odNorth) == 0) - { - surplus = flip_tl + flip_bl - al_lt; - if (surplus > 0) - { - flip_tl -= int(floor(surplus/2.0)); - flip_bl -= int(ceil(surplus/2.0)); - } - }//if - - } - //cout<<"resulting flip numbers: "< l_it; - - OrthoDir od = odNorth; -/*TO BE REMOVED IF OBSOLETE - do - { - l_it = infos[v].inList(od).begin(); - while (l_it.valid()) - { - l_it++; //TODO: what happens here?07.2004 - } - od =OrthoRep::nextDir(od); - } while (od != odNorth); -*/ - //start flipping - l_it = infos[v].inList(odNorth).rbegin(); - for (flipedges = 0; flipedges < flip_lt; flipedges++) - { - m_abends[outEntry(infos[v], odNorth, infos[v].inList(odNorth).size() - 1 - flipedges)] = bend_1right; - infos[v].flips(odNorth, odEast)++; - l_it--; - } - //********************************* - int newbendfree; - int newbf; - if (flip_lt) //we flipped and may save bends, if may be not necessary cause fliplt parameter in betamove - { - newbendfree = beta_move(odNorth, odEast, flip_lt, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odNorth, infos[v].inList(odNorth).size() - 1 - flip_lt - newbf)] = bend_free; - m_agp_y[outEntry(infos[v], odNorth, infos[v].inList(odNorth).size() - 1 - flip_lt - newbf)] = - cp_y(outEntry(infos[v], odNorth, infos[v].inList(odNorth).size() - 1 - flip_lt - newbf)); - }//for - }//if - //********************************* - l_it = infos[v].inList(odNorth).begin(); - for (flipedges = 0; flipedges < flip_lb; flipedges++) - { - infos[v].flips(odNorth, odWest)++; - m_abends[outEntry(infos[v], odNorth, flipedges)] = bend_1left; - l_it++; - } - //********************************** - newbendfree = beta_move(odNorth, odWest, flip_lb, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odNorth, flip_lb + newbf)] = bend_free; - m_agp_y[outEntry(infos[v], odNorth, flip_lb + newbf)] = - cp_y(outEntry(infos[v], odNorth, flip_lb + newbf)); - }//for - //********************************** - l_it = infos[v].inList(odSouth).rbegin(); - for (flipedges = 0; flipedges < flip_rt; flipedges++) - { - infos[v].flips(odSouth, odEast)++; - m_abends[outEntry(infos[v], odSouth, infos[v].inList(odSouth).size() - 1 - flipedges)] = bend_1left; - l_it--; - } - //*********************************** - newbendfree = beta_move(odSouth, odEast, flip_rt, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odSouth, infos[v].inList(odSouth).size() - 1 - flip_rt - newbf)] = bend_free; - m_agp_y[outEntry(infos[v], odSouth, infos[v].inList(odSouth).size() - 1 - flip_rt - newbf)] = - cp_y(outEntry(infos[v], odSouth, infos[v].inList(odSouth).size() - 1 - flip_rt - newbf)); - }//for - //*********************************** - l_it = infos[v].inList(odSouth).begin(); - for (flipedges = 0; flipedges < flip_rb; flipedges++) - { - m_abends[outEntry(infos[v], odSouth, flipedges)] = bend_1right; - infos[v].flips(odSouth, odWest)++; - l_it++; - } - //********************************** - newbendfree = beta_move(odSouth, odWest, flip_rb, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odSouth, flip_rb + newbf)] = bend_free; - m_agp_y[outEntry(infos[v], odSouth, flip_rb + newbf)] = - cp_y(outEntry(infos[v], odSouth, flip_rb + newbf)); - }//for - //********************************** - //only one of the quadruples will we executed - l_it = infos[v].inList(odEast).begin(); - for (flipedges = 0; flipedges < flip_tl; flipedges++) - { - m_abends[outEntry(infos[v], odEast, flipedges)] = bend_1left; - infos[v].flips(odEast, odNorth)++; - l_it++; - } - //********************************** - newbendfree = beta_move(odEast, odNorth, flip_tl, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odEast, flip_tl + newbf)] = bend_free; - m_agp_x[outEntry(infos[v], odEast, flip_tl + newbf)] = - cp_x(outEntry(infos[v], odEast, flip_tl + newbf)); - }//for - //********************************** - l_it = infos[v].inList(odWest).begin(); - for (flipedges = 0; flipedges < flip_bl; flipedges++) - { - m_abends[outEntry(infos[v], odWest, flipedges)] = bend_1right; - infos[v].flips(odWest, odNorth)++; - l_it++; - } - //********************************** - newbendfree = beta_move(odWest, odNorth, flip_bl, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odWest, flip_bl + newbf)] = bend_free; - m_agp_x[outEntry(infos[v], odWest, flip_bl + newbf)] = - cp_x(outEntry(infos[v], odWest, flip_bl + newbf)); - }//for - //********************************** - l_it = infos[v].inList(odEast).rbegin(); - for (flipedges = 0; flipedges < flip_tr; flipedges++) - { - if (l_it.valid()) //temporary check - { - m_abends[outEntry(infos[v], odEast, infos[v].inList(odEast).size() - 1 - flipedges)] = bend_1right; - infos[v].flips(odEast, odSouth)++; - l_it--; - } - } - //*************************************************** - newbendfree = beta_move(odEast, odSouth, flip_tr, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odEast, infos[v].inList(odEast).size() - 1 - flip_tr - newbf)] = bend_free; - m_agp_x[outEntry(infos[v], odEast, infos[v].inList(odEast).size() - 1 - flip_tr - newbf)] = - cp_x(outEntry(infos[v], odEast, infos[v].inList(odEast).size() - 1 - flip_tr - newbf)); - }//for - //*************************************************** - l_it = infos[v].inList(odWest).rbegin(); - for (flipedges = 0; flipedges < flip_br; flipedges++) - { - m_abends[outEntry(infos[v], odWest, infos[v].inList(odWest).size() - 1 - flipedges)] = bend_1left; - infos[v].flips(odWest, odSouth)++; - l_it--; - } - //*************************************************** - newbendfree = beta_move(odWest, odSouth, flip_br, v); - for (newbf = 0; newbf < newbendfree; newbf++) - { - m_abends[outEntry(infos[v], odWest, infos[v].inList(odWest).size() - 1 - flip_br - newbf)] = bend_free; - m_agp_x[outEntry(infos[v], odWest, infos[v].inList(odWest).size() - 1 - flip_br - newbf)] = - cp_x(outEntry(infos[v], odWest, infos[v].inList(odWest).size() - 1 - flip_br - newbf)); - }//for - //*************************************************** - //rest loeschen ????? - od = odNorth; - do - { - l_it = infos[v].inList(od).begin(); - while (l_it.valid()) - { - l_it++; - } - od =OrthoRep::nextDir(od); - } while (od != odNorth); - -}//reroute - - -void EdgeRouter::initialize_node_info(node v, int sep) -{ - //derive simple data - const OrthoRep::VertexInfoUML* vinfo = m_orp->cageInfo(v); - //inf.get_data(*m_prup, *m_orp, v); - //zuerst die kantenlisten und generalizations finden und pos festlegen - {//construct the edge lists for the incoming edges on ev side - //struct VertexInfoUML { - // side information (odNorth, odEast, odSouth, odWest corresponds to left, top, right, bottom) - //SideInfoUML m_side[4]; - // m_corner[dir] is adjacency entry in direction dir starting at - // a corner - //adjEntry m_corner[4]; - infos[v].firstAdj() = 0; - - adjEntry adj = m_prup->expandAdj(v); - - if (adj != 0) - { - //preliminary: reset PlanRep expandedNode values if necessary - adjEntry adjRun = adj; - - do - { - if (!m_prup->expandedNode(adjRun->theNode())) - m_prup->setExpandedNode(adjRun->theNode(), v); - adjRun = adjRun->faceCycleSucc(); - } while (adjRun != adj); - - OGDF_ASSERT(m_prup->typeOf(v) != Graph::generalizationMerger); - OrthoDir od = odNorth; //start with edges to the left - do { - adjEntry sadj = vinfo->m_corner[od]; - adjEntry adjSucc = sadj->faceCycleSucc(); - - List& inedges = infos[v].inList(od); - List& inpoint = infos[v].inPoint(od); - - //parse the side and insert incoming edges - while (m_orp->direction(sadj) == m_orp->direction(adjSucc)) //edges may never be attached at corners - { - adjEntry in_edge_adj = adjSucc->cyclicPred(); - edge in_edge = in_edge_adj->theEdge(); - //clockwise cyclic search ERROR: in/out edges: I always use target later for cage nodes!! - bool is_in = (in_edge->adjTarget() == in_edge_adj); - if (infos[v].firstAdj() == 0) infos[v].firstAdj() = in_edge_adj; - - OGDF_ASSERT(m_orp->direction(in_edge_adj) == OrthoRep::nextDir(od) || - m_orp->direction(in_edge_adj) == OrthoRep::prevDir(od)); - if ((od == odNorth) || (od == odEast)) //if left or top - { - inedges.pushBack(in_edge); - inpoint.pushBack(is_in); - } - else - { - inedges.pushFront(in_edge); - inpoint.pushFront(is_in); - } - //setting connection point coordinates - if (is_in) - { - m_acp_x[in_edge_adj] = m_layoutp->x(in_edge->target()); - m_acp_y[in_edge_adj] = m_layoutp->y(in_edge->target()); - m_cage_point[in_edge_adj] = in_edge->target(); - //align test - if (m_prup->typeOf(in_edge->source()) == Graph::generalizationExpander) - { - if (m_align) m_mergerSon[v] = true; - m_mergeDir[v] = OrthoRep::oppDir(m_orp->direction(in_edge->adjSource())); - }//if align - } - else - { - m_acp_x[in_edge_adj] = m_layoutp->x(in_edge->source()); - m_acp_y[in_edge_adj] = m_layoutp->y(in_edge->source()); - m_cage_point[in_edge_adj] = in_edge->source(); - //align test - if (m_prup->typeOf(in_edge->target()) == Graph::generalizationExpander) - { - if (m_align) m_mergerSon[v] = true; - m_mergeDir[v] = m_orp->direction(in_edge->adjSource()); - }//if align - } - sadj = adjSucc; - adjSucc = sadj->faceCycleSucc(); - - }//while - od = OrthoRep::nextDir(od); - } while (od != odNorth); - - infos[v].get_data(*m_orp, *m_layoutp, v, *m_rc, *m_nodewidth, *m_nodeheight); - }//if no adj, this should never happen - }//construct edge lists - - //derive the maximum separation between edges on the node sides - //left side - int dval, dsep; - - if (infos[v].has_gen(odNorth)) - { - int le = vinfo->m_side[0].m_nAttached[0]; //to bottom side - int re = vinfo->m_side[0].m_nAttached[1]; //to top - dsep = ( (le+Cconst == 0) ? sep : int(floor(infos[v].node_ysize() / (2*(le+Cconst)))) ); - dval = min(dsep,sep); - OGDF_ASSERT( dval > 0); - infos[v].set_delta(OrthoDir(0),OrthoDir(3),dval); infos[v].set_eps(OrthoDir(0),OrthoDir(3),int(floor(Cconst*dval))); - //top side - dsep = ( (re+Cconst == 0) ? sep : int(floor(infos[v].node_ysize() / (2*(re+Cconst)))) ); - dval = min(dsep, sep); - OGDF_ASSERT( dval > 0); - infos[v].set_delta(OrthoDir(0),OrthoDir(1),dval); infos[v].set_eps(OrthoDir(0),OrthoDir(1),int(floor(Cconst*dval))); - }//if left - else - { - int ae = vinfo->m_side[0].m_nAttached[0]; - if (ae > 0) - dsep = ( (ae+Cconst == 1) ? sep : int(floor(infos[v].node_ysize() / (ae - 1 + 2*Cconst))) ); //may be < 0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - else dsep = sep; - dval = min(dsep, sep); - OGDF_ASSERT( dval > 0); - if (dval >= infos[v].node_ysize()) dval = int(floor((double)(infos[v].node_ysize()) / 2)); //allow 1 flip - OGDF_ASSERT( dval < infos[v].node_ysize() ); - infos[v].set_delta(OrthoDir(0),OrthoDir(1),dval); infos[v].set_eps(OrthoDir(0),OrthoDir(1),int(floor(Cconst*dval))); - infos[v].set_delta(OrthoDir(0),OrthoDir(3),dval); infos[v].set_eps(OrthoDir(0),OrthoDir(3),int(floor(Cconst*dval))); - }//else left - if (infos[v].has_gen(odEast)) - { - int le = vinfo->m_side[1].m_nAttached[0]; //to left side - int re = vinfo->m_side[1].m_nAttached[1]; //to right - dsep = ( (le+Cconst == 0) ? sep : int(floor(infos[v].node_xsize() / (2*(le+Cconst)))) ); - dval = min(dsep,sep); - OGDF_ASSERT(dval > 0); - infos[v].set_delta(odEast,odNorth,dval); infos[v].set_eps(odEast,odNorth,int(floor(Cconst*dval))); - //top side - dsep = ( (re+Cconst == 0) ? sep : int(floor((double)(infos[v].node_xsize()) / (2*(re+Cconst)))) ); - dval = min(dsep, sep); - OGDF_ASSERT( dval > 0); - infos[v].set_delta(odEast,odSouth,dval); infos[v].set_eps(odEast,odSouth,int(floor(Cconst*dval))); - }//if top - else - { - int ae = vinfo->m_side[1].m_nAttached[0]; - if (ae > 0) - dsep = ( (ae+Cconst == 1) ? sep : int(floor((double)(infos[v].node_xsize()) / (ae - 1 + 2*Cconst))) ); //may be <= 0 - else dsep = (sep < int(floor((double)(infos[v].node_xsize())/2)) ? sep : int(floor((double)(infos[v].node_xsize())/2))); - dval = min(dsep, sep); - OGDF_ASSERT( dval > 0); - - infos[v].set_delta(odEast,odNorth,dval); infos[v].set_eps(odEast,odNorth,int(floor(Cconst*dval))); - infos[v].set_delta(odEast,odSouth,dval); infos[v].set_eps(odEast,odSouth,int(floor(Cconst*dval))); - }//else top - if (infos[v].has_gen(odSouth)) - { - int le = vinfo->m_side[2].m_nAttached[0]; //to top - int re = vinfo->m_side[2].m_nAttached[1]; //to bottom - dsep = ( (le+Cconst == 0) ? sep : int(floor((double)(infos[v].node_ysize()) / (2*(le+Cconst)))) ); - dval = min(dsep,sep); - OGDF_ASSERT( dval > 0); - infos[v].set_delta(odSouth,odEast,dval); infos[v].set_eps(odSouth,odEast,int(floor(Cconst*dval))); - //top side - dsep = ( (re+Cconst == 0) ? sep : int(floor((double)(infos[v].node_ysize()) / (2*(re+Cconst)))) ); - dval = min(dsep, sep); - infos[v].set_delta(odSouth,odWest,dval); infos[v].set_eps(odSouth,odWest,int(floor(Cconst*dval))); - }//if right - else - { - int ae = vinfo->m_side[2].m_nAttached[0]; - if (ae > 0) - dsep = ( (ae+Cconst == 1) ? sep : int(floor(infos[v].node_ysize() / (ae - 1 + 2*Cconst))) ); //may be <= 0 - else dsep = sep; - dval = min(dsep, sep); - infos[v].set_delta(odSouth,odEast,dval); infos[v].set_eps(odSouth,odEast,int(floor(Cconst*dval))); - infos[v].set_delta(odSouth,odWest,dval); infos[v].set_eps(odSouth,odWest,int(floor(Cconst*dval))); - }//else right - if (infos[v].has_gen(odWest)) - { - int le = vinfo->m_side[3].m_nAttached[0]; //to left side - int re = vinfo->m_side[3].m_nAttached[1]; //to right - dsep = ( (le+Cconst == 0) ? sep : int(floor((double)(infos[v].node_xsize()) / (2*(le+Cconst)))) ); - dval = min(dsep,sep); - OGDF_ASSERT( dval > 0); - infos[v].set_delta(odWest,odSouth,dval); infos[v].set_eps(odWest,odSouth,int(floor(Cconst*dval))); - //top side - dsep = ( (re+Cconst == 0) ? sep : int(floor((double)(infos[v].node_xsize()) / (2*(re+Cconst)))) ); - dval = min(dsep, sep); - infos[v].set_delta(odWest,odNorth,dval); infos[v].set_eps(odWest,odNorth,int(floor(Cconst*dval))); - }//if bottom - else - { - int ae = vinfo->m_side[3].m_nAttached[0]; - if (ae > 0) - dsep = ( (ae+Cconst == 1) ? sep : int(floor((double)(infos[v].node_xsize()) / (ae - 1 + 2*Cconst))) ); //may be <= 0 - else dsep = sep; - dval = min(dsep, sep); - OGDF_ASSERT( dval > 0); - infos[v].set_delta(odWest,odSouth,dval); infos[v].set_eps(odWest,odSouth,int(floor(Cconst*dval))); - infos[v].set_delta(odWest,odNorth,dval); infos[v].set_eps(odWest,odNorth,int(floor(Cconst*dval))); - }//else bottom - //{cagesize, boxsize, delta, epsilon, gen_pos ...} -}//initialize_node_info - - -//COMPUTING THE CONSTANTS -//maybe faster: alpha as parameter, recompute if -1, use otherwise -//paper algorithm 2 -int EdgeRouter::compute_move(OrthoDir s_from, OrthoDir s_to, int& kflip, node v) -//compute the maximal number of moveable edges from s_from to s_to -//(and thereby the moveable edges, counted from the box corner) -//and return the number of saved bends -{ - //debug: first, we compute (min(al_21, E12) - kflip = min( alpha_move(s_to, s_from, v), infos[v].num_routable(s_from, s_to) ); - OGDF_ASSERT(kflip > -1); - - return kflip + 2*beta_move(s_from, s_to, kflip, v); -}//compute_move - - -//helper functions computing the intermediate values -//number of edges that can additionally be routed bendfree at s_from if move_num edges are -//moved from s_from to s_to -int EdgeRouter::beta_move(OrthoDir s_from, OrthoDir s_to, int move_num, node v) -{ - //check the edges in E if their connection point - //could be routed bendfree to an glue point if move_num edges are flipped to s_to - if (move_num < 1) return 0; - int ic = 0; - bool down = (s_to == odNorth) || (s_to == odWest); - - //try to find out which bend direction is opposite - //these edges can not be routed bendfree - bend_type bt1, bt2, bt3, bt4; - switch (s_from) - { - case odEast: - switch (s_to) - { - case odSouth: - bt1 = prob_b1l; - bt2 = prob_b2l; - bt3 = bend_1left; - bt4 = bend_2left; - break; - case odNorth: bt1 = prob_b1r; - bt2 = prob_b2r; - bt3 = bend_1right; - bt4 = bend_2right; - break; - OGDF_NODEFAULT - }//switch s_to - break; - case odWest: - switch (s_to) - { - case odSouth: - bt1 = prob_b1r; - bt2 = prob_b2r; - bt3 = bend_1right; - bt4 = bend_2right; - break; - case odNorth: - bt1 = prob_b1l; - bt2 = prob_b2l; - bt3 = bend_1left; - bt4 = bend_2left; - break; - OGDF_NODEFAULT - }//switch s_to - break; - case odNorth: - switch (s_to) - { - case odWest: - bt1 = prob_b1r; - bt2 = prob_b2r; - bt3 = bend_1right; - bt4 = bend_2right; - break; - case odEast: - bt1 = prob_b1l; - bt2 = prob_b2l; - bt3 = bend_1left; - bt4 = bend_2left; - break; - OGDF_NODEFAULT - }//switch s_to - break; - case odSouth: - switch (s_to) - { - case odEast: - bt1 = prob_b1r; - bt2 = prob_b2r; - bt3 = bend_1right; - bt4 = bend_2right; - break; - case odWest: - bt1 = prob_b1l; - bt2 = prob_b2l; - bt3 = bend_1left; - bt4 = bend_2left; - break; - OGDF_NODEFAULT - }//switch s_to - break; - - OGDF_NODEFAULT - }//switch s_from - - - {//debug top side to - //first list all bend edges at corner s_from->s_to by increasing distance to corner in list E - ListIterator ep; - adjEntry ae; //used to find real position - int adjcount; - - if (down) - { - ep = infos[v].inList(s_from).begin(); //first entry iterator - if (ep.valid()) ae = outEntry(infos[v], s_from, 0); - adjcount = 0; - } - else - { - adjcount = infos[v].inList(s_from).size()-1; - ep = infos[v].inList(s_from).rbegin(); //last entry iterator - if (ep.valid()) ae = outEntry(infos[v], s_from, adjcount); - } - ic = 0; - while (ep.valid() && (ic < move_num)) - { - ic++; - if (down) {ep++; adjcount++;} - else { ep--; adjcount--; } - } - - if (ep.valid()) ae = outEntry(infos[v], s_from, adjcount); - - //now ep should point to first usable edge, if list was not empty - if (!ep.valid()) return 0; - - //if this edge is already unbend, there is nothing to save - if ((m_abends[ae] == bend_free) || - (m_abends[ae] == bt1) || - (m_abends[ae] == bt2) || - (m_abends[ae] == bt3) || - (m_abends[ae] == bt4) ) - return 0; - - bool bend_saveable; - bool in_E_sfrom_sto; //models set E_s_from_s_to from paper - - ic = 0; //will hold the number of new unbend edges - - //four cases: - switch (s_to) - { - case odEast: //from left and right - bend_saveable = (cp_y(ae) <= (infos[v].coord(odEast) - - infos[v].delta(s_from, s_to)*ic - - infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_y(ae) > gp_y(ae)); - break; - case odNorth: //from top and bottom - bend_saveable = (cp_x(ae) >= (infos[v].coord(odNorth) - + infos[v].delta(s_from, s_to)*ic - + infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_x(ae) < gp_x(ae)); - break; - case odSouth: - bend_saveable = (cp_x(ae) <= (infos[v].coord(odSouth) - - infos[v].delta(s_from, s_to)*ic - - infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_x(ae) > gp_x(ae)); - break; - case odWest: - bend_saveable = (cp_y(ae) >= (infos[v].coord(odWest) - + infos[v].delta(s_from, s_to)*ic - + infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_y(ae) < gp_y(ae)); - break; - OGDF_NODEFAULT - }//switch - - //compare edges connection point with available space - while (ep.valid() && - bend_saveable && - in_E_sfrom_sto &&//models E_from_to set in paper - (down ? (adjcount < infos[v].inList(s_from).size()-1) : (adjcount > 0)) - ) //valid, connection point ok and edge was preliminarily bend (far enough from corner) - { - if (down) - { - ep++; - ae = outEntry(infos[v], s_from, ++adjcount); - } - else { - ep--; - ae = outEntry(infos[v], s_from, --adjcount); - } - ic++; - - //four cases: - if (ep.valid()) - { - - if ((m_abends[ae] == bend_free) || - (m_abends[ae] == bt1) || - (m_abends[ae] == bt2) || - (m_abends[ae] == bt3) || - (m_abends[ae] == bt4) ) - break; //no further saving possible - //hier noch: falls Knick in andere Richtung: auch nicht bendfree - - switch (s_to) - { - case odEast: //from left and right , ersetzte cp(*ep) durch cp(ae) - bend_saveable = (cp_y(ae) <= (infos[v].coord(odEast) - - infos[v].delta(s_from, s_to)*ic - - infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_y(ae) > gp_y(ae)); - break; - case odNorth: //from top and bottom - bend_saveable = (cp_x(ae) >= (infos[v].coord(odNorth) - + infos[v].delta(s_from, s_to)*ic - + infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_x(ae) < gp_x(ae)); - break; - case odSouth: - bend_saveable = (cp_x(ae) <= (infos[v].coord(odSouth) - - infos[v].delta(s_from, s_to)*ic - - infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_x(ae) > gp_x(ae)); - break; - case odWest: - bend_saveable = (cp_y(ae) >= (infos[v].coord(odWest) - + infos[v].delta(s_from, s_to)*ic - + infos[v].eps(s_from, s_to))); - in_E_sfrom_sto = (cp_y(ae) < gp_y(ae)); - break; - OGDF_NODEFAULT - }//switch - }//if - }//while - }//debug - - return ic; -}//beta_move - - -//compute the maximum number of edges to be moved from s_from to s_to -//attention: order of sides reversed: to - from -//optimisation: check for the minimum distance (separaration on "to" side, -//separation on from side) to allow flipping improvement even if the separation -//cannot be guaranted, but the "to" separation will be improved (but assure -//that the postprocessing knows the changed values -//maybe reassign all glue points at the two sides -int EdgeRouter::alpha_move(OrthoDir s_to, OrthoDir s_from, node v) -{ - //Test fuer alignment: Falls der Knoten aligned wird, Kanten nicht an Seiten verlegen - //zunaechst: garnicht - if ((m_align) && m_mergerSon[m_prup->expandedNode(v)]) - { - return 0; - } - - int result = -1; - //we can implode the cases, but... - switch (s_to) - { - case odNorth: //two from cases: top or bottom - switch (s_from) - { - case odEast: - if (infos[v].num_bend_free(odNorth) != 0) - result = int(floor( (double)((infos[v].coord(odEast) - infos[v].l_upper_unbend() - //oder doch ftop - infos[v].delta(odNorth, odEast)*infos[v].num_bend_edges(odNorth, odEast) - infos[v].eps(odNorth, odEast) - ) )/ infos[v].delta(odNorth, odEast) - )); - else //there cant be a generalization: delta = delta_t = delta_l - result = int(floor( (double)((infos[v].node_ysize() - //box size - (infos[v].num_bend_edges(odNorth, odEast) + infos[v].num_bend_edges(odNorth, odWest) - 1)* - infos[v].delta(odNorth, odEast) - //adjacent edges - 2*infos[v].eps(odNorth, odEast)) / infos[v].delta(odNorth, odEast)) ) - ); //left side epsilon without generalization - break; - case odWest: - if (infos[v].num_bend_free(odNorth) != 0) - result = int(floor( (double)((infos[v].l_lower_unbend() - infos[v].coord(odWest) - - infos[v].delta(odNorth, odWest)*infos[v].num_bend_edges(odNorth, odWest) - - infos[v].eps(odNorth, odWest) - ) / infos[v].delta(odNorth, odWest) - ))); - else //al_lb = al_lt, just copied, check!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - result = int(floor((double)((infos[v].node_ysize() //box size - - (infos[v].num_bend_edges(odNorth, odEast) + infos[v].num_bend_edges(odNorth, odWest) - 1) - * infos[v].delta(odNorth, odEast) //adjacent edges - - 2*infos[v].eps(odNorth, odEast)) / infos[v].delta(odNorth, odEast) - ))); //left side epsilon without generalization - break; - default: - //unmatched s_to in EdgeRouter::alpha_move - OGDF_THROW(AlgorithmFailureException); - }//switch - - break; - case odSouth: - switch (s_from) - { - case odEast: - if (infos[v].num_bend_free(odSouth) != 0) - { - result = int(floor( (double)((infos[v].coord(odEast) - infos[v].r_upper_unbend() - - infos[v].num_bend_edges(odSouth, odEast)*infos[v].delta(odSouth, odEast) - - infos[v].eps(odSouth, odEast) - ) / infos[v].delta(odSouth, odEast) - ))); - } - else - result = int(floor((double)( (infos[v].node_ysize() - - (infos[v].num_bend_edges(odSouth, odEast) + infos[v].num_bend_edges(odSouth, odWest) - 1) - * infos[v].delta(odSouth, odEast) - - 2*infos[v].eps(odSouth, odEast) - ) / infos[v].delta(odSouth, odEast) - ))); - break; - case odWest: - if (infos[v].num_bend_free(odSouth) != 0) - result = int(floor( (double)((infos[v].r_lower_unbend() - - infos[v].coord(odWest) - - (infos[v].num_bend_edges(odSouth, odWest))*infos[v].delta(odSouth, odWest) - - infos[v].eps(odSouth, odWest) - ) / infos[v].delta(odSouth, odWest) - ))); - else //same as top, check !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - result = int(floor( (double)((infos[v].node_ysize() - - (infos[v].num_bend_edges(odSouth, odEast) + infos[v].num_bend_edges(odSouth, odWest) - 1) - * infos[v].delta(odSouth, odEast) - - 2*infos[v].eps(odSouth, odEast) - ) / infos[v].delta(odSouth, odEast) - ))); - break; - default: - // unmatched s_to in EdgeRouter::alpha_move - OGDF_THROW(AlgorithmFailureException); - }//switch - - break; - case odEast: - switch (s_from) - { - case odNorth : - if (infos[v].num_bend_free(odEast) != 0) - { - result = int(floor( (double)(((infos[v].t_left_unbend() - infos[v].coord(odNorth) - //linkeste bf pos. - linken boxrand - infos[v].eps(odEast, odNorth) - - infos[v].delta(odEast, odNorth)*infos[v].num_bend_edges(odEast, odNorth)) / //linkes epsilon und linke Kanten - infos[v].delta(odEast, odNorth)) - ))); - } - else - result = int(floor( (double)((infos[v].node_xsize() - - (infos[v].num_bend_edges(odEast, odNorth) + infos[v].num_bend_edges(odEast, odSouth) - 1)*infos[v].delta(odEast, odNorth) - - 2*infos[v].eps(odEast, odNorth) ) / infos[v].delta(odEast, odNorth) - ))); - break; - case odSouth: - if (infos[v].num_bend_free(odEast) != 0) - result = int(floor( (double)((infos[v].coord(odSouth) - infos[v].t_right_unbend() - - infos[v].num_bend_edges(odEast, odSouth)*infos[v].delta(odEast, odSouth) - - infos[v].eps(odEast, odSouth)) / infos[v].delta(odEast, odSouth) - ))); - else //same as left, check !!! - result = int(floor( (double)((infos[v].node_xsize() - - (infos[v].num_bend_edges(odEast, odNorth) + infos[v].num_bend_edges(odEast, odSouth) - 1)*infos[v].delta(odEast, odNorth) - - 2*infos[v].eps(odEast, odNorth) - ) / infos[v].delta(odEast, odNorth) - ))); - break; - default: - // unmatched s_to in EdgeRouter::alpha_move - OGDF_THROW(AlgorithmFailureException); - }//switch - break; - case odWest: - switch (s_from) - { - case odNorth: - if (infos[v].num_bend_free(odWest) != 0) - result = int(floor( (double)((infos[v].b_right_unbend() - infos[v].coord(odNorth) - - infos[v].num_bend_edges(odWest, odNorth)*infos[v].delta(odWest, odNorth) - - infos[v].eps(odWest, odNorth) - ) / infos[v].delta(odWest, odNorth) - ))); - else - result = int(floor( (double)((infos[v].node_xsize() - - (infos[v].num_bend_edges(odWest, odNorth) + infos[v].num_bend_edges(odWest, odSouth) - 1)*infos[v].delta(odWest, odNorth) - - 2*infos[v].eps(odWest, odNorth) - ) / infos[v].delta(odWest, odNorth) - ))); - break; - case odSouth: - if (infos[v].num_bend_free(odWest) != 0) - result = int(floor ( (double)((infos[v].coord(odSouth) - infos[v].b_left_unbend() - - infos[v].num_bend_edges(odWest, odSouth)*infos[v].delta(odWest, odSouth) - - infos[v].eps(odWest, odSouth) - ) / infos[v].delta(odWest, odSouth) - ))); - else - result = int(floor( (double)((infos[v].node_xsize() - - (infos[v].num_bend_edges(odWest, odNorth) + infos[v].num_bend_edges(odWest, odSouth) - 1)*infos[v].delta(odWest, odNorth) - - 2*infos[v].eps(odWest, odNorth) - ) / infos[v].delta(odWest, odNorth) - ))); - - break; - default: - // unmatched s_to in EdgeRouter::alpha_move - OGDF_THROW(AlgorithmFailureException); - }//switch - break; - - default: - // unrecognized side in EdgeRouter::alpha_move - OGDF_THROW(AlgorithmFailureException); - }//switch - - if (result < 0) result = 0; - return result; - -}//alpha_move - - -void EdgeRouter::addbends(BendString& bs, const char* s2) -{ - const char* s1 = bs.toString(); - size_t len = strlen(s1) + strlen(s2) + 1; - char* resi = new char[len]; - bs.set(resi); - delete[] resi; -}//addbends - - -//add a left bend to edge e -edge EdgeRouter::addLeftBend(edge e) -{ - int a1 = m_orp->angle(e->adjSource()); - int a2 = m_orp->angle(e->adjTarget()); - - edge ePrime = m_comb->split(e); - m_orp->angle(ePrime->adjSource()) = 3; - m_orp->angle(ePrime->adjTarget()) = a2; - m_orp->angle(e->adjSource()) = a1; - m_orp->angle(e->adjTarget()) = 1; - - return ePrime; -}//addLeftBend - - -//add a right bend to edge e -edge EdgeRouter::addRightBend(edge e) -{ - String msg; - - int a1 = m_orp->angle(e->adjSource()); - int a2 = m_orp->angle(e->adjTarget()); - - edge ePrime = m_comb->split(e); - - m_orp->angle(ePrime->adjSource()) = 1; - m_orp->angle(ePrime->adjTarget()) = a2; - m_orp->angle(e->adjSource()) = a1; - m_orp->angle(e->adjTarget()) = 3; - - return ePrime; -} - - -//set the computed values in the m_med structure -void EdgeRouter::setDistances() -{ - node v; - forall_nodes(v, *m_prup) - { - if ((m_prup->expandAdj(v) != 0) && (m_prup->typeOf(v) != Graph::generalizationMerger)) - { - OrthoDir od = odNorth; - do - { - m_med->delta(v, od, 0) = infos[v].delta(od, OrthoRep::prevDir(od)); - m_med->delta(v, od, 1) = infos[v].delta(od, OrthoRep::nextDir(od)); - m_med->epsilon(v, od, 0) = infos[v].eps(od, OrthoRep::prevDir(od)); - m_med->epsilon(v, od, 1) = infos[v].eps(od, OrthoRep::nextDir(od)); - - od = OrthoRep::nextDir(od); - } while (od != odNorth); - }//if - }//forallnodes -} - - -void EdgeRouter::unsplit(edge e1, edge e2) -{ - //precondition: ae1 is adjsource/sits on original edge - int a1 = m_orp->angle(e1->adjSource()); //angle at source - int a2 = m_orp->angle(e2->adjTarget()); //angle at target - m_prup->unsplit(e1, e2); - m_orp->angle(e1->adjSource()) = a1; - m_orp->angle(e1->adjTarget()) = a2; -}//unsplit - - -void EdgeRouter::set_position(node v, int x, int y) -{ - if (!m_fixed[v]) - { - m_layoutp->x(v) = x; - m_layoutp->y(v) = y; - } -}//set_position - - -void EdgeRouter::fix_position(node v, int x, int y) -{ - m_layoutp->x(v) = x; - m_layoutp->y(v) = y; - m_fixed[v] = true; -} - -} //end namespace - diff --git a/ext/OGDF/src/orthogonal/FlowCompaction.cpp b/ext/OGDF/src/orthogonal/FlowCompaction.cpp deleted file mode 100644 index 5df9a8d0f..000000000 --- a/ext/OGDF/src/orthogonal/FlowCompaction.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements constructive and improvement heurisitcs for - * comapction applying computation of min-cost flow in the - * dual of the constraint graph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -//#define foutputRC -//#define foutputMD - - -namespace ogdf { - - -// output in gml-format with special edge colouring -// arcs with cost 0 are green, other arcs red -void printCCGx(const char *filename, - const CompactionConstraintGraph &D, - const GridLayoutMapped &drawing); - -// output in gml-format with special edge colouring -// arcs with cost 0 are green, other arcs red -void printCCGy(const char *filename, - const CompactionConstraintGraph &D, - const GridLayoutMapped &drawing); - - -void writeGridDrawing(const char *name, PlanRep &PG, GridLayoutMapped &drawing) -{ - ofstream os(name); - - node v; - forall_nodes(v,PG) { - os << v->index() << ": " << drawing.x(v) << ", " << drawing.y(v) << endl; - } -} - - - -// constructor -FlowCompaction::FlowCompaction(int maxImprovementSteps, - int costGen, - int costAssoc) -{ - m_maxImprovementSteps = maxImprovementSteps; - m_costGen = costGen; - m_costAssoc = costAssoc; - m_cageExpense = true; - m_numGenSteps = 3; //number of improvement steps for generalizations only + 1 - m_scalingSteps = 0; - m_align = false; -} - - -// constructive heuristics for orthogonal representation OR -void FlowCompaction::constructiveHeuristics( - PlanRep &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing) -{ - OGDF_ASSERT(OR.isOrientated()); - - // x-coordinates of vertical segments - CompactionConstraintGraph Dx(OR, PG, odEast, rc.separation(), - m_costGen, m_costAssoc, m_align); - Dx.insertVertexSizeArcs(PG, drawing.width(), rc); - - NodeArray xDx(Dx.getGraph(), 0); - computeCoords(Dx, xDx); - - // y-coordinates of horizontal segments - CompactionConstraintGraph Dy(OR, PG, odNorth, rc.separation(), - m_costGen, m_costAssoc, m_align); - Dy.insertVertexSizeArcs(PG, drawing.height(), rc); - - NodeArray yDy(Dy.getGraph(), 0); - computeCoords(Dy, yDy); - - // final coordinates of vertices - node v; - forall_nodes(v,PG) { - drawing.x(v) = xDx[Dx.pathNodeOf(v)]; - drawing.y(v) = yDy[Dy.pathNodeOf(v)]; - } -} - - -// improvement heuristics for orthogonal drawing -void FlowCompaction::improvementHeuristics( - PlanRep &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing) -{ - OGDF_ASSERT(OR.isOrientated()); - - double costs = double(INT_MAX), lastCosts; - int steps = 0, maxSteps = m_maxImprovementSteps; - if (maxSteps == 0) maxSteps = INT_MAX; - - // OPTIMIZATION POTENTIAL: - // update constraint graphs "incrementally" by only re-inserting - // visibility arcs - do { - lastCosts = costs; - ++steps; - - // x-coordinates of vertical segments - CompactionConstraintGraph Dx(OR, PG, odEast, rc.separation(), - m_costGen, m_costAssoc, m_align); - - Dx.insertVertexSizeArcs(PG, drawing.width(), rc); - Dx.insertVisibilityArcs(PG, drawing.x(), drawing.y()); - - NodeArray xDx(Dx.getGraph(), 0); - - // set position of segments in order to fix arcs of length 0 in - // computeCoords() - node w; - forall_nodes(w,Dx.getGraph()) - { - if (!Dx.extraNode(w)) - xDx[w] = drawing.x(Dx.nodesIn(w).front()); - else - xDx[w] = drawing.x(Dx.extraRep(w)) + Dx.extraOfs(w); - } - - -#ifdef foutputRC - String fileName; - fileName.sprintf("Dx_%d.gml",steps); - printCCGx(fileName,Dx,drawing); -#endif - - //first steps: only vertical generalizations - if ((steps > 0) && (steps Dy(OR, PG, odNorth, rc.separation(), - m_costGen, m_costAssoc, m_align); - - Dy.insertVertexSizeArcs(PG, drawing.height(), rc); - Dy.insertVisibilityArcs(PG, drawing.y(), drawing.x()); - - - NodeArray yDy(Dy.getGraph(), 0); - - // set position of segments in order to fix arcs of length 0 in - // computeCoords() - forall_nodes(w,Dy.getGraph()) - { - if (!Dy.extraNode(w)) //maybe only nec in next impro - yDy[w] = drawing.y(Dy.nodesIn(w).front()); - else - yDy[w] = drawing.y(Dy.extraRep(w)) + Dy.extraOfs(w); - } - -#ifdef foutputRC - fileName.sprintf("Dy_%d.gml",steps); - printCCGy(fileName,Dy,drawing); -#endif - - if ((steps > 0) && (steps &minDist, - GridLayoutMapped &drawing, - int originalSeparation //test for compaction improvement - ) -{ - OGDF_ASSERT(OR.isOrientated()); - - double costs = double(INT_MAX), lastCosts; - int steps = 0, maxSteps = m_maxImprovementSteps; - if (maxSteps == 0) maxSteps = INT_MAX; - - // OPTIMIZATION POTENTIAL: - // update constraint graphs "incrementally" by only re-inserting - // visibility arcs - do { - lastCosts = costs; - ++steps; - - // x-coordinates of vertical segments - CompactionConstraintGraph Dx(OR, PG, odEast, originalSeparation, - //minDist.separation(), - m_costGen, m_costAssoc, m_align); - - Dx.insertVertexSizeArcs(PG, drawing.width(), minDist); - Dx.insertVisibilityArcs(PG, drawing.x(), drawing.y(), minDist); - -#ifdef foutputMD - String fileName; - fileName.sprintf("Dx_%d.gml",steps); - printCCGx(fileName,Dx,drawing); -#endif - - NodeArray xDx(Dx.getGraph(), 0); - - // set position of segments in order to fix arcs of length 0 in - // computeCoords() - node w; - forall_nodes(w,Dx.getGraph()) - { - if (!Dx.extraNode(w)) - xDx[w] = drawing.x(Dx.nodesIn(w).front()); - else xDx[w] = drawing.x(Dx.extraRep(w)) + Dx.extraOfs(w); - } - - if ((steps > 0) && (steps Dy(OR, PG, odNorth, originalSeparation, - //minDist.separation(), - m_costGen, m_costAssoc, m_align); - - Dy.insertVertexSizeArcs(PG, drawing.height(), minDist); - Dy.insertVisibilityArcs(PG,drawing.y(),drawing.x(),minDist); - - NodeArray yDy(Dy.getGraph(), 0); - - // set position of segments in order to fix arcs of length 0 in - // computeCoords() - forall_nodes(w,Dy.getGraph()) - { - if (!Dy.extraNode(w)) - yDy[w] = drawing.y(Dy.nodesIn(w).front()); - else - yDy[w] = drawing.y(Dy.extraRep(w)) + Dy.extraOfs(w); - } - -#ifdef foutputMD - fileName.sprintf("Dy_%d.gml",steps); - printCCGy(fileName,Dy,drawing); - - fileName.sprintf("c-edges y %d.txt", steps); - ofstream os(fileName); - const Graph &Gd = Dy.getGraph(); - edge ee; - forall_edges(ee,Gd) - os << (yDy[ee->target()] - yDy[ee->source()]) << " " << - ee->source()->index() << " -> " << ee->target()->index() << endl; - os.close(); -#endif - - //computeCoords(Dy, yDy, true, true, true); - if ((steps > 0) && (steps < m_numGenSteps)) //first compact cages - computeCoords(Dy, yDy, true, true, true, true); - else - computeCoords(Dy, yDy, true, true, true, false); - - // final y-coordinates of vertices - forall_nodes(v,PG) { - drawing.y(v) = yDy[Dy.pathNodeOf(v)]; - } - -#ifdef foutputMD - fileName.sprintf("Gy_%d.txt",steps); - writeGridDrawing(fileName, PG, drawing); - - fileName.sprintf("Gy_%d.gml",steps); - PGUml.writeGML(fileName,OR,drawing); -#endif - - costs = Dx.computeTotalCosts(xDx) + Dy.computeTotalCosts(yDy); - - if (steps <= m_scalingSteps) minDist.separation(max(originalSeparation, minDist.separation() / 2)); - - } while (steps < maxSteps && (steps < max(m_scalingSteps + 1, m_numGenSteps) || costs < lastCosts)); -} - - - -// computes coordinates pos of horizontal (resp. vertical) segments by -// computing a min-cost flow in the dual of the constraint graph D -void FlowCompaction::computeCoords( - CompactionConstraintGraph &D, - NodeArray &pos, - bool fixZeroLength, - bool fixVertexSize, - bool improvementHeuristics, - bool onlyGen //compact only generalizations - ) -{ - Graph &Gd = D.getGraph(); - - //D.writeGML("computecoords.gml"); - - // - // embed constraint graph such that all sources and sinks lie - // in a common face - - D.embed(); - CombinatorialEmbedding E(Gd); - - // - // construct dual graph - Graph dual; - FaceArray dualNode(E); - m_dualEdge.init(Gd); - - // insert a node in the dual graph for each face in E - face f; - forall_faces(f,E) { - dualNode[f] = dual.newNode(); - } - - // Insert an edge into the dual graph for each edge in Gd - // The edges are directed from the left face to the right face. - edge e; - forall_edges(e,Gd) - { - node vLeft = dualNode[E.rightFace(e->adjTarget())]; - node vRight = dualNode[E.rightFace(e->adjSource())]; - edge eDual = dual.newEdge(vLeft,vRight); - m_dualEdge[e] = eDual; - } - - - MinCostFlowReinelt mcf; - - const int infinity = mcf.infinity(); - - NodeArray supply(dual,0); - EdgeArray lowerBound(dual), upperBound(dual,infinity); - EdgeArray cost(dual); - m_flow.init(dual); - - forall_edges(e,Gd) - { - edge eDual = m_dualEdge[e]; - - lowerBound[eDual] = D.length(e); - cost [eDual] = D.cost(e); - - // if fixZeroLength is activated, we fix the length of all arcs - // which have length 0 in the current drawing to 0. - // This has to be changed if we use special constructs for allowing - // left or right bends - int currentLength = pos[e->target()] - pos[e->source()]; - if ((fixZeroLength && currentLength == 0) && (D.typeOf(e) == cetFixToZeroArc)) - lowerBound[eDual] = upperBound[eDual] = 0; - else if (improvementHeuristics && currentLength < lowerBound[eDual]) - lowerBound[eDual] = currentLength; - - //fix length of alignment edges after some rounds - //(preliminary use onlyGen setting here) - - if (m_align && improvementHeuristics) - { - if (D.alignmentArc(e) && !onlyGen) //use onlyGen instead of extra bool to test - upperBound[eDual] = currentLength; - - }//if align - - - //fix cage boundary edge segments to values smaller than sep - if ( improvementHeuristics && D.fixOnBorder(e) && (currentLength < D.separation()) ) - { - if (currentLength < lowerBound[eDual]) lowerBound[eDual] = currentLength; - //lowerBound[eDual] = test fuer skalierung - - upperBound[eDual] = currentLength; - } - - //reducible arcs are currently out of play - //maybe they will be inserted later on for some special purpose, - //therefore we keep the code - OGDF_ASSERT(D.typeOf(e) != cetReducibleArc) - // if (D.typeOf(e) == cetReducibleArc) - // { - //OGDF_ASSERT(false); - // lowerBound[eDual] = min(0, currentLength); - // upperBound[eDual] = infinity; - // } - //should we reset median arcs here? - - if (onlyGen) - { - //vertexsize sind aber nur innen, border muss noch geaendert werden - //also expansion!=generalization - if (!(D.verticalArc(e) || (D.typeOf(e) == cetVertexSizeArc) - || D.onBorder(e)) ) { - lowerBound[eDual] = currentLength; - upperBound[eDual] = infinity; - } - } - - }//forall Gd edges - - if (fixVertexSize) { - forall_edges(e,Gd) { - if (D.typeOf(e) == cetVertexSizeArc) { - edge eDual = m_dualEdge[e]; - upperBound[eDual] = lowerBound[eDual]; - } - } - } - - - // - // apply min-cost flow - if (dual.numberOfNodes() == 1) - { - edge eDual; - forall_edges(eDual,dual) - m_flow[eDual] = lowerBound[eDual]; - - } else { -#ifdef OGDF_DEBUG - bool feasible = -#endif - mcf.call(dual,lowerBound,upperBound,cost,supply,m_flow); - - OGDF_ASSERT(feasible); - } - - // - // interpret result; set coordinates of segments - // note: positions are currently not 0-aligned! - NodeArray visited(Gd,false); - dfsAssignPos(visited, pos, Gd.firstNode(), 0); - - // free resources - m_dualEdge.init(); - m_flow.init(); -} - - -// compute position of nodes in the constraint graph by a DFS-traversel -// if (v,w) is an edge in D and len is the flow on the corresponding dual -// edge, we know that pos[v] + len = pos[w] -void FlowCompaction::dfsAssignPos( - NodeArray &visited, - NodeArray &pos, - node v, - int x) -{ - pos[v] = x; - visited[v] = true; - - edge e; - forall_adj_edges(e,v) { - node w = e->opposite(v); - if (visited[w]) continue; - - if (e->source() == v) - dfsAssignPos(visited,pos,w,x + m_flow[m_dualEdge[e]]); - else - dfsAssignPos(visited,pos,w,x - m_flow[m_dualEdge[e]]); - } -} - - - -// output in gml-format with special edge colouring -// arcs with cost 0 are green, other arcs red -void writeCcgGML(const CompactionConstraintGraph &D, - const GraphAttributes &AG, - const char *filename) -{ - ofstream os(filename); - const Graph &G = D.getGraph(); - - NodeArray id(G); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::writeCcgGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - os << " label \"" << v << "\"\n"; - - os << " graphics [\n"; - os << " x " << AG.x(v) << "\n"; - os << " y " << AG.y(v) << "\n"; - os << " w " << AG.width(v) << "\n"; - os << " h " << AG.height(v) << "\n"; - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - os << " arrow \"last\"\n"; - - switch(D.typeOf(e)) - { - case cetBasicArc: // red - os << " fill \"#FF0000\"\n"; - break; - case cetVertexSizeArc: // blue - os << " fill \"#0000FF\"\n"; - break; - case cetVisibilityArc: // green - os << " fill \"#00FF00\"\n"; - break; - case cetReducibleArc: // pink - os << " fill \"#FF00FF\"\n"; - break; - case cetFixToZeroArc: // violet - os << " fill \"#AF00FF\"\n"; - break; - case cetMedianArc: // black - os << " fill \"#0F000F\"\n"; - break; - } - - const DPolyline &dpl = AG.bends(e); - if (!dpl.empty()) { - os << " Line [\n"; - os << " point [ x " << AG.x(e->source()) << " y " << - AG.y(e->source()) << " ]\n"; - - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - os << " point [ x " << (*it).m_x << " y " << (*it).m_y << " ]\n"; - - os << " point [ x " << AG.x(e->target()) << " y " << - AG.y(e->target()) << " ]\n"; - - os << " ]\n"; // Line - } - - os << " ]\n"; // graphics - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - -void printCCGx(const char *filename, - const CompactionConstraintGraph &D, - const GridLayoutMapped &drawing) -{ - const Graph &Gd = D.getGraph(); - const NodeArray &x = drawing.x(); - const NodeArray &y = drawing.y(); - - node v; - edge e; - - GraphAttributes AG(Gd,GraphAttributes::nodeLabel | GraphAttributes::nodeGraphics | GraphAttributes::edgeGraphics); - - forall_nodes(v,Gd) - { - if (D.extraNode(v)) - { - AG.height(v) = 1.0; - AG.width (v) = 1.0; - - AG.x(v) = drawing.x(D.extraRep(v)) + D.extraOfs(v); - - continue; - } - - const SListPure &L = D.nodesIn(v); - if (L.empty()) - continue;//should not happen, extraNode - - node v1 = L.front(); - int minY = y[v1]; - int maxY = y[v1]; - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) { - if (y[*it] < minY) minY = y[*it]; - if (y[*it] > maxY) maxY = y[*it]; - } - AG.y(v) = 0.5*drawing.toDouble(minY + maxY); - AG.x(v) = drawing.toDouble(x[v1]); - AG.height(v) = (maxY != minY) ? drawing.toDouble(maxY - minY) : 0.1; - AG.width(v) = 1; - } - - const Graph &G = D.getOrthoRep(); - forall_edges(e,G) { - edge eD = D.basicArc(e); - if (eD == 0) continue; - - AG.bends(eD).pushFront(DPoint(AG.x(eD->source()),drawing.toDouble(drawing.y(e->source())))); - AG.bends(eD).pushBack (DPoint(AG.x(eD->target()),drawing.toDouble(drawing.y(e->source())))); - } - writeCcgGML(D,AG,filename); -} - - -void printCCGy(const char *filename, - const CompactionConstraintGraph &D, - const GridLayoutMapped &drawing) -{ - const Graph &Gd = D.getGraph(); - const NodeArray &x = drawing.x(); - const NodeArray &y = drawing.y(); - - node v; - edge e; - - GraphAttributes AG(Gd,GraphAttributes::nodeLabel | GraphAttributes::nodeGraphics | GraphAttributes::edgeGraphics); - - forall_nodes(v,Gd) - { - if (D.extraNode(v)) - { - AG.height(v) = 1.0; - AG.width (v) = 1.0; - - //AG.x(v) = drawing.x(D.extraRep(v)) + D.extraOfs(v); - - continue; - } - - const SListPure &L = D.nodesIn(v); - if (L.empty()) - continue;//should not happen, extraNode - - node v1 = L.front(); - int minX = x[v1]; - int maxX = x[v1]; - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) { - if (x[*it] < minX) minX = x[*it]; - if (x[*it] > maxX) maxX = x[*it]; - } - AG.x(v) = 0.5*drawing.toDouble(minX + maxX); - AG.y(v) = drawing.toDouble(y[v1]); - AG.width(v) = (minX != maxX) ? drawing.toDouble(maxX - minX) : 0.1; - AG.height(v) = 1; - } - - const Graph &G = D.getOrthoRep(); - forall_edges(e,G) { - edge eD = D.basicArc(e); - if (eD == 0) continue; - AG.bends(eD).pushFront(DPoint(drawing.toDouble(drawing.x(e->source())), - AG.y(eD->source()))); - AG.bends(eD).pushBack (DPoint(drawing.toDouble(drawing.x(e->source())), - AG.y(eD->target()))); - } - - writeCcgGML(D,AG,filename); -} - - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/orthogonal/LongestPathCompaction.cpp b/ext/OGDF/src/orthogonal/LongestPathCompaction.cpp deleted file mode 100644 index 445ccdfc0..000000000 --- a/ext/OGDF/src/orthogonal/LongestPathCompaction.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements constructive and improvement heurisitcs for - * longest-paths based compaction of orthogonal drawings - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -// constructor -LongestPathCompaction::LongestPathCompaction(bool tighten, - int maxImprovementSteps) -{ - m_tighten = tighten; - m_maxImprovementSteps = maxImprovementSteps; -} - - -// constructive heuristics for orthogonal representation OR -void LongestPathCompaction::constructiveHeuristics( - PlanRepUML &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing) -{ - OGDF_ASSERT(OR.isOrientated()); - - // x-coordinates of vertical segments - CompactionConstraintGraph Dx(OR, PG, odEast, rc.separation()); - Dx.insertVertexSizeArcs(PG, drawing.width(), rc); - - NodeArray xDx(Dx.getGraph(), 0); - computeCoords(Dx, xDx); - - // y-coordinates of horizontal segments - CompactionConstraintGraph Dy(OR, PG, odNorth, rc.separation()); - Dy.insertVertexSizeArcs(PG, drawing.height(), rc); - - NodeArray yDy(Dy.getGraph(), 0); - computeCoords(Dy, yDy); - - // final coordinates of vertices - node v; - forall_nodes(v,PG) { - drawing.x(v) = xDx[Dx.pathNodeOf(v)]; - drawing.y(v) = yDy[Dy.pathNodeOf(v)]; - } -} - - -// improvement heuristics for orthogonal drawing -void LongestPathCompaction::improvementHeuristics( - PlanRepUML &PG, - OrthoRep &OR, - const RoutingChannel &rc, - GridLayoutMapped &drawing) -{ - OGDF_ASSERT(OR.isOrientated()); - - int costs, lastCosts; - int steps = 0, maxSteps = m_maxImprovementSteps; - if (maxSteps == 0) maxSteps = INT_MAX; - - // OPTIMIZATION POTENTIAL: - // update constraint graphs "incrementally" by only re-inserting - // visibility arcs - costs = 0; - do { - lastCosts = costs; - ++steps; - - // x-coordinates of vertical segments - CompactionConstraintGraph Dx(OR, PG, odEast, rc.separation()); - Dx.insertVertexSizeArcs(PG, drawing.width(), rc); - Dx.insertVisibilityArcs(PG, drawing.x(),drawing.y()); - - NodeArray xDx(Dx.getGraph(), 0); - computeCoords(Dx, xDx); - - // final x-coordinates of vertices - node v; - forall_nodes(v,PG) { - drawing.x(v) = xDx[Dx.pathNodeOf(v)]; - } - - - // y-coordinates of horizontal segments - CompactionConstraintGraph Dy(OR, PG, odNorth, rc.separation()); - Dy.insertVertexSizeArcs(PG, drawing.height(), rc); - Dy.insertVisibilityArcs(PG, drawing.y(),drawing.x()); - - NodeArray yDy(Dy.getGraph(), 0); - computeCoords(Dy, yDy); - - // final y-coordinates of vertices - forall_nodes(v,PG) { - drawing.y(v) = yDy[Dy.pathNodeOf(v)]; - } - - costs = Dx.computeTotalCosts(xDx) + Dy.computeTotalCosts(yDy); - - } while (steps < maxSteps && (steps == 1 || costs < lastCosts)); -} - - - -// computes coordinates pos of horizontal (resp. vertical) segments by -// computing longest paths in the constraint graph D -void LongestPathCompaction::computeCoords( - const CompactionConstraintGraph &D, - NodeArray &pos) -{ - const Graph &Gd = D.getGraph(); - - // compute a first ranking with usual longest paths - applyLongestPaths(D,pos); - - - if (m_tighten == true) - { - // improve cost of ranking by moving pseudo-components - moveComponents(D,pos); - - - // find node with minimal position - SListConstIterator it = m_pseudoSources.begin(); - int min = pos[*it]; - for(++it; it.valid(); ++it) { - if (pos[*it] < min) - min = pos[*it]; - } - - // move all nodes such that node with minimum position has position 0 - node v; - forall_nodes(v,Gd) - pos[v] -= min; - - } - - // free resources - m_pseudoSources.clear(); - m_component.init(); -} - - -void LongestPathCompaction::applyLongestPaths( - const CompactionConstraintGraph &D, - NodeArray &pos) -{ - const Graph &Gd = D.getGraph(); - - m_component.init(Gd); - - NodeArray indeg(Gd); - StackPure sources; - - node v; - forall_nodes(v,Gd) { - indeg[v] = v->indeg(); - if(indeg[v] == 0) - sources.push(v); - } - - while(!sources.empty()) - { - node v = sources.pop(); - - int predComp = -1; // means "unset" - bool isPseudoSource = true; - - edge e; - forall_adj_edges(e,v) { - if(e->source() != v) { - // incoming edge - if (D.cost(e) > 0) { - isPseudoSource = false; - node w = e->source(); - // is tight? - if (pos[w] + D.length(e) == pos[v]) { - if (predComp == -1) - predComp = m_component[w]; - else if (predComp != m_component[w]) - predComp = 0; // means "vertex is in no pseudo-comp. - } - } - - } else { - // outgoing edge - node w = e->target(); - - if (pos[w] < pos[v] + D.length(e)) - pos[w] = pos[v] + D.length(e); - - if (--indeg[w] == 0) - sources.push(w); - } - } - - if (predComp == -1) - predComp = 0; - - if( isPseudoSource) { - m_pseudoSources.pushFront(v); - m_component[v] = m_pseudoSources.size(); - } else { - m_component[v] = predComp; - } - } -} - - - -void LongestPathCompaction::moveComponents( - const CompactionConstraintGraph &D, - NodeArray &pos) -{ - const Graph &Gd = D.getGraph(); - - // compute for each component the list of nodes contained - Array > nodesInComp(1,m_pseudoSources.size()); - - node v; - forall_nodes(v,Gd) { - if (m_component[v] > 0) - nodesInComp[m_component[v]].pushBack(v); - } - - - // iterate over all pseudo-sources in reverse topological order - SListConstIterator it; - for(it = m_pseudoSources.begin(); it.valid(); ++it) - { - node v = *it; - int c = m_component[v]; - - // list of outgoing/incoming edges of pseudo-component C(v) - SListPure outCompV, inCompV; - - //cout << "component " << c << endl; - SListConstIterator itW; - for(itW = nodesInComp[c].begin(); itW.valid(); ++itW) - { - node w = *itW; - //cout << " " << w; - edge e; - forall_adj_edges(e,w) { - if(m_component[e->target()] != c) { - outCompV.pushBack(e); - } else if (m_component[e->source()] != c) - inCompV.pushBack(e); - } - } - //cout << endl; - - if(outCompV.empty()) - continue; - - SListConstIterator itE = outCompV.begin(); - int costOut = D.cost(*itE); - int delta = (pos[(*itE)->target()] - pos[(*itE)->source()]) - - D.length(*itE); - - for(++itE; itE.valid(); ++itE) { - costOut += D.cost(*itE); - int d = (pos[(*itE)->target()] - pos[(*itE)->source()]) - - D.length(*itE); - if (d < delta) - delta = d; - } - - //cout << " delta = " << delta << ", costOut = " << costOut << endl; - - // if all outgoing edges have cost 0, we wouldn't save any cost! - if (costOut == 0) continue; - - // move component up by delta; this shortens all outgoing edges and - // enlarges all incoming edges (which have cost 0) - for(itW = nodesInComp[c].begin(); itW.valid(); ++itW) - pos[*itW] += delta; - } - -} - - - -/* -// computes coordinates pos of horizontal (resp. vertical) segments by -// computing longest paths in the constraint graph D -void LongestPathCompaction::computeCoords( - CompactionConstraintGraph &D, - NodeArray &pos) -{ - const Graph &Gd = D.getGraph(); - - NodeArray indeg(Gd); - StackPure sources; - - node v; - forall_nodes(v,Gd) { - indeg[v] = v->indeg(); - if(indeg[v] == 0) - sources.push(v); - } - - while(!sources.empty()) - { - node v = sources.pop(); - - edge e; - forall_adj_edges(e,v) { - if(e->source() != v) continue; - - node w = e->target(); - - if (pos[w] < pos[v] + D.length(e)) - pos[w] = pos[v] + D.length(e); - - if (--indeg[w] == 0) - sources.push(w); - } - } -} -*/ - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/orthogonal/NodeInfo.cpp b/ext/OGDF/src/orthogonal/NodeInfo.cpp deleted file mode 100644 index 5fa7e374b..000000000 --- a/ext/OGDF/src/orthogonal/NodeInfo.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * $Revision: 2571 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 17:25:20 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class NodeInfo. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - - -namespace ogdf { - -void NodeInfo::get_data( - OrthoRep& O, - GridLayout& L, - node v, - RoutingChannel& rc, - NodeArray& nw, - NodeArray& nh) -//initializes basic node data -//nodeboxsize, numsedges, mgenpos -//ACHTUNG: odNorth ist 0, soll aber links sein -{ - edge e; - //first, initialize the node and cage size - box_x_size = nw[v]; //nw[P.original(v)];//P.widthOrig(P.original(v)); - box_y_size = nh[v]; //nh[P.original(v)];//P.heightOrig(P.original(v)); - //{ fright, fleft, ftop, fbottom} - m_vdegree = 0; - //get the generalization edge position on all four sides if existant - OrthoDir od = odNorth; - do - { - OrthoRep::SideInfoUML sinfo = O.cageInfo(v)->m_side[od]; - if (sinfo.m_adjGen) - { - if ((od == odNorth) || (od == odEast)) set_gen_pos(od, sinfo.m_nAttached[0]); - else set_gen_pos(od, sinfo.m_nAttached[1]); - set_num_edges(od, sinfo.m_nAttached[0] + 1 + sinfo.m_nAttached[1]); - m_vdegree += num_s_edges[od]; - } - else - { - set_gen_pos(od, -1); - set_num_edges(od, sinfo.m_nAttached[0]); - m_vdegree += num_s_edges[od]; - } - m_rc[od] = rc(v, od);//sinfo.m_routingChannel; - - od = OrthoRep::nextDir(od); - } while (od != odNorth); - - //cout<<"input nodedeg: "<m_corner[0]; e = *ae; //pointing towards north, on left side - m_ccoord[0] = L.x(e->source()); //already odDir - ae = vinfo->m_corner[1]; e = *ae; - m_ccoord[1] = L.y(e->source()); //already odDir - ae = vinfo->m_corner[2]; e = *ae; - m_ccoord[2] = L.x(e->source()); //already odDir - ae = vinfo->m_corner[3]; e = *ae; - m_ccoord[3] = L.y(e->source()); //already odDir - compute_cage_size(); - //fill the in_edges lists for all box_sides -} - - -int NodeInfo::free_coord(OrthoDir s_main, OrthoDir s_to) -{ - int result = coord(s_main); - int offset; - switch (s_main) - { - case odNorth: offset = flips(odNorth, s_to)*delta(s_to, odNorth); - case odSouth: offset = flips(odSouth, s_to)*delta(s_to, odSouth); - case odWest: offset = flips(odWest, s_to)*delta(s_to, odWest); - case odEast: offset = -flips(odEast, s_to)*delta(s_to, odEast); - OGDF_NODEFAULT - }//switch - - result = result + offset; - return result; -}//freecoord - - -ostream& operator<<(ostream& O, const NodeInfo& inf) -{ - O.precision(5);//O.setf(ios::fixed);??????? - O - << "\n********************************************\nnodeinfo: \n********************************************\n" - << "box left/top/right/bottom: " << inf.coord(OrthoDir(0)) << "/" << inf.coord(OrthoDir(1)) << "/" - << inf.coord(OrthoDir(2)) << "/" << inf.coord(OrthoDir(3)) << "\n" - << "boxsize: " << inf.box_x_size << ":" << inf.box_y_size << "\n" - << "cage l/t/r/b: " << inf.cage_coord(OrthoDir(0)) << "/" << inf.cage_coord(OrthoDir(1)) << "/" - << inf.cage_coord(OrthoDir(2)) << "/" << inf.cage_coord(OrthoDir(3)) << "\n" - << "gen. pos.: " << inf.gen_pos(OrthoDir(0)) << "/" - << inf.gen_pos(OrthoDir(1)) << "/" - << inf.gen_pos(OrthoDir(2)) << "/" << inf.gen_pos(OrthoDir(3)) << "\n" - << "delta l/t/r/b (left/right):" << inf.delta(odNorth, odWest) << ":" << inf.delta(odNorth, odEast) << " / \n" - << " " << inf.delta(odEast, odNorth) << ":" << inf.delta(odEast, odSouth) << " / \n" - << " " << inf.delta(odSouth, odEast) << ":" << inf.delta(odSouth, odWest) << " / " - << inf.delta(odWest, odSouth) << ":" << inf.delta(odWest, odNorth) << "\n" - << "eps l/t/r/b (left/right): " << inf.eps(odNorth, odWest) << ":" << inf.eps(odNorth, odEast) << " / \n" - << " " << inf.eps(odEast, odNorth) << ":" << inf.eps(odEast, odSouth) << " / \n" - << " " << inf.eps(odSouth, odEast) << ":" << inf.eps(odSouth, odWest) << " / " - << inf.eps(odWest, odSouth) << ":" << inf.eps(odWest, odNorth) << "\n" - << "rc: " << inf.rc(OrthoDir(0)) << "/" << inf.rc(OrthoDir(1)) << "/" << inf.rc(OrthoDir(2)) << "/" << inf.rc(OrthoDir(3)) << "\n" - << "num edges: " << inf.num_edges(OrthoDir(0)) << "/" << inf.num_edges(OrthoDir(1)) << "/" << inf.num_edges(OrthoDir(2)) - << "/" << inf.num_edges(OrthoDir(3)) << "\n" - << "num bendfree edges: " << inf.num_bend_free(OrthoDir(0)) << "/" << inf.num_bend_free(OrthoDir(1)) << "/" << inf.num_bend_free(OrthoDir(2)) - << "/" << inf.num_bend_free(OrthoDir(3)) << endl; - - return O; -} - -} //end namespace diff --git a/ext/OGDF/src/orthogonal/OrthoLayout.cpp b/ext/OGDF/src/orthogonal/OrthoLayout.cpp deleted file mode 100644 index e3ed25d74..000000000 --- a/ext/OGDF/src/orthogonal/OrthoLayout.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements planar orthogonal drawing algorithm for - * mixed-upward embedded graphs - * - * \author Carsten Gutwenger, Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -OrthoLayout::OrthoLayout() -{ - //drawing object distances - m_separation = 40.0; - m_cOverhang = 0.2; - m_margin = 40.0; - //preferred hierarchy direction - // SHOULD ACTUALLY BE odNorth, but we use odSouth since gml's are flipped! - m_preferedDir = odSouth; - m_optionProfile = 0; - //edge costs - m_costAssoc = 1;//should be set by profile - m_costGen = 4; - //align hierarchy nodes on same level - m_align = false; - //scale layout while improving it - m_useScalingCompaction = false; - m_scalingSteps = 0; - m_bendBound = 2; //bounds number of bends per edge in ortho shaper - - m_orthoStyle = 0;//0; //traditional 0, progressive 1 - -} - - -void OrthoLayout::call(PlanRepUML &PG, - adjEntry adjExternal, - Layout &drawing) -{ - // if we have only one vertex in PG ... - if(PG.numberOfNodes() == 1) { - node v1 = PG.firstNode(); - node vOrig = PG.original(v1); - double w = PG.widthOrig(vOrig); - double h = PG.heightOrig(vOrig); - - drawing.x(v1) = m_margin + w/2; - drawing.y(v1) = m_margin + h/2; - m_boundingBox = DPoint(w + 2*m_margin, h + 2*m_margin); - return; - } - - - //classify brother-to-brother hierarchy edges to allow alignment - if (m_align) - { - classifyEdges(PG, adjExternal); - }//if align - //compaction with scaling: help node cages to pass by each other - double l_orsep = m_separation; - if (m_useScalingCompaction) - { - m_scalingSteps = 6; - double scaleFactor = double(int(1 << m_scalingSteps)); - m_separation = scaleFactor*m_separation; //reduce this step by step in compaction - }//if scaling - - - //*********************************** - // PHASE 1: determine orthogonal shape - - // expand high-degree vertices and generalization mergers - PG.expand(); - - //check preconditions, currently not necessary - //assureDrawability(PG); - - // get combinatorial embedding - CombinatorialEmbedding E(PG); - E.setExternalFace(E.rightFace(adjExternal)); - - // determine orthogonal shape - OrthoRep OR; - - //OrthoFormerUML OF; - OrthoShaper OFG; - - //set some options - OFG.align(m_align); //align brother objects on hierarchy levels - OFG.traditional(m_orthoStyle > 0 ? false : true); //prefer 90/270 degree angles over 180/180 - - // New Call - OFG.setBendBound(m_bendBound); - OFG.call(PG,E,OR); - - // remove face splitter - edge e, eSucc; - for(e = PG.firstEdge(); e; e = eSucc) - { - eSucc = e->succ(); - if(PG.faceSplitter(e)) { - OR.angle(e->adjSource()->cyclicPred()) = 2; - OR.angle(e->adjTarget()->cyclicPred()) = 2; - PG.delEdge(e); - } - } - - //****************************************************************** - // PHASE 2: construction of a feasible drawing of the expanded graph - - // expand low degree vertices - PG.expandLowDegreeVertices(OR); - - OGDF_ASSERT(PG.representsCombEmbedding()); - - // restore embedding - E.computeFaces(); - E.setExternalFace(E.rightFace(adjExternal)); - - // apply constructive compaction heuristics - - OR.normalize(); - OR.dissect2(&PG); //OR.dissect(); - - OR.orientate(PG,m_preferedDir); - - // compute cage information and routing channels - OR.computeCageInfoUML(PG); - - // adjust value of cOverhang - if(m_cOverhang < 0.05) - m_cOverhang = 0.0; - if(m_cOverhang > 0.5) - m_cOverhang = 0.5; - - //temporary grid layout - GridLayoutMapped gridDrawing(PG,OR,m_separation,m_cOverhang,2); - - RoutingChannel rcGrid(PG,gridDrawing.toGrid(m_separation),m_cOverhang); - rcGrid.computeRoutingChannels(OR, m_align); - - - node v; - const OrthoRep::VertexInfoUML *pInfoExp; - forall_nodes(v,PG) { - pInfoExp = OR.cageInfo(v); - - if (pInfoExp) break; - } - - FlowCompaction fca(0,m_costGen,m_costAssoc); - - fca.constructiveHeuristics(PG,OR,rcGrid,gridDrawing); - - OR.undissect(m_align); - - // call flow compaction on grid - FlowCompaction fc(0,m_costGen,m_costAssoc); - fc.align(m_align); - fc.scalingSteps(m_scalingSteps); - - fc.improvementHeuristics(PG,OR,rcGrid,gridDrawing); - - //remove alignment edges before edgerouter call because compaction - //may do an unsplit at the nodes corners, which is impossible if - //there are alignment edges attached - if (m_align) OR.undissect(false); - - // PHASE 3: routing of edges - // - - EdgeRouter router; - MinimumEdgeDistances minDistGrid(PG, gridDrawing.toGrid(m_separation)); - //router.setOrSep(int(gridDrawing.toGrid(l_orsep))); //scaling test - router.call(PG,OR,gridDrawing,E,rcGrid,minDistGrid, gridDrawing.width(), - gridDrawing.height(), m_align); - - - String msg; - OGDF_ASSERT(OR.check(msg) == true); - - OR.orientate(pInfoExp->m_corner[odNorth],odNorth); - - //************************************************* - // PHASE 4: apply improvement compaction heuristics - - // call flow compaction on grid - fc.improvementHeuristics(PG, OR, minDistGrid, gridDrawing, int(gridDrawing.toGrid(l_orsep))); - - - // re-map result - gridDrawing.remap(drawing); - - // collapse all expanded vertices by introducing a new node in the center - // of each cage representing the original vertex - PG.collapseVertices(OR,drawing); - - // finally set the bounding box - computeBoundingBox(PG,drawing); - - m_separation = l_orsep; -}//call - - - -//----------------------------------------------------------------------------- -//Helpers -//----------------------------------------------------------------------------- -void OrthoLayout::classifyEdges(PlanRepUML &PG, adjEntry &adjExternal) -{ - //classify brother-to-brother hierarchy edges to allow alignment - //when shifting this to planrep, guarantee edge type correction in planarization - //save external face entry - - //PG.classifyEdges - //potential direct connection are all non-gen. edges that are alignUpward - edge e, eSucc; - for(e = PG.firstEdge(); e; e = eSucc) - { - eSucc = e->succ(); - if (PG.typeOf(e) != Graph::generalization) - { - adjEntry as = e->adjSource(); - node v = e->source(); - if ( (PG.alignUpward(as)) - && (PG.typeOf(e->target()) != Graph::dummy)//TODO: crossings ? - && (PG.typeOf(v) != Graph::dummy) - ) - { - edge gen1, gen2; - int stop = 0; - adjEntry runAE = as->cyclicSucc(); - edge run = runAE->theEdge(); - while ( (stop < v->degree()) && //only once - ((PG.typeOf(run) != Graph::generalization) || //search generalization - (run->source() != v) //outgoing gen - ) - ) - { - stop++; - runAE = runAE->cyclicSucc(); - run = runAE->theEdge(); - }//while - OGDF_ASSERT(stop <= v->degree()); - - //now we have the outgoing generalization (to the merger) at v - gen1 = run; - - node w = e->target(); //crossings ? - adjEntry asTwin = as->twin(); - - stop = 0; - runAE = asTwin->cyclicSucc(); - run = runAE->theEdge(); - while ( (stop < w->degree()) && - ((PG.typeOf(run) != Graph::generalization) || - (run->source() != w) - ) - ) - { - stop++; - runAE = runAE->cyclicSucc(); - run = runAE->theEdge(); - }//while - OGDF_ASSERT(stop <= w->degree()); - - //now we have the outgoing generalization (to the merger) at w - gen2 = run; - - //two possible orientations - //left to right - bool ltr = ( gen1->adjSource()->faceCycleSucc() == gen2->adjTarget() ); - //right to left - bool rtl = ( gen2->adjSource()->faceCycleSucc() == gen1->adjTarget() ); - if (ltr || rtl) //should be disjoint cases because of merger node - { - PG.setBrother(e); - - //now check if the embedding does include unnecessary nodes in the slope - if (ltr) - { - //there are edges between e and gen2 at target - if (!(e->adjTarget()->faceCyclePred() == gen2->adjTarget())) - { - OGDF_ASSERT(v != e->target()); - PG.moveAdj(e->adjTarget(), before, gen2->adjTarget()->twin()); - } - //there are edges between e and gen1 at source - if (!(e->adjTarget()->faceCycleSucc() == gen1->adjSource())) - { - //test if we discard the outer face entry - if (adjExternal == e->adjSource()) - { - adjExternal = e->adjSource()->faceCyclePred(); - } - PG.moveAdj(e->adjSource(), after, gen1->adjSource()); - } - }//if gen 1 left of gen 2 - if (rtl) - { - //there are edges between e and gen2 at target - if (!(e->adjSource()->faceCycleSucc() == gen2->adjSource())) - { - //test if we discard the outer face entry - if (adjExternal == e->adjTarget()) - { - adjExternal = e->adjTarget()->faceCycleSucc(); - } - PG.moveAdj(e->adjTarget(), after, gen2->adjSource()); - } - //there are edges between e and gen1 at source - if (!(e->adjSource()->faceCyclePred() == gen1->adjTarget())) - { - PG.moveAdj(e->adjSource(), before, gen1->adjSource()); - } - - }//if gen 2 left of gen 1 - }//if - else PG.setHalfBrother(e); - - }//if upward edge - }//if not generalization - }//for -}//classifyedges - - - -// compute bounding box and move final drawing such that it is 0 aligned -// respecting margins -void OrthoLayout::computeBoundingBox( - const PlanRepUML &PG, - Layout &drawing) -{ - double minX, maxX, minY, maxY; - - minX = maxX = drawing.x(PG.firstNode()); - minY = maxY = drawing.y(PG.firstNode()); - - node v; - forall_nodes(v,PG) - { - double x = drawing.x(v); - if (x < minX) minX = x; - if (x > maxX) maxX = x; - - double y = drawing.y(v); - if (y < minY) minY = y; - if (y > maxY) maxY = y; - } - - double deltaX = m_margin - minX; - double deltaY = m_margin - minY; - - forall_nodes(v,PG) - { - drawing.x(v) += deltaX; - drawing.y(v) += deltaY; - } - - m_boundingBox = DPoint(maxX+deltaX+m_margin, maxY+deltaY+m_margin); -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/orthogonal/OrthoRep.cpp b/ext/OGDF/src/orthogonal/OrthoRep.cpp deleted file mode 100644 index d5e69c41d..000000000 --- a/ext/OGDF/src/orthogonal/OrthoRep.cpp +++ /dev/null @@ -1,1238 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of classes BendString and OrthoRep. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - - -//TODO: Verknuepfe Uebergabe von PlanRep in dissect mit option align -//in undissect, denn nur so koennen Hierarchien korrekt erkannt werden - - -namespace ogdf { - - -//--------------------------------------------------------- -// BendString -// represents the bends on an edge e consisting of vertical -// and horizontal segments -//--------------------------------------------------------- - -// initializes bends string to a given C-string -void BendString::init(const char *str) -{ -#ifdef OGDF_DEBUG - const char *q; - for(q = str; *q; ++q) - OGDF_ASSERT(*q == '0' || *q == '1'); -#endif - - m_len = strlen(str); - if (m_len > 0) - { - m_pBend = new char[m_len+1]; - char *p = m_pBend; - while ((*p++ = *str++) != 0) ; - - } else - m_pBend = 0; -} - - -// initializes bends string to the string consoisting of n c's -void BendString::init(char c, size_t n) -{ - OGDF_ASSERT(c == '0' || c == '1'); - - m_len = n; - if (n > 0) - { - m_pBend = new char[n+1]; - m_pBend[n] = 0; - do - m_pBend[--n] = c; - while(n > 0); - } - else - { - m_pBend = 0; - } -} - - -// initializes bends string to a copy of bs -void BendString::init(const BendString &bs) -{ - m_len = bs.m_len; - - if (m_len == 0) { - m_len = 0; - m_pBend = 0; - - } else { - m_pBend = new char[m_len+1]; - char *p = m_pBend; - const char *str = bs.m_pBend; - while ((*p++ = *str++) != 0) ; - } -} - - - -//--------------------------------------------------------- -// OrthoRep -// orthogonal representation of an embedded graph -//--------------------------------------------------------- - -// constructor -OrthoRep::OrthoRep(CombinatorialEmbedding &E) : m_pE(&E), m_angle(E,0), - m_bends(E) -{ - m_preprocess = true; - m_pattern2 = true; -} - - -// initialization function; performs actual construction -void OrthoRep::init(CombinatorialEmbedding &E) -{ - m_pE = &E; - m_angle.init(E,0); - m_bends.init(E); - m_preprocess = true; - m_pattern2 = true; -} - - -// The check function below tests if the current OrthoRep instance really -// represents a correct orthogonal representation, i.e., it tests if -// * the associated graph is embedded. -// * the external face of the embedding is set -// * the sum of the angles at each vertex is 4 -// * if corresponding bend strings are consistent, that is, if e has -// adj. entries adjSrc and adjTgt, then the bend string of adjTgt -// is the string obtained from bend string of adjSrc by reversing the -// sequence and flipping the bits -// * the shape of each face is rectagonal, i.e., if -// #zeros(f) - #ones(f) - 2|f| + sum of angles at vertices in f -// is 4 if f is an internal face or -4 if f is the external face. -bool OrthoRep::check(String &error) -{ - const Graph &G = (Graph&) *m_pE; - - // is the associated graph embedded ? - if (G.representsCombEmbedding() == false) { - error = "Graph is not embedded!"; - return false; - } - - // sum of angles at each vertex equals 4 ? - node v; - forall_nodes(v,G) - { - int sumAngles = 0; - adjEntry adj; - forall_adj(adj,v) - sumAngles += angle(adj); - if(sumAngles != 4) { - error.sprintf("Angle sum at vertex %d is %d.", - v->index(), sumAngles); - return false; - } - } - - // corresponding bend strings are consistent ? - edge e; - forall_edges(e,G) - { - const BendString &bs1 = bend(e->adjSource()); - const BendString &bs2 = bend(e->adjTarget()); - - if (bs1.size() != bs2.size()) { - error.sprintf( - "Size of corresponding bend strings at edge %d differ!", - e->index()); - return false; - } - - size_t i = 0, j = bs2.size()-1; - while(i < bs1.size()) { - if (bs1[i] != flip(bs2[j])) { - error.sprintf( - "Corresponding bend strings at edge %d not consistent!", - e->index()); - return false; - } - ++i; --j; - } - } - - - // external face set ? - if (m_pE->externalFace() == 0) { - error = "External face is not set!"; - return false; - } - - // is shape of each face rectagonal ? - face f; - forall_faces(f,*m_pE) - { - int rho = 0; - - adjEntry adj; - forall_face_adj(adj,f) { - const BendString &bs = bend(adj); - int zeroes = 0, ones = 0; - for(size_t i = 0; i < bs.size(); ++i) { - switch (bs[i]) - { - case '0': - zeroes++; break; - case '1': - ones++; break; - default: - error.sprintf("bend string of adjacency entry %d contains \ -illegal character!", adj->index()); - return false; - } - } - - rho += zeroes - ones + 2 - angle(adj); - } - - if (rho != ((f == m_pE->externalFace()) ? -4 : 4)) { - error.sprintf("Shape of face %d not rectagonal!", f->index()); - return false; - } - } - - - return true; -} - - -// normalizes an orthogonal representation, i.e., replaces each bend -// by a dummy vertex and updates the embedding as well as the orthogonal -// representation -void OrthoRep::normalize() -{ - const Graph &G = (Graph &) *m_pE; - - edge e; - forall_edges(e,G) - { - // store current bend string in bs - BendString bs(m_bends[e->adjSource()]); - const char *str = bs.toString(); - if (str == 0) continue; - - m_bends[e->adjSource()].set(); - m_bends[e->adjTarget()].set(); - - // for each bend in bs, introduce a new vertex by splitting - for(; *str; ++str) - { - edge ePrime = m_pE->split(e); - m_angle[ePrime->adjTarget()] = m_angle[e->adjTarget()]; - - if(*str == '0') { - m_angle[ePrime->adjSource()] = 1; - m_angle[e ->adjTarget()] = 3; - - } else { - m_angle[ePrime->adjSource()] = 3; - m_angle[e ->adjTarget()] = 1; - } - } - - } -} - - -// checks if each bends string is empty -bool OrthoRep::isNormalized() const -{ - const Graph &G = (Graph &) *m_pE; - - edge e; - forall_edges(e,G) - { - if (m_bends[e->adjSource()].size() != 0) - return false; - if (m_bends[e->adjTarget()].size() != 0) - return false; - } - - return true; -} - - - -// Procedure dissect() modifies the orthogonal representation by splitting -// edges and faces until no more rectangular ears are contained. A rectangular -// ear consists of two 90 degree angles with only 180 degree angles inbetween. -// -// More exactly, each internal face has rectangular shape afterwards. For the -// external face, we guarantee only the absence of rectangular ears. -// -// Precondition: The orthogonal representation is normalized and contains -// no 0 degree angles -void OrthoRep::dissect() -{ - // dissect() requires a normalized orthogonal representation - OGDF_ASSERT(isNormalized()); - - CombinatorialEmbedding &E = *m_pE; - Graph &G = E; - - // assert that dissect hasn't been called before - OGDF_ASSERT(m_splitNodes.empty()); - m_dissectionEdge.init(G,false); - - adjEntry saveExt = E.externalFace()->firstAdj(); //should check supersink - m_adjExternal = saveExt; - - face f; - forall_faces(f, E) - { - // dissect face f - - // We build the list faceCycle consisting of all adjacency entries - // that do not form a 180 degree angle with their successors - // (180 degree angles do not contribute to the shape of the face) - List faceCycle; - - adjEntry adj; - forall_face_adj(adj,f) { - // dissection does not work for graphs with 0 degree angles! - OGDF_ASSERT(m_angle[adj] != 0); - if (m_angle[adj] != 2) - faceCycle.pushBack(adj); - } - - // We iterate over faceCycle and look for occurrences of two - // consecutive 90 degree angles - ListIterator it;; - for(it = faceCycle.begin(); faceCycle.size() > 4 && it.valid(); ++it) - { - if (m_angle[*it] == 1 && m_angle[*faceCycle.cyclicPred(it)] == 1) - { - // now we run backwards and look for angles >= 270 degree. We - // can eliminate such angles as long as the following two - // angles (faceCycle is seen as cyclic list) are 90 degree. - ListIterator itBack = - faceCycle.cyclicPred(faceCycle.cyclicPred(it)); - - // Look for the next angle >= 270 degree. - // We will find one since faceCylce has at least two elements - // Note: For each 90 degree angle we have to skip we can - // eliminate one more angle >= 270 degree. - - // if we did not find a >= 270 degree angle until it, the - // face must be a rectangle and faceCycle consists of four 90 - // degree angles. Hence, we terminate also the for-loop above! - while(it != itBack) - { - // If we see a 90 degree angle, we move further backwards - if(m_angle[*itBack] < 3) { - itBack = faceCycle.cyclicPred(itBack); - continue; - } - - ListIterator itBackSucc = - faceCycle.cyclicSucc(itBack); - - // If we see a >= 270 degree angle whose successor is it, - // we do not have a rectangular ear anymore, so we break. - // We then have processed all >= 270 degree angles behind - // it - if(itBackSucc == it) - break; - - adjEntry &adjSplit = *faceCycle.cyclicSucc(itBackSucc); - // We now have the following situation: - // The rectangular ear (pattern 100) consists of - // *itBack -> *itBackSucc -> adjSplit - - // Since a split operation can also change the id's of the - // adjacency entries at the edge, we have to backup two - // angles a1 and a2. - int a1 = m_angle[adjSplit]; - adjEntry adj2 = adjSplit->twin(); - int a2 = m_angle[adj2]; - - // We split *itBackSuccSucc ... - node u = E.split(adjSplit->theEdge())->source(); - if (m_dissectionEdge[adjSplit] == false) - m_splitNodes.push(u); - adjEntry adjSplitSucc = adjSplit->faceCycleSucc(); - // and close a rectangular face - edge eDissect = E.splitFace(*itBack, adjSplitSucc); - m_dissectionEdge[eDissect] = true; - - // restore backup angles - m_angle[adjSplit] = a1; - m_angle[adj2] = a2; - - // set angles at the split node - m_angle[adjSplitSucc] = 1; - m_angle[adjSplitSucc->cyclicSucc()] = 1; - m_angle[adjSplitSucc->cyclicPred()] = 2; - - adjEntry adjSucc = (*itBack)->cyclicSucc(); - if (m_angle[*itBack] == 4) { - // If the former >= 270 degree angle was 360 degree, - // we keep it as 270 degree angle ... - m_angle[*itBack] = 1; - m_angle[adjSucc] = 3; - *itBack = adjSucc; - - } else { - // ... otherwise, it is now a 180 degree angle and - // we remove it - m_angle[*itBack] = 1; - m_angle[adjSucc] = 2; - - ListIterator itDel = itBack; - itBack = faceCycle.cyclicPred(itBack); - faceCycle.del(itDel); - } - - // The other edge (not adjSplit) which resulted from the - // split edge operation is contained in the face we - // consider - adjSplit = adjSplitSucc; - - // This 90 degree angle vanishes from our face - faceCycle.del(itBackSucc); - } - } - } - } -} - - -//artificial node saving test****************************************************** -//gunnars vorschlag: segment saving -void OrthoRep::dissect2(PlanRepUML* PG) -{ - String msg; - m_adjAlign = 0; - // dissect() requires a normalized orthogonal representation - OGDF_ASSERT(isNormalized()); - - CombinatorialEmbedding &E = *m_pE; - Graph &G = E; - - // assert that dissect hasn't been called before - OGDF_ASSERT(m_splitNodes.empty()); - m_dissectionEdge.init(G,false); - m_alignmentEdge.init(G, false); - - m_adjExternal = E.externalFace()->firstAdj(); - - face f; - forall_faces(f, E) - { - // dissect face f - - // We build the list faceCycle consisting of all adjacency entries - // that do not form a 180 degree angle with their successors - // (180 degree angles do not contribute to the shape of the face) - List faceCycle; - - adjEntry adj; - forall_face_adj(adj,f) { - // dissection does not work for graphs with 0 degree angles! - OGDF_ASSERT(m_angle[adj] != 0); - if (m_angle[adj] != 2) - faceCycle.pushBack(adj); - } - //PREPROCESSING - // some of the preprocessing steps could be mixed or used iteratively - //is it better to mix? or to iterate? pattern1 and pattern2 don't mess with - //each other - bool change = true; - - while (change) - { - change = false; - //preprocessing: we look for 311113 angle patterns and replace them by inserting an edge - //between the two angle 3 adjacencies, thought for generalization merger / son nodes - //if parameter PG is set, we use the type info to set some dissection edges as - //alignment edges - //in the case of m_align we have to take care of the situation that the adjExternal - //lies in the cut ear, which is an error in the improvement compaction steps - if (m_preprocess) - { - ListIterator prit; - - //only run until no more patterns left - //and dont iterate over the face, only check this one time - //int prerun = 0; - //prit = faceCycle.begin(); - //while ( prit.valid() && (prerun < faceCycle.size() + 1)) - //check if possible - ListIterator itEnd, itStart, it1one, it1two, it1three, it1four; //pattern defining edges - //take care of prit, it will be deleted - for (prit = faceCycle.begin(); prit.valid() && (faceCycle.size()>7); prit++) //go clockwise around face!? - { - itEnd = prit; //search pattern backwards - if (m_angle[*itEnd] != 3) continue; - it1four = faceCycle.cyclicPred(itEnd); - if (m_angle[*it1four] != 1) continue; - it1three = faceCycle.cyclicPred(it1four); - if (m_angle[*it1three] != 1) continue; - it1two = faceCycle.cyclicPred(it1three); - if (m_angle[*it1two] != 1) continue; - it1one = faceCycle.cyclicPred(it1two); - if (m_angle[*it1one] != 1) continue; - itStart = faceCycle.cyclicPred(it1one); - if (m_angle[*itStart] != 3) continue; - - //PATTERN FOUND - // we proudly present the pattern we searched for - //now we insert the new dissection edge, delete the entries in faceCycle, - //and set the angles accordingly - - //take care of the special alignment situation where alignment edges - //are kept during compaction - if ( ( (m_adjExternal == (*itEnd)) || - (m_adjExternal == (*it1four)) || - (m_adjExternal == (*it1three)) || - (m_adjExternal == (*it1two)) || - (m_adjExternal == (*it1one)) || - (m_adjExternal == (*itStart)) - ) - || - ( (m_adjAlign == (*itEnd)) || - (m_adjAlign == (*it1four)) || - (m_adjAlign == (*it1three)) || - (m_adjAlign == (*it1two)) || - (m_adjAlign == (*it1one)) || - (m_adjAlign == (*itStart)) - ) - ) - //check: is itEnd appropriate? - m_adjAlign = (*itEnd);//->faceCycleSucc(); - - adjEntry& adEnd = *itEnd; - adjEntry& adStart = *itStart; - //split the face between two corners - edge eDissect = E.splitFace(adStart, adEnd); - - //alignment part - if (PG != 0) - { - if ( (PG->typeOf((*it1two)->theEdge()->source()) == Graph::generalizationExpander) && - (PG->typeOf((*it1two)->theEdge()->target()) == Graph::generalizationExpander)) - m_alignmentEdge[eDissect] = true; - }//if Pg - m_dissectionEdge[eDissect] = true; - - change = true; - //if (PG) PG->typeOf(e) = Graph::dissect; - - //set the angles, old values 3 are divided - m_angle[adEnd] = 1; - m_angle[adStart] = 2; - m_angle[adStart->cyclicSucc()] = 1; //new edge entry from start to end - m_angle[adEnd->cyclicSucc()] = 2; //new edge entry from end to start - //we dont have any angles > 2 left, so delete some participants - //Start and all itone are out of the face in the new rectangle - faceCycle.del(it1four); - faceCycle.del(it1three); - faceCycle.del(it1two); - faceCycle.del(it1one); - //do not delete itStart, copy the new edges entry to this position - //faceCycle.del(itStart); - adStart = adStart->cyclicSucc();//use reference - //itEnd stays with angle value 1 - - OGDF_ASSERT_IF(dlConsistencyChecks,check(msg)); - }//for - }//preprocessing pattern1 - //if (m_people) - //we search for a 3111 pattern - if (m_pattern2) - { - ListIterator prit, savenext; - - //only run until no more patterns left - //and dont iterate over the face, only check this one time - //check if possible - ListIterator it1Top, itTopSucc, it1Back, it1Base, it3Start; //pattern defining edges - //take care of prit, it will be deleted - savenext = faceCycle.begin(); - for (prit = faceCycle.begin(); (prit.valid() && savenext.valid()) && (faceCycle.size()>6); (prit = savenext)) //go clockwise around face!? - { - savenext++; - itTopSucc = prit; //search pattern backwards - it1Top = faceCycle.cyclicPred(itTopSucc); - if (m_angle[*it1Top] != 1) continue; - it1Back = faceCycle.cyclicPred(it1Top); - if (m_angle[*it1Back] != 1) continue; - it1Base = faceCycle.cyclicPred(it1Back); - if (m_angle[*it1Base] != 1) continue; - it3Start = faceCycle.cyclicPred(it1Base); - if (m_angle[*it3Start] != 3) continue; - - //first version - if (m_angle[*itTopSucc] < 2) continue; - - // we proudly present the pattern we searched for - //now we insert the new dissection edge, delete the entries in faceCycle, - //and set the angles accordingly - - adjEntry& adEnd = *itTopSucc; - adjEntry& adStart = *it3Start; - //split the face between two corners - edge eDissect = E.splitFace(adStart, adEnd); - - m_dissectionEdge[eDissect] = true; - - change = true; - //if (PG) PG->typeOf(e) = Graph::dissect; - - //set the angles, old values 3 are divided - m_angle[adEnd] = m_angle[adEnd] - 1; - m_angle[adStart] = 2; - m_angle[adStart->cyclicSucc()] = 1; //new edge entry from start to end - m_angle[adEnd->cyclicSucc()] = 1; //new edge entry from end to start - //we dont have any angles > 2 left, so delete some participants - //Start and all itone are out of the face in the new rectangle - faceCycle.del(it1Top); - faceCycle.del(it1Back); - faceCycle.del(it1Base); - //do not delete itStart, copy the new edges entry to this position - //faceCycle.del(itStart); - adStart = adStart->cyclicSucc();//use reference - //check if itEnd stays - if (m_angle[adEnd] == 2) - { - faceCycle.del(itTopSucc); - }//if - - //OGDF_ASSERT(check(msg)); - }//for - }//pattern2 - - - }//iterate pattern search - //search for ears in connection between two cages and fill them in a preprocessing - //step to avoid the separation, works only in combination with segment-saving - //and if PlanRep-ifnormation is known, maybe use degree1-simplification - if (PG != 0) - { - ListIterator prit, savenext; - //check if possible - ListIterator itEnd, itEar, itHead, itToe; //pattern defining edges - //take care of prit, it will be deleted - savenext = faceCycle.begin(); - - //if (PG->original((*savenext)->theNode()) != 0) - //cout << "Knotengraeder: " << PG->original((*savenext)->theNode())->degree() << "\n" << flush; - - for (prit = faceCycle.begin(); (prit.valid() && savenext.valid()) && (faceCycle.size()>5); (prit = savenext)) //go clockwise around face!? - { - savenext++; - //es bleibt herauszufinden, in welcher reihenfolge die kanten ohnehin korrekt - //durchlaufen werden, dann die andere nehmen - itEnd = prit; //search pattern backwards - //if (m_angle[*itEnd] != 3) continue; //nur in einer Richtung - itHead = faceCycle.cyclicPred(itEnd); - if (m_angle[*itHead] != 1) continue; - itEar = faceCycle.cyclicPred(itHead); - if (m_angle[*itEar] != 1) continue; - itToe = faceCycle.cyclicPred(itEar); - if (m_angle[*itToe] != 3) continue; //andersherum anders - - - node ov = PG->expandedNode( (*itEar)->theNode() ); - if (ov == 0) continue; - ov = PG->original( ov ); - if (ov == 0) continue; - //cout<<"Grad ist "<original( PG->expandedNode( (*itEar)->theNode() ) )->degree()<<"\n"<expandedNode( (*itHead)->theNode() ); - if (ov2 == 0) continue; - ov2 = PG->original( ov2 ); - if (ov2 == 0) continue; - //cout<<"Grad ist "<original( PG->expandedNode( (*itEar)->theNode() ) )->degree()<<"\n"<degree() != 1) && (ov->degree() != 1) ) continue; - ///if ( PG->typeOf((*itEar)->theEdge()) == -1) continue; - //I dropped this classification due to dirty programmed edge type decision - //if not ass it is gen.... - // we proudly present the pattern we searched for - //now we insert the new dissection edge, delete the entries in faceCycle, - //and set the angles accordingly - //cout<<"FOUND PATTERN \n\n"; - //adjEntry& adEnd = *itEnd; - adjEntry& adHead = *itHead; - adjEntry& adToe = *itToe; - adjEntry adjHeadSucc; - adjEntry adj2; - - adjHeadSucc = adHead->faceCycleSucc(); - - int a1 = m_angle[adjHeadSucc]; - int a2; - //bool splitted = false; - edge eDissect; - node u; - - //cout<<"PRE2splitting: head "<twin()<<"\n"; - //cout<<"Winkel: "<twin()]<<"\n"; - //Hier noch einfuegen: natuerlich muss head.fcsucc statt faceCycle.succ getestet werden, da auch 180 Grad zulaessig - - //if (m_angle[*itEnd] != 1) - if (m_angle[adjHeadSucc] != 1) - { - //split the face between two corners - eDissect = E.splitFace(adToe, adjHeadSucc); - //if (PG) PG->typeOf(e) = Graph::dissect; - //hier koennte man highprio type gen setzen - m_angle[adjHeadSucc] = a1 - 1; - m_angle[adjHeadSucc->cyclicSucc()] = 1; //new edge entry from end to start - if (m_angle[adjHeadSucc] == 1) adHead = adjHeadSucc; - else faceCycle.del(itHead); - if (m_angle[adjHeadSucc] == 2) faceCycle.del(itEnd); //it must have been in list - } - else - { - - //split edge - a1 = m_angle[adHead]; - adj2 = adHead->twin(); - a2 = m_angle[adj2]; - - edge savee = adHead->theEdge(); - bool wasDissected = m_dissectionEdge[savee]; - bool wasAlign = m_alignmentEdge[savee]; - Graph::EdgeType savetype; - if (PG) savetype = PG->typeOf(adHead->theEdge()); - edge se = E.split(adHead->theEdge()); - if (PG) PG->typeOf(se) = savetype; - adjHeadSucc = adHead->faceCycleSucc(); - //cout<<"headsucc: "<source(); - //cout<<"Neuer Knoten: "<cyclicPred()<<" "<<2<<"\n"; - //cout<<"restore: headsucccyclicSucc"<cyclicSucc()<<" "<<1<<"\n"; - // restore backup angles - m_angle[adHead] = a1; //alter Winkel unten - m_angle[adj2] = a2; //alter winkel oben - m_angle[adjHeadSucc] = 1; //Winkel oben zu neuer Kante - m_angle[adjHeadSucc->cyclicPred()] = 2; - m_angle[adjHeadSucc->cyclicSucc()] = 1; - adHead = adjHeadSucc; - - }//else - //cout<<"inserted edge "<cyclicSucc()] = 2; //new edge entry from start to end - m_angle[adToe] = 1; - - //we dont have any angles > 2 left, so delete some participants - faceCycle.del(itEar); - faceCycle.del(itToe); - //do not delete itStart, copy the new edges entry to this position - //if (splitted) - - //OGDF_ASSERT(check(msg)); - - }//for - }//preprocessing 2 - - - // We iterate over faceCycle and look for occurrences of two - // consecutive 90 degree angles - ListIterator it; - int runcount = 0; //check progress - it = faceCycle.begin(); - while ((faceCycle.size() > 4) && it.valid() && (runcount <= 2*faceCycle.size())) - { - - if (m_angle[*it] == 1 && m_angle[*faceCycle.cyclicPred(it)] == 1) - { - runcount = 0; //start it over again - // now we run backwards and look for angles >= 270 degree. We - // can eliminate such angles as long as the following two - // angles (faceCycle is seen as cyclic list) are 90 degree. - ListIterator itBack = - faceCycle.cyclicPred(faceCycle.cyclicPred(it)); - - // Look for the next angle >= 270 degree. - // We will find one since faceCylce has at least two elements - // Note: For each 90 degree angle we have to skip we can - // eliminate one more angle >= 270 degree. - - // if we did not find a >= 270 degree angle until it, the - // face must be a rectangle and faceCycle consists of four 90 - // degree angles. Hence, we terminate also the while-loop above! - while((it != itBack) && (faceCycle.size() > 4)) - { - if ((m_angle[*it] != 1) || (m_angle[*faceCycle.cyclicPred(it)] != 1)) break; - - // If we see a 90 degree angle, we move further backwards - if( m_angle[*itBack] < 3) { - itBack = faceCycle.cyclicPred(itBack); - continue; - } - - ListIterator itBackSucc = - faceCycle.cyclicSucc(itBack); - - // If we see a >= 270 degree angle whose successor is it, - // we do not have a rectangular ear anymore, so we break. - // We then have processed all >= 270 degree angles behind - // it - //if (itBackSucc == it) - // break; - - adjEntry &adjSplit = *faceCycle.cyclicSucc(itBackSucc); - ListIterator itsplit = faceCycle.cyclicSucc(itBackSucc); - // We now have the following situation: - // The rectangular ear (pattern 100) consists of - // *itBack -> *itBackSucc -> adjSplit - - - // Since a split operation can also change the id's of the - // adjacency entries at the edge, we have to backup two - // angles a1 and a2. - int a1 = m_angle[adjSplit]; - adjEntry adj2 = adjSplit->twin(); - int a2 = m_angle[adj2]; - - //hier nur splitten, falls noetig, aber testen, ob es in der Reihenfolge - //Probleme macht, wenn man auch fuer 180 Grad, die nicht im cycle sind, nicht splittet - //save the angle - int earSlope = m_angle[adjSplit->faceCycleSucc()]; - //the target node of the split operation - node u; - bool savevertex = (earSlope >= 2); //should be >= 2, but 2 not in cycle - ListIterator itsucc; - //check if we cant save a bend - if (!savevertex) - { - // We split *itBackSuccSucc ... - - edge savee = adjSplit->theEdge(); - bool wasDissected = m_dissectionEdge[savee]; - bool wasAlign = m_alignmentEdge[savee]; - - edge se = E.split(adjSplit->theEdge()); - - u = se->source(); - //die neue Kante erhaelt adj, ist aber adjSplit, also immer false?Nein, aber nicht korrekt - //order problem: first delete disection edges, then unsplit, but what if split(dissection) - if (m_dissectionEdge[adjSplit] == false) - m_splitNodes.push(u); - if (wasDissected) m_dissectionEdge[se] = true; - if (wasAlign) m_alignmentEdge[se] = true; - } - else - { - u = (adjSplit->faceCycleSucc())->theNode(); //use this node instead - itsucc = faceCycle.cyclicSucc(faceCycle.cyclicSucc(itBackSucc)); - //cout<<"we will save a vertex\n"<faceCycleSucc(); - //if (savevertex) OGDF_ASSERT(adjSplitSucc == *itsucc);//doesnt work with 180 degree - // and close a rectangular face - edge eDissect = E.splitFace(*itBack, adjSplitSucc); - m_dissectionEdge[eDissect] = true; - - //cout<<"inserted new edge "<cyclicSucc()<<" : "<<1<<"\n"<cyclicSucc()] = 1; - //m_angle[adjSplitSucc->cyclicPred()] = 2; - //Achtung, geht nur, wenn nicht vorher 180, sonst abhaengig von u.U. v. dritter Kante abziehen - //spaeter zusammenlegen - if (!savevertex) - if (earSlope != 4) //already has new value - m_angle[adjSplitSucc->cyclicPred()] = 4 - 1 - m_angle[adjSplitSucc]; - //if (savevertex && (earSlope == 2)) m_angle[adjSplitSucc->cyclicPred()] = ??? - - adjEntry adjSucc = (*itBack)->cyclicSucc(); - if (m_angle[*itBack] == 4) { - // If the former >= 270 degree angle was 360 degree, - // we keep it as 270 degree angle ... - m_angle[*itBack] = 1; - m_angle[adjSucc] = 3; - *itBack = adjSucc; - - } else { - // ... otherwise, it is now a 180 degree angle and - // we remove it - m_angle[*itBack] = 1; - m_angle[adjSucc] = 2; - - ListIterator itDel = itBack; - itBack = faceCycle.cyclicPred(itBack); - if (it == itDel) - { - it = faceCycle.cyclicSucc(it); shiftedit = true; - //cout<<"shifted it to "<<*it<<"\n"<succ(); - if (m_dissectionEdge[e] == true) { - - if (!(align && m_alignmentEdge[e])) - { - // angles at source and target node are joined ... - adjEntry adjSrc = e->adjSource(); - m_angle[adjSrc->cyclicPred()] += m_angle[adjSrc]; - - adjEntry adjTgt = e->adjTarget(); - m_angle[adjTgt->cyclicPred()] += m_angle[adjTgt]; - - // ... when dissection edge is removed - node sv = adjSrc->theNode(); - node tv = adjTgt->theNode(); - - G.delEdge(e); - //remember that sv and tv are not allowed to be in splitNodes, see dissect - if (sv->degree() == 0) G.delNode(sv); - if (tv->degree() == 0) G.delNode(tv); - }//if - }//if - }//for - // free allocated memory - if (!align) m_dissectionEdge.init(); - - //alignment edges never split - // unsplit remaining split nodes - while(!m_splitNodes.empty()) - { - G.unsplit(m_splitNodes.pop()); - } - - // recompute list of faces and restore external face - m_pE->computeFaces(); - - //may be the external face is still in the alignment part - if (align && (m_adjAlign != 0)) - { - m_pE->setExternalFace(m_pE->rightFace(m_adjAlign)); - //m_adjAlign = 0; - } - else m_pE->setExternalFace(m_pE->rightFace(m_adjExternal)); - - //ofstream out("c:\\outerface.txt"); - //out<<"Aeusseres Face: \n"; - //adjEntry eo = m_pE->externalFace()->firstAdj(); - //adjEntry stop = eo; - //do - //{ - // out<faceCycleSucc(); - //} while (eo!=stop); -}//undissect - - - -// assigns consistent directions (vertical or horizontal) to adj. entries -void OrthoRep::orientate() -{ - orientate(m_pE->getGraph().firstEdge()->adjSource(), odWest); -} - - -// assigns consistent directions to adj. entries such that most -// generalizations are directed in preferedDir -void OrthoRep::orientate(const PlanRep &PG, OrthoDir preferedDir) -{ - // assign an arbitrary orientation - orientate(); - - // count how many adjacency entries are orientated in a direction - Array num(0,3,0); - edge e; - forall_edges(e,PG) { - if (PG.typeOf(e) == Graph::generalization) - ++num[m_dir[e->adjSource()]]; - } - - // find direction with maximum number - int maxDir = 0; - for(int i = 1; i < 4; ++i) - if (num[i] > num[maxDir]) - maxDir = i; - - // rotate directions by (preferedDir - maxDir) - rotate(preferedDir - maxDir); - //orientate(PG.firstEdge()->adjSource(),m_dir[PG.firstEdge()->adjSource()]); -} - - -// assigns consistent directions (vertical or horizontal) to adj. entries, -// assigning dir to adj (this fixes all others!) -void OrthoRep::orientate(adjEntry adj, OrthoDir dir) -{ - OGDF_ASSERT(isNormalized()); - OGDF_ASSERT(adj != 0); - OGDF_ASSERT( - dir == odEast || dir == odWest || dir == odNorth || dir == odSouth - ); - - const Graph &G = (Graph &) *m_pE; - - m_dir.init(G, odUndefined); - - orientateFace(adj, dir); -} - - -void OrthoRep::orientateFace(adjEntry adj, OrthoDir dir) -{ - // We run only till the next already processed adj. entry, potentially - // not around the whole face. This is important for linear runtime - while (m_dir[adj] == odUndefined) - { - m_dir[adj] = dir; - - adj = adj->twin(); - - dir = oppDir(dir); - if (m_dir[adj] == odUndefined) - orientateFace(adj, dir); - - // orientation changes at 90 and 270 degree angles - dir = OrthoDir((dir + m_angle[adj]) & 3); - - // next adjacency entry in the face - adj = adj->cyclicSucc(); - } -} - - -// rotate directions of adjacency entries by r -void OrthoRep::rotate(int r) -{ - const Graph &G = (Graph &) *m_pE; - - if (r < 0) { - r = r + (-r / 4 + 1) * 4; - } - - edge e; - forall_edges(e,G) { - m_dir[e->adjSource()] = - OrthoDir((m_dir[e->adjSource()] + r) & 3); - - m_dir[e->adjTarget()] = - OrthoDir((m_dir[e->adjTarget()] + r) & 3); - } -} - - -// computes further information about cages which are collected in class -// VertexInfoUML -void OrthoRep::computeCageInfoUML( - const PlanRep &PG) -{ - OGDF_ASSERT(&(const Graph &)PG == &m_pE->getGraph()); - - if (m_umlCageInfo.valid()) - freeCageInfoUML(); - - m_umlCageInfo.init(PG,0); - - node v; - forall_nodes(v,PG) - { - adjEntry adj = PG.expandAdj(v); - - if (adj == 0) continue; - - m_umlCageInfo[v] = OGDF_NEW VertexInfoUML; - VertexInfoUML &vi = *m_umlCageInfo[v]; - - adjEntry adjSucc = adj->faceCycleSucc(); - - // look for a corner such that the while-loop below starts by - // considering adjacency entry adj at the beginning of a side - while(m_dir[adj] == m_dir[adjSucc]) { - adj = adjSucc; - adjSucc = adj->faceCycleSucc(); - } - - int nCorners = 0; - int attSide = 0; - while(nCorners < 4) { - adj = adjSucc; - adjSucc = adj->faceCycleSucc(); - - // reached a corner ? - if(m_dir[adj] != m_dir[adjSucc]) { - ++nCorners; - attSide = 0; - vi.m_corner[m_dir[adjSucc]] = adjSucc; - - } else { - adjEntry adjAttached = adjSucc->cyclicPred(); - edge eAttached = adjAttached->theEdge(); - - if (PG.typeOf(eAttached) == Graph::generalization) { - vi.m_side[m_dir[adj]].m_adjGen = adjAttached; - ++attSide; - } else if (PG.original(eAttached) != 0) { - vi.m_side[m_dir[adj]].m_nAttached[attSide]++; - } - } - } - } -} - - -void OrthoRep::freeCageInfoUML() -{ - if( !m_umlCageInfo.valid() ) return; - - const Graph &G = (Graph &) *m_pE; - - node v; - forall_nodes(v,G) { - delete m_umlCageInfo[v]; - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/orthogonal/OrthoShaper.cpp b/ext/OGDF/src/orthogonal/OrthoShaper.cpp deleted file mode 100644 index 44b4509d3..000000000 --- a/ext/OGDF/src/orthogonal/OrthoShaper.cpp +++ /dev/null @@ -1,1746 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes the Orthogonal Representation of a Planar - * Representation of a UML Graph. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - - -const int flowBound = 4; //cant have more than 4 bends in cage boundary, not > 360 degree - -enum netArcType {defaultArc, angle, backAngle, bend}; - -namespace ogdf { - - -//************************************************************* -//call function: compute a flow in a dual network and interpret -//result as bends and angles (representation shape) -void OrthoShaper::call(PlanRepUML &PG, - CombinatorialEmbedding &E, - OrthoRep &OR, - bool fourPlanar) -{ - const bool angleMaxBound = true; - const bool angleMinBound = false; - - if (PG.numberOfEdges() == 0) - return; - - m_fourPlanar = fourPlanar; - - - // the min cost flow we use - MinCostFlowReinelt flowModule; - const int infinity = flowModule.infinity(); - - - //************************************************************ - //fix some values depending on traditional or progressive mode - //************************************************************ - //Progressive: Fluss/Winkel Werte: - // Grad, v->f, f->v - // 0 , 2 , 0 - // 90 , 1 , 0 - // 180, 0 , 0 - // 270, 0 , 1 - // 360, 0 , 2 - //standard flow boundaries for traditional and progressive mode - const int upperAngleFlow = (m_traditional ? 4 : 1); //non zero - const int maxAngleFlow = (m_traditional ? 4 : 2); //use 2 for multialign zero degree - const int maxBackFlow = 2; //maximal flow on back arcs in progressive mode - const int upperBackAngleFlow = 2; // and 360 back (only progressive mode) - const int lowerAngleFlow = (m_traditional ? 1 : 0); - const int piAngleFlow = (m_traditional ? 2 : 0); - const int halfPiAngleFlow = 1; - //const int halfPiBackAngleFlow = 0; //(only progressive mode) - const int zeroAngleFlow = (m_traditional ? 0 : 2); - const int zeroBackAngleFlow = 0; //(only progressive mode) - - //in progressive mode, angles need cost to work out properly - //const int tradAngleCost = 0; - const int progAngleCost = 1; - const int tradBendCost = 1; - const int progBendCost = 3*PG.numberOfNodes(); //should use supply - - - OR.init(E); - FaceArray F(E); - - OGDF_ASSERT(PG.representsCombEmbedding()) - OGDF_ASSERT(F.valid()) - - - - //****************** - // NETWORK VARIABLES - //****************** - - Graph Network; //the dual network - EdgeArray lowerBound(Network,0); // lower bound for flow - EdgeArray upperBound(Network,0); // upper bound for flow - - EdgeArray cost(Network,0); // cost of an edge - NodeArray supply(Network,0); // supply of every node - - - //alignment helper - NodeArray fixedVal(Network, false); //already set somewhere - EdgeArray noBendEdge(Network, false); //for splitter, brother edges etc. - - //********************************* - //NETWORK TO PlanRepUML INFORMATION - - // stores for edges of the Network the corresponding adjEntries - // nodes, and faces of PG - EdgeArray adjCor(Network,0); - EdgeArray nodeCor(Network,0); - EdgeArray faceCor(Network,0); - - NodeArray nodeType(Network, low); - - //********************************* - //PlanRepUML TO NETWORK INFORMATION - - //Contains for every node of PG the corresponding node in the network - NodeArray networkNode(PG,0); - //Contains for every adjEntry of PG the corresponding edge in the network - AdjEntryArray backAdjCor(PG,0); //bends - //contains for every adjEntry of PG the corresponding angle arc in the network - //note: this doesn't need to correspond to resulting drawing angles - //bends on the boundary define angles at expanded nodes - AdjEntryArray angleArc(PG, 0); //angle - //contains the corresponding back arc face to node in progressive mode - AdjEntryArray angleBackArc(PG, 0); //angle - - //****************** - // OTHER INFORMATION - - // Contains for adjacency Entry of PG the face it belongs to in PG - AdjEntryArray adjF(PG,0); - - //Contains for angle network arc progressive mode backward arc - EdgeArray angleTwin(Network, 0); - - //types of network edges, to be used in flow to values - EdgeArray l_arcType(Network, angle); - - //contains the outer face - //face theOuterFace = E.externalFace(); - - //******************* - // STANDARD VARIABLES - - node v; - adjEntry adj; - edge e; - - - //********************************** - // GENERATE ALL NODES OF THE NETWORK - //********************************** - - //corresponding to the graphs nodes - int checksum = 0; - forall_nodes(v,PG) - { - OGDF_ASSERT((!m_fourPlanar) || (v->degree() < 5)); - - networkNode[v] = Network.newNode(); - //maybe install a shortcut here for degree 4 nodes if not expanded - - if (v->degree() > 4) nodeType[networkNode[v]] = high; - else nodeType[networkNode[v]] = low; - - //already set the supply - if (m_traditional) supply[networkNode[v]] = 4; - else supply[networkNode[v]] = 2*v->degree() - 4; - - checksum += supply[networkNode[v]]; - } - - //corresponding to the graphs faces - face f; - for (f = E.firstFace(); f; f = f->succ()) - { - F[f] = Network.newNode(); - - if (f == E.externalFace()) - { - nodeType[F[f]] = outer; - if (m_traditional) supply[F[f]] = - 2*f->size() - 4; - else supply[F[f]] = 4; - } - else { - nodeType[F[f]] = inner; - if (m_traditional) supply[F[f]] = - 2*f->size() + 4; - else supply[F[f]] = -4; - } - } - -#ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)) { - //check the supply sum - checksum = 0; - forall_nodes(v, Network) - checksum += supply[v]; - OGDF_ASSERT(checksum == 0); - - forall_nodes(v,PG) - cout << " v = " << v << " corresponds to " - << networkNode[v] << endl; - for (f = E.firstFace(); f; f = f->succ()) { - cout << " face = " << f->index() << " corresponds to " << F[f]; - if (f == E.externalFace()) - cout<<" (Outer Face)"; - cout << endl; - } - } -#endif - - - - //********************************** - // GENERATE ALL EDGES OF THE NETWORK - //********************************** - - // OPTIMIZATION POTENTIAL: - // Do not insert edges with upper bound 0 into the network. - - // Locate for every adjacency entry its adjacent faces. - for (f = E.firstFace(); f; f = f->succ()) - { - forall_face_adj(adj,f) - adjF[adj] = f; - } - - #ifdef OGDF_DEBUG - if(int(ogdf::debugLevel) >= int(dlHeavyChecks)) { - for(f = E.firstFace(); f; f = f->succ()) { - cout << "Face " << f->index() << " : "; - forall_face_adj(adj,f) - cout << adj << "; "; - cout<adjSource()] && adjF[e->adjTarget()]) - if (F[adjF[e->adjSource()]] != F[adjF[e->adjTarget()]]) - { - // not a selfloop. - edge newE = Network.newEdge(F[adjF[e->adjSource()]],F[adjF[e->adjTarget()]]); - - l_arcType[newE] = bend; - - adjCor[newE] = e->adjSource(); - if ((PG.typeOf(e) == Graph::generalization) || - (PG.isBoundary(e) && (!m_traditional))) - upperBound[newE] = 0; - else - upperBound[newE] = infinity; - cost[newE] = (m_traditional ? tradBendCost : progBendCost); - //cost[newE] = 1; - backAdjCor[e->adjSource()] = newE; - - newE = Network.newEdge(F[adjF[e->adjTarget()]],F[adjF[e->adjSource()]]); - - l_arcType[newE] = bend; - - adjCor[newE] = e->adjTarget(); - if ((PG.typeOf(e) == Graph::generalization) || - (PG.isBoundary(e) && (m_traditional))) - upperBound[newE] = 0; - else - upperBound[newE] = infinity; - cost[newE] = (m_traditional ? tradBendCost : progBendCost); - //cost[newE] = 1; - backAdjCor[e->adjTarget()] = newE; - } - } - - - //***************************************************************** - // insert for every node edges to all appearances of adjacent faces - // flow defines angles at nodes - // progressive: and vice-versa - //***************************************************************** - - - //************************************************************ - // Observe that two generalizations are not allowed to bend on - // a node. There must be a 180 degree angle between them. - - // assure that there is enough flow between adjacent generalizations - NodeArray genshift(PG, false); - - //non-expanded vertex - forall_nodes(v,PG) - { - //***************************************** - // Locate possible adjacent generalizations - adjEntry gen1 = 0; - adjEntry gen2 = 0; - - if (PG.typeOf(v) != Graph::generalizationMerger - && PG.typeOf(v) != Graph::generalizationExpander) - { - forall_adj(adj,v) - { - if (PG.typeOf(adj->theEdge()) == Graph::generalization) - { - if (!gen1) gen1 = adj; - else gen2 = adj; - } - } - }// if not generalization - - - forall_adj(adj,v) - { - edge e2 = Network.newEdge(networkNode[v],F[adjF[adj]]); - - l_arcType[e2] = angle; - //CHECK bounded edges? and upper == 2 for zero degree - //progressive and traditional - upperBound[e2] = upperAngleFlow; - nodeCor [e2] = v; - adjCor [e2] = adj; - faceCor [e2] = adjF[adj]; - angleArc [adj] = e2; - - //do not allow zero degree at non-expanded vertex - //&& !m_allowLowZero - //progressive and traditional (compatible) - if (m_fourPlanar) lowerBound[e2] = lowerAngleFlow; //trad 1 = 90, prog 0 = 180 - - //insert opposite arcs face to node in progressive style - edge e3; - if (!m_traditional) - { - e3 = Network.newEdge(F[adjF[adj]], networkNode[v]); //flow for >180 degree - - l_arcType[e3] = backAngle; - - angleTwin[e2] = e3; - angleTwin[e3] = e2; - - cost[e2] = progAngleCost; - cost[e3] = progAngleCost; - - lowerBound[e3] = lowerAngleFlow; //180 degree,check highdegree drawings - upperBound[e3] = upperBackAngleFlow; //infinity; - //nodeCor [e3] = v; has no node, is face to node - adjCor [e3] = adj; - faceCor [e3] = adjF[adj]; - angleBackArc[adj] = e3; - - }//progressive - }//initialize - - //second run to have all angleArcs already initialized - //set the flow boundaries for special cases - //association classes - adjEntry assClassAdj = 0; - forall_adj(adj,v) - { - //save the entry opposite to an association class - //(only at the edgeToedge connection node) - - if ((v->degree() != 1) && (PG.isAssClass(adj->theEdge())) ) - { - OGDF_ASSERT(assClassAdj == 0) - assClassAdj = adj->cyclicSucc(); - } - - edge e2 = angleArc[adj]; - edge e3 = 0; - if (!m_traditional) e3 = angleTwin[e2]; - - //******************************************************************* - //check alignment - //******************************************************************* - - if (m_align && !skipAlign) - { - //at generalization, search for connected brother nodes - if ((PG.alignUpward(adj)) && (PG.isVertex(adj->theNode()))) - { - if (adj == adj->theEdge()->adjSource()) - { - if (PG.typeOf(adj->theEdge()) == Graph::generalization) - { - //search for next real edge entries - //as this is for non-expanded nodes, we dont need the expansion check - adjEntry run = adj->faceCycleSucc(); - while ((PG.isExpansion(run->theEdge())) && - (PG.typeOf(run->theEdge()) == Graph::generalization) ) - run = run->faceCycleSucc(); - adjEntry run2 = adj->faceCyclePred(); - while ((PG.isExpansion(run2->theEdge())) && - (PG.typeOf(run2->theEdge()) != Graph::generalization) ) - run2 = run2->faceCyclePred(); - - if ((PG.alignUpward(run) || PG.alignUpward(run->twin())) - && //check for crossings - (PG.typeOf(run->theEdge()) == Graph::generalization) - ) - { - if (PG.isBrother(run2->theEdge())) - { - if (m_traditional) - lowerBound[e2] = halfPiAngleFlow;//brother? - else { - lowerBound[e2] = 0;//brother? - upperBound[e2] = halfPiAngleFlow; - edge eA = angleTwin[e2]; - if (eA) - { - lowerBound[eA] = 0; - upperBound[eA] = 2; - } - }//if progressive - } - else - { - //entweder run2 != adj->theEdge oder - if (PG.typeOf(run2->theEdge()) != Graph::generalization) - { - if (m_traditional) - lowerBound[e2] = 2; - else { - lowerBound[e2] = 0;//nonbrother has >= 180 - upperBound[e2] = 0; - edge eA = angleTwin[e2]; - if (eA) { - lowerBound[eA] = 0; - upperBound[eA] = upperBackAngleFlow; - }//if backarc - }//if progressive - }//if not generalization - }//else brother - //angles: guarantee lower < upper even if stepwise flow computation - if (m_traditional) - upperBound[e2] = flowBound; - - //next angle entry after adj/e2 - adjEntry nextAE = run2->twin(); - OGDF_ASSERT(nextAE->theNode() == adj->theNode()); - OGDF_ASSERT(nextAE->theNode()->degree() <= 4); - //genauer: 2 gen 3, 1 gen 4 - - //check if next edges are forced/allowed to attach at same side - //eigentlich: teste ob zwei gen, dann setze lowerbound - //entsprechend fuer folgende Kanten bis naechste gen - if (m_traditional) - { - if (lowerBound[e2] > 1) { - if (v->degree() > 2) { - lowerBound[angleArc[nextAE]] = 0; - } else { - lowerBound[angleArc[nextAE]] = max(0, lowerBound[angleArc[nextAE]]-1); - } - } - //angles: guarantee lower < upper even if stepwise flow computation - upperBound[e2] = flowBound; - }//if traditional - else - { - //there may be brothers on both sides, so allow zero degree - if (upperBound[e2] == 0) - { - if (v->degree() > 2) - { - lowerBound[angleArc[nextAE]] = 0; - upperBound[angleArc[nextAE]] = zeroAngleFlow; - edge eA = angleTwin[e2]; - if (eA) - { - lowerBound[eA] = 0; - upperBound[eA] = 0; - } - } - else //adjust this to max above? - { - lowerBound[angleArc[nextAE]] = 0; - upperBound[angleArc[nextAE]] = zeroAngleFlow; - edge eA = angleTwin[e2]; - if (eA) - { - lowerBound[eA] = 0; - upperBound[eA] = 0; - } - }//degree 1-2 - }//if >= 180 degree - }//progressive - PG.setUserType(adj->theEdge(),1); - fixedVal[e2->source()] = true; - }//if inner hierarchy gen - }//if gen - else - { - //from left side to gen - //search for next real edge entries - adjEntry run2 = adj->faceCyclePred(); - while ((PG.isExpansion(run2->theEdge())) && - (PG.typeOf(run2->theEdge()) != Graph::generalization) ) - run2 = run2->faceCyclePred(); //is vertex, no iteration!? - - if (PG.alignUpward(run2) && //check for crossings - (PG.typeOf(adj->faceCyclePred()->theEdge()) == Graph::generalization) - ) - { - //check if min 90 (brother) or 180 degree - if (m_traditional) - { - if (PG.isBrother(adj->theEdge())) lowerBound[e2] = 1; - else lowerBound[e2] = 2;//2; teste 1 - //angles: guarantee lower < upper even if stepwise flow computation - upperBound[e2] = flowBound; - } - else - { - lowerBound[e2] = 0; - edge eA = angleTwin[e2]; - if (eA) - { - lowerBound[eA] = 0; - upperBound[eA] = upperBackAngleFlow; - } - //90 degree min - if (PG.isBrother(adj->theEdge())) upperBound[e2] = halfPiAngleFlow; - //180 degree min - else upperBound[e2] = 0; - }//progressive - - OGDF_ASSERT(lowerBound[e2] <= upperBound[e2]); - adjEntry nextAE = adj->twin()->faceCycleSucc(); - OGDF_ASSERT(nextAE->theNode() == v); - - //eigentlich: teste ob zwei gen, dann setze lowerbound - //entsprechend fuer folgende Kanten bis naechste gen - if (m_traditional) - lowerBound[angleArc[nextAE]] = 0; - else - { - lowerBound[angleArc[nextAE]] = 0; - upperBound[angleArc[nextAE]] = maxAngleFlow; - edge eA = angleTwin[angleArc[nextAE]]; - if (eA) - { - lowerBound[eA] = 0; - upperBound[eA] = upperBackAngleFlow; - } - } - - PG.setUserType(adj->theEdge(),1); - fixedVal[e2->source()] = true; - - }//if inner hierarchy gen - }//if not gen - }//srcadj - - }//if alignupward edge - else - //search backwards for non-brother edges in hierarchies - { - //first guarantee that this is only a non-expanded vertex - if (PG.isVertex(adj->theNode())) - //outer gen right of hierarchy level - if ( (PG.typeOf(adj->theEdge()) != Graph::generalization) && - !(PG.isExpansion(adj->theEdge()))) - { - - adjEntry run2 = adj->faceCyclePred(); - while ((PG.isExpansion(run2->theEdge())) && - (PG.typeOf(run2->theEdge()) != Graph::generalization) ) - run2 = run2->faceCyclePred(); - - //is this a gen to a merger - //if (false) - if (PG.alignUpward(run2->twin()) && //check for crossings - (PG.typeOf(run2->theEdge()) == Graph::generalization) && - (run2 == run2->theEdge()->adjTarget()) - ) - { - adjEntry run = run2->faceCyclePred(); - while ((PG.isExpansion(run->theEdge())) && - (PG.typeOf(run->theEdge()) == Graph::generalization) ) - run = run->faceCyclePred(); - if ((PG.alignUpward(run)) && - (PG.isGeneralization(run->theEdge())) && - (run == run->theEdge()->adjSource()) - ) - { - if (m_traditional) - { - if (PG.isBrother(adj->theEdge())) lowerBound[e2] = 1; - else lowerBound[e2] = 2;//2; teste 1 - //angles: guarantee lower < upper even if stepwise flow computation - upperBound[e2] = flowBound; - }//if traditional - else - { - if (PG.isBrother(adj->theEdge())) - setAngleBound(e2, 90, lowerBound, upperBound, angleTwin, angleMinBound); - else - setAngleBound(e2, 180, lowerBound, upperBound, angleTwin, angleMinBound); - } - - //relax next entries angle - adjEntry nextAE = adj->cyclicPred(); - //eigentlich: teste ob zwei gen, dann setze lowerbound - //entsprechend fuer folgende Kanten bis naechste gen - if (m_traditional) - lowerBound[angleArc[nextAE]] = 0; - else - setAngleBound(angleArc[nextAE], 0, lowerBound, upperBound, angleTwin, angleMinBound); - - PG.setUserType(adj->theEdge(),1); - fixedVal[e2->source()] = true; - } - }//if inner hierarchy gen - - } - - }//else alignupward - }//if align - - //******************************************************************* - //******************************************************************* - - //hier muss man fuer die Kanten, die rechts ansetzen noch lowerbound 2 setzen - - if (gen2 == adj && gen1 == adj->cyclicSucc()) - { - upperBound[e2] = piAngleFlow; - lowerBound[e2] = piAngleFlow; - if (e3 && !m_traditional) - { - upperBound[e3] = 0; - lowerBound[e3] = 0; - } - genshift[v] = true; - } - else if (gen1 == adj && gen2 == adj->cyclicSucc()) - { - upperBound[e2] = piAngleFlow; - lowerBound[e2] = piAngleFlow; - if (e3 && !m_traditional) - { - upperBound[e3] = 0; - lowerBound[e3] = 0; - }//progressive - genshift[v] = true; - } - }//forall_adj - //process special case of association classes: 180 degree angle - if (assClassAdj != 0) - { - - edge e2 = angleArc[assClassAdj]; - lowerBound[e2] = piAngleFlow; - - if (!m_traditional) - { - edge e3 = angleTwin[e2]; - upperBound[e3] = lowerBound[e3] = 0; - }//if not traditional - - }//if association class - }//forall_nodes - - - //*************************************************** - // Reset upper and lower Bounds for network arcs that - // correspond to edges of generalizationmerger faces - // and edges of expanded nodes. - - forall_nodes(v,PG) - { - if (PG.expandAdj(v)) - { - adj = PG.expandAdj(v); - // Get the corresponding face in the original embedding. - f = adjF[adj]; - - //***********************+ - //expanded merger cages - if (PG.typeOf(v) == Graph::generalizationMerger) - { - // Set upperBound to 0 for all edges. - forall_face_adj(adj,f) - { - //no bends on boundary (except special case following) - upperBound[backAdjCor[adj]] = 0; - upperBound[backAdjCor[adj->twin()]] = 0; - - // Node w is in Network - node w = networkNode[adj->twinNode()]; - forall_adj_edges(e,w) - { - if (e->target() == F[f]) - { - //is this: 180 degree? - lowerBound[e] = piAngleFlow; //traditional: 2 progressive: 0 - upperBound[e] = piAngleFlow; - if (!m_traditional) - { - edge aTwin = angleTwin[e]; - if (aTwin) - { - upperBound[aTwin] = 0; - lowerBound[aTwin] = 0; - } - }//if not traditional limit angle back arc - - } - } - - } - //special bend case - // Set the upper and lower bound for the first edge of - // the mergeexpander face to guarantee a 90 degree bend. - if (m_traditional) - { - upperBound[backAdjCor[PG.expandAdj(v)]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)]]= 1; - } - else - { - //progressive mode: bends are in opposite direction - upperBound[backAdjCor[PG.expandAdj(v)->twin()]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)->twin()]]= 1; - } - - // Set the upper and lower bound for the first node in - // clockwise order of the mergeexpander face to - // guaranty a 90 degree angle at the node in the interior - // and a 180 degree angle between the generalizations in the - // exterior. - node secFace; - - if (F[f] == backAdjCor[PG.expandAdj(v)]->target()) - secFace = backAdjCor[PG.expandAdj(v)]->source(); - else { - OGDF_ASSERT(F[f] == backAdjCor[PG.expandAdj(v)]->source()) - secFace = backAdjCor[PG.expandAdj(v)]->target(); - } - - node w = networkNode[PG.expandAdj(v)->twinNode()]; - - forall_adj(adj,w) - { - if (adj->theEdge()->target() == F[f]) - { - lowerBound[adj->theEdge()] = 1; - upperBound[adj->theEdge()] = 1; - if (!m_traditional) - { - edge aTwin = angleTwin[adj->theEdge()]; - if (aTwin) - { - upperBound[aTwin] = 0; - lowerBound[aTwin] = 0; - } - }//if not traditional limit angle back arc - break; - } - } - - if (m_traditional) - e = adj->cyclicSucc()->theEdge(); - else - { - //we have two edges instead of one per face - adjEntry ae = adj->cyclicSucc(); - e = ae->theEdge(); - if (e->target() != secFace) - //maybe we have to jump one step further - e = ae->cyclicSucc()->theEdge(); - - }//progressive mode - - if (e->target() == secFace) - { - lowerBound[e] = piAngleFlow; - upperBound[e] = piAngleFlow; - if (!m_traditional) - { - edge aTwin = angleTwin[e]; - if (aTwin) - { - upperBound[aTwin] = piAngleFlow; - lowerBound[aTwin] = piAngleFlow; - } - }//if not traditional limit angle back arc - } - - // Set the upper and lower bound for the last edge of - // the mergeexpander face to guarantee a 90 degree bend. - if (m_traditional) - { - upperBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()]] = 1; - } - else - { - //progressive mode: bends are in opposite direction - upperBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()->twin()]] = 1; - lowerBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()->twin()]] = 1; - }//progressive - - - // Set the upper and lower bound for the last node in - // clockwise order of the mergeexpander face to - // guaranty a 90 degree angle at the node in the interior - // and a 180 degree angle between the generalizations in the - // exterior. - if (F[f] == backAdjCor[PG.expandAdj(v)->faceCyclePred()]->target()) - secFace = backAdjCor[PG.expandAdj(v)->faceCyclePred()]->source(); - else { - OGDF_ASSERT(F[f] == backAdjCor[PG.expandAdj(v)->faceCyclePred()]->source()) - secFace = backAdjCor[PG.expandAdj(v)->faceCyclePred()]->target(); - } - - w = networkNode[PG.expandAdj(v)->faceCyclePred()->theNode()]; - - forall_adj(adj,w) - { - if (adj->theEdge()->target() == F[f]) - { - lowerBound[adj->theEdge()] = 1; - upperBound[adj->theEdge()] = 1; - if (!m_traditional) - { - edge aTwin = angleTwin[adj->theEdge()]; - if (aTwin) - { - upperBound[aTwin] = 0; - lowerBound[aTwin] = 0; - } - }//if not traditional limit angle back arc - break; - } - } - - if (m_traditional) - e = adj->cyclicPred()->theEdge(); - else - { - //we have two edges instead of one per face - adjEntry ae = adj->cyclicPred(); - e = ae->theEdge(); - if (e->target() != secFace) - //maybe we have to jump one step further - e = ae->cyclicPred()->theEdge(); - - }//progressive mode - - if (e->target() == secFace) - { - lowerBound[e] = piAngleFlow; - upperBound[e] = piAngleFlow; - if (!m_traditional) - { - edge aTwin = angleTwin[e]; - if (aTwin) - { - upperBound[aTwin] = piAngleFlow; - lowerBound[aTwin] = piAngleFlow; - } - }//if not traditional limit angle back arc - } - - - } - //************************** - //expanded high degree cages - else if (PG.typeOf(v) == Graph::highDegreeExpander ) - { - - if (m_align && !skipAlign) - { - adjEntry splitter = 0; - face expansionFace = f; - int bendCount = 0; //check bend maximum in face - - do - { - //this double iteration slows the algorithm down - forall_face_adj(adj, expansionFace) - { - if (!PG.faceSplitter(adj->theEdge())) - { - //right from generalization - adjEntry srcadj = adj->cyclicPred(); - adjEntry tgtadj = adj->twin()->cyclicSucc(); - //set min 90 degree if brother edge - if (PG.isBrother(tgtadj->theEdge())) - { - if ( PG.isGeneralization(srcadj->theEdge()) && - (srcadj == srcadj->theEdge()->adjSource()) - ) - { - bendCount++; - if (m_traditional) - lowerBound[backAdjCor[adj]] = 1; - - //progressive CHECK - else - lowerBound[backAdjCor[adj->twin()]] = 1; - - //maybe set upperBound to avoid conflict - //upperBound[backAdjCor[adj]] = flowBound; - // max(1, upperBound[backAdjCor[adj]]); - }//if right of generalization - - - noBendEdge[backAdjCor[tgtadj]] = true; - }//if is brother - else - { - //hier: falls brother src, gen tgt - //nonbrother src, gn tgt - - //non-brothers start from lower node side - if ( PG.isGeneralization(srcadj->theEdge()) && - (srcadj == srcadj->theEdge()->adjSource()) && - PG.alignUpward(srcadj) //edge to merger - ) - { - bendCount += 2; - if (m_traditional) - { - lowerBound[backAdjCor[adj]]= 2; - //angles: guarantee lower < upper even if stepwise flow computation - upperBound[backAdjCor[adj]] = flowBound; - }//if traditional - else - { - lowerBound[backAdjCor[adj->twin()]]= 2; - //angles: guarantee lower < upper even if stepwise flow computation - upperBound[backAdjCor[adj->twin()]] = flowBound; - }//progressive - } - else //check if we are left from gen - { - if (PG.isGeneralization(tgtadj->theEdge()) && - (tgtadj == tgtadj->theEdge()->adjSource()) - //recent test change, maybe delete again - && PG.alignUpward(tgtadj) - ) - { - if (PG.isBrother(srcadj->theEdge())) - { - bendCount++; - if (m_traditional) lowerBound[backAdjCor[adj]]= 1; - else lowerBound[backAdjCor[adj->twin()]]= 1; - noBendEdge[backAdjCor[srcadj]] = true; - }//if - else - { - bendCount += 2; - if (m_traditional) - { - lowerBound[backAdjCor[adj]]= 2; - upperBound[backAdjCor[adj]] = flowBound; - } - else - { - lowerBound[backAdjCor[adj->twin()]]= 2; - upperBound[backAdjCor[adj->twin()]] = flowBound; - } - }//else - - }//if to gen - - - }//not right from gen - }//no brother - }//if not splitter - else splitter = adj; - }//forallfaceadj - if (splitter && (expansionFace == f)) - { - adj = splitter->twin(); - // Get the corresponding face in the original embedding. - expansionFace = adjF[adj]; - splitter = splitter->twin(); - }//if - else expansionFace = 0; - } while (expansionFace); - OGDF_ASSERT(bendCount <= 4); - }//if align - - // Set upperBound to 1 for all edges, allowing maximal one - // 90 degree bend. - // Set upperBound to 0 for the corresponding entering edge - // allowing no 270 degree bend. - // Set upperbound to 1 for every edge corresponding to the - // angle of a vertex. This permitts 270 degree angles in - // the face - - adjEntry splitter = 0; - - - //assure that edges are only spread around the sides if not too - //many multi edges are aligned - - //************************ - //count multiedges at node - int multis = 0; - AdjEntryArray isMulti(PG, false); - if (m_multiAlign) - { - //if all edges are multi edges, find a 360 degree position - bool allMulti = true; - forall_face_adj(adj, f) //this double iteration slows the algorithm down - { - if (!PG.faceSplitter(adj->theEdge())) - { - adjEntry srcadj = adj->cyclicPred(); - adjEntry tgtadj = adj->twin()->cyclicSucc(); - //check if the nodes are expanded - node vt1, vt2; - if (PG.expandedNode(srcadj->twinNode())) - vt1 = PG.expandedNode(srcadj->twinNode()); - else vt1 = srcadj->twinNode(); - if (PG.expandedNode(tgtadj->twinNode())) - vt2 = PG.expandedNode(tgtadj->twinNode()); - else vt2 = tgtadj->twinNode(); - if (vt1 == vt2) - { - //we forbid bends between two incident multiedges - if (m_traditional) - { - lowerBound[backAdjCor[adj]] = upperBound[backAdjCor[adj]] = 0; - isMulti[adj] = true; - } - else - { - lowerBound[backAdjCor[adj->twin()]] = - lowerBound[backAdjCor[adj]] = - upperBound[backAdjCor[adj]] = - upperBound[backAdjCor[adj->twin()]] = 0; - isMulti[adj->twin()] = true; - } - multis++; - }//multi edge - else allMulti = false; - }//if outer boundary - - }//forallfaceadj count multis - //multi edge correction: only multi edges => one edge needs 360 degree - if (allMulti) - { - //find an edge that allows 360 degree without bends - bool twoNodeCC = true; //no foreign non-multi edge to check for - forall_face_adj(adj, f) - { - //now check for expanded nodes - adjEntry adjOut = adj->cyclicPred(); //outgoing edge entry - node vOpp = adjOut->twinNode(); - if (PG.expandedNode(vOpp)) - { - adjOut = adjOut->faceCycleSucc(); //on expanded boundary - //does not end on self loops - node vStop = vOpp; - if (PG.expandedNode(vStop)) vStop = PG.expandedNode(vStop); - while (PG.expandedNode(adjOut->twinNode()) == vStop) - //we are still on vOpps cage - adjOut = adjOut->faceCycleSucc(); - } - //now adjOut is either a "foreign" edge or one of the - //original multi edges if two-node-CC - //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin(); - adjEntry testAdj = adjOut->twin(); - node vBack = testAdj->theNode(); - if (PG.expandedNode(vBack)) - { - vBack = PG.expandedNode(vBack); - } - if (vBack != v) //v is expanded node - { - //dont use iteration result, set firstedge! - upperBound[backAdjCor[adj]] = 4; //4 bends for 360 - twoNodeCC = false; - break; - } - }//forall_adj_edges - //if only two nodes with multiedges are in current CC, - //assign 360 degree to first edge - if (twoNodeCC) - { - //it would be difficult to guarantee that the networkedge - //on the other side of the face would get the 360, so alllow - //360 for all edges or search for the outer face - - forall_face_adj(adj, f) - { - adjEntry ae = adj->cyclicPred(); - if (adjF[ae] == E.externalFace()) - { - upperBound[backAdjCor[adj]] = 4; //4 bends for 360 - break; - } - }//forall expansion adj - }//if - }//if allMulti - //End multi edge correction - }//if multialign - - - - //********************** - //now set the upper Bounds - forall_face_adj(adj,f) - { - //should be: no 270 degrees - if (m_traditional) - upperBound[backAdjCor[adj->twin()]] = 0; - else - upperBound[backAdjCor[adj]] = 0; - - if (PG.faceSplitter(adj->theEdge())) - { - // No bends allowed on the face splitter - upperBound[backAdjCor[adj]] = 0; - - //CHECK - //progressive??? sollte sein: - upperBound[backAdjCor[adj->twin()]] = 0; - - splitter = adj; - continue; - } - else - //should be: only one bend - { - - if (m_distributeEdges) - //CHECK - //maybe we should change this to setting the lower bound too, - //depending on the degree (<= 4 => deg 90) - { - //check the special case degree >=4 with 2 - // generalizations following each other if degree - // > 4, only 90 degree allowed, nodeType high - // bloed, da nicht original - //if (nodeType[ networkNode[adj->twinNode()] ] == high) - //hopefully size is original degree - if (m_traditional) - { - if (!isMulti[adj]) //m_multiAlign??? - { - //check if original node degree minus multi edges - //is high enough - //Attention: There are some lowerBounds > 1 -#ifdef OGDF_DEBUG - int oldBound = -#endif - upperBound[backAdjCor[adj]]; - if ((!genshift[v]) && (f->size()-multis>3)) - upperBound[backAdjCor[adj]] = - //max(2, lowerBound[backAdjCor[adj]]); - //due to mincostflowreinelt errors, we are not - //allowed to set ub 1 - max(1, lowerBound[backAdjCor[adj]]); - else upperBound[backAdjCor[adj]] = - max(2, lowerBound[backAdjCor[adj]]); - //nur zum Testen der Faelle - OGDF_ASSERT(oldBound >= upperBound[backAdjCor[adj]]); - }// if not multi - }//traditional - else - { - //preliminary set the bound in all cases - - if (!isMulti[adj]) //m_multiAlign??? - { - //Attention: There are some lowerBounds > 1 - //if ((!genshift[v]) && (f->size()-multis>3)) - - if ((!genshift[v]) && (f->size()-multis>3)) - upperBound[backAdjCor[adj->twin()]] = - max(1, lowerBound[backAdjCor[adj->twin()]]); - else upperBound[backAdjCor[adj->twin()]] = - max(2, lowerBound[backAdjCor[adj->twin()]]); - - //upperBound[backAdjCor[adj->twin()]] = 1; - - - //max(1, lowerBound[backAdjCor[adj]]); - //else upperBound[backAdjCor[adj]] = 2; - //max(2, lowerBound[backAdjCor[adj]]); - }// if not multi - }//progressive - }//distributeedges - }// else no face splitter - - // Node w is in Network - node w = networkNode[adj->twinNode()]; - - // if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4))) - { - //should be: inner face angles set to 180 - forall_adj_edges(e,w) - { - if (e->target() == F[f]) - { - upperBound[e] = piAngleFlow; - lowerBound[e] = piAngleFlow; - if (!m_traditional) - { - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = piAngleFlow; - lowerBound[angleTwin[e]] = piAngleFlow; - }//if twin - }//if progressive mode - } - } - } - }// forallfaceadj - - //******************************************************** - // In case a face splitter was used, we need to update the - // second face of the cage. - if (splitter) - { - - adj = splitter->twin(); - // Get the corresponding face in the original embedding. - face f2 = adjF[adj]; - - forall_face_adj(adj,f2) - { - if (adj == splitter->twin()) - continue; - - //todo: Alignment - - if (m_traditional) - upperBound[backAdjCor[adj->twin()]] = 0; - else //progressive bends are in opposite direction - upperBound[backAdjCor[adj]] = 0; - - // Node w is in Network - node w = networkNode[adj->twinNode()]; - //if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4))) - { - forall_adj_edges(e,w) - { - if (e->target() == F[f2]) - { - upperBound[e] = piAngleFlow; - lowerBound[e] = piAngleFlow; - if (!m_traditional) - { - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = piAngleFlow; - lowerBound[angleTwin[e]] = piAngleFlow; - }//angleTwin - }//if progressive mode - } - }//forall adjacent edges - }//if not preset - } - } - } - }//if expanded - - else - { - - //********************************************* - //non-expanded (low degree) nodes - //check for alignment and for multi edges - //********************************************* - - //check for multi edges and decrease lowerbound if align - int lowerb = 0; - - if (PG.isVertex(v)) - { - node w = networkNode[v]; - if ((nodeType[w] != low) || (w->degree()<2)) continue; - - bool allMulti = true; - forall_adj_edges(e,w) - { - lowerb += max(lowerBound[e], 0); - - OGDF_ASSERT((!m_traditional) || (e->source() == w)); - if (m_traditional && (e->source() != w)) OGDF_THROW(AlgorithmFailureException); - if (e->source() != w) continue; //dont treat back angle edges - - if (m_multiAlign && (v->degree()>1)) - { - adjEntry srcAdj = adjCor[e]; - adjEntry tgtAdj = adjCor[e]->faceCyclePred(); - - //check if the nodes are expanded - node vt1, vt2; - if (PG.expandedNode(srcAdj->twinNode())) - vt1 = PG.expandedNode(srcAdj->twinNode()); - else vt1 = srcAdj->twinNode(); - - if (PG.expandedNode(tgtAdj->theNode())) - vt2 = PG.expandedNode(tgtAdj->theNode()); - else vt2 = tgtAdj->theNode(); - - if (vt1 == vt2) - { - - fixedVal[w] = true; - - //we forbid bends between incident multi edges - //or is it angle? - lowerBound[e] = upperBound[e] = zeroAngleFlow; - if (!m_traditional) - { - lowerBound[angleTwin[e]] = upperBound[angleTwin[e]] - = zeroBackAngleFlow; - }//if progressive mode - - }//multi edge - else - { - - - //CHECK - //to be done: only if multiedges - if (!genshift[v]) upperBound[e] = upperAngleFlow; - allMulti = false; - } - }//multiAlign - }//foralladjedges - - - if (m_multiAlign && allMulti && (v->degree()>1)) - { - - fixedVal[w] = true; - - //find an edge that allows 360 degree without bends - bool twoNodeCC = true; - forall_adj_edges(e, w) - { - //if (PG.expandedNode(srcAdj->twinNode())) - // vt1 = PG.expandedNode(srcAdj->twinNode()); - //now check for expanded nodes - adjEntry runAdj = adjCor[e]; - node vOpp = runAdj->twinNode(); - node vStop; - vStop = vOpp; - runAdj = runAdj->faceCycleSucc(); - if (PG.expandedNode(vStop)) - { - - //does not end on self loops - vStop = PG.expandedNode(vStop); - while (PG.expandedNode(runAdj->twinNode()) == vStop) - //we are still on vOpps cage - runAdj = runAdj->faceCycleSucc(); - } - //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin(); - adjEntry testAdj = runAdj->twin(); - node vBack = testAdj->theNode(); - - if (vBack != v) //not same node - { - if (PG.expandedNode(vBack)) - { - vBack = PG.expandedNode(vBack); - } - if (vBack != vStop) //vstop !=0, not inner face in 2nodeCC - { - //CHECK: 4? upper - OGDF_ASSERT(!PG.expandedNode(v)); //otherwise not angle flow - if (m_traditional) - upperBound[e] = maxAngleFlow; //dont use iteration result, set firstedge! - else - { - upperBound[e] = lowerBound[e] = lowerAngleFlow; - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = maxBackFlow; - lowerBound[angleTwin[e]] = maxBackFlow; - } - } - twoNodeCC = false; - break; - }//if not 2nodeCC - }//if - }//forall_adj_edges - //if only two nodes with multiedges are in current CC, - //assign 360 degree to first edge - if (twoNodeCC) - { - //it would be difficult to guarantee that the networkedge - //on the other side of the face would get the 360, so allow - //360 for all edges or search for external face - forall_adj_edges(e, w) - { - adjEntry adje = adjCor[e]; - if (adjF[adje] == E.externalFace()) - { - //CHECK: 4? upper - OGDF_ASSERT(!PG.expandedNode(v)); //otherwise not angle flow - if (m_traditional) - upperBound[e] = maxAngleFlow;//upperAngleFlow; - if (!m_traditional) - { - upperBound[e] = lowerAngleFlow;//upperAngleFlow; - lowerBound[e] = lowerAngleFlow; - if (angleTwin[e]) - { - upperBound[angleTwin[e]] = maxBackFlow; - lowerBound[angleTwin[e]] = maxBackFlow; - } - } - break; - }//if - }//forall - }//if - }//if allMulti - }//replaces vertex - - } - }//forallnodes - - //********************************** - node tv; edge te; - //int flowSum = 0; - - //To Be done: hier multiedges testen - forall_nodes(tv, Network) - { - //flowSum += supply[tv]; - - //only check representants of original nodes, not faces - if (((nodeType[tv] == low) || (nodeType[tv] == high))) - { - //if node representant with degree 4, set angles preliminary - //degree four nodes with two gens are expanded in PlanRepUML - //all others are allowed to change the edge positions - if ( (m_traditional && (tv->degree() == 4)) || - ((tv->degree() == 8) && !m_traditional) ) - { - //three types: degree4 original nodes and facesplitter end nodes, - //maybe crossings - //fixassignment tells us that low degree nodes are not allowed to - //have zero degree and special nodes are already assigned - bool fixAssignment = true; - - //check if free assignment is possible for degree 4 - if (m_deg4free) - { - fixAssignment = false; - forall_adj_edges(te, tv) - { - if (te->source() == tv) - { - adjEntry pgEntry = adjCor[te]; - node pgNode = pgEntry->theNode(); - - if ((PG.expandedNode(pgNode)) - || (PG.faceSplitter(adjCor[te]->theEdge())) - || (PG.typeOf(pgNode) == Graph::dummy) //test crossings - ) - { - fixAssignment = true; - break; - } - }//if no angle back arc in progressive mode - }//forall_adj_edges - }//deg4free - - //CHECK - //now set the angles at degree 4 nodes to distribute edges - forall_adj_edges(te, tv) - { - - if (te->source() == tv) - { - if (fixedVal[tv]) continue; //if already special values set - - if (!fixAssignment) - { - lowerBound[te] = 0; //lowerAngleFlow maybe 1;//0; - upperBound[te] = upperAngleFlow;//4; - } - else - { - //only allow 90 degree arc value - lowerBound[te] = halfPiAngleFlow; - upperBound[te] = halfPiAngleFlow; - } - }//if no angle back arc in progressive mode - else - { - if (fixedVal[tv]) continue; //if already special values set - - if (!fixAssignment) - { - OGDF_ASSERT(lowerAngleFlow == 0); //should only be in progressive mode - lowerBound[te] = lowerAngleFlow; - upperBound[te] = upperBackAngleFlow; - } - else - { - //only allow 0-180 degree back arc value - lowerBound[te] = 0; //1 - upperBound[te] = 0; //halfPiAngleFlow; //1 - } - }//back angle arc - }//forall_adj_edges - }//degree 4 node - int lowsum = 0, upsum = 0; - forall_adj_edges(te, tv) - { - OGDF_ASSERT(lowerBound[te] <= upperBound[te]); - if (noBendEdge[te]) lowerBound[te] = 0; - lowsum += lowerBound[te]; - upsum += upperBound[te]; - }//forall_adj_edges - if (m_traditional) { - OGDF_ASSERT( (lowsum <= supply[tv]) && (upsum >= supply[tv])) - } - }//if node, no faces - }//forallnodes - //only for debugging: check faces - forall_nodes(tv, Network) - { - int lowsum = 0, upsum = 0; - forall_adj_edges(te, tv) - { - if (noBendEdge[te]) lowerBound[te] = 0; - lowsum += lowerBound[te]; - upsum += upperBound[te]; - }//forall_adj_edges - } - - //********************************** - - bool isFlow = false; - SList capacityBoundedEdges; - EdgeArray flow(Network,0); - - // Set upper Bound. Do not leave it to INT_NAX. - // Causes problems with MinCostFlowReinelt - - //but some edges are no longer capacitybounded, therefore save their status - EdgeArray isBounded(Network, false); - - forall_edges(e,Network) - - if (upperBound[e] == infinity) - { - capacityBoundedEdges.pushBack(e); - isBounded[e] = true; - }//if bounded - - - int currentUpperBound; - if (m_startBoundBendsPerEdge > 0) - currentUpperBound = m_startBoundBendsPerEdge; - else - currentUpperBound = 4*PG.numberOfEdges(); - - while ( (!isFlow) && (currentUpperBound<=4*PG.numberOfEdges()) ) - { - - SListIterator it; - for (it = capacityBoundedEdges.begin(); it.valid(); it++) - upperBound[(*it)] = currentUpperBound; - - - - isFlow = flowModule.call(Network,lowerBound,upperBound,cost,supply,flow); - - //#ifdef foutput - //if (isFlow) - // { - // //if (int(ogdf::debugLevel) >= int(dlHeavyChecks)) { - // forall_edges(e,Network) { - // fout << "e = " << e << " flow = " << flow[e]; - // if(nodeCor[e] == 0 && adjCor[e]) - // fout << " real edge = " << adjCor[e]->theEdge(); - // fout << endl; - // } - // forall_edges(e,Network) { - // if(nodeCor[e] == 0 && adjCor[e] != 0 && flow[e] > 0) { - // fout << "Bends " << flow[e] << " on edge " - // << adjCor[e]->theEdge() - // << " between faces " << adjF[adjCor[e]]->index() << " - " - // << adjF[adjCor[e]->twin()]->index() << endl; - // } - // } - // forall_edges(e,Network) { - // if(nodeCor[e] != 0 && faceCor[e] != 0) { - // fout << "Angle " << (flow[e])*90 << "\tdegree on node " - // << nodeCor[e] << " at face " << faceCor[e]->index() - // << "\tbetween edge " << adjCor[e]->faceCyclePred() - // << "\tand " << adjCor[e] << endl; - // } - // } - // if (startBoundBendsPerEdge> 0) { - // fout << "Minimizing edge bends for upper bound " - // << currentUpperBound; - // if(isFlow) - // fout << " ... Successful"; - // fout << endl; - // } - // //} - //} - //#endif - - OGDF_ASSERT(m_startBoundBendsPerEdge >= 1 || isFlow); - - currentUpperBound++; - - }// while (!isflow) - - - if (m_startBoundBendsPerEdge && !isFlow) - OGDF_THROW_PARAM(AlgorithmFailureException, afcNoFlow); - - - int totalNumBends = 0; - - - //int gap = currentUpperBound; - - forall_edges(e,Network) - { - - if (nodeCor[e] == 0 && adjCor[e] != 0 && (flow[e] > 0) && - (angleTwin[e] == 0) ) //no angle edges - { - - OGDF_ASSERT(OR.bend(adjCor[e]).size() == 0) - - char zeroChar = (m_traditional ? '0' : '1'); - char oneChar = (m_traditional ? '1' : '0'); - //we depend on the property that there is no flow - //in opposite direction due to the cost - OR.bend(adjCor[e]).set(zeroChar,flow[e]); - OR.bend(adjCor[e]->twin()).set(oneChar,flow[e]); - - totalNumBends += flow[e]; - - ////check if bends fit bounds - //if (isBounded[e]) - //{ - // OGDF_ASSERT((int)OR.bend(adjCor[e]).size() <= currentUpperBound); - // OGDF_ASSERT((int)OR.bend(adjCor[e]->twin()).size() <= currentUpperBound); - //}//if bounded - } - else if (nodeCor[e] != 0 && faceCor[e] != 0) - { - if (m_traditional) OR.angle(adjCor[e]) = (flow[e]); - else - { - OGDF_ASSERT(angleTwin[e] != 0); - switch (flow[e]) - { - case 0: - switch (flow[angleTwin[e]]) - { - case 0: OR.angle(adjCor[e]) = 2; break; - case 1: OR.angle(adjCor[e]) = 3; break; - case 2: OR.angle(adjCor[e]) = 4; break; - OGDF_NODEFAULT - }//switch - break; - case 1: - switch (flow[angleTwin[e]]) - { - case 0: OR.angle(adjCor[e]) = 1; break; - OGDF_NODEFAULT - }//switch - break; - case 2: - switch (flow[angleTwin[e]]) - { - case 0: OR.angle(adjCor[e]) = 0; break; - OGDF_NODEFAULT - }//switch - break; - OGDF_NODEFAULT - }//switch - }//progressive mode - }//if angle arc - } - -#ifdef OGDF_DEBUG - if (int(ogdf::debugLevel) >= int(dlHeavyChecks)) { - cout << "\n\nTotal Number of Bends : "<< totalNumBends << endl << endl; - - String error; - if (OR.check(error) == false) { - cout << error << endl; - OGDF_ASSERT(false); - } - } -#endif - -}//call - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/packing/CCLayoutPackModule.cpp b/ext/OGDF/src/packing/CCLayoutPackModule.cpp deleted file mode 100644 index 110328c21..000000000 --- a/ext/OGDF/src/packing/CCLayoutPackModule.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of class CCLayoutPackModule. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - - -namespace ogdf { - -template -bool CCLayoutPackModule::checkOffsetsTP( - const Array &box, - const Array &offset) -{ - OGDF_ASSERT(box.size() == offset.size()); - const int n = box.size(); - - for (int i = 0; i < n; ++i) - { - typename POINT::numberType xl = offset[i].m_x; - typename POINT::numberType xr = xl + box[i].m_x; - typename POINT::numberType yb = offset[i].m_y; - typename POINT::numberType yt = yb + box[i].m_y; - - OGDF_ASSERT(xl <= xr && yb <= yt); - - for (int j = i+1; j < n; ++j) - { - typename POINT::numberType xl2 = offset[j].m_x; - typename POINT::numberType xr2 = xl2 + box[j].m_x; - typename POINT::numberType yb2 = offset[j].m_y; - typename POINT::numberType yt2 = yb2 + box[j].m_y; - - if (xr2 > xl && xl2 < xr && yt2 > yb && yb2 < yt) - return false; - } - } - - return true; -} - -bool CCLayoutPackModule::checkOffsets(const Array &box, - const Array &offset) -{ - return checkOffsetsTP(box,offset); -} - -bool CCLayoutPackModule::checkOffsets(const Array &box, - const Array &offset) -{ - return checkOffsetsTP(box,offset); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/packing/ComponentSplitterLayout.cpp b/ext/OGDF/src/packing/ComponentSplitterLayout.cpp deleted file mode 100644 index 7f2b0cd50..000000000 --- a/ext/OGDF/src/packing/ComponentSplitterLayout.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Splits and packs the components of a Graph - * - * \author Gereon Bartel - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -//used for splitting -#include -#include - - -namespace ogdf { - -ComponentSplitterLayout::ComponentSplitterLayout() -{ - m_packer.set(new TileToRowsCCPacker); - m_targetRatio = 1.f; - m_border = 30; -} - - -void ComponentSplitterLayout::call(GraphAttributes &GA) -{ - // Only do preparations and call if layout is valid - if (m_secondaryLayout.valid()) - { - //first we split the graph into its components - const Graph& G = GA.constGraph(); - - NodeArray componentNumber(G); - m_numberOfComponents = connectedComponents(G, componentNumber); - if (m_numberOfComponents == 0) { - return; - } - - //std::vector< std::vector > componentArray; - //componentArray.resize(numComponents); - //Array components(numComponents); - // - - // intialize the array of lists of nodes contained in a CC - nodesInCC.init(m_numberOfComponents); - - node v; - forall_nodes(v,G) - nodesInCC[componentNumber[v]].pushBack(v); - - // Create copies of the connected components and corresponding - // GraphAttributes - GraphCopy GC; - GC.createEmpty(G); - - EdgeArray auxCopy(G); - - for (int i = 0; i < m_numberOfComponents; i++) - { - GC.initByNodes(nodesInCC[i],auxCopy); - GraphAttributes cGA(GC); - //copy information into copy GA - forall_nodes(v, GC) - { - cGA.width(v) = GA.width(GC.original(v)); - cGA.height(v) = GA.height(GC.original(v)); - cGA.x(v) = GA.x(GC.original(v)); - cGA.y(v) = GA.y(GC.original(v)); - } - m_secondaryLayout.get().call(cGA); - - //copy layout information back into GA - forall_nodes(v, GC) - { - node w = GC.original(v); - if (w != 0) - GA.x(w) = cGA.x(v); - GA.y(w) = cGA.y(v); - } - } - - - // rotate component drawings and call the packer - reassembleDrawings(GA); - // free - nodesInCC.init(); - - }//if valid - -} - - -//----------------- -// geometry helpers - -/* copied from multilevelgraph -//moves point set average to origin -void moveToZero() -{ - // move Graph to zero - node v; - double avg_x = 0.0; - double avg_y = 0.0; - forall_nodes(v, getGraph()) { - avg_x += x(v); - avg_y += y(v); - } - avg_x /= getGraph().numberOfNodes(); - avg_y /= getGraph().numberOfNodes(); - forall_nodes(v, getGraph()) { - x(v, x(v) - avg_x); - y(v, y(v) - avg_y); - } -} -*/ - -double atan2ex(double y, double x) -{ - double angle = atan2(y, x); - - if (x == 0) - { - if (y >= 0) { - angle = 0.5 * Math::pi; - } else { - angle = 1.5 * Math::pi; - } - } - - if (y == 0) - { - if (x >= 0) - { - angle = 0.0; - } else { - angle = Math::pi; - } - } - - return angle; -} - -//TODO: Regard some kind of aspect ration (input) -//(then also the rotation of a single component makes sense) -void ComponentSplitterLayout::reassembleDrawings(GraphAttributes& GA) -{ - Array box; - Array offset; - Array oldOffset; - Array rotation; - ConvexHull CH; - - // rotate components and create bounding rectangles - - //iterate through all components and compute convex hull - for (int j = 0; j < m_numberOfComponents; j++) - { - //todo: should not use std::vector, but in order not - //to have to change all interfaces, we do it anyway - std::vector points; - - //collect node positions and at the same time center average - // at origin - //node v; - ListConstIterator it = nodesInCC[j].begin(); - double avg_x = 0.0; - double avg_y = 0.0; - while (it.valid()) - { - DPoint dp(GA.x(*it), GA.y(*it)); - avg_x += dp.m_x; - avg_y += dp.m_y; - points.push_back(dp); - it++; - } - avg_x /= nodesInCC[j].size(); - avg_y /= nodesInCC[j].size(); - - //adapt positions to origin - it = nodesInCC[j].begin(); - int count = 0; - //assume same order of vertices and positions - while (it.valid()) - { - //TODO: I am not sure if we need to update both - GA.x(*it) = GA.x(*it) - avg_x; - GA.y(*it) = GA.y(*it) - avg_y; - points.at(count).m_x -= avg_x; - points.at(count).m_y -= avg_y; - - it++; - count++; - } - - // calculate convex hull - DPolygon hull = CH.call(points); - - double best_area = DBL_MAX; - DPoint best_normal; - double best_width = 0.0; - double best_height = 0.0; - - // find best rotation by using every face as rectangle border once. - for (DPolygon::iterator j = hull.begin(); j != hull.end(); j++) { - DPolygon::iterator k = hull.cyclicSucc(j); - - double dist = 0.0; - DPoint norm = CH.calcNormal(*k, *j); - for (DPolygon::iterator z = hull.begin(); z != hull.end(); z++) { - double d = CH.leftOfLine(norm, *z, *k); - if (d > dist) { - dist = d; - } - } - - double left = 0.0; - double right = 0.0; - norm = CH.calcNormal(DPoint(0, 0), norm); - for (DPolygon::iterator z = hull.begin(); z != hull.end(); z++) { - double d = CH.leftOfLine(norm, *z, *k); - if (d > left) { - left = d; - } - else if (d < right) { - right = d; - } - } - double width = left - right; - - dist = max(dist, 1.0); - width = max(width, 1.0); - - double area = dist * width; - - if (area <= best_area) { - best_height = dist; - best_width = width; - best_area = area; - best_normal = CH.calcNormal(*k, *j); - } - } - - if (hull.size() <= 1) { - best_height = 1.0; - best_width = 1.0; - best_area = 1.0; - best_normal = DPoint(1.0, 1.0); - } - - double angle = -atan2(best_normal.m_y, best_normal.m_x) + 1.5 * Math::pi; - if (best_width < best_height) { - angle += 0.5f * Math::pi; - double temp = best_height; - best_height = best_width; - best_width = temp; - } - rotation.grow(1, angle); - double left = hull.front().m_x; - double top = hull.front().m_y; - double bottom = hull.front().m_y; - // apply rotation to hull and calc offset - for (DPolygon::iterator j = hull.begin(); j != hull.end(); j++) { - DPoint tempP = *j; - double ang = atan2(tempP.m_y, tempP.m_x); - double len = sqrt(tempP.m_x*tempP.m_x + tempP.m_y*tempP.m_y); - ang += angle; - tempP.m_x = cos(ang) * len; - tempP.m_y = sin(ang) * len; - - if (tempP.m_x < left) { - left = tempP.m_x; - } - if (tempP.m_y < top) { - top = tempP.m_y; - } - if (tempP.m_y > bottom) { - bottom = tempP.m_y; - } - } - oldOffset.grow(1, DPoint(left + 0.5 * static_cast(m_border), -1.0 * best_height + 1.0 * bottom + 0.0 * top + 0.5 * (double)m_border)); - - // save rect - int w = static_cast(best_width); - int h = static_cast(best_height); - box.grow(1, IPoint(w + m_border, h + m_border)); - }// components - - offset.init(box.size()); - - // call packer - m_packer.get().call(box, offset, m_targetRatio); - - int index = 0; - // Apply offset and rebuild Graph - for (int j = 0; j < m_numberOfComponents; j++) - { - //for (std::vector::iterator i = m_components.begin(); - // i != m_components.end(); i++, index++) - //{ - // MultilevelGraph *temp = *i; - - // if (temp != 0) - // { - double angle = rotation[index]; - // apply rotation and offset to all nodes - node v; - - ListConstIterator it = nodesInCC[j].begin(); - while (it.valid()) - { - v = *it; - double x = GA.x(v); - double y = GA.y(v); - double ang = atan2(y, x); - double len = sqrt(x*x + y*y); - ang += angle; - x = cos(ang) * len; - y = sin(ang) * len; - - x += static_cast(offset[index].m_x); - y += static_cast(offset[index].m_y); - - x -= oldOffset[index].m_x; - y -= oldOffset[index].m_y; - - GA.x(v) = x; - GA.y(v) = y; - - it++; - - }// while nodes in component - -// MLG.reInsertGraph(*temp); - //} - index++; - } // for components - - //now we center the whole graph again - //TODO: why? - //const Graph& G = GA.constGraph(); - //forall_nodes(v, G) - //MLG.moveToZero(); -} - - -} // namespace ogdf diff --git a/ext/OGDF/src/packing/TileToRowsCCPacker.cpp b/ext/OGDF/src/packing/TileToRowsCCPacker.cpp deleted file mode 100644 index 1e1437e0e..000000000 --- a/ext/OGDF/src/packing/TileToRowsCCPacker.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of class TileToRowsCCPacker - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - - -namespace ogdf { - - -template -struct TileToRowsCCPacker::RowInfo { - SListPure m_boxes; - typename POINT::numberType m_maxHeight, m_width; - - RowInfo() { - m_maxHeight = m_width = 0; - } -}; - - -template -class DecrIndexComparer -{ - const Array &m_box; - -public: - DecrIndexComparer(const Array &box) : m_box(box) { } - - int compare(const int &i, const int &j) const - { - typename POINT::numberType y1 = m_box[i].m_y, y2 = m_box[j].m_y; - - if (y1 > y2) return -1; - else if (y1 < y2) return 1; - else return 0; - } - - // avoid automatic creation of assignment operator - DecrIndexComparer &operator=(const DecrIndexComparer &); - - OGDF_AUGMENT_COMPARER(int) -}; - - -void TileToRowsCCPacker::call(Array &box, - Array &offset, - double pageRatio) -{ - callGeneric(box,offset,pageRatio); -} - - -void TileToRowsCCPacker::call(Array &box, - Array &offset, - double pageRatio) -{ - callGeneric(box,offset,pageRatio); -} - - -// -// finds out to which row box rect has to be added in order to minimize the -// covered area taking page ratio into account (the area is the area of the -// smallest rectangle covering all boxes and having the desired width/height -// ratio) -template -int TileToRowsCCPacker::findBestRow( - Array > &row, // current rows - int nRows, // number of rows currently used - double pageRatio, // desired page ratio (width / height) - const POINT &rect) // box to be added -{ - // Compute the width and height of the current arrangement of boxes - typename POINT::numberType totalWidth = 0; - typename POINT::numberType totalHeight = 0; - - int i; - for(i = 0; i < nRows; ++i) - { - const RowInfo &r = row[i]; - if (r.m_width > totalWidth) - totalWidth = r.m_width; - - totalHeight += r.m_maxHeight; - } - - // For each row, we compute the area we need if rect is added to this row; - // We store the index of the row minimizing the area in bestRow and return - // it. - int bestRow = -1; // we start with the case of a new row - totalWidth = max(totalWidth,rect.m_x); - totalHeight += rect.m_y; - - // note: the area has to take into account the desired page ratio! - double bestArea = max(pageRatio*totalHeight*totalHeight, - totalWidth*totalWidth/pageRatio); - - for(i = 0; i < nRows; ++i) - { - const RowInfo &r = row[i]; - - typename POINT::numberType w = r.m_width + rect.m_x; - typename POINT::numberType h = max(r.m_maxHeight,rect.m_y); - - double area = max(pageRatio*h*h, w*w/pageRatio); - - if (area < bestArea) { - bestArea = area; - bestRow = i; - } - } - - return bestRow; -} - - -template -void TileToRowsCCPacker::callGeneric(Array &box, - Array &offset, - double pageRatio) -{ - OGDF_ASSERT(box.size() == offset.size()); - // negative pageRatio makes no sense, - // pageRatio = 0 will cause division by zero - OGDF_ASSERT(pageRatio > 0); - - const int n = box.size(); - int nRows = 0; - Array > row(n); - - // sort the box indices according to decreasing height of the - // corresponding boxes - Array sortedIndices(n); - - int i; - for(i = 0; i < n; ++i) - sortedIndices[i] = i; - - DecrIndexComparer comp(box); - sortedIndices.quicksort(comp); - - // i iterates over all box indices according to decreasing height of - // the boxes - for(int iSI = 0; iSI < n; ++iSI) - { - int i = sortedIndices[iSI]; - - // Find the row which increases the covered area as few as possible. - // The area measured is the area of the smallest rectangle that covers - // all boxes and whose width / height ratio is pageRatio - int bestRow = findBestRow(row,nRows,pageRatio,box[i]); - - // bestRow = -1 indictes that a new row is added - if (bestRow < 0) { - struct RowInfo &r = row[nRows++]; - r.m_boxes.pushBack(i); - r.m_maxHeight = box[i].m_y; - r.m_width = box[i].m_x; - - } else { - struct RowInfo &r = row[bestRow]; - r.m_boxes.pushBack(i); - r.m_maxHeight = max(r.m_maxHeight,box[i].m_y); - r.m_width += box[i].m_x; - } - } - - // At this moment, we know which box is contained in which row. - // The following loop sets the required offset of each box - typename POINT::numberType y = 0; // sum of the heights of boxes 0,...,i-1 - for(i = 0; i < nRows; ++i) - { - const RowInfo &r = row[i]; - - typename POINT::numberType x = 0; // sum of the widths of the boxes to the left of box *it - - SListConstIterator it; - for(it = r.m_boxes.begin(); it.valid(); ++it) - { - offset[*it] = POINT(x,y); - x += box[*it].m_x; - } - - y += r.m_maxHeight; - } - - OGDF_ASSERT_IF(dlConsistencyChecks, checkOffsets(box,offset)); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/BoothLueker.cpp b/ext/OGDF/src/planarity/BoothLueker.cpp deleted file mode 100644 index a2758a528..000000000 --- a/ext/OGDF/src/planarity/BoothLueker.cpp +++ /dev/null @@ -1,582 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the Booth-Lueker planarity test. - * - * Implements planarity test and planar embedding algorithm. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf{ - -bool BoothLueker::isPlanarDestructive(Graph &G) -{ - bool ret = preparation(G,false); - m_parallelEdges.init(); - m_isParallel.init(); - - return ret; -} - -bool BoothLueker::isPlanar(const Graph &G) -{ - Graph Gp(G); - bool ret = preparation(Gp,false); - m_parallelEdges.init(); - m_isParallel.init(); - - return ret; -} - -// Prepares the planarity test and the planar embedding -// Parallel edges: do not need to be ignored, they can be handled -// by the planarity test. -// Selfloops: need to be ignored. -bool BoothLueker::preparation(Graph &G, bool embed) -{ - if (G.numberOfEdges() < 9 && !embed) - return true; - else if (G.numberOfEdges() < 3 && embed) - return true; - - node v; - edge e; - - SListPure selfLoops; - makeLoopFree(G,selfLoops); - - prepareParallelEdges(G); - - int isolated = 0; - forall_nodes(v,G) - if (v->degree() == 0) - isolated++; - - if (((G.numberOfNodes()-isolated) > 2) && - ((3*(G.numberOfNodes()-isolated) -6) < (G.numberOfEdges() - m_parallelCount))) - return false; - - bool planar = true; - - NodeArray tableNodes(G,0); - EdgeArray tableEdges(G,0); - NodeArray mark(G,0); - - EdgeArray componentID(G); - - // Determine Biconnected Components - int bcCount = biconnectedComponents(G,componentID); - - // Determine edges per biconnected component - Array > blockEdges(0,bcCount-1); - forall_edges(e,G) - { - blockEdges[componentID[e]].pushFront(e); - } - - // Determine nodes per biconnected component. - Array > blockNodes(0,bcCount-1); - int i; - for (i = 0; i < bcCount; i++) - { - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - if (!mark[e->source()]) - { - blockNodes[i].pushBack(e->source()); - mark[e->source()] = true; - } - if (!mark[e->target()]) - { - blockNodes[i].pushBack(e->target()); - mark[e->target()] = true; - } - } - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++itn) - mark[*itn] = false; - } - - // Perform Planarity Test for every biconnected component - - if (bcCount == 1) - { - if (G.numberOfEdges() >= 2) - { - // Compute st-numbering - NodeArray numbering(G,0); -#ifdef OGDF_DEBUG - int n = -#endif - stNumber(G,numbering); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(G,numbering,n)) - - EdgeArray backTableEdges(G,0); - forall_edges(e,G) - backTableEdges[e] = e; - - if (embed) - planar = doEmbed(G,numbering,backTableEdges,backTableEdges); - else - planar = doTest(G,numbering); - } - } - else - { - NodeArray > entireEmbedding(G); - for (i = 0; i < bcCount; i++) - { - Graph C; - - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - { - v = *itn; - node w = C.newNode(); - tableNodes[v] = w; - } - - NodeArray backTableNodes(C,0); - if (embed) - { - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - backTableNodes[tableNodes[*itn]] = *itn; - } - - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - edge f = C.newEdge(tableNodes[e->source()],tableNodes[e->target()]); - tableEdges[e] = f; - } - - EdgeArray backTableEdges(C,0); - for (it = blockEdges[i].begin(); it.valid(); ++it) - backTableEdges[tableEdges[*it]] = *it; - - if (C.numberOfEdges() >= 2) - { - // Compute st-numbering - NodeArray numbering(C,0); -#ifdef OGDF_DEBUG - int n = -#endif - stNumber(C,numbering); - OGDF_ASSERT_IF(dlConsistencyChecks,testSTnumber(C,numbering,n)) - - if (embed) - planar = doEmbed(C,numbering,backTableEdges,tableEdges); - else - planar = doTest(C,numbering); - - if (!planar) - break; - } - - if (embed) - { - forall_nodes(v,C) - { - node w = backTableNodes[v]; - adjEntry a; - forall_adj(a,v) - { - edge e = backTableEdges[a->theEdge()]; - adjEntry adj = (e->adjSource()->theNode() == w)? - e->adjSource() : e->adjTarget(); - entireEmbedding[w].pushBack(adj); - } - } - } - } - - if (planar && embed) - { - forall_nodes(v,G) - G.sort(v,entireEmbedding[v]); - } - - } - - while (!selfLoops.empty()) - { - v = selfLoops.popFrontRet(); - G.newEdge(v,v); - } - - OGDF_ASSERT_IF(dlConsistencyChecks, - planar == false || embed == false || G.representsCombEmbedding()) - - return planar; -} - - -// Performs a planarity test on a biconnected component -// of G. numbering contains an st-numbering of the component. -bool BoothLueker::doTest(Graph &G,NodeArray &numbering) -{ - bool planar = true; - - NodeArray* > > inLeaves(G); - NodeArray* > > outLeaves(G); - Array table(G.numberOfNodes()+1); - - node v; - forall_nodes(v,G) - { - edge e; - forall_adj_edges(e,v) - { - if (numbering[e->opposite(v)] > numbering[v]) - //sideeffect: loops are ignored - { - PlanarLeafKey* L = OGDF_NEW PlanarLeafKey(e); - inLeaves[v].pushFront(L); - } - } - table[numbering[v]] = v; - } - - forall_nodes(v,G) - { - SListIterator* > it; - for (it = inLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* L = *it; - outLeaves[L->userStructKey()->opposite(v)].pushFront(L); - } - } - - PlanarPQTree T; - - T.Initialize(inLeaves[table[1]]); - for (int i = 2; i < G.numberOfNodes(); i++) - { - if (T.Reduction(outLeaves[table[i]])) - { - T.ReplaceRoot(inLeaves[table[i]]); - T.emptyAllPertinentNodes(); - - } - else - { - planar = false; - break; - } - } - if (planar) - T.emptyAllPertinentNodes(); - - - // Cleanup - forall_nodes(v,G) - { - while (!inLeaves[v].empty()) - { - PlanarLeafKey* L = inLeaves[v].popFrontRet(); - delete L; - } - } - - return planar; -} - - -// Performs a planarity test on a biconnected component -// of G and embedds it planar. -// numbering contains an st-numbering of the component. -bool BoothLueker::doEmbed( - Graph &G, - NodeArray &numbering, - EdgeArray &backTableEdges, - EdgeArray &forwardTableEdges) -{ - - NodeArray* > > inLeaves(G); - NodeArray* > > outLeaves(G); - NodeArray > frontier(G); - NodeArray > opposed(G); - NodeArray > nonOpposed(G); - Array table(G.numberOfNodes()+1); - Array toReverse(1,G.numberOfNodes()+1,false); - - node v; - forall_nodes(v,G) - { - edge e; - - forall_adj_edges(e,v) - { - if (numbering[e->opposite(v)] > numbering[v]) - { - PlanarLeafKey* L = OGDF_NEW PlanarLeafKey(e); - inLeaves[v].pushFront(L); - } - } - table[numbering[v]] = v; - } - - forall_nodes(v,G) - { - SListIterator* > it; - for (it = inLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* L = *it; - outLeaves[L->userStructKey()->opposite(v)].pushFront(L); - } - } - - EmbedPQTree T; - - T.Initialize(inLeaves[table[1]]); - int i; - for (i = 2; i <= G.numberOfNodes(); i++) - { - if (T.Reduction(outLeaves[table[i]])) - { - T.ReplaceRoot(inLeaves[table[i]], frontier[table[i]], opposed[table[i]], nonOpposed[table[i]], table[i]); - T.emptyAllPertinentNodes(); - } - else - { - // Cleanup - forall_nodes(v,G) - { - while (!inLeaves[v].empty()) - { - PlanarLeafKey* L = inLeaves[v].popFrontRet(); - delete L; - } - } - return false; - } - } - - // Reverse adjacency lists if necessary - // This gives an upward embedding - for (i = G.numberOfNodes(); i >= 2; i--) - { - if (toReverse[i]) - { - while (!nonOpposed[table[i]].empty()) - { - v = nonOpposed[table[i]].popFrontRet(); - toReverse[numbering[v]] = true; - } - frontier[table[i]].reverse(); - } - else - { - while (!opposed[table[i]].empty()) - { - v = opposed[table[i]].popFrontRet(); - toReverse[numbering[v]] = true; - } - } - nonOpposed[table[i]].clear(); - opposed[table[i]].clear(); - } - - // Compute the entire embedding - NodeArray > entireEmbedding(G); - forall_nodes(v,G) - { - while (!frontier[v].empty()) - { - edge e = frontier[v].popFrontRet(); - entireEmbedding[v].pushBack( - (e->adjSource()->theNode() == v)? e->adjSource() : e->adjTarget()); - } - } - - NodeArray mark(G,false); - NodeArray > adjMarker(G,0); - forall_nodes(v,G) - adjMarker[v] = entireEmbedding[v].begin(); - v = table[G.numberOfNodes()]; - entireEmbed(G,entireEmbedding,adjMarker,mark,v); - - NodeArray > newEntireEmbedding(G); - if (m_parallelCount > 0) - { - forall_nodes(v,G) - { - //adjEntry a; - SListIterator it; - for(it=entireEmbedding[v].begin();it.valid();it++) - { - edge e = (*it)->theEdge(); // edge in biconnected component - edge trans = backTableEdges[e]; // edge in original graph. - if (!m_parallelEdges[trans].empty()) - { - // This original edge is the reference edge - // of a bundle of parallel edges - - ListIterator it; - // If v is source of e, insert the parallel edges - // in the order stored in the list. - if (e->adjSource()->theNode() == v) - { - adjEntry adj = e->adjSource(); - newEntireEmbedding[v].pushBack(adj); - for (it = m_parallelEdges[trans].begin(); it.valid(); it++) - { - edge parallel = forwardTableEdges[*it]; - adjEntry adj = parallel->adjSource()->theNode() == v ? - parallel->adjSource() : parallel->adjTarget(); - newEntireEmbedding[v].pushBack(adj); - } - } - else - // v is target of e, insert the parallel edges - // in the opposite order stored in the list. - // This keeps the embedding. - { - for (it = m_parallelEdges[trans].rbegin(); it.valid(); it--) - { - edge parallel = forwardTableEdges[*it]; - adjEntry adj = parallel->adjSource()->theNode() == v ? - parallel->adjSource() : parallel->adjTarget(); - newEntireEmbedding[v].pushBack(adj); - } - adjEntry adj = e->adjTarget(); - newEntireEmbedding[v].pushBack(adj); - } - } - else if (!m_isParallel[trans]) - // normal non-multi-edge - { - adjEntry adj = e->adjSource()->theNode() == v? - e->adjSource() : e->adjTarget(); - newEntireEmbedding[v].pushBack(adj); - } - // else e is a multi-edge but not the reference edge - } - } - - forall_nodes(v,G) - G.sort(v,newEntireEmbedding[v]); - } - else - { - forall_nodes(v,G) - G.sort(v,entireEmbedding[v]); - } - - - //cleanup - forall_nodes(v,G) - { - while (!inLeaves[v].empty()) - { - PlanarLeafKey* L = inLeaves[v].popFrontRet(); - delete L; - } - } - - return true; -} - -// Used by doEmbed. Computes an entire embedding from an -// upward embedding. -void BoothLueker::entireEmbed( - Graph &G, - NodeArray > &entireEmbedding, - NodeArray > &adjMarker, - NodeArray &mark, - node v) -{ - mark[v] = true; - SListIterator it; - for (it = adjMarker[v]; it.valid(); ++it) - { - adjEntry a = *it; - edge e = a->theEdge(); - adjEntry adj = (e->adjSource()->theNode() == v)? - e->adjTarget() : e->adjSource(); - node w = adj->theNode(); - entireEmbedding[w].pushFront(adj); - if (!mark[w]) - entireEmbed(G,entireEmbedding,adjMarker,mark,w); - } -} - - - -void BoothLueker::prepareParallelEdges(Graph &G) -{ - edge e; - - // Stores for one reference edge all parallel edges. - m_parallelEdges.init(G); - // Is true for any multiedge, except for the reference edge. - m_isParallel.init(G,false); - getParallelFreeUndirected(G,m_parallelEdges); - m_parallelCount = 0; - forall_edges(e,G) - { - if (!m_parallelEdges[e].empty()) - { - ListIterator it; - for (it = m_parallelEdges[e].begin(); it.valid(); it++) - { - m_isParallel[*it] = true; - m_parallelCount++; - } - } - } -} - - -} diff --git a/ext/OGDF/src/planarity/BoyerMyrvold.cpp b/ext/OGDF/src/planarity/BoyerMyrvold.cpp deleted file mode 100644 index 84accf40a..000000000 --- a/ext/OGDF/src/planarity/BoyerMyrvold.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of the wrapper class of the Boyer-Myrvold planarity test - * - * \author Jens Schmidt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - -// returns true, if g is planar, false otherwise. this is the -// routine, which avoids the overhead of copying the input graph. -// it is therefore not suitable, if your graph must not be changed. -bool BoyerMyrvold::isPlanarDestructive(Graph& g) -{ - clear(); - nOfStructures = 0; - - // less than 9 edges are always planar - if (g.numberOfEdges() < 9) return true; - - SListPure dummy; - pBMP = new BoyerMyrvoldPlanar(g,false,BoyerMyrvoldPlanar::doNotEmbed,false, - dummy,false,true); - return pBMP->start(); -} - - -// returns true, if g is planar, false otherwise. -// use this slower routine, if your graph must not be changed. -bool BoyerMyrvold::isPlanar(const Graph& g) -{ - clear(); - nOfStructures = 0; - - // less than 9 edges are always planar - if (g.numberOfEdges() < 9) return true; - - Graph h(g); - SListPure dummy; - pBMP = new BoyerMyrvoldPlanar(h,false,BoyerMyrvoldPlanar::doNotEmbed,false, - dummy,false,true); - return pBMP->start(); -} - - -// Transforms KuratowskiWrapper in KuratowskiSubdivision -void BoyerMyrvold::transform( - const KuratowskiWrapper& source, - KuratowskiSubdivision& target, - NodeArray& count, - EdgeArray& countEdge) -{ - // init linear counting structure - node kn[6]; - int k = 0; - SListConstIterator itE; - for (itE = source.edgeList.begin(); itE.valid(); ++itE) { - const edge& e(*itE); - OGDF_ASSERT(!countEdge[e]); - countEdge[e] = 1; - if (++count[e->source()] == 3) kn[k++] = e->source(); - if (++count[e->target()] == 3) kn[k++] = e->target(); - } - - // transform edgelist of KuratowskiSubdivision to KuratowskiWrapper - OGDF_ASSERT(k==5 || k==6); - node n; - edge e,f,h; - List L; - if (k==5) { // K5 - kn[5] = 0; - target.init(10); - for (int k = 0; k<5; k++) { - forall_adj_edges(e,kn[k]) { - if (!countEdge[e]) continue; - n = kn[k]; - f = e; - // traverse degree-2-path - while (count[n = f->opposite(n)] == 2) { - L.pushBack(f); - forall_adj_edges(h,n) { - if (countEdge[h] && h != f) { - f = h; - break; - } - } - } - L.pushBack(f); - int i = 0; - while (kn[i] != n) i++; - if (i > k) { - if (k==0) i--; - else if (k==1) i+=2; - else i += k+2; - target[i].conc(L); - } else L.clear(); - } - } - } else { // k33 - target.init(9); - int touched[6] = { -1, -1, -1, -1, -1, -1}, t=0, i=0; - for (int k = 0; k<6; k++) { - if (touched[k] != -1) continue; - forall_adj_edges(e,kn[k]) { - if (!countEdge[e]) continue; - n = kn[k]; - f = e; - while(count[n = f->opposite(n)] == 2) { - L.pushBack(f); - forall_adj_edges(h,n) { - if (countEdge[h] && h != f) { - f = h; - break; - } - } - } - L.pushBack(f); - int j = 0; - while (kn[j] != n) j++; - if (touched[j] == -1) - touched[j] = t++; - target[i*3 + touched[j]].conc(L); - } - i++; - } - } - - // destruct linear counting structure - for (itE = source.edgeList.begin(); itE.valid(); ++itE) { - const edge& e(*itE); - countEdge[e] = 0; - count[e->source()] = 0; - count[e->target()] = 0; - } -} - -// Transforms KuratowskiWrapper-List in KuratowskiSubdivision-List with respect to sieving constraints -void BoyerMyrvold::transform( - const SList& sourceList, - SList& targetList, - const Graph& g, - const bool onlyDifferent) -{ - if (sourceList.empty()) return; - targetList.clear(); - NodeArray count(g,0); - EdgeArray countEdge(g,0); - SListConstIterator it; - node lastEmbeddedVertex = NULL; - - // transform each KuratowskiWrapper into KuratowskiSubdivision - for (it = sourceList.begin(); it.valid(); ++it) { - if (!onlyDifferent || (*it).V != lastEmbeddedVertex) { - lastEmbeddedVertex = (*it).V; - KuratowskiSubdivision s; - transform(*it,s,count,countEdge); - - targetList.pushBack(s); - } - } -} - -// returns true, if g is planar, false otherwise. in addition, -// g contains a planar embedding, if planar. if not planar, -// kuratowski subdivisions are added to output. -// use this function, if g may be changed. -// use embeddingGrade to bound the overall number of extracted kuratowski subdivisions; -// use the value 0 to extract no kuratowski subdivision and the value -1 to find as much -// as possible. value -2 doesn't even invoke the FIND-procedure. -bool BoyerMyrvold::planarEmbedDestructive( - Graph& g, - SList& output, - int embeddingGrade, - bool bundles, - bool limitStructures, - bool randomDFSTree, - bool avoidE2Minors) -{ - OGDF_ASSERT(embeddingGrade != BoyerMyrvoldPlanar::doNotEmbed); - - clear(); - SListPure dummy; - pBMP = new BoyerMyrvoldPlanar(g,bundles,embeddingGrade,limitStructures,dummy, - randomDFSTree,avoidE2Minors); - bool planar = pBMP->start(); - OGDF_ASSERT(!planar || g.genus()==0); - - nOfStructures = dummy.size(); - - // Kuratowski extraction - if (embeddingGrade > BoyerMyrvoldPlanar::doFindZero || - embeddingGrade == BoyerMyrvoldPlanar::doFindUnlimited) { - ExtractKuratowskis extract(*pBMP); - if (bundles) { - extract.extractBundles(dummy,output); - } else { - extract.extract(dummy,output); - } - OGDF_ASSERT(planar || !output.empty()); - } - return planar; -} - -// returns true, if g is planar, false otherwise. in addition, -// h contains a planar embedding, if planar. if not planar, list -// contains a kuratowski subdivision. -// use this slower function, if g must not be changed. -// use embeddingGrade to bound the overall number of extracted kuratowski subdivisions; -// use the value 0 to extract no kuratowski subdivision and the value -1 to find as much -// as possible. value -2 doesn't even invoke the FIND-procedure. -bool BoyerMyrvold::planarEmbed( - Graph& g, - SList& output, - int embeddingGrade, - bool bundles, - bool limitStructures, - bool randomDFSTree, - bool avoidE2Minors) -{ - OGDF_ASSERT(embeddingGrade != BoyerMyrvoldPlanar::doNotEmbed); - - clear(); - GraphCopySimple h(g); - SListPure dummy; - pBMP = new BoyerMyrvoldPlanar(h,bundles,embeddingGrade,limitStructures,dummy, - randomDFSTree,avoidE2Minors); - bool planar = pBMP->start(); - OGDF_ASSERT(!planar || h.genus()==0); - - nOfStructures = dummy.size(); - - // Kuratowski extraction - if (embeddingGrade > BoyerMyrvoldPlanar::doFindZero || - embeddingGrade == BoyerMyrvoldPlanar::doFindUnlimited) { - ExtractKuratowskis extract(*pBMP); - if (bundles) { - extract.extractBundles(dummy,output); - } else { - extract.extract(dummy,output); - } - OGDF_ASSERT(planar || !output.empty()); - - // convert kuratowski edges in original graph edges - if (!output.empty()) { - SListIterator it; - SListIterator itE; - for (it = output.begin(); it.valid(); ++it) { - for (itE = (*it).edgeList.begin(); itE.valid(); ++itE) - (*itE) = h.original(*itE); - } - } - } - - // copy adjacency lists, if planar - if (planar) { - node v; - adjEntry adj; - SListPure entries; - forall_nodes(v,g) { - entries.clear(); - forall_adj(adj,h.copy(v)) { - OGDF_ASSERT(adj->theNode() == h.copy(v)); - edge e = h.original(adj->theEdge()); - OGDF_ASSERT(e->graphOf() == &g); - //if (e->source() == v) { - if(adj == adj->theEdge()->adjSource()) { - entries.pushBack(e->adjSource()); - OGDF_ASSERT(e->adjSource()->theNode() == v); - } else { - entries.pushBack(e->adjTarget()); - OGDF_ASSERT(e->adjTarget()->theNode() == v); - } - } - g.sort(v,entries); - } - } - - return planar; -} - -// returns true, if graph copy h is planar, false otherwise. in addition, -// h contains a planar embedding, if planar. if not planar, list -// contains a kuratowski subdivision. -// use this slower function, if g must not be changed. -// use embeddingGrade to bound the overall number of extracted kuratowski subdivisions; -// use the value 0 to extract no kuratowski subdivision and the value -1 to find as much -// as possible. value -2 doesn't even invoke the FIND-procedure. -bool BoyerMyrvold::planarEmbed( - //const Graph& g, - GraphCopySimple& h, - SList& output, - int embeddingGrade, - bool bundles, - bool limitStructures, - bool randomDFSTree, - bool avoidE2Minors) -{ - OGDF_ASSERT(embeddingGrade != BoyerMyrvoldPlanar::doNotEmbed); - - clear(); - //OGDF_ASSERT(&h.original() == &g); - SListPure dummy; - pBMP = new BoyerMyrvoldPlanar(h,bundles,embeddingGrade,limitStructures,dummy, - randomDFSTree,avoidE2Minors); - bool planar = pBMP->start(); - OGDF_ASSERT(!planar || h.genus()==0); - - nOfStructures = dummy.size(); - - // Kuratowski extraction - if (embeddingGrade > BoyerMyrvoldPlanar::doFindZero || - embeddingGrade == BoyerMyrvoldPlanar::doFindUnlimited) { - ExtractKuratowskis extract(*pBMP); - if (bundles) { - extract.extractBundles(dummy,output); - } else { - extract.extract(dummy,output); - } - OGDF_ASSERT(planar || !output.empty()); - - // convert kuratowski edges in original graph edges - if (!output.empty()) { - SListIterator it; - SListIterator itE; - for (it = output.begin(); it.valid(); ++it) { - for (itE = (*it).edgeList.begin(); itE.valid(); ++itE) - (*itE) = h.original(*itE); - } - } - } - - return planar; -} - -} diff --git a/ext/OGDF/src/planarity/BoyerMyrvoldInit.cpp b/ext/OGDF/src/planarity/BoyerMyrvoldInit.cpp deleted file mode 100644 index 9133feed2..000000000 --- a/ext/OGDF/src/planarity/BoyerMyrvoldInit.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of the class BoyerMyrvoldInit - * - * \author Jens Schmidt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -// constructor -BoyerMyrvoldInit::BoyerMyrvoldInit(BoyerMyrvoldPlanar* pBM) : - m_g(pBM->m_g), - // initialize Members of BoyerMyrvoldPlanar - m_embeddingGrade(pBM->m_embeddingGrade), - m_randomDFSTree(pBM->m_randomDFSTree), - - m_realVertex(pBM->m_realVertex), - m_dfi(pBM->m_dfi), - m_nodeFromDFI(pBM->m_nodeFromDFI), - m_link(pBM->m_link), - m_adjParent(pBM->m_adjParent), - m_leastAncestor(pBM->m_leastAncestor), - m_edgeType(pBM->m_edgeType), - m_lowPoint(pBM->m_lowPoint), - m_highestSubtreeDFI(pBM->m_highestSubtreeDFI), - m_separatedDFSChildList(pBM->m_separatedDFSChildList), - m_pNodeInParent(pBM->m_pNodeInParent) -{ - OGDF_ASSERT(pBM != NULL); - OGDF_ASSERT(m_embeddingGrade <= BoyerMyrvoldPlanar::doNotFind || - m_highestSubtreeDFI.graphOf() == &m_g); -} - -// start DFS-traversal -void BoyerMyrvoldInit::computeDFS() { - StackPure stack; - int nextDFI = 1; - const int numberOfNodes = m_g.numberOfNodes(); - node v,w,next,parentNode; - adjEntry adj,prnt; - edge e; - - // get random dfs-tree, if wanted - if (m_randomDFSTree) { - SListPure list; - SListPure adjList; - SListIterator it; - // permute nodelist - m_g.allNodes(list); - list.permute(); - for (it = list.begin(); it.valid(); ++it) { - node& v(*it); - // permute adjEntries - if (v->degree() == 0) { - m_dfi[v] = nextDFI; - m_leastAncestor[v] = nextDFI; - m_nodeFromDFI[nextDFI] = v; - ++nextDFI; - } else { - adjList.clear(); - m_g.adjEntries(v,adjList); - adjList.permute(); - m_g.sort(v,adjList); - stack.push(v->firstAdj()); - } - } - } else { - for (next = m_g.firstNode(); next; next = next->succ()) - if (next->degree() == 0) { - m_dfi[next] = nextDFI; - m_leastAncestor[next] = nextDFI; - m_nodeFromDFI[nextDFI] = next; - ++nextDFI; - } else stack.push(next->firstAdj()); - } - - while (nextDFI <= numberOfNodes) { - OGDF_ASSERT(!stack.empty()); - prnt = stack.pop(); - v = prnt->theNode(); - // check, if node v was visited before. - if (m_dfi[v] != 0) continue; - // parentNode=NULL on first node on connected component - parentNode = prnt->twinNode(); - if (m_dfi[parentNode] == 0) parentNode = NULL; - - // if not, mark node as visited and initialize NodeArrays - m_dfi[v] = nextDFI; - m_leastAncestor[v] = nextDFI; - m_nodeFromDFI[nextDFI] = v; - ++nextDFI; - - // push all adjacent nodes onto stack - forall_adj(adj,v) { - e = adj->theEdge(); - if (adj == prnt && parentNode != NULL) continue; - - // check for self-loops and dfs- and dfs-parallel edges - w = adj->twinNode(); - if (m_dfi[w] == 0) { - m_edgeType[e] = EDGE_DFS; - m_adjParent[w] = adj; - m_link[CW][w] = adj; - m_link[CCW][w] = adj; - - // found new dfs-edge: preorder - stack.push(adj->twin()); - } else if (w == v) { - // found self-loop - m_edgeType[e] = EDGE_SELFLOOP; - } else { - // node w already has been visited and is an dfs-ancestor of v - OGDF_ASSERT(m_dfi[w] < m_dfi[v]); - if (w == parentNode) { - // found parallel edge of dfs-parent-edge - m_edgeType[e] = EDGE_DFS_PARALLEL; - } else { - // found backedge - m_edgeType[e] = EDGE_BACK; - // set least Ancestor - if (m_dfi[w] < m_leastAncestor[v]) - m_leastAncestor[v] = m_dfi[w]; - } - } - } - } -} - -// creates a virtual vertex of vertex father and embeds it as -// root in the biconnected child component containing of one edge -void BoyerMyrvoldInit::createVirtualVertex(const adjEntry father) -{ - // check that adjEntry is valid - OGDF_ASSERT(father != NULL); - - // create new virtual Vertex and copy properties from non-virtual node - const node virt = m_g.newNode(); - m_realVertex[virt] = father->theNode(); - m_dfi[virt] = -m_dfi[father->twinNode()]; - m_nodeFromDFI[m_dfi[virt]] = virt; - - // set links for traversal of bicomps - m_link[CW][virt] = father->twin(); - m_link[CCW][virt] = father->twin(); - - // move edge to new virtual Vertex - edge e = father->theEdge(); - if (e->source() == father->theNode()) { - // e is outgoing edge - m_g.moveSource(e,virt); - } else { - // e is ingoing edge - m_g.moveTarget(e,virt); - } -} - -// calculates the lowpoints -void BoyerMyrvoldInit::computeLowPoints() -{ - node w; - adjEntry adj,lastAdj; - - for (int i = m_g.numberOfNodes(); i >= 1; --i) { - const node v = m_nodeFromDFI[i]; - - // initialize lowpoints with least Ancestors and highpoints with dfi of node - m_lowPoint[v] = m_leastAncestor[v]; - if (m_embeddingGrade > BoyerMyrvoldPlanar::doNotFind) m_highestSubtreeDFI[v] = i; - - // set the lowPoint of v by minimizing over its children lowPoints - // create virtual vertex for each child - adj = v->firstAdj(); - while (adj) { - lastAdj = adj; - adj = adj->succ(); - - // avoid self-loops, parallel- and backedges - if (m_edgeType[lastAdj->theEdge()] != EDGE_DFS) continue; - w = lastAdj->twinNode(); - - // avoid parent dfs-node - if (m_dfi[w] <= i) continue; - - // set lowPoints and highpoints - if (m_lowPoint[w] < m_lowPoint[v]) m_lowPoint[v] = m_lowPoint[w]; - if (m_embeddingGrade > BoyerMyrvoldPlanar::doNotFind && - m_highestSubtreeDFI[w] > m_highestSubtreeDFI[v]) - m_highestSubtreeDFI[v] = m_highestSubtreeDFI[w]; - - // create virtual vertex for each dfs-child - createVirtualVertex(lastAdj); - } - } -} - -// compute the separated DFS children for all nodes in ascending order of -// their lowpoint values in linear time -void BoyerMyrvoldInit::computeDFSChildLists() { - // Bucketsort by lowpoint values - BucketLowPoint blp(m_lowPoint); - - // copy all non-virtual nodes in a list and sort them with Bucketsort - SListPure allNodes; - node v; - forall_nodes(v,m_g) if (m_dfi[v]>0) allNodes.pushBack(v); - allNodes.bucketSort(1,m_nodeFromDFI.high(),blp); - - // build DFS-child list - SListConstIterator it; - for (it = allNodes.begin(); it.valid(); ++it) { - v = *it; - OGDF_ASSERT(m_dfi[v]>0); - - // if node is not root: insert node after last element of parent's DFSChildList - // to achieve constant time deletion later: - // set a pointer for each node to predecessor of his representative in the list - if (m_adjParent[v] != NULL) { - OGDF_ASSERT(m_realVertex[m_adjParent[v]->theNode()]!=NULL); - - m_pNodeInParent[v] = m_separatedDFSChildList[m_realVertex[m_adjParent[v]->theNode()]].pushBack(v); - - OGDF_ASSERT(m_pNodeInParent[v].valid()); - OGDF_ASSERT(v == *m_pNodeInParent[v]); - } else m_pNodeInParent[v] = NULL; - } -} - -} - diff --git a/ext/OGDF/src/planarity/BoyerMyrvoldPlanar.cpp b/ext/OGDF/src/planarity/BoyerMyrvoldPlanar.cpp deleted file mode 100644 index a56cdbf69..000000000 --- a/ext/OGDF/src/planarity/BoyerMyrvoldPlanar.cpp +++ /dev/null @@ -1,927 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of the class BoyerMyrvoldPlanar - * - * \author Jens Schmidt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -namespace ogdf { - - -// constructor -BoyerMyrvoldPlanar::BoyerMyrvoldPlanar( - Graph& g, - bool bundles, - int embeddingGrade, // see enumeration enumEmbeddingGrade for options - bool limitStructures, // limits number of structures to embeddingGrade - SListPure& output, - bool randomDFSTree, // creates a random DFS-Tree, if true - bool avoidE2Minors) // avoids multiple identical minors (type AE2/E2) -: -m_g(g), - m_bundles(bundles), - m_embeddingGrade(embeddingGrade), - m_limitStructures(limitStructures), - m_randomDFSTree(randomDFSTree), - m_avoidE2Minors(avoidE2Minors), - - // BoyerMyrvoldInit members - m_realVertex(g,0), - m_dfi(g,0), - m_nodeFromDFI(-g.numberOfNodes(),g.numberOfNodes(),0), - m_adjParent(g,0), - m_leastAncestor(g), // doesn't need initialization - m_edgeType(g,EDGE_UNDEFINED), - m_lowPoint(g), // doesn't need initialization - m_separatedDFSChildList(g), - m_pNodeInParent(g), // doesn't need initialization - - // Walkup & Walkdown members - m_visited(g,0), - m_flipped(g,false), - m_backedgeFlags(g), - m_pertinentRoots(g), - m_output(output) -{ - m_link[CCW].init(g,0); - m_link[CW].init(g,0); - m_beforeSCE[CCW].init(g,0); - m_beforeSCE[CW].init(g,0); - m_output.clear(); - // apply this only, if FIND-procedure will be called - if (m_embeddingGrade > doNotFind) { - m_pointsToRoot.init(g,0); - m_visitedWithBackedge.init(g,0); - m_highestSubtreeDFI.init(g); // doesn't need initialization - } - m_flippedNodes = 0; -} - - -// walk upon external face in the given direction, see getSucessorOnExternalFace -// the difference is, that all inactive vertices are skipped, i.e. the returned node -// is active in relation to the node with dfi v -// in the special case of degree-one nodes the direction is not changed -// info returns the dynamic nodetype of the endnode -node BoyerMyrvoldPlanar::activeSuccessor(node w, int& direction, int v, int& info) -{ - OGDF_ASSERT(w!=0); - OGDF_ASSERT(w->degree()>0); - OGDF_ASSERT(m_link[CW][w]!=0 && m_link[CCW][w]!=0); - node next; - adjEntry adj; - - do { - adj = m_link[direction][w]; - next = adj->theNode(); - OGDF_ASSERT(next!=0); - OGDF_ASSERT(next->degree()>0); - OGDF_ASSERT(m_link[CW][next]!=0 && m_link[CCW][next]!=0); - - if (w->degree() > 1) - direction = adj==beforeShortCircuitEdge(next,CCW)->twin(); - w=next; - info = infoAboutNode(next,v); - - } while (info==0); // until not inactive - return next; -} - - -// merges adjEntries of virtual node w and associated real vertex x according to -// given outgoing directions x_dir and w_dir. -// j is the outgoing traversal direction of the current embedded node. -void BoyerMyrvoldPlanar::mergeBiconnectedComponent(StackPure& stack, const int /* j */) -{ - const int w_dir = stack.pop(); // outgoing direction of w - const int x_dir = stack.pop(); // outgoing direction of x - int tmp = stack.pop(); - const node w = m_nodeFromDFI[tmp]; // virtual DFS-Successor of x - const node w_child = m_nodeFromDFI[-tmp]; // real unique DFS-Child of bicomp with root w - const node x = m_realVertex[w]; - - // set new external face neighbors and save adjEntry, where edges will be merged - adjEntry mergeEntry; - Direction dir = (x_dir == CCW) ? before : after; - mergeEntry = beforeShortCircuitEdge(x,!x_dir)->twin(); - m_link[!x_dir][x] = m_link[!w_dir][w]; - m_beforeSCE[!x_dir][x] = m_beforeSCE[!w_dir][w]; - - // merge real and virtual nodes, flip biconnected component root if neccesary - OGDF_ASSERT(!m_flipped[w_child]); - adjEntry adj = w->firstAdj(); - edge e; - if (x_dir==w_dir) { - // if not flipped - if (dir==after) { - mergeEntry=mergeEntry->cyclicSucc(); - dir=before; - } - } else { - // if flipped: - // set unique DFS-child of associated bicomp root node to "flipped" - m_flipped[w_child] = true; - ++m_flippedNodes; - if (dir==before) { - mergeEntry = mergeEntry->cyclicPred(); - dir = after; - } - } - - // merge adjEntries - adjEntry temp; - while (adj != 0) { - temp = adj->succ(); - e = adj->theEdge(); - OGDF_ASSERT(e->source() != x && e->target() != x); - // this allows also self-loops when moving adjacency entries - if (e->source() == w) { - m_g.moveSource(e,mergeEntry,dir); - } else m_g.moveTarget(e,mergeEntry,dir); - adj = temp; - } - - // remove w from pertinent roots of x - OGDF_ASSERT(!m_pertinentRoots[x].empty()); - OGDF_ASSERT(m_pertinentRoots[x].front() == w); - m_pertinentRoots[x].popFront(); - - // consider x's unique dfs-successor in pertinent bicomp: - // remove this successor from separatedChildList of x using - // saved pointer pNodeInParent in constant time - OGDF_ASSERT(!m_separatedDFSChildList[x].empty()); - OGDF_ASSERT(m_pNodeInParent[w_child].valid()); - m_separatedDFSChildList[x].del(m_pNodeInParent[w_child]); - - // delete virtual vertex, it must not contain any edges any more - OGDF_ASSERT(w->firstAdj()==0); - m_nodeFromDFI[m_dfi[w]]=0; - m_g.delNode(w); -} - - -// the same as mergeBiconnectedComponent, but without any embedding-related -// operations -void BoyerMyrvoldPlanar::mergeBiconnectedComponentOnlyPlanar( - StackPure& stack, - const int /* j */) -{ - const int w_dir = stack.pop(); // outgoing direction of w - const int x_dir = stack.pop(); // outgoing direction of x - int tmp = stack.pop(); - const node w = m_nodeFromDFI[tmp]; // virtual DFS-Successor of x - const node w_child = m_nodeFromDFI[-tmp]; // real unique DFS-Child of bicomp with root w - const node x = m_realVertex[w]; - - // set new external face neighbors and save adjEntry, where edges will be merged - m_link[!x_dir][x] = m_link[!w_dir][w]; - m_beforeSCE[!x_dir][x] = m_beforeSCE[!w_dir][w]; - - // merge real and virtual nodes, flipping is not necessary here - OGDF_ASSERT(!m_flipped[w_child]); - adjEntry adj = w->firstAdj(); - edge e; - adjEntry temp; - while (adj != 0) { - temp = adj->succ(); - e = adj->theEdge(); - OGDF_ASSERT(e->source() != x && e->target() != x); - // this allows also self-loops when moving adjacency entries - if (e->source() == w) { - m_g.moveSource(e,x); - } else m_g.moveTarget(e,x); - adj = temp; - } - - // remove w from pertinent roots of x - OGDF_ASSERT(m_pertinentRoots[x].front() == w); - m_pertinentRoots[x].popFront(); - - // consider x's unique dfs-successor in pertinent bicomp: - // remove this successor from separatedChildList of x using - // saved pointer pNodeInParent in constant time - OGDF_ASSERT(m_pNodeInParent[w_child].valid()); - m_separatedDFSChildList[x].del(m_pNodeInParent[w_child]); - - // delete virtual vertex, it must not contain any edges any more - OGDF_ASSERT(w->firstAdj()==0); - m_nodeFromDFI[m_dfi[w]]=0; - m_g.delNode(w); -} - - -// embeds backedges from node v with direction v_dir to node w -// with direction w_dir. i is the current embedded node. -void BoyerMyrvoldPlanar::embedBackedges( - const node v, - const int v_dir, - const node w, - const int w_dir, - const int /* i */) -{ - OGDF_ASSERT(!m_backedgeFlags[w].empty()); - OGDF_ASSERT(v!=0 && w!=0); - OGDF_ASSERT(m_link[CCW][v]!=0 && m_link[CW][v]!=0); - OGDF_ASSERT(m_link[CCW][w]!=0 && m_link[CW][w]!=0); - - // if one edge is a short circuit edge, compute the former underlying adjEntry - // the adjEntry of v, used for inserting backedges - adjEntry mergeEntryV = beforeShortCircuitEdge(v,v_dir)->twin(); - Direction insertv = (v_dir==CCW) ? after : before; - // the adjEntry of w, used for inserting backedges - adjEntry mergeEntryW = beforeShortCircuitEdge(w,!w_dir)->twin(); - Direction insertw = (w_dir==CCW) ? before : after; - - // the first backedge in the backedgeFlags-list will be - // the new external face adjEntry - edge e; - SListConstIterator it; - // save first BackedgeEntry - adjEntry firstBack = m_backedgeFlags[w].front(); - for (it = m_backedgeFlags[w].begin(); it.valid(); ++it) { - // embed this backedge - e = (*it)->theEdge(); - - OGDF_ASSERT(w==e->source() || w==e->target()); - //OGDF_ASSERT((*it)->theNode()==m_nodeFromDFI[i]); - - if (e->source() == w) { - // insert backedge to v - m_g.moveTarget(e,mergeEntryV,insertv); - // insert backedge to w - m_g.moveSource(e,mergeEntryW,insertw); - } else { - // insert backedge to v - m_g.moveSource(e,mergeEntryV,insertv); - // insert backedge to w - m_g.moveTarget(e,mergeEntryW,insertw); - } - } - - // set external face link for this backedge and delete out-dated short - // circuit links - m_link[v_dir][v] = firstBack->twin(); - m_beforeSCE[v_dir][v]=0; - m_link[!w_dir][w] = firstBack; - m_beforeSCE[!w_dir][w]=0; - - // decrease counter of backedges per bicomp - if (m_embeddingGrade > doNotFind) { - node bicompRoot = m_pointsToRoot[m_backedgeFlags[w].front()->theEdge()]; - m_visitedWithBackedge[bicompRoot] -= m_backedgeFlags[w].size(); - OGDF_ASSERT(m_visitedWithBackedge[bicompRoot] >= 0); - } - - // delete BackedgeFlags - m_backedgeFlags[w].clear(); -} - - -// the same as embedBackedges, but for the planar check without returned embedding -void BoyerMyrvoldPlanar::embedBackedgesOnlyPlanar( - const node v, - const int v_dir, - const node w, - const int w_dir, - const int /* i */) -{ - OGDF_ASSERT(!m_backedgeFlags[w].empty()); - OGDF_ASSERT(m_link[CCW][v]!=0 && m_link[CW][v]!=0); - OGDF_ASSERT(m_link[CCW][w]!=0 && m_link[CW][w]!=0); - - // the last backedge in the backedgeFlags-list will be - // the new external face adjEntry - edge e; - SListIterator it; - // save last BackedgeEntry - adjEntry lastBack = m_backedgeFlags[w].back(); - for(it=m_backedgeFlags[w].begin();it.valid();++it) { - // embed backedge - e = (*it)->theEdge(); - - //OGDF_ASSERT((*it)->theNode()==m_nodeFromDFI[i]); - OGDF_ASSERT(w==e->source() || w==e->target()); - - if (e->source() == w) { - // insert backedge to v - m_g.moveTarget(e,v); - } else { - // insert backedge to v - m_g.moveSource(e,v); - } - } - - // set external face link for this backedge and delete out-dated short - // circuit links - m_link[v_dir][v] = lastBack->twin(); - m_beforeSCE[v_dir][v]=0; - m_link[!w_dir][w] = lastBack; - m_beforeSCE[!w_dir][w]=0; - - // delete BackedgeFlags - m_backedgeFlags[w].clear(); -} - - -// create short circuit edge from node v with direction v_dir to node w with outgoing -// direction w_dir. -void BoyerMyrvoldPlanar::createShortCircuitEdge( - const node v, - const int v_dir, - const node w, - const int w_dir) -{ - // save former neighbors - if (m_beforeSCE[v_dir][v]==0) m_beforeSCE[v_dir][v]=m_link[v_dir][v]; - if (m_beforeSCE[!w_dir][w]==0) m_beforeSCE[!w_dir][w]=m_link[!w_dir][w]; - // set new short circuit edge - adjEntry temp = m_beforeSCE[!w_dir][w]->twin(); - m_link[!w_dir][w] = m_beforeSCE[v_dir][v]->twin(); - m_link[v_dir][v] = temp; -} - - -// Walkup -// finds pertinent subgraph for descendant w of v. -// marks visited nodes with marker and returns the last traversed node. -node BoyerMyrvoldPlanar::walkup( - const node v, - const node w, - const int marker, - const edge back) -{ - const int i = m_dfi[v]; - node x = w; - node y = w; - node temp; - int x_dir = CW; - int y_dir = CCW; - - while (m_visited[x]!=marker && m_visited[y]!=marker) - { - m_visited[x] = marker; - m_visited[y] = marker; - if (m_embeddingGrade > doNotFind) { - m_visitedWithBackedge[x] = back->index(); - m_visitedWithBackedge[y] = back->index(); - } - - // is x or y root vertex? - if (m_realVertex[x] != 0) { - temp=x; - } else if (m_realVertex[y] != 0) { - temp=y; - } else temp=0; - - if (temp != 0) { - // put pertinent root into the list of its non-virtual vertex. - // the insert-position is either front or back of the list, this - // depends on the external activity of the pertinent root's - // biconnected component. - - x = m_realVertex[temp]; - y = x; - - OGDF_ASSERT(m_visited[x]==marker || m_pertinentRoots[x].empty()); - // push pertinent root - if (m_lowPoint[m_nodeFromDFI[-m_dfi[temp]]] < i) { - m_pertinentRoots[x].pushBack(temp); - } else m_pertinentRoots[x].pushFront(temp); - // found v, finish walkup and return last traversed node - if (x==v) { - m_visited[x] = marker; - return temp; - } - } else { - // traverse to external face successors - x = successorOnExternalFace(x,x_dir); - y = successorOnExternalFace(y,y_dir); - } - } - - // return last traversed node - return (m_visited[x] == marker) ? x : y; -} - - -// Walkdown -// for DFS-child w of the current processed vertex v': embed all backedges -// to the virtual node v of v' -// returns 1, iff the embedding process found a stopping configuration -int BoyerMyrvoldPlanar::walkdown( - const int i, // dfi of rootvertex v' - const node v, // v is virtual node of v' - FindKuratowskis *findKuratowskis) -{ - StackPure stack; - node stopX = 0; - - bool stoppingNodesFound = 0; // 0=false,1=true,2=break - - // in both directions - // j=current outgoing direction of current embedded node v - for (int j = CCW; j <= CW; ++j) { - int w_dir = j; // direction of traversal of node w - - node w = successorOnExternalFace(v,w_dir); // current node - - while (w != v) { - // assert, that CCW[] and CW[] return that adjEntry of the neighbor - OGDF_ASSERT(beforeShortCircuitEdge(w,w_dir)->twinNode()==w); - - // if backedgeFlag is set - if (!m_backedgeFlags[w].empty()) { - if (m_embeddingGrade != doNotEmbed) { - // compute entire embedding - while (!stack.empty()) mergeBiconnectedComponent(stack,j); - // embed the backedge - embedBackedges(v,j,w,w_dir,i); - } else { - // compute only planarity, not the entire embedding - while (!stack.empty()) mergeBiconnectedComponentOnlyPlanar(stack,j); - // embed the backedge - embedBackedgesOnlyPlanar(v,j,w,w_dir,i); - } - } - - // if pertinentRoots of w is not empty - if (!m_pertinentRoots[w].empty()) { - // append pertinent root of w and direction of entry in w to stack - // y is root of pertinent child bicomp - node root = m_pertinentRoots[w].front(); - stack.push(m_dfi[root]); - - // append outgoing direction of entry in w to stack - OGDF_ASSERT(w->degree() > 0); - stack.push(w_dir); - - // get active successor in pertinent bicomp - // variables for recognizing the right direction after descending to a bicomp - int x_dir = CCW; - int y_dir = CW; - int infoX, infoY; // gives information about the type of endnode in that direction - node x = activeSuccessor(root,x_dir,i,infoX); - node y = activeSuccessor(root,y_dir,i,infoY); - - OGDF_ASSERT(x != root && y != root); - createShortCircuitEdge(root,CCW,x,x_dir); - createShortCircuitEdge(root,CW,y,y_dir); - - // push counterclockwise resp. clockwise active successor - // in pertinent bicomp - if (infoX == infoY) { - // if both attributes are externally active and non-pertinent, - // save stopping nodes - if (infoX==3) { - OGDF_ASSERT(x != y); - if (m_embeddingGrade <= doNotFind) return true; - - // extract Kuratowskis - stoppingNodesFound = 1; - // check, if we have found enough kuratowski structures - if (m_embeddingGrade > 0 && - findKuratowskis->getAllKuratowskis().size() >= m_embeddingGrade) { - return 2; - } - findKuratowskis->addKuratowskiStructure(m_nodeFromDFI[i],root,x,y); - - // go to the pertinent starting node on father bicomp - stack.pop(); // delete new w_dir from stack - w = m_realVertex[m_nodeFromDFI[stack.pop()]]; // x itself - // refresh pertinentRoots information - m_pertinentRoots[w].popFront(); - - // if more pertinent child bicomps exist on the same root, - // let the walkdown either embed it or find a new kuratowski structure - while (!stack.empty() && !pertinent(w)) { - // last real root - node lastActiveNode = w; - - // not in V-bicomp: - // go to the unvisited active node on father bicomp - w_dir = stack.pop(); // outgoing direction of w - x_dir = stack.pop(); // outgoing direction of x - w = m_nodeFromDFI[stack.top()]; // w, virtual node - - node otherActiveNode = m_link[!w_dir][w]->theNode(); - - OGDF_ASSERT(otherActiveNode == constActiveSuccessor(w,!w_dir,i,infoX)); - OGDF_ASSERT(externallyActive(otherActiveNode,i)); - OGDF_ASSERT(lastActiveNode == m_link[w_dir][w]->theNode()); - if (pertinent(otherActiveNode)) { - // push adapted information about actual bicomp in stack - stack.push(x_dir); - stack.push(!w_dir); - // go on with walkdown on unvisited active node - w_dir = !w_dir; - break; - } else { - // delete old root - stack.pop(); - // if there are two stopping vertices, that are not pertinent - // there could be another kuratowski structure - if (lastActiveNode != otherActiveNode && - wNodesExist(w,lastActiveNode,otherActiveNode)) { - // check, if we have found enough kuratowski structures - if (m_embeddingGrade > 0 && - findKuratowskis->getAllKuratowskis().size() >= m_embeddingGrade) { - return 2; - } - // different stopping nodes: - // try to extract kuratowski structure and put the two - // stopping nodes in the right traversal order - if (w_dir==CCW) { - findKuratowskis->addKuratowskiStructure(m_nodeFromDFI[i], - w,lastActiveNode,otherActiveNode); - } else { - findKuratowskis->addKuratowskiStructure(m_nodeFromDFI[i], - w,otherActiveNode,lastActiveNode); - } - } - - // refresh pertinentRoots information - w = m_realVertex[w]; // x - m_pertinentRoots[w].popFront(); - w_dir = x_dir; - } - } - } - // if both attributes are the same: minimize flips - else if (w_dir==CCW) { - w = x; - w_dir = x_dir; - stack.push(CCW); - - } else { - w = y; - w_dir = y_dir; - stack.push(CW); - } - } else if (infoX <= infoY) { - // push x - w=x; w_dir=x_dir; - stack.push(CCW); - - } else { - // push y - w=y; w_dir=y_dir; - stack.push(CW); - } - - } else if (inactive(w,i)) { - // w is an inactive vertex - w = successorOnExternalFace(w,w_dir); - - } else { - // w must be a stopping vertex - OGDF_ASSERT(externallyActive(w,i)); - OGDF_ASSERT(m_lowPoint[m_nodeFromDFI[-m_dfi[v]]] < i); - - // embed shortCircuitEdge - /*if (stack.empty())*/ createShortCircuitEdge(v,j,w,w_dir); - - // only save single stopping nodes, if we don't have already one - if (j==CCW) { - stopX = w; - } else if (w != stopX) { - OGDF_ASSERT(stopX!=0); - - if (m_embeddingGrade <= doNotFind) return false; - // check, if some backedges were not embedded (=> nonplanar) - // note, that this is performed at most one time per virtual root - if (m_visitedWithBackedge[v] > 0) { - // some backedges are left on this bicomp - stoppingNodesFound = 1; - // check, if we have found enough kuratowski structures - if (m_embeddingGrade > 0 && - findKuratowskis->getAllKuratowskis().size() >= m_embeddingGrade) { - return 2; - } - findKuratowskis->addKuratowskiStructure(m_nodeFromDFI[i],v,stopX,w); - } - } - - break; // while - } - } // while - - stack.clear(); - } // for - - return stoppingNodesFound; -} - -// embed graph m_g node by node in descending DFI-order beginning with dfi i -bool BoyerMyrvoldPlanar::embed() -{ - bool nonplanar=false; // true, if graph is not planar - - //FindKuratowskis findKuratowskis(this); - FindKuratowskis* findKuratowskis = - (m_embeddingGrade <= doNotFind) ? 0 : new FindKuratowskis(this); - - for (int i = m_nodeFromDFI.high(); i >= 1; --i) - { - const node v = m_nodeFromDFI[i]; - - // call Walkup - // for all sources of backedges of v: find pertinent subgraph - - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); // dfs-descendant of v - edge e = adj->theEdge(); - if (m_dfi[w] > i && m_edgeType[e] == EDGE_BACK) { - m_backedgeFlags[w].pushBack(adj); - - node x = walkup(v,w,i,e); - if (m_embeddingGrade <= doNotFind) continue; - - // divide children bicomps - if (m_realVertex[x] == v) { - m_pointsToRoot[e] = x; - // set backedgenumber to 1 on this root - m_visitedWithBackedge[x] = 1; - } else { - x = m_pointsToRoot[m_visitedWithBackedge[x]]; - m_pointsToRoot[e] = x; - // increase backedgenumber on this root - OGDF_ASSERT(m_visitedWithBackedge[x]>=1); - ++m_visitedWithBackedge[x]; - } - } - } - - // call Walkdown - // for every pertinent subtrees with children w of v as roots - // embed all backedges to v - SListPure& pert(m_pertinentRoots[v]); - while (!pert.empty()) { - OGDF_ASSERT(pert.front()->degree()==1); - int result = walkdown(i,pert.popFrontRet(),findKuratowskis); - if (result == 2) { - m_output = findKuratowskis->getAllKuratowskis(); - delete findKuratowskis; - return false; - } else if (result == 1) { - // found stopping configuration - nonplanar = true; - if (m_embeddingGrade <= doNotFind) return false; - } - } - - // if !embed, check, if there are any backedges left - if (m_embeddingGrade <= doNotFind) { - forall_adj(adj,v) { - if (m_edgeType[adj->theEdge()] == EDGE_BACK && - m_dfi[adj->twinNode()] > m_dfi[v]) - return false; // nonplanar - } - } - } - - // embed and flip bicomps, if necessary - if (nonplanar) { - if(findKuratowskis) - m_output = findKuratowskis->getAllKuratowskis(); - } else - postProcessEmbedding(); // flip graph and embed self-loops, etc. - - delete findKuratowskis; - return !nonplanar; -} - - -// merge unprocessed virtual nodes such as the dfs-roots -void BoyerMyrvoldPlanar::mergeUnprocessedNodes() -{ - node v = m_g.firstNode(); - while (v) { - node next = v->succ(); - if (m_dfi[v] < 0) { - node w = m_realVertex[v]; - adjEntry adj = v->firstAdj(); - // copy all adjEntries to non-virtual node - while (adj) { - edge e = adj->theEdge(); - adj = adj->succ(); - if (e->source()==v) { - m_g.moveSource(e,w); - } else m_g.moveTarget(e,w); - } - m_nodeFromDFI[m_dfi[v]]=0; - m_g.delNode(v); - } - v = next; - } -} - - -// flips all nodes of the bicomp with unique real root-child c as necessary. -// in addition all connected components with dfs-root c without virtual -// nodes are allowed. this function can be used to reverse the flip, too! -// marker has to be an non-existing int in array visited. -// if wholeGraph ist true, all bicomps of all connected components will be traversed. -// if deleteFlipFlags ist true, the flipping flags will be deleted after flipping -void BoyerMyrvoldPlanar::flipBicomp( - int c, - int marker, - NodeArray& visited, - bool wholeGraph, - bool deleteFlipFlags) -{ - if (m_flippedNodes == 0) { - if (wholeGraph) mergeUnprocessedNodes(); - return; - } - - StackPure stack; // stack for dfs-traversal - node v; - int temp; - adjEntry adj; - - if (wholeGraph) { - mergeUnprocessedNodes(); - for (int i = 1; i <= m_g.numberOfNodes(); ++i) - stack.push(-i); - } - - // flip bicomps, if the flipped-flag is set - bool flip; - stack.push(-c); // negative numbers: flip=false, otherwise flip=true - while (!stack.empty()) { - temp = stack.pop(); - if (temp < 0) { - flip = false; - v = m_nodeFromDFI[-temp]; - } else { - flip = true; - v = m_nodeFromDFI[temp]; - } - if (wholeGraph) { - if (visited[v]==marker) continue; - // mark visited nodes - visited[v] = marker; - } - - // flip adjEntries of node, if necessary - if (m_flipped[v]) { - flip = !flip; - - // don't do this, if all flips on nodes of this bicomp will be reversed - if (deleteFlipFlags) { - m_flipped[v] = false; - --m_flippedNodes; - OGDF_ASSERT(m_flippedNodes >= 0); - } - } - if (flip) { - m_g.reverseAdjEdges(v); - if (deleteFlipFlags) { - adjEntry tmp = m_link[CCW][v]; - m_link[CCW][v] = m_link[CW][v]; - m_link[CW][v] = tmp; - - tmp = m_beforeSCE[CCW][v]; - m_beforeSCE[CCW][v] = m_beforeSCE[CW][v]; - m_beforeSCE[CW][v] = tmp; - } - } - - // go along the dfs-edges - forall_adj(adj,v) { - temp = m_dfi[adj->twinNode()]; - OGDF_ASSERT(m_edgeType[adj->theEdge()] != EDGE_UNDEFINED); - if (temp > m_dfi[v] && m_edgeType[adj->theEdge()]==EDGE_DFS) { - stack.push(flip ? temp : -temp); - } - } - } -} - - -// postprocess the embedding, so that all unprocessed virtual vertices are -// merged with their non-virtual counterpart. Furthermore all bicomps -// are flipped, if necessary and parallel edges and self-loops are embedded. -void BoyerMyrvoldPlanar::postProcessEmbedding() -{ - StackPure stack; // stack for dfs-traversal - node v,w; - adjEntry adj; - int temp; - - mergeUnprocessedNodes(); - - // flip bicomps, if the flipped-flag is set, i.e. postprocessing in - // reverse dfi-order - bool flip; - for(int i=1; i<=m_g.numberOfNodes(); ++i) { - if (m_visited[m_nodeFromDFI[i]] == -1) continue; - stack.push(-i); // negative numbers: flip=false, otherwise flip=true - - while (!stack.empty()) { - temp = stack.pop(); - if (temp < 0) { - flip=false; - v = m_nodeFromDFI[-temp]; - } else { - flip=true; - v = m_nodeFromDFI[temp]; - } - if (m_visited[v]==-1) continue; - // mark visited nodes with visited[v]==-1 - m_visited[v] = -1; - - // flip adjEntries of node, if necessary - if (m_flipped[v]) { - m_flipped[v] = false; - flip = !flip; - } - if (flip) m_g.reverseAdjEdges(v); - - adj=v->firstAdj(); - while (adj) { - w = adj->twinNode(); - temp = m_edgeType[adj->theEdge()]; - if (temp==EDGE_DFS) { - // go along the dfs-edges - stack.push(flip ? m_dfi[w] : -m_dfi[w]); - adj=adj->succ(); - } else if (temp==EDGE_SELFLOOP) { - // embed self-loops - m_g.moveAdjBefore(adj->twin(),adj); - adj=adj->succ(); - } else if (temp==EDGE_DFS_PARALLEL && - m_adjParent[v]!=0 && - w == m_adjParent[v]->theNode()) { - // embed edges that are parallel to dfs-edges - // it is only possible to deal with the parallel edges to the - // parent, since children nodes could be flipped later - adjEntry tmp = adj->succ(); - m_g.moveAdjAfter(adj,m_adjParent[v]->twin()); - m_g.moveAdjBefore(adj->twin(),m_adjParent[v]); - adj = tmp; - } else adj=adj->succ(); - } - } - } -} - - -// tests Graph m_g for planarity -// if graph should be embedded, a planar embedding or a kuratowski subdivision -// of m_g is returned in addition, depending on whether m_g is planar -bool BoyerMyrvoldPlanar::start() -{ - BoyerMyrvoldInit bmi(this); - bmi.computeDFS(); - bmi.computeLowPoints(); - bmi.computeDFSChildLists(); - - // call the embedding procedure - return embed(); -} - - -} diff --git a/ext/OGDF/src/planarity/ClusterPlanRep.cpp b/ext/OGDF/src/planarity/ClusterPlanRep.cpp deleted file mode 100644 index eac338993..000000000 --- a/ext/OGDF/src/planarity/ClusterPlanRep.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of ClusterPlanRep class - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include - - -enum edgeDir {undef, in, out}; - -namespace ogdf { - -ClusterPlanRep::ClusterPlanRep( - const ClusterGraphAttributes &acGraph, - const ClusterGraph &clusterGraph) - : - PlanRep(acGraph), - m_pClusterGraph(&clusterGraph) -{ - OGDF_ASSERT(&clusterGraph.getGraph() == &acGraph.constGraph()) - - m_edgeClusterID.init(*this, -1); - m_nodeClusterID.init(*this, -1); - - //const Graph &CG = clusterGraph; - //const Graph &G = acGraph.constGraph(); - - //if (&acGraph != 0) - //{ - // OGDF_ASSERT(&CG == &G); - //} - - m_rootAdj = 0; - - //cluster numbers don't need to be consecutive - cluster ci; - forall_clusters(ci, clusterGraph) - m_clusterOfIndex[ci->index()] = ci; //numbers are unique -}//constructor - - -void ClusterPlanRep::initCC(int i) -{ - PlanRep::initCC(i); - - //this means that for every reinitialization IDs are set - //again, but this should not lead to problems - //it cant be done in the constructor because the copies - //in CCs are not yet initialized then - //they are maintained for original nodes and for crossings - //nodes on cluster boundaries - const Graph &CG = *m_pClusterGraph; - node v; - forall_nodes(v, CG) - { - m_nodeClusterID[copy(v)] = m_pClusterGraph->clusterOf(v)->index(); - }//forallnodes - - //todo: initialize dummy node ids for different CCs - - //initialize all edges totally contained in a single cluster - edge e; - forall_edges(e, *this) - { - if (ClusterID(e->source()) == ClusterID(e->target())) - m_edgeClusterID[e] = ClusterID(e->source()); - }//foralledges - -}//initCC - -/** - * Inserts edge eOrig - * This is only an insertion for graphs with already modeled - * boundary edges, otherwise cluster recognition won't work - * */ -void ClusterPlanRep::insertEdgePathEmbedded( - edge eOrig, - CombinatorialEmbedding &E, - const SList &crossedEdges) -{ - //inherited insert - PlanRep::insertEdgePathEmbedded(eOrig,E,crossedEdges); - - //update node cluster ids for crossing dummies - ListConstIterator it; - for(it = chain(eOrig).begin(); it.valid(); ++it) - { - node dummy = (*it)->target(); - if (dummy == copy(eOrig->target())) continue; - - OGDF_ASSERT(dummy->degree() == 4) - - //get the entries on the crossed edge - adjEntry adjIn = (*it)->adjTarget(); - adjEntry adjC1 = adjIn->cyclicPred(); - adjEntry adjC2 = adjIn->cyclicSucc(); - - //insert edge end points have the problem that the next one - //does not need to have a clusterid yet - //therefore we use the crossed edges endpoints - //the two endpoints of the splitted edge - node v1 = adjC1->twinNode(); - node v2 = adjC2->twinNode(); - OGDF_ASSERT(v1 != dummy) - OGDF_ASSERT(v2 != dummy) - node orV1 = original(v1); - node orV2 = original(v2); - //inserted edges are never boundaries - //cases: - //cross boundary edge - //cross edge between different boundaries - //cross edge between boundary and crossing/end - //cross edge between crossings/ends - //there are three types of nodes: orig, boundary, crossing - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - //should only be used with modeled boundaries - cluster c1, c2; - if (orV1 && orV2) - { - OGDF_ASSERT(m_pClusterGraph->clusterOf(orV1) == - m_pClusterGraph->clusterOf(orV2)); - OGDF_ASSERT(m_nodeClusterID[v1] != -1) - m_nodeClusterID[dummy] = m_nodeClusterID[v1]; - continue; - }//if two originals - if (orV1 || orV2) //a dummy (crossing/boundary) and an original - { - node orV = (orV1 ? orV1 : orV2); - //node vOr = (orV1 ? v1 : v2); - node vD = (orV1 ? v2 : v1); - cluster orC = m_pClusterGraph->clusterOf(orV); - cluster dC = clusterOfDummy(vD); - - OGDF_ASSERT( (orC == dC) || //original and crossing - (orC == dC->parent()) || //original and boundary - (orC->parent() == dC) ) - - if (orC == dC) m_nodeClusterID[dummy] = orC->index(); - else if (orC == dC->parent()) m_nodeClusterID[dummy] = orC->index(); - else OGDF_THROW (AlgorithmFailureException); - continue; - }//if one original - //no originals, only crossings/boundaries - c1 = clusterOfDummy(v1); - c2 = clusterOfDummy(v2); - OGDF_ASSERT( (c1 == c2) || //min.one crossing - (c1 == c2->parent()) || //min. one boundary - (c1->parent() == c2) || - (c1->parent() == c2->parent()) - ) - - if (c1 == c2) - m_nodeClusterID[dummy] = c1->index(); - else if (c1 == c2->parent()) - m_nodeClusterID[dummy] = c1->index(); - else if (c2 == c1->parent()) - m_nodeClusterID[dummy] = c2->index(); - else - m_nodeClusterID[dummy] = c1->parent()->index(); - continue; - - - }//for - -}//insertEdgePathEmbedded - -//use cluster structure to insert edges representing the cluster boundaries -void ClusterPlanRep::ModelBoundaries() -{ - //clusters hold their adjacent adjEntries and edges in lists, but after - //insertion of boundaries these lists are outdated due to edge splittings - - //is the clusteradjacent edge outgoing? - //2 means undef (only at inner leaf cluster) - AdjEntryArray outEdge(*m_pClusterGraph, 2); //0 in 1 out - //what edge is currently adjacent to cluster (after possible split) - //with original adjEntry in clusteradjlist - AdjEntryArray currentEdge(*m_pClusterGraph, 0); - - List rootEdges; //edges that can be used to set the outer face - - convertClusterGraph(m_pClusterGraph->rootCluster(), currentEdge, outEdge); -} - -//recursively insert cluster boundaries for all clusters in cluster tree -void ClusterPlanRep::convertClusterGraph(cluster act, - AdjEntryArray& currentEdge, - AdjEntryArray& outEdge) -{ - - //are we at the first call (no real cluster) - bool isRoot = (act == m_pClusterGraph->rootCluster()); - - //check if we have to set the external face adj by hand - if (isRoot && !act->cBegin().valid()) - m_rootAdj = firstEdge()->adjSource(); //only root cluster present - //check if leaf cluster in cluster tree (most inner) - bool isLeaf = false; - if ((!act->cBegin().valid()) && (!isRoot)) isLeaf = true; - // Test children first - ListConstIterator it; - for (it = act->cBegin(); it.valid();) - { - ListConstIterator succ = it.succ(); - convertClusterGraph((*it), currentEdge, outEdge); - - it = succ; - } - //do not convert root cluster - if (isRoot) return; - - OGDF_ASSERT(this->representsCombEmbedding()) - - insertBoundary(act, currentEdge, outEdge, isLeaf); - - OGDF_ASSERT(this->representsCombEmbedding()) - - -}//convertclustergraph - -//inserts Boundary for a single cluster, needs the cluster and updates a -//hashtable linking splitted original edges (used in clusteradjlist) to the -//current (new) edge, if cluster is leafcluster, we check and set the edge -//direction and the adjacent edge corresponding to the adjEntries in the clusters -//adjEntry List -void ClusterPlanRep::insertBoundary(cluster C, - AdjEntryArray& currentEdge, - AdjEntryArray& outEdge, - bool clusterIsLeaf) -{ - //we insert edges to represent the cluster boundary - //by splitting the outgoing edges and connecting the - //split nodes - - OGDF_ASSERT(this->representsCombEmbedding()) - - //retrieve the outgoing edges - - //TODO: nichtverbundene Cluster abfangen - - SList outAdj; - //outgoing adjEntries in clockwise order - m_pClusterGraph->adjEntries(C, outAdj); - - //now split the edges and save adjEntries - //we maintain two lists of adjentries - List targetEntries, sourceEntries; - //we need to find out if edge is outgoing - bool isOut = false; - SListIterator it = outAdj.begin(); - //if no outAdj exist, we have a connected component - //and dont need a boundary, change this when unconnected - //graphs are allowed - if (!it.valid()) return; - - while (it.valid()) - { - //if clusterIsLeaf, save the corresponding direction and edge - if (clusterIsLeaf) - { - //save the current, unsplitted edge - //be careful with clusterleaf connecting, layered cl - if (currentEdge[(*it)] == 0) - currentEdge[(*it)] = copy((*it)->theEdge()); - //set twin here? - - //check direction, adjEntry is outgoing, compare with edge - outEdge[(*it)] = ( ((*it) == (*it)->theEdge()->adjSource()) ? 1 : 0); - } - - //workaround for nonleaf edges - if (outEdge[(*it)] == 2) - outEdge[(*it)] = ( ((*it) == (*it)->theEdge()->adjSource()) ? 1 : 0); - - if (currentEdge[(*it)] == 0) - { - //may already be splitted from head - currentEdge[(*it)] = copy((*it)->theEdge()); - } - - - //We need to find the real edge here - edge splitEdge = currentEdge[(*it)]; - - //...outgoing...? - OGDF_ASSERT(outEdge[(*it)] != 2); - isOut = outEdge[(*it)] == 1; - - edge newEdge = split(splitEdge); - - //store the adjEntries depending on in/out direction - if (isOut) - { - //splitresults "upper" edge to old target is newEdge!? - //only update for outgoing edges, ingoing stay actual - currentEdge[(*it)] = newEdge; - currentEdge[(*it)->twin()] = newEdge; - sourceEntries.pushBack(newEdge->adjSource()); - targetEntries.pushBack(splitEdge->adjTarget()); - - m_nodeClusterID[newEdge->source()] = C->index(); - //m_nodeClusterID[splitEdge->source()]; - }//if outgoing - else - { - sourceEntries.pushBack(splitEdge->adjTarget()); - targetEntries.pushBack(newEdge->adjSource()); - - m_nodeClusterID[newEdge->source()] = C->index(); - }//else outgoing - - //always set some rootAdj for external face - if ( (C->parent() == m_pClusterGraph->rootCluster()) && !(it.succ().valid())) - { - //save the adjentry corresponding to new splitresult edge - m_rootAdj = currentEdge[(*it)]->adjSource(); - OGDF_ASSERT(m_rootAdj != 0); - }//if - - //go on with next edge - it++; - - }//while outedges - - - //we need pairs of adjEntries - OGDF_ASSERT(targetEntries.size() == sourceEntries.size()); - //now flip first target entry to front - //should be nonempty - adjEntry flipper = targetEntries.popFrontRet(); - targetEntries.pushBack(flipper); - - //connect the new nodes to form the boundary - while (!targetEntries.empty()) - { - - edge e = newEdge(sourceEntries.popFrontRet(), targetEntries.popFrontRet()); - //set type of new edges - setClusterBoundary(e); - m_edgeClusterID[e] = C->index(); - - OGDF_ASSERT(this->representsCombEmbedding()) - } - - OGDF_ASSERT(this->representsCombEmbedding()) - -}//insertBoundary - - - -void ClusterPlanRep::expand(bool lowDegreeExpand) -{ - PlanRep::expand(lowDegreeExpand); - //update cluster info - node v; - forall_nodes(v, *this) - { - if (expandedNode(v) != 0) - { - OGDF_ASSERT(m_nodeClusterID[expandedNode(v)] != -1) - m_nodeClusterID[v] = m_nodeClusterID[expandedNode(v)]; - } - } -}//expand - -void ClusterPlanRep::expandLowDegreeVertices(OrthoRep &OR) -{ - PlanRep::expandLowDegreeVertices(OR); - //update cluster info - node v; - forall_nodes(v, *this) - { - if (expandedNode(v) != 0) - { - OGDF_ASSERT(m_nodeClusterID[expandedNode(v)] != -1) - m_nodeClusterID[v] = m_nodeClusterID[expandedNode(v)]; - } - } -}//expandlowdegree - - -//***************************************************************************** -//file output - -void ClusterPlanRep::writeGML(const char *fileName, const Layout &drawing) -{ - ofstream os(fileName); - writeGML(os,drawing); -} - - -void ClusterPlanRep::writeGML(const char *fileName) -{ - Layout drawing(*this); - ofstream os(fileName); - writeGML(os,drawing); -} - - -void ClusterPlanRep::writeGML(ostream &os, const Layout &drawing) -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - - node ori = original(v); - - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " graphics [\n"; - os << " x " << drawing.x(v) << "\n"; - os << " y " << drawing.y(v) << "\n"; - os << " w " << 10.0 << "\n"; - os << " h " << 10.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (typeOf(v) == Graph::dummy) - os << " type \"oval\"\n"; - - else - if (m_pClusterGraph->clusterOf(ori)->index() != 0) //cluster - { - //only < 16 - os << " fill \"#" << std::hex << std::setw(6) << std::setfill('0') - << m_pClusterGraph->clusterOf(ori)->index()*256*256+ - m_pClusterGraph->clusterOf(ori)->index()*256+ - m_pClusterGraph->clusterOf(ori)->index()*4 << std::dec << "\"\n"; - } - else - { - if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - } - - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << typeOf(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (typeOf(e) == Graph::generalization) - { - os << " arrow \"last\"\n"; - - os << " fill \"#FF0000\"\n"; - os << " width 3.0\n"; - } - else - { - - if (typeOf(e->source()) == Graph::generalizationExpander || - typeOf(e->source()) == Graph::generalizationMerger || - typeOf(e->target()) == Graph::generalizationExpander || - typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else if (isClusterBoundary(e)) - os << " fill \"#FF0000\"\n"; - else - os << " fill \"#FF0000\"\n"; - } - else - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else if (isClusterBoundary(e)) - os << " fill \"#FF0000\"\n"; - else - os << " fill \"#00000F\"\n"; - os << " width 1.0\n"; - }//else generalization - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -}//namespace - diff --git a/ext/OGDF/src/planarity/EdgeInsertionModule.cpp b/ext/OGDF/src/planarity/EdgeInsertionModule.cpp deleted file mode 100644 index 5192a00bd..000000000 --- a/ext/OGDF/src/planarity/EdgeInsertionModule.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of class EdgeInsertionModule - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -#ifdef OGDF_DEBUG - -bool EdgeInsertionModule::checkCrossingGens(const PlanRepUML &PG) -{ - edge e; - forall_edges(e,PG) { - Graph::EdgeType et = PG.typeOf(e); - if (et != Graph::generalization && et != Graph::association) - return false; - } - - node v; - forall_nodes(v,PG) - { - if (PG.typeOf(v) == PlanRepUML::dummy && v->degree() == 4) { - adjEntry adj = v->firstAdj(); - - edge e1 = adj->theEdge(); - edge e2 = adj->succ()->theEdge(); - - if (PG.typeOf(e1) == Graph::generalization && - PG.typeOf(e2) == Graph::generalization) - return false; - } - } - - return true; -} - -#endif - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarity/EmbedPQTree.cpp b/ext/OGDF/src/planarity/EmbedPQTree.cpp deleted file mode 100644 index d08561ab9..000000000 --- a/ext/OGDF/src/planarity/EmbedPQTree.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class EmbedPQTree. - * - * Implements a PQTree with added features for the planar - * embedding algorithm. Used by BoothLueker. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf{ - -// Overriding the function doDestruction (see basic.h) -// Allows deallocation of lists of PQLeafKey -// in constant time using OGDF memory management. - - -typedef PQLeafKey *PtrPQLeafKeyEIB; - -template<> -inline bool doDestruction(const PtrPQLeafKeyEIB*) { return false; } - - - -// Replaces the pertinent subtree by a P-node with leaves as children -// corresponding to the incoming edges of the node v. These edges -// are to be specified by their keys stored in leafKeys. -// The function returns the frontier of the pertinent subtree and -// the direction indicators found within the pertinent leaves. -// The direction indicators are returned in two list: -// opposed: containing the keys of indicators pointing into reverse -// frontier scanning direction (thus their corsponding list has to be -// reversed. -// nonOpposed: containing the keys of indicators pointing into -// frontier scanning direction (thus their corsponding list do not need -// reversed in the first place) - -void EmbedPQTree::ReplaceRoot( - SListPure*> &leafKeys, - SListPure &frontier, - SListPure &opposed, - SListPure &nonOpposed, - node v) -{ - SListPure*> nodeFrontier; - - if (leafKeys.empty() && m_pertinentRoot == m_root) - { - front(m_pertinentRoot,nodeFrontier); - m_pertinentRoot = 0; // check for this emptyAllPertinentNodes - - } else { - if (m_pertinentRoot->status() == PQNodeRoot::FULL) - ReplaceFullRoot(leafKeys,nodeFrontier,v); - else - ReplacePartialRoot(leafKeys,nodeFrontier,v); - } - - // Check the frontier and get the direction indicators. - while (!nodeFrontier.empty()) - { - PQBasicKey* entry = nodeFrontier.popFrontRet(); - if (entry->userStructKey()) // is a regular leaf - frontier.pushBack(entry->userStructKey()); - - else if (entry->userStructInfo()) { - if (entry->userStructInfo()->changeDir) - opposed.pushBack(entry->userStructInfo()->v); - else - nonOpposed.pushBack(entry->userStructInfo()->v); - } - } -} - - -// The function [[emptyAllPertinentNodes]] has to be called after a reduction -// has been processed. This overloaded function first destroys all full nodes -// by marking them as TO_BE_DELETED and then calling the base class function -// [[emptyAllPertinentNodes]]. -void EmbedPQTree::emptyAllPertinentNodes() -{ - ListIterator*> it; - - for (it = m_pertinentNodes->begin(); it.valid(); it++) - { - PQNode* nodePtr = (*it); - if (nodePtr->status() == PQNodeRoot::FULL) - destroyNode(nodePtr); - } - if (m_pertinentRoot) // Node was kept in the tree. Do not free it. - m_pertinentRoot->status(PQNodeRoot::FULL); - - PQTree::emptyAllPertinentNodes(); -} - - - -void EmbedPQTree::clientDefinedEmptyNode(PQNode* nodePtr) -{ - if (nodePtr->status() == PQNodeRoot::INDICATOR) - delete nodePtr; - else - PQTree::clientDefinedEmptyNode(nodePtr); -} - - - -// Initializes a PQTree by a set of leaves that will korrespond to -// the set of Keys stored in leafKeys. -int EmbedPQTree::Initialize(SListPure*> &leafKeys) -{ - SListIterator* > it; - - SListPure*> castLeafKeys; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - - return PQTree::Initialize(castLeafKeys); -} - - -// Reduction reduced a set of leaves determined by their keys stored -// in leafKeys. Integer redNumber is for debugging only. -bool EmbedPQTree::Reduction(SListPure*> &leafKeys) -{ - SListIterator* > it; - - SListPure*> castLeafKeys; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - - return PQTree::Reduction(castLeafKeys); -} - - - -// Function ReplaceFullRoot either replaces the full root -// or one full child of a partial root of a pertinent subtree -// by a single P-node with leaves corresponding the keys stored in leafKeys. -// Furthermore it scans the frontier of the pertinent subtree, and returns it -// in frontier. -// If called by ReplacePartialRoot, the function ReplaceFullRoot handles -// the introduction of the direction indicator. (This must be indicated -// by addIndicator. -// Node v determines the node related to the pertinent leaves. It is needed -// to assign the dirrection indicator to this sequence. - -void EmbedPQTree::ReplaceFullRoot( - SListPure*> &leafKeys, - SListPure*> &frontier, - node v, - bool addIndicator, - PQNode *opposite) -{ - EmbedIndicator *newInd = 0; - - front(m_pertinentRoot,frontier); - if (addIndicator) - { - IndInfo *newInfo = OGDF_NEW IndInfo(v); - PQNodeKey *nodeInfoPtr = OGDF_NEW PQNodeKey(newInfo); - newInd = OGDF_NEW EmbedIndicator(m_identificationNumber++, nodeInfoPtr); - newInd->setNodeInfo(nodeInfoPtr); - nodeInfoPtr->setNodePointer(newInd); - } - - if (!leafKeys.empty() && leafKeys.front() == leafKeys.back()) - { - //ReplaceFullRoot: replace pertinent root by a single leaf - if (addIndicator) - { - opposite = m_pertinentRoot->getNextSib(opposite); - if (!opposite) // m_pertinentRoot is endmost child - { - addNodeToNewParent(m_pertinentRoot->parent(), newInd, m_pertinentRoot, opposite); - } - else - addNodeToNewParent(0,newInd,m_pertinentRoot,opposite); - - // Setting the sibling pointers into opposite direction of - // scanning the front allows to track swaps of the indicator - newInd->changeSiblings(m_pertinentRoot,0); - newInd->changeSiblings(opposite,0); - newInd->putSibling(m_pertinentRoot,PQNodeRoot::LEFT); - newInd->putSibling(opposite,PQNodeRoot::RIGHT); - } - PQLeaf *leafPtr = - OGDF_NEW PQLeaf(m_identificationNumber++, - PQNodeRoot::EMPTY,(PQLeafKey*)leafKeys.front()); - exchangeNodes(m_pertinentRoot,(PQNode*) leafPtr); - if (m_pertinentRoot == m_root) - m_root = (PQNode*) leafPtr; - m_pertinentRoot = 0; // check for this emptyAllPertinentNodes - } - - else if (!leafKeys.empty()) // at least two leaves - { - //replace pertinent root by a $P$-node - if (addIndicator) - { - opposite = m_pertinentRoot->getNextSib(opposite); - if (!opposite) // m_pertinentRoot is endmost child - { - addNodeToNewParent(m_pertinentRoot->parent(), newInd, m_pertinentRoot, opposite); - } - else - addNodeToNewParent(0, newInd, m_pertinentRoot, opposite); - - // Setting the sibling pointers into opposite direction of - // scanning the front allows to track swaps of the indicator - newInd->changeSiblings(m_pertinentRoot,0); - newInd->changeSiblings(opposite,0); - newInd->putSibling(m_pertinentRoot,PQNodeRoot::LEFT); - newInd->putSibling(opposite,PQNodeRoot::RIGHT); - } - - PQInternalNode *nodePtr = 0; // dummy - if ((m_pertinentRoot->type() == PQNodeRoot::PNode) || - (m_pertinentRoot->type() == PQNodeRoot::QNode)) - { - nodePtr = (PQInternalNode*)m_pertinentRoot; - nodePtr->type(PQNodeRoot::PNode); - nodePtr->childCount(0); - while (!fullChildren(m_pertinentRoot)->empty()) - { - PQNode *currentNode = - fullChildren(m_pertinentRoot)->popFrontRet(); - removeChildFromSiblings(currentNode); - } - } - else if (m_pertinentRoot->type() == PQNodeRoot::leaf) - { - nodePtr = OGDF_NEW PQInternalNode(m_identificationNumber++, - PQNodeRoot::PNode,PQNodeRoot::EMPTY); - exchangeNodes(m_pertinentRoot,nodePtr); - m_pertinentRoot = 0; // check for this emptyAllPertinentNodes - } - - SListPure*> castLeafKeys; - SListIterator* > it; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - addNewLeavesToTree(nodePtr,castLeafKeys); - } -} - - -// Function ReplacePartialRoot replaces all full nodes by a single P-node -// with leaves corresponding the keys stored in leafKeys. -// Furthermore it scans the frontier of the pertinent subtree, and returns it -// in frontier. -// node v determines the node related to the pertinent leaves. It is needed -// to assign the dirrection indicator to this sequence. - -void EmbedPQTree::ReplacePartialRoot( - SListPure*> &leafKeys, - SListPure*> &frontier, - node v) -{ - m_pertinentRoot->childCount(m_pertinentRoot->childCount() + 1 - - fullChildren(m_pertinentRoot)->size()); - - PQNode *predNode = 0; // dummy - PQNode *beginSequence = 0; // marks begin consecuitve seqeunce - PQNode *endSequence = 0; // marks end consecutive sequence - PQNode *beginInd = 0; // initially, marks direct sibling indicator - // next to beginSequence not contained - // in consectuive sequence - - // Get beginning and end of sequence. - while (fullChildren(m_pertinentRoot)->size()) - { - PQNode *currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); - if (!clientSibLeft(currentNode) || - clientSibLeft(currentNode)->status() == PQNodeRoot::EMPTY) - { - if (!beginSequence) - { - beginSequence = currentNode; - predNode = clientSibLeft(currentNode); - beginInd =PQTree::clientSibLeft(currentNode); - } - else - endSequence = currentNode; - } - else if (!clientSibRight(currentNode) || - clientSibRight(currentNode)->status() == PQNodeRoot::EMPTY ) - { - if (!beginSequence) - { - beginSequence = currentNode; - predNode = clientSibRight(currentNode); - beginInd =PQTree::clientSibRight(currentNode); - } - else - endSequence = currentNode; - } - } - - SListPure*> partialFrontier; - - - // Now scan the sequence of full nodes. Remove all of them but the last. - // Call ReplaceFullRoot on the last one. - // For every full node get its frontier. Scan intermediate indicators. - - PQNode *currentNode = beginSequence; - while (currentNode != endSequence) - { - PQNode* nextNode = - clientNextSib(currentNode,predNode); - front(currentNode,partialFrontier); - frontier.conc(partialFrontier); - - PQNode* currentInd = PQTree:: - clientNextSib(currentNode,beginInd); - - // Scan for intermediate direction indicators. - while (currentInd != nextNode) - { - PQNode *nextInd = PQTree:: - clientNextSib(currentInd,currentNode); - if (currentNode == currentInd->getSib(PQNodeRoot::RIGHT)) //Direction changed - currentInd->getNodeInfo()->userStructInfo()->changeDir = true; - frontier.pushBack((PQBasicKey*) - currentInd->getNodeInfo()); - removeChildFromSiblings(currentInd); - m_pertinentNodes->pushBack(currentInd); - currentInd = nextInd; - } - - removeChildFromSiblings(currentNode); - currentNode = nextNode; - } - - currentNode->parent(m_pertinentRoot); - m_pertinentRoot = currentNode; - ReplaceFullRoot(leafKeys,partialFrontier,v,true,beginInd); - frontier.conc(partialFrontier); -} - - - -// Overloads virtual function of base class PQTree -// Allows ignoring the virtual direction indicators during -// the template matching algorithm. -PQNode* EmbedPQTree::clientSibLeft( - PQNode *nodePtr) const -{ - PQNode *predNode = nodePtr; - nodePtr = PQTree::clientSibLeft(predNode); - while (nodePtr && nodePtr->status() == PQNodeRoot::INDICATOR) - { - PQNode *holdSib = predNode; - predNode = nodePtr; - nodePtr = predNode->getNextSib(holdSib); - } - - return nodePtr; -} - - -// Overloads virtual function of base class PQTree -// Allows ignoring the virtual direction indicators during -// the template matching algorithm. -PQNode* EmbedPQTree::clientSibRight( - PQNode *nodePtr) const -{ - PQNode *predNode = nodePtr; - nodePtr = PQTree::clientSibRight(predNode); - while (nodePtr && nodePtr->status() == PQNodeRoot::INDICATOR) - { - PQNode *holdSib = predNode; - predNode = nodePtr; - nodePtr = predNode->getNextSib(holdSib); - } - - return nodePtr; -} - - -// Overloads virtual function of base class PQTree -// Allows ignoring the virtual direction indicators during -// the template matching algorithm. -PQNode* EmbedPQTree::clientLeftEndmost( - PQNode *nodePtr) const -{ - PQNode *left = PQTree::clientLeftEndmost(nodePtr); - - if (!left || left->status() != PQNodeRoot::INDICATOR) - return left; - else - return clientNextSib(left,NULL); -} - - -// Overloads virtual function of base class PQTree -// Allows ignoring the virtual direction indicators during -// the template matching algorithm. -PQNode* EmbedPQTree::clientRightEndmost( - PQNode *nodePtr) const -{ - PQNode *right = PQTree::clientRightEndmost(nodePtr); - - if (!right || right->status() != PQNodeRoot::INDICATOR) - return right; - else - return clientNextSib(right,NULL); -} - - -// Overloads virtual function of base class PQTree -// Allows ignoring the virtual direction indicators during -// the template matching algorithm. -PQNode* EmbedPQTree::clientNextSib( - PQNode *nodePtr, - PQNode *other) const -{ - PQNode *left = clientSibLeft(nodePtr); - if (left != other) return left; - - PQNode *right = clientSibRight(nodePtr); - if (right != other) return right; - - return 0; -} - - -// Overloads virtual function of base class PQTree -// Allows to print debug information on the direction indicators -const char* EmbedPQTree::clientPrintStatus(PQNode *nodePtr) -{ - if (nodePtr->status() == PQNodeRoot::INDICATOR) - return "INDICATOR"; - else - return PQTree::clientPrintStatus(nodePtr); -} - - -// The function front scans the frontier of nodePtr. It returns the keys -// of the leaves found in the frontier of nodePtr in a SListPure. -// These keys include keys of direction indicators detected in the frontier. -// -// CAREFUL: Funktion marks all full nodes for destruction. -// Only to be used in connection with replaceRoot. -// -void EmbedPQTree::front( - PQNode* nodePtr, - SListPure*> &keys) -{ - Stack*> S; - S.push(nodePtr); - - while (!S.empty()) - { - PQNode *checkNode = S.pop(); - - if (checkNode->type() == PQNodeRoot::leaf) - keys.pushBack((PQBasicKey*) checkNode->getKey()); - else - { - PQNode* firstSon = 0; - if (checkNode->type() == PQNodeRoot::PNode) - { - firstSon = checkNode->referenceChild(); - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - firstSon = checkNode->getEndmost(PQNodeRoot::RIGHT); - // By this, we make sure that we start on the left side - // since the left endmost child will be on top of the stack - } - - if (firstSon->status() == PQNodeRoot::INDICATOR) - { - keys.pushBack((PQBasicKey*) firstSon->getNodeInfo()); - m_pertinentNodes->pushBack(firstSon); - destroyNode(firstSon); - } - else - S.push(firstSon); - - PQNode *nextSon = firstSon->getNextSib(0); - PQNode *oldSib = firstSon; - while (nextSon && nextSon != firstSon) - { - if (nextSon->status() == PQNodeRoot::INDICATOR) - { - // Direction indicators point with their left sibling pointer - // in the direction of their sequence. If an indicator is scanned - // from the opposite direction, coming from its right sibling - // the corresponding sequence must be reversed. - if (oldSib == nextSon->getSib(PQNodeRoot::LEFT)) //Direction changed - nextSon->getNodeInfo()->userStructInfo()->changeDir = true; - keys.pushBack((PQBasicKey*) nextSon->getNodeInfo()); - m_pertinentNodes->pushBack(nextSon); - } - else - S.push(nextSon); - - PQNode *holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - } - } -} - - - -// The function front scans the frontier of nodePtr. It returns the keys -// of the leaves found in the frontier of nodePtr in a SListPure. -// These keys include keys of direction indicators detected in the frontier. -// -// No direction is assigned to the direction indicators. -// -void EmbedPQTree::getFront( - PQNode* nodePtr, - SListPure*> &keys) -{ - Stack*> S; - S.push(nodePtr); - - while (!S.empty()) - { - PQNode *checkNode = S.pop(); - - if (checkNode->type() == PQNodeRoot::leaf) - keys.pushBack((PQBasicKey*) checkNode->getKey()); - else - { - PQNode* firstSon = 0; - if (checkNode->type() == PQNodeRoot::PNode) - { - firstSon = checkNode->referenceChild(); - } - else if (checkNode->type() == PQNodeRoot::QNode) - { - firstSon = checkNode->getEndmost(PQNodeRoot::RIGHT); - // By this, we make sure that we start on the left side - // since the left endmost child will be on top of the stack - } - - if (firstSon->status() == PQNodeRoot::INDICATOR) - { - keys.pushBack((PQBasicKey*) firstSon->getNodeInfo()); - } - else - S.push(firstSon); - - PQNode *nextSon = firstSon->getNextSib(0); - PQNode *oldSib = firstSon; - while (nextSon && nextSon != firstSon) - { - if (nextSon->status() == PQNodeRoot::INDICATOR) - keys.pushBack((PQBasicKey*) nextSon->getNodeInfo()); - else - S.push(nextSon); - - PQNode *holdSib = nextSon->getNextSib(oldSib); - oldSib = nextSon; - nextSon = holdSib; - } - } - } -} - - - -} diff --git a/ext/OGDF/src/planarity/EmbedderMaxFace.cpp b/ext/OGDF/src/planarity/EmbedderMaxFace.cpp deleted file mode 100644 index fbb20541b..000000000 --- a/ext/OGDF/src/planarity/EmbedderMaxFace.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with maximum external face. - * See paper "Graph Embedding with Minimum Depth and Maximum External - * Face" by C. Gutwenger and P. Mutzel (2004) for details. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void EmbedderMaxFace::call(Graph& G, adjEntry& adjExternal) -{ - adjExternal = 0; - pAdjExternal = &adjExternal; - - //simple base cases: - if (G.numberOfNodes() <= 1) - return; - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //HINT: Edges are directed from child to parent in BC-trees - pBCTree = new BCTree(G); - - //base case of biconnected graph: - if (pBCTree->bcTree().numberOfNodes() == 1) - { - NodeArray m_nodeLength(G, 0); - EdgeArray m_edgeLength(G, 1); - adjEntry m_adjExternal; - EmbedderMaxFaceBiconnectedGraphs::embed(G, m_adjExternal, m_nodeLength, m_edgeLength); - adjExternal = m_adjExternal->twin(); - - delete pBCTree; - return; - } - - //***************************************************************************/ - //First step: calculate maximum face and node lengths - //***************************************************************************/ - - //Find root Block (root node is only node with out-degree of 0): - node rootBlockNode; - node n; - forall_nodes(n, pBCTree->bcTree()) - { - if (n->outdeg() == 0) - { - rootBlockNode = n; - break; - } - } - - //compute block graphs and SPQR trees: - blockG.init(pBCTree->bcTree()); - nBlockEmbedding_to_nH.init(pBCTree->bcTree()); - eBlockEmbedding_to_eH.init(pBCTree->bcTree()); - nH_to_nBlockEmbedding.init(pBCTree->bcTree()); - eH_to_eBlockEmbedding.init(pBCTree->bcTree()); - nodeLength.init(pBCTree->bcTree()); - cstrLength.init(pBCTree->bcTree()); - spqrTrees.init(pBCTree->bcTree(),0); - computeBlockGraphs(rootBlockNode, 0); - - //Bottom-Up-Traversal: - edge e; - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, rootBlockNode); - node cB = nH_to_nBlockEmbedding[rootBlockNode][cH]; - - //set length of v in block graph of root block node: - int length_v_in_rootBlock = 0; - edge e2; - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - length_v_in_rootBlock += constraintMaxFace(blockNode, cutVertex); - } - nodeLength[rootBlockNode][cB] = length_v_in_rootBlock; - } - - node bT_opt = G.chooseNode(); //= G.chooseNode() only to get rid of warning - int ell_opt = 0; - maximumFaceRec(rootBlockNode, bT_opt, ell_opt); - - - //**************************************************************************** - //Second step: Embed G by expanding a maximum face in bT_opt - //**************************************************************************** - newOrder.init(G); - treeNodeTreated.init(pBCTree->bcTree(), false); - embedBlock(bT_opt); - - node v; - forall_nodes(v, G) - G.sort(v, newOrder[v]); - - forall_nodes(v, pBCTree->bcTree()) - delete spqrTrees[v]; - - delete pBCTree; -} - - -void EmbedderMaxFace::computeBlockGraphs(const node& bT, const node& cH) -{ - //recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->source() == bT) - continue; - - node cT = e->source(); - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->source() == cT) - continue; - node cH2 = pBCTree->cutVertex(cT, e2->source()); - computeBlockGraphs(e2->source(), cH2); - } - } - - //embed block bT: - node m_cH = cH; - if (m_cH == 0) - m_cH = pBCTree->cutVertex(bT->firstAdj()->twinNode(), bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockG[bT], m_cH, - nBlockEmbedding_to_nH[bT], eBlockEmbedding_to_eH[bT], - nH_to_nBlockEmbedding[bT], eH_to_eBlockEmbedding[bT]); - nodeLength[bT].init(blockG[bT], 0); - cstrLength[bT].init(blockG[bT], 0); - if ( !blockG[bT].empty() - && blockG[bT].numberOfNodes() != 1 - && blockG[bT].numberOfEdges() > 2) - { - spqrTrees[bT] = new StaticSPQRTree(blockG[bT]); - } -} - - -int EmbedderMaxFace::constraintMaxFace(const node& bT, const node& cH) -{ - //forall (v \in B, v \neq c) do: - // length_B(v) := \sum_{(v, B') \in B} ConstraintMaxFace(B', v); - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node vT = e->source(); - node vH = pBCTree->cutVertex(vT, bT); - - //set length of vertex v in block graph of bT: - int length_v_in_block = 0; - edge e2; - forall_adj_edges(e2, vT) - { - //check if edge is an incoming edge: - if (e2->target() != vT) - continue; - - node bT2 = e2->source(); - node cutVertex = pBCTree->cutVertex(vT, bT2); - length_v_in_block += constraintMaxFace(bT2, cutVertex); - } - nodeLength[bT][nH_to_nBlockEmbedding[bT][vH]] = length_v_in_block; - } - - EdgeArray edgeLength(blockG[bT], 1); - int cstrLengthBc = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT]); - cstrLength[bT][nH_to_nBlockEmbedding[bT][cH]] = cstrLengthBc; - return cstrLengthBc; -} - - -void EmbedderMaxFace::maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt) -{ - //(B*, \ell*) := (B, size of a maximum face in B): - node m_bT_opt = bT; - EdgeArray edgeLength(blockG[bT], 1); - NodeArray< EdgeArray > edgeLengthSkel; - int m_ell_opt = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockG[bT], nodeLength[bT], edgeLength, *spqrTrees[bT], edgeLengthSkel); - - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, bT); - - EdgeArray edgeLength(blockG[bT], 1); - cstrLength[bT][nH_to_nBlockEmbedding[bT][cH]] - = EmbedderMaxFaceBiconnectedGraphs::computeSize(blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT], - edgeLengthSkel); - - //L := \sum_{(B', c) \in bcTree} cstrLength(B', c) - int L = 0; - edge e2; - { - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->source() != cT) - continue; - - //get partner vertex of c in the block graph of B'=e->target() and add - //cstrLength(B', c) to L: - node bT2 = e2->target(); - L += cstrLength[bT2][nH_to_nBlockEmbedding[bT2][pBCTree->cutVertex(cT, bT2)]]; - } - } - - forall_adj_edges(e2, cT) - { - //check if edge is an outgoing edge or the edge from bT to cT: - if (e2->target() != cT || e2->source() == bT) - continue; - - //get partner vertex of c in the block graph of B'=e->source(): - node pT = e2->source(); - node partnerV = pBCTree->cutVertex(cT, pT); - node pB = nH_to_nBlockEmbedding[pT][partnerV]; - nodeLength[pT][pB] = L - cstrLength[pT][pB]; - - //pBCTree->originalGraph().chooseNode() just to get rid of warning: - node thisbT_opt = pBCTree->originalGraph().chooseNode(); - int thisell_opt = 0; - maximumFaceRec(pT, thisbT_opt, thisell_opt); - if (thisell_opt > m_ell_opt) - { - m_bT_opt = thisbT_opt; - m_ell_opt = thisell_opt; - } - } - } - - //return (B*, \ell*): - bT_opt = m_bT_opt; - ell_opt = m_ell_opt; -} - - -void EmbedderMaxFace::embedBlock(const node& bT) -{ - ListIterator after; - node cT = 0; - embedBlock(bT, cT, after); -} - - -void EmbedderMaxFace::embedBlock( - const node& bT, - const node& cT, - ListIterator& after) -{ - treeNodeTreated[bT] = true; - node cH = 0; - if (!(cT == 0)) - cH = pBCTree->cutVertex(cT, bT); - - //*************************************************************************** - // 1. Compute embedding of block - //*************************************************************************** - EdgeArray edgeLength(blockG[bT], 1); - adjEntry m_adjExternal = 0; - if (cH == 0) - EmbedderMaxFaceBiconnectedGraphs::embed(blockG[bT], m_adjExternal, - nodeLength[bT], edgeLength); - else - EmbedderMaxFaceBiconnectedGraphs::embed(blockG[bT], m_adjExternal, - nodeLength[bT], edgeLength, nH_to_nBlockEmbedding[bT][cH]); - - //*************************************************************************** - // 2. Copy block embedding into graph embedding and call recursively - // embedBlock for all cut vertices in bT - //*************************************************************************** - CombinatorialEmbedding CE(blockG[bT]); - face f = CE.leftFace(m_adjExternal); - - if (*pAdjExternal == 0) - { - node on = pBCTree->original(nBlockEmbedding_to_nH[bT][m_adjExternal->theNode()]); - adjEntry ae1 = on->firstAdj(); - for (adjEntry ae = ae1; ae; ae = ae->succ()) - { - if (ae->theEdge() == pBCTree->original(eBlockEmbedding_to_eH[bT][m_adjExternal->theEdge()])) - { - *pAdjExternal = ae->twin(); - break; - } - } - } - - node nSG; - forall_nodes(nSG, blockG[bT]) - { - node nH = nBlockEmbedding_to_nH[bT][nSG]; - node nG = pBCTree->original(nH); - adjEntry ae = nSG->firstAdj(); - ListIterator* pAfter; - if (pBCTree->bcproper(nG) == cT) - pAfter = &after; - else - pAfter = OGDF_NEW ListIterator(); - - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node cT2 = pBCTree->bcproper(nG); - bool no_recursion = false; - if (cT2 == cT) - { - node parent_bT_of_cT2; - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - if (e_cT2_to_bT2->source() == cT2) - { - parent_bT_of_cT2 = e_cT2_to_bT2->target(); - break; - } - } - if (treeNodeTreated[parent_bT_of_cT2]) - no_recursion = true; - } - - if (no_recursion) - { - //find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - } - else //!no_recursion - { - //(if exists) find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - node bT2; - if (e_cT2_to_bT2->source() == cT2) - bT2 = e_cT2_to_bT2->target(); - else - bT2 = e_cT2_to_bT2->source(); - if (!treeNodeTreated[bT2]) - embedBlock(bT2, cT2, *pAfter); - } - } - } - - //embed all edges of block bT: - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : nSG->firstAdj()) - { - edge eG = pBCTree->original(eBlockEmbedding_to_eH[bT][aeNode->theEdge()]); - if (nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjSource()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjSource(), *pAfter); - } - else //!(nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjTarget()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - - if (!(*pAfter == after)) - delete pAfter; - } //forall_nodes(nSG, blockG[bT]) -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/EmbedderMaxFaceLayers.cpp b/ext/OGDF/src/planarity/EmbedderMaxFaceLayers.cpp deleted file mode 100644 index 3310b947b..000000000 --- a/ext/OGDF/src/planarity/EmbedderMaxFaceLayers.cpp +++ /dev/null @@ -1,646 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with maximum external face. - * - * See the paper "Graph Embedding with Minimum Depth and Maximum External - * Face" by C. Gutwenger and P. Mutzel (2004) for details. - * The algorithm for maximum external face is combined with the - * algorithm for maximum external layers which defines how to embed - * blocks into inner faces. See diploma thesis "Algorithmen zur - * Bestimmung von guten Graph-Einbettungen für orthogonale - * Zeichnungen" (in german) by Thorsten Kerkhof (2007) for details. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void EmbedderMaxFaceLayers::call(Graph& G, adjEntry& adjExternal) -{ - adjExternal = 0; - pAdjExternal = &adjExternal; - - //simple base cases: - if (G.numberOfNodes() <= 1) - return; - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //HINT: Edges are directed from child to parent in BC-trees - pBCTree = new BCTree(G); - - //base case of biconnected graph: - if (pBCTree->bcTree().numberOfNodes() == 1) - { - NodeArray m_nodeLength(G, 0); - EdgeArray m_edgeLength(G, 1); - adjEntry m_adjExternal; - EmbedderMaxFaceBiconnectedGraphsLayers::embed(G, m_adjExternal, m_nodeLength, m_edgeLength); - adjExternal = m_adjExternal; - - delete pBCTree; - return; - } - - //***************************************************************************/ - //First step: calculate maximum face and node lengths - //***************************************************************************/ - - //Find root Block (root node is only node with out-degree of 0): - node rootBlockNode; - node n; - forall_nodes(n, pBCTree->bcTree()) - { - if (n->outdeg() == 0) - { - rootBlockNode = n; - break; - } - } - - //compute block graphs and SPQR trees: - blockG.init(pBCTree->bcTree()); - nBlockEmbedding_to_nH.init(pBCTree->bcTree()); - eBlockEmbedding_to_eH.init(pBCTree->bcTree()); - nH_to_nBlockEmbedding.init(pBCTree->bcTree()); - eH_to_eBlockEmbedding.init(pBCTree->bcTree()); - nodeLength.init(pBCTree->bcTree()); - cstrLength.init(pBCTree->bcTree()); - spqrTrees.init(pBCTree->bcTree(),0); - computeBlockGraphs(rootBlockNode, 0); - - //Bottom-Up-Traversal: - edge e; - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, rootBlockNode); - node cB = nH_to_nBlockEmbedding[rootBlockNode][cH]; - - //set length of v in block graph of root block node: - int length_v_in_rootBlock = 0; - edge e2; - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - length_v_in_rootBlock += constraintMaxFace(blockNode, cutVertex); - } - nodeLength[rootBlockNode][cB] = length_v_in_rootBlock; - } - - node bT_opt = G.chooseNode(); //= G.chooseNode() only to get rid of warning - int ell_opt = 0; - maximumFaceRec(rootBlockNode, bT_opt, ell_opt); - - - //**************************************************************************** - //Second step: Embed G by expanding a maximum face in bT_opt - //**************************************************************************** - newOrder.init(G); - treeNodeTreated.init(pBCTree->bcTree(), false); - embedBlock(bT_opt); - - node v; - forall_nodes(v, G) - G.sort(v, newOrder[v]); - - forall_nodes(v, pBCTree->bcTree()) - delete spqrTrees[v]; - - delete pBCTree; -} - - -void EmbedderMaxFaceLayers::computeBlockGraphs(const node& bT, const node& cH) -{ - //recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->source() == bT) - continue; - - node cT = e->source(); - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->source() == cT) - continue; - node cH2 = pBCTree->cutVertex(cT, e2->source()); - computeBlockGraphs(e2->source(), cH2); - } - } - - //embed block bT: - node m_cH = cH; - if (m_cH == 0) - m_cH = pBCTree->cutVertex(bT->firstAdj()->twinNode(), bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockG[bT], m_cH, - nBlockEmbedding_to_nH[bT], eBlockEmbedding_to_eH[bT], - nH_to_nBlockEmbedding[bT], eH_to_eBlockEmbedding[bT]); - nodeLength[bT].init(blockG[bT], 0); - cstrLength[bT].init(blockG[bT], 0); - if ( !blockG[bT].empty() - && blockG[bT].numberOfNodes() != 1 - && blockG[bT].numberOfEdges() > 2) - { - spqrTrees[bT] = new StaticSPQRTree(blockG[bT]); - } -} - - -int EmbedderMaxFaceLayers::constraintMaxFace(const node& bT, const node& cH) -{ - //forall (v \in B, v \neq c) do: - // length_B(v) := \sum_{(v, B') \in B} ConstraintMaxFace(B', v); - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node vT = e->source(); - node vH = pBCTree->cutVertex(vT, bT); - - //set length of vertex v in block graph of bT: - int length_v_in_block = 0; - edge e2; - forall_adj_edges(e2, vT) - { - //check if edge is an incoming edge: - if (e2->target() != vT) - continue; - - node bT2 = e2->source(); - node cutVertex = pBCTree->cutVertex(vT, bT2); - length_v_in_block += constraintMaxFace(bT2, cutVertex); - } - nodeLength[bT][nH_to_nBlockEmbedding[bT][vH]] = length_v_in_block; - } - - EdgeArray edgeLength(blockG[bT], 1); - int cstrLengthBc - = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize(blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT]); - cstrLength[bT][nH_to_nBlockEmbedding[bT][cH]] = cstrLengthBc; - return cstrLengthBc; -} - - -void EmbedderMaxFaceLayers::maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt) -{ - //(B*, \ell*) := (B, size of a maximum face in B): - node m_bT_opt = bT; - EdgeArray edgeLength(blockG[bT], 1); - NodeArray< EdgeArray > edgeLengthSkel; - int m_ell_opt = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockG[bT], - nodeLength[bT], - edgeLength, - *spqrTrees[bT], - edgeLengthSkel); - - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, bT); - - EdgeArray edgeLength(blockG[bT], 1); - cstrLength[bT][nH_to_nBlockEmbedding[bT][cH]] = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT], - edgeLengthSkel); - - //L := \sum_{(B', c) \in bcTree} cstrLength(B', c) - int L = 0; - edge e2; - { - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->source() != cT) - continue; - - //get partner vertex of c in the block graph of B'=e->target() and add - //cstrLength(B', c) to L: - node bT2 = e2->target(); - L += cstrLength[bT2][nH_to_nBlockEmbedding[bT2][pBCTree->cutVertex(cT, bT2)]]; - } - } - - forall_adj_edges(e2, cT) - { - //check if edge is an outgoing edge or the edge from bT to cT: - if (e2->target() != cT || e2->source() == bT) - continue; - - //get partner vertex of c in the block graph of B'=e->source(): - node pT = e2->source(); - node partnerV = pBCTree->cutVertex(cT, pT); - node pB = nH_to_nBlockEmbedding[pT][partnerV]; - nodeLength[pT][pB] = L - cstrLength[pT][pB]; - - //pBCTree->originalGraph().chooseNode() just to get rid of warning: - node thisbT_opt = pBCTree->originalGraph().chooseNode(); - int thisell_opt = 0; - maximumFaceRec(pT, thisbT_opt, thisell_opt); - if (thisell_opt > m_ell_opt) - { - m_bT_opt = thisbT_opt; - m_ell_opt = thisell_opt; - } - } - } - - //return (B*, \ell*): - bT_opt = m_bT_opt; - ell_opt = m_ell_opt; -} - - -void EmbedderMaxFaceLayers::embedBlock(const node& bT) -{ - ListIterator after; - node cT = 0; - embedBlock(bT, cT, after); -} - - -void EmbedderMaxFaceLayers::embedBlock( - const node& bT, - const node& cT, - ListIterator& after) -{ - treeNodeTreated[bT] = true; - node cH = 0; - if (!(cT == 0)) - cH = pBCTree->cutVertex(cT, bT); - - //*************************************************************************** - // 1. Compute embedding of block - //*************************************************************************** - EdgeArray edgeLength(blockG[bT], 1); - adjEntry m_adjExternal = 0; - if (cH == 0) - EmbedderMaxFaceBiconnectedGraphsLayers::embed(blockG[bT], m_adjExternal, - nodeLength[bT], edgeLength); - else - EmbedderMaxFaceBiconnectedGraphsLayers::embed(blockG[bT], m_adjExternal, - nodeLength[bT], edgeLength, nH_to_nBlockEmbedding[bT][cH]); - - //*************************************************************************** - // 2. Copy block embedding into graph embedding and call recursively - // embedBlock for all cut vertices in bT - //*************************************************************************** - CombinatorialEmbedding CE(blockG[bT]); - face f = CE.leftFace(m_adjExternal); - - if (*pAdjExternal == 0) - { - node on = pBCTree->original(nBlockEmbedding_to_nH[bT][m_adjExternal->theNode()]); - adjEntry ae1 = on->firstAdj(); - for (adjEntry ae = ae1; ae; ae = ae->succ()) - { - if (ae->theEdge() == pBCTree->original(eBlockEmbedding_to_eH[bT][m_adjExternal->theEdge()])) - { - *pAdjExternal = ae->twin(); - break; - } - } - } - - bool DGcomputed = false; - int extFaceID = 0; - Graph* p_DG; - List* p_fPG_to_nDG; - NodeArray* p_nDG_to_fPG; - NodeArray< List >* p_adjacencyList; - List< List >* p_faces; - NodeArray* p_distances; - - node nSG; - forall_nodes(nSG, blockG[bT]) - { - node nH = nBlockEmbedding_to_nH[bT][nSG]; - node nG = pBCTree->original(nH); - adjEntry ae = nSG->firstAdj(); - ListIterator* pAfter; - if (pBCTree->bcproper(nG) == cT) - pAfter = &after; - else - pAfter = OGDF_NEW ListIterator(); - - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node cT2 = pBCTree->bcproper(nG); - bool no_recursion = false; - if (cT2 == cT) - { - node parent_bT_of_cT2; - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - if (e_cT2_to_bT2->source() == cT2) - { - parent_bT_of_cT2 = e_cT2_to_bT2->target(); - break; - } - } - if (treeNodeTreated[parent_bT_of_cT2]) - no_recursion = true; - } - - if (no_recursion) - { - //find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - } - else //!no_recursion - { - //(if exists) find adjacency entry of nSG which lies on external face f: - bool aeExtExists = false; - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - aeExtExists = true; - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - - if (!aeExtExists) - { - if (!DGcomputed) - { - p_DG = new Graph(); - p_fPG_to_nDG = OGDF_NEW List(); - p_nDG_to_fPG = OGDF_NEW NodeArray(); - p_adjacencyList = OGDF_NEW NodeArray< List >(); - p_faces = OGDF_NEW List< List >; - p_distances = OGDF_NEW NodeArray; - DGcomputed = true; - - //compute dual graph of skeleton graph: - p_adjacencyList->init(blockG[bT]); - node nBG; - forall_nodes(nBG, blockG[bT]) - { - adjEntry ae_nBG; - forall_adj(ae_nBG, nBG) - (*p_adjacencyList)[nBG].pushBack(ae_nBG); - } - - NodeArray< List > adjEntryTreated(blockG[bT]); - forall_nodes(nBG, blockG[bT]) - { - adjEntry adj; - forall_adj(adj, nBG) - { - if (adjEntryTreated[nBG].search(adj) != -1) - continue; - - List newFace; - adjEntry adj2 = adj; - do - { - newFace.pushBack(adj2); - adjEntryTreated[adj2->theNode()].pushBack(adj2); - node tn = adj2->twinNode(); - int idx = (*p_adjacencyList)[tn].search(adj2->twin()); - if (idx - 1 < 0) - idx = (*p_adjacencyList)[tn].size() - 1; - else - idx -= 1; - adj2 = *((*p_adjacencyList)[tn].get(idx)); - } while (adj2 != adj); - p_faces->pushBack(newFace); - } - } //forall_nodes(nBG, blockG[bT]) - - p_nDG_to_fPG->init(*p_DG); - - for (ListIterator< List > it = p_faces->begin(); it.valid(); it++) - { - node nn = p_DG->newNode(); - (*p_nDG_to_fPG)[nn] = p_fPG_to_nDG->search(*(p_fPG_to_nDG->pushBack(nn))); - } - - NodeArray< List > adjFaces(*p_DG); - int i = 0; - for (ListIterator< List > it = p_faces->begin(); it.valid(); it++) - { - int f1_id = i; - for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - { - int f2_id = 0; - int j = 0; - for (ListIterator< List > it3 = p_faces->begin(); it3.valid(); it3++) - { - bool do_break = false; - for (ListIterator it4 = (*it3).begin(); it4.valid(); it4++) - { - if ((*it4) == (*it2)->twin()) - { - f2_id = j; - do_break = true; - break; - } - } - if (do_break) - break; - j++; - } - - if ( f1_id != f2_id - && adjFaces[*(p_fPG_to_nDG->get(f1_id))].search(*(p_fPG_to_nDG->get(f2_id))) == -1 - && adjFaces[*(p_fPG_to_nDG->get(f2_id))].search(*(p_fPG_to_nDG->get(f1_id))) == -1) - { - adjFaces[*(p_fPG_to_nDG->get(f1_id))].pushBack(*(p_fPG_to_nDG->get(f2_id))); - p_DG->newEdge(*(p_fPG_to_nDG->get(f1_id)), *(p_fPG_to_nDG->get(f2_id))); - } - - if (*it2 == f->firstAdj()) - extFaceID = f1_id; - } //for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - i++; - } //for (ListIterator< List > it = faces.begin(); it.valid(); it++) - - //compute shortest path from every face to the external face: - List DG_edges; - p_DG->allEdges(DG_edges); - for (ListIterator it_e = DG_edges.begin(); it_e.valid(); it_e++) - { - node s = (*it_e)->source(); - node t = (*it_e)->target(); - p_DG->newEdge(t, s); - } - ShortestPathWithBFM shortestPath; - node efDG = *(p_fPG_to_nDG->get(extFaceID)); - EdgeArray el(*p_DG, 1); - p_distances->init(*p_DG); - NodeArray pi(*p_DG); - shortestPath.call(*p_DG, efDG, el, *p_distances, pi); - } //if (!DGcomputed) - - //choose face with minimal shortest path: - List optFace; - int optFaceDist = -1; - for (int fID = 0; fID < p_faces->size(); fID++) - { - List theFace = *(p_faces->get(fID)); - adjEntry ae_nSG; - bool contains_nSG = false; - for (ListIterator it_ae = theFace.begin(); it_ae.valid(); it_ae++) - { - if ((*it_ae)->theNode() == nSG) - { - contains_nSG = true; - ae_nSG = *it_ae; - break; - } - } - - if (contains_nSG) - { - int thisDist = (*p_distances)[*p_fPG_to_nDG->get(fID)]; - if (optFaceDist == -1 || optFaceDist > thisDist) - { - optFace = theFace; - optFaceDist = thisDist; - if (ae_nSG->succ()) - ae = ae_nSG->succ(); - else - ae = nSG->firstAdj(); - } - } - } //for (int fID = 0; fID < faces.size(); fID++) - } //if (!aeExtExists) - - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - node bT2; - if (e_cT2_to_bT2->source() == cT2) - bT2 = e_cT2_to_bT2->target(); - else - bT2 = e_cT2_to_bT2->source(); - if (!treeNodeTreated[bT2]) - embedBlock(bT2, cT2, *pAfter); - } - } - } - - //embed all edges of block bT: - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : nSG->firstAdj()) - { - edge eG = pBCTree->original(eBlockEmbedding_to_eH[bT][aeNode->theEdge()]); - if (nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjSource()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjSource(), *pAfter); - } - else //!(nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjTarget()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - - if (!(*pAfter == after)) - delete pAfter; - } //forall_nodes(nSG, blockG[bT]) - - if (DGcomputed) - { - delete p_DG; - delete p_fPG_to_nDG; - delete p_nDG_to_fPG; - delete p_adjacencyList; - delete p_faces; - delete p_distances; - } -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/EmbedderMinDepth.cpp b/ext/OGDF/src/planarity/EmbedderMinDepth.cpp deleted file mode 100644 index 42a69d843..000000000 --- a/ext/OGDF/src/planarity/EmbedderMinDepth.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with minimum depth. - * See paper "Graph Embedding with Minimum Depth and Maximum External - * Face" by C. Gutwenger and P. Mutzel (2004) for details. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void EmbedderMinDepth::call(Graph& G, adjEntry& adjExternal) -{ - adjExternal = 0; - pAdjExternal = &adjExternal; - - //simple base cases: - if (G.numberOfNodes() <= 1) - return; - - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //HINT: Edges are directed from child to parent in BC-trees - pBCTree = new BCTree(G); - - //base case of biconnected graph: - if (pBCTree->bcTree().numberOfNodes() == 1) - { - NodeArray m_nodeLength(G, 0); - EdgeArray m_edgeLength(G, 0); - adjEntry m_adjExternal; - EmbedderMaxFaceBiconnectedGraphs::embed(G, m_adjExternal, m_nodeLength, m_edgeLength); - adjExternal = m_adjExternal->twin(); - - delete pBCTree; - return; - } - - - //***************************************************************************/ - //First step: calculate min depth and node lengths - //***************************************************************************/ - //Find root Block (only node with out-degree of 0): - node rootBlockNode; - node n; - forall_nodes(n, pBCTree->bcTree()) - { - if (n->outdeg() == 0) - { - rootBlockNode = n; - break; - } - } - - //compute block graphs: - blockG.init(pBCTree->bcTree()); - nBlockEmbedding_to_nH.init(pBCTree->bcTree()); - eBlockEmbedding_to_eH.init(pBCTree->bcTree()); - nH_to_nBlockEmbedding.init(pBCTree->bcTree()); - eH_to_eBlockEmbedding.init(pBCTree->bcTree()); - nodeLength.init(pBCTree->bcTree()); - spqrTrees.init(pBCTree->bcTree(),0); - computeBlockGraphs(rootBlockNode, 0); - - //Edge lengths of BC-tree, values m_{c, B} for all (c, B) \in bcTree: - m_cB.init(pBCTree->bcTree(), 0); - - //Bottom-up traversal: (set m_cB for all {c, B} \in bcTree) - nodeLength[rootBlockNode].init(blockG[rootBlockNode], 0); - edge e; - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - //node cH = pBCTree->cutVertex(cT, rootBlockNode); - - //set length of c in block graph of root block node: - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - - //Start recursion: - m_cB[e2] = bottomUpTraversal(blockNode, cutVertex); - } - } - - //Top-down traversal: (set m_cB for all {B, c} \in bcTree and get min depth - //for each block) - int maxint = 2147483647; - minDepth.init(pBCTree->bcTree(), maxint); - M_B.init(pBCTree->bcTree()); - M2.init(pBCTree->bcTree()); - topDownTraversal(rootBlockNode); - - //compute bT_opt: - int depth = maxint; - node bT_opt; - forall_nodes(n, pBCTree->bcTree()) - { - if (pBCTree->typeOfBNode(n) != BCTree::BComp) - continue; - if (minDepth[n] < depth) - { - depth = minDepth[n]; - bT_opt = n; - } - } - - //**************************************************************************** - //Second step: Embed G by expanding a maximum face in bT_opt - //**************************************************************************** - newOrder.init(G); - treeNodeTreated.init(pBCTree->bcTree(), false); - embedBlock(bT_opt); - - forall_nodes(n, G) - G.sort(n, newOrder[n]); - - forall_nodes(n, pBCTree->bcTree()) - delete spqrTrees[n]; - - delete pBCTree; -} - - -void EmbedderMinDepth::computeBlockGraphs(const node& bT, const node& cH) -{ - //recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->source() == bT) - continue; - - node cT = e->source(); - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->source() == cT) - continue; - node cH2 = pBCTree->cutVertex(cT, e2->source()); - computeBlockGraphs(e2->source(), cH2); - } - } - - //embed block bT: - node m_cH = cH; - if (m_cH == 0) - m_cH = pBCTree->cutVertex(bT->firstAdj()->twinNode(), bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockG[bT], m_cH, - nBlockEmbedding_to_nH[bT], eBlockEmbedding_to_eH[bT], - nH_to_nBlockEmbedding[bT], eH_to_eBlockEmbedding[bT]); - - if ( !blockG[bT].empty() - && blockG[bT].numberOfNodes() != 1 - && blockG[bT].numberOfEdges() > 2) - { - spqrTrees[bT] = new StaticSPQRTree(blockG[bT]); - } -} - - -int EmbedderMinDepth::bottomUpTraversal(const node& bT, const node& cH) -{ - int m_B = 0; //max_{c \in B} m_B(c) - List M_B; //{c \in B | m_B(c) = m_B} - - //Recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - //node c_in_bT = pBCTree->cutVertex(cT, bT); - - //set length of c in block graph of root block node: - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e == e_cT_bT2) - continue; - - node bT2 = e_cT_bT2->source(); - node c_in_bT2 = pBCTree->cutVertex(cT, bT2); - m_cB[e_cT_bT2] = bottomUpTraversal(bT2, c_in_bT2); - - //update m_B and M_B: - if (m_B < m_cB[e_cT_bT2]) - { - node cV_in_bT = pBCTree->cutVertex(cT, bT); - m_B = m_cB[e_cT_bT2]; - M_B.clear(); - M_B.pushBack(cV_in_bT); - } - else if (m_B == m_cB[e_cT_bT2] && M_B.search(pBCTree->cutVertex(cT, bT)) == -1) - { - node cV_in_bT = pBCTree->cutVertex(cT, bT); - M_B.pushBack(cV_in_bT); - } - } - } - - //set vertex length for all vertices in bH to 1 if vertex is in M_B: - nodeLength[bT].init(blockG[bT], 0); - for (ListIterator iterator = M_B.begin(); iterator.valid(); iterator++) - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 1; - - //leafs of BC-tree: - if (M_B.size() == 0) - return 1; - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockG[bT], 0); - - //compute maximum external face of block graph and get its size: - int cstrLength_B_c = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT]); - - if (cstrLength_B_c == M_B.size()) - return m_B; - //else: - return m_B + 2; -} - - -void EmbedderMinDepth::topDownTraversal(const node& bT) -{ - //m_B(c) = max {0} \cup {m_{c, B'} | c \in B', B' \neq B} - int m_B = 0; //max_{c \in B} m_B(c) - - //Compute m_B and M_B: - node cT_parent = 0; - edge e_bT_cT; - { - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->source() == bT) - cT_parent = e_bT_cT->target(); - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_cT_bT2 == e_bT_cT) - continue; - - //update m_B and M_B: - if (m_B < m_cB[e_cT_bT2]) - { - m_B = m_cB[e_cT_bT2]; - M_B[bT].clear(); - M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m_B == m_cB[e_cT_bT2] && M_B[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - } - //set vertex length for all vertices in bH to 1 if vertex is in M_B: - nodeLength[bT].fill(0); - NodeArray m_nodeLength(blockG[bT], 0); - for (ListIterator iterator = M_B[bT].begin(); iterator.valid(); iterator++) - { - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 1; - m_nodeLength[nH_to_nBlockEmbedding[bT][*iterator]] = 1; - } - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLengthBlock(blockG[bT], 0); - - //compute size of a maximum external face of block graph: - NodeArray< EdgeArray > edgeLengthSkel; - int cstrLength_B_c = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockG[bT], - m_nodeLength, - edgeLengthBlock, - *spqrTrees[bT], - edgeLengthSkel); - - //Prepare recursion by setting m_{c, B} for all edges {B, c} \in bcTree: - if (M_B[bT].size() > 0) - { - node cT1 = pBCTree->bcproper(pBCTree->original(*(M_B[bT].begin()))); - bool calculateNewNodeLengths; - if (M_B[bT].size() == 1 && cT1 == cT_parent) - calculateNewNodeLengths = true; - else - calculateNewNodeLengths = false; - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - node cT = e_bT_cT->source(); - node cH = pBCTree->cutVertex(cT, bT); - - if (M_B[bT].size() == 1 && cT1 == cT) - { - //Compute new vertex lengths according to - //m2 = max_{v \in V_B, v != c} m_B(v) and - //M2 = {c \in V_B \ {v} | m_B(c) = m2}. - int m2 = 0; - - //Compute m2 and M2: - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < m_cB[e_cT2_bT2]) - { - m2 = m_cB[e_cT2_bT2]; - M2[bT].clear(); - M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == m_cB[e_cT2_bT2] && M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - - //set vertex length for all vertices in bH to 1 if vertex is in M2 and - //0 otherwise: - nodeLength[bT][nH_to_nBlockEmbedding[bT][*(M_B[bT].begin())]] = 0; - for (ListIterator iterator = M2[bT].begin(); iterator.valid(); iterator++) - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 1; - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockG[bT], 0); - - //compute a maximum external face size of a face containing c in block graph: - int maxFaceSize = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT]); - if (M2[bT].size() == 0) - m_cB[e_bT_cT] = 1; - else - { - if (maxFaceSize == M2[bT].size()) - m_cB[e_bT_cT] = m2; - else - m_cB[e_bT_cT] = m2 + 2; - } - - if (calculateNewNodeLengths) - calculateNewNodeLengths = false; - else - { - //reset node lengths: - for (ListIterator iterator = M2[bT].begin(); iterator.valid(); iterator++) - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 0; - nodeLength[bT][nH_to_nBlockEmbedding[bT][*(M_B[bT].begin())]] = 1; - } - } - else //M_B.size() != 1 - { - //Compute a maximum face in block B containing c using the vertex lengths - //already assigned. - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockG[bT], 0); - - //compute a maximum external face size of a face containing c in block graph: - int maxFaceSize = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockG[bT], - nH_to_nBlockEmbedding[bT][cH], - nodeLength[bT], - edgeLength, - *spqrTrees[bT], - edgeLengthSkel); - if (M_B[bT].size() == 0) - m_cB[e_bT_cT] = 1; - else - { - if (maxFaceSize == M_B[bT].size()) - m_cB[e_bT_cT] = m_B; - else - m_cB[e_bT_cT] = m_B + 2; - } - } - }//forall_adj_edges(e_bT_cT, bT) - - if (calculateNewNodeLengths) - { - //Compute new vertex lengths according to - //m2 = max_{v \in V_B, v != c} m_B(v) and - //M2 = {c \in V_B \ {v} | m_B(c) = m2}. - int m2 = 0; - - //Compute m2 and M2: - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < m_cB[e_cT2_bT2]) - { - m2 = m_cB[e_cT2_bT2]; - M2[bT].clear(); - M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == m_cB[e_cT2_bT2] && M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - - //set vertex length for all vertices in bH to 1 if vertex is in M2 and - //0 otherwise: - nodeLength[bT][nH_to_nBlockEmbedding[bT][*(M_B[bT].begin())]] = 0; - for (ListIterator iterator = M2[bT].begin(); iterator.valid(); iterator++) - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 1; - } //if (calculateNewNodeLengths - else if (M_B[bT].size() == 1) - { - //Compute M2 = {c \in V_B \ {v} | m_B(c) = m2} with - //m2 = max_{v \in V_B, v != c} m_B(v). - int m2 = 0; - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < m_cB[e_cT2_bT2]) - { - m2 = m_cB[e_cT2_bT2]; - M2[bT].clear(); - M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == m_cB[e_cT2_bT2] && M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - } - } - - //Recursion: - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - - node cT = e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_cT_bT2 == e_bT_cT) - continue; - - topDownTraversal(e_cT_bT2->source()); - } - } - - //Compute M_B and M2 for embedBlock-function: - { - M_B[bT].clear(); - M2[bT].clear(); - m_B = 0; - int m2 = 0; - forall_adj_edges(e_bT_cT, bT) - { - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_bT_cT == e_cT_bT2) - continue; - - //update m_B and M_B: - if (m_B < m_cB[e_cT_bT2]) - { - m_B = m_cB[e_cT_bT2]; - M_B[bT].clear(); - M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m_B == m_cB[e_cT_bT2] && M_B[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - - if (M_B[bT].size() == 1) - { - node cT1 = pBCTree->bcproper(pBCTree->original(*(M_B[bT].begin()))); - forall_adj_edges(e_bT_cT, bT) - { - node cT2 = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - if (cT1 == cT2) - continue; - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - //update m2 and M2: - if (m2 < m_cB[e_cT_bT2]) - { - m2 = m_cB[e_cT_bT2]; - M2[bT].clear(); - M2[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m2 == m_cB[e_cT_bT2] - && M2[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - M2[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - } - } - - if (cstrLength_B_c == M_B[bT].size()) - minDepth[bT] = m_B; - else - minDepth[bT] = m_B + 2; -} - - -void EmbedderMinDepth::embedBlock(const node& bT) -{ - ListIterator after; - node cT = 0; - embedBlock(bT, cT, after); -} - - -void EmbedderMinDepth::embedBlock( - const node& bT, - const node& cT, - ListIterator& after) -{ - treeNodeTreated[bT] = true; - node cH = 0; - if (!(cT == 0)) - cH = pBCTree->cutVertex(cT, bT); - - //*************************************************************************** - // 1. Compute node lengths depending on M_B, M2 and cT - //*************************************************************************** - nodeLength[bT].fill(0); - if (!(cT == 0) && M_B[bT].size() == 1 && *(M_B[bT].begin()) == cH) - { - //set node length to 1 if node is in M2 and 0 otherwise - for (ListIterator iterator = M2[bT].begin(); iterator.valid(); iterator++) - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 1; - } - else - { - //set node length to 1 if node is in M_B and 0 otherwise - for (ListIterator iterator = M_B[bT].begin(); iterator.valid(); iterator++) - nodeLength[bT][nH_to_nBlockEmbedding[bT][*iterator]] = 1; - } - - //*************************************************************************** - // 2. Compute embedding of block - //*************************************************************************** - EdgeArray edgeLength(blockG[bT], 0); - adjEntry m_adjExternal = 0; - if (cH == 0) - EmbedderMaxFaceBiconnectedGraphs::embed(blockG[bT], m_adjExternal, nodeLength[bT], edgeLength); - else - EmbedderMaxFaceBiconnectedGraphs::embed(blockG[bT], m_adjExternal, nodeLength[bT], edgeLength, - nH_to_nBlockEmbedding[bT][cH]); - - //*************************************************************************** - // 3. Copy block embedding into graph embedding and call recursively - // embedBlock for all cut vertices in bT - //*************************************************************************** - CombinatorialEmbedding CE(blockG[bT]); - face f = CE.leftFace(m_adjExternal); - - if (*pAdjExternal == 0) - { - node on = pBCTree->original(nBlockEmbedding_to_nH[bT][m_adjExternal->theNode()]); - adjEntry ae1 = on->firstAdj(); - for (adjEntry ae = ae1; ae; ae = ae->succ()) - { - if (ae->theEdge() == pBCTree->original(eBlockEmbedding_to_eH[bT][m_adjExternal->theEdge()])) - { - *pAdjExternal = ae->twin(); - break; - } - } - } - - node nSG; - forall_nodes(nSG, blockG[bT]) - { - node nH = nBlockEmbedding_to_nH[bT][nSG]; - node nG = pBCTree->original(nH); - adjEntry ae = nSG->firstAdj(); - ListIterator* pAfter; - if (pBCTree->bcproper(nG) == cT) - pAfter = &after; - else - pAfter = OGDF_NEW ListIterator(); - - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node cT2 = pBCTree->bcproper(nG); - bool no_recursion = false; - if (cT2 == cT) - { - node parent_bT_of_cT2; - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - if (e_cT2_to_bT2->source() == cT2) - { - parent_bT_of_cT2 = e_cT2_to_bT2->target(); - break; - } - } - if (treeNodeTreated[parent_bT_of_cT2]) - no_recursion = true; - } - - if (no_recursion) - { - //find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - } - else //!no_recursion - { - //(if exists) find adjacency entry of nSG which lies on external face f: - //bool aeExtExists = false; - adjEntry aeFace = f->firstAdj(); - //List extFaceEdges; - do - { - //extFaceEdges.pushBack(aeFace->theEdge()); - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - //aeExtExists = true; - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - - //if (aeExtExists) - //{ - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - node bT2; - if (e_cT2_to_bT2->source() == cT2) - bT2 = e_cT2_to_bT2->target(); - else - bT2 = e_cT2_to_bT2->source(); - if (!treeNodeTreated[bT2]) - embedBlock(bT2, cT2, *pAfter); - } - //} - //else - //{ - // //cannot embed block into external face, so find a face with an adjacent - // //edge of the external face: - // bool foundIt = false; - // edge adjEdge; - // forall_adj_edges(adjEdge, nSG) - // { - // face m_f = CE.leftFace(adjEdge->adjSource()); - // adjEntry aeF = m_f->firstAdj(); - // do - // { - // if (extFaceEdges.search(aeF->theEdge()) != -1) - // { - // ae = adjEdge->adjSource(); - // foundIt = true; - // break; - // } - // aeF = aeF->faceCycleSucc(); - // } while(aeF != m_f->firstAdj()); - // if (foundIt) - // break; - // } - //} - } - } - - //embed all edges of block bT: - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : nSG->firstAdj()) - { - edge eG = pBCTree->original(eBlockEmbedding_to_eH[bT][aeNode->theEdge()]); - if (nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjSource()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjSource(), *pAfter); - } - else //!(nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjTarget()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - - if (!(*pAfter == after)) - delete pAfter; - } //forall_nodes(nSG, blockG[bT]) -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/EmbedderMinDepthMaxFace.cpp b/ext/OGDF/src/planarity/EmbedderMinDepthMaxFace.cpp deleted file mode 100644 index f52a23532..000000000 --- a/ext/OGDF/src/planarity/EmbedderMinDepthMaxFace.cpp +++ /dev/null @@ -1,958 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with minimum depth and - * maximum external face. See paper "Graph Embedding with Minimum - * Depth and Maximum External Face" by C. Gutwenger and P. Mutzel - * (2004) for details. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void EmbedderMinDepthMaxFace::call(Graph& G, adjEntry& adjExternal) -{ - edge e; - node n; - int maxint = 2147483647; - - adjExternal = 0; - pAdjExternal = &adjExternal; - - //simple base cases: - if (G.numberOfNodes() <= 1) - return; - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //HINT: Edges are directed from child to parent in BC-trees - pBCTree = new BCTree(G); - - //base case of biconnected graph: - if (pBCTree->bcTree().numberOfNodes() == 1) - { - NodeArray m_nodeLength(G, 0); - EdgeArray m_edgeLength(G, 1); - adjEntry m_adjExternal; - EmbedderMaxFaceBiconnectedGraphs::embed(G, - m_adjExternal, - m_nodeLength, - m_edgeLength); - adjExternal = m_adjExternal->twin(); - - delete pBCTree; - return; - } - - - //============================================================================ - // First step: calculate min depth and node lengths - //============================================================================ - //Find root Block (only node with out-degree of 0): - node rootBlockNode; - forall_nodes(n, pBCTree->bcTree()) - { - if (n->outdeg() == 0) - { - rootBlockNode = n; - break; - } - } - - /****************************************************************************/ - /* MIN DEPTH */ - /****************************************************************************/ - //Node lengths of block graph: - md_nodeLength.init(pBCTree->auxiliaryGraph(), 0); - - //Edge lengths of BC-tree, values m_{c, B} for all (c, B) \in bcTree: - md_m_cB.init(pBCTree->bcTree(), 0); - - //Bottom-up traversal: (set m_cB for all {c, B} \in bcTree) - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - //node cH = pBCTree->cutVertex(cT, rootBlockNode); - - //set length of c in block graph of root block node: - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - - //Start recursion: - md_m_cB[e2] = md_bottomUpTraversal(blockNode, cutVertex); - } - } - - //Top-down traversal: (set m_cB for all {B, c} \in bcTree and get min depth - //for each block) - md_nodeLength.fill(0); - md_minDepth.init(pBCTree->bcTree(), maxint); - md_M_B.init(pBCTree->bcTree()); - md_M2.init(pBCTree->bcTree()); - md_topDownTraversal(rootBlockNode); - - /****************************************************************************/ - /* MAX FACE */ - /****************************************************************************/ - mf_cstrLength.init(pBCTree->auxiliaryGraph(), 0); - mf_nodeLength.init(pBCTree->auxiliaryGraph(), 0); - mf_maxFaceSize.init(pBCTree->bcTree(), 0); - - //Bottom-Up-Traversal: - { - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, rootBlockNode); - - //set length of v in block graph of root block node: - int length_v_in_rootBlock = 0; - edge e2; - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - length_v_in_rootBlock += mf_constraintMaxFace(blockNode, cutVertex); - } - mf_nodeLength[cH] = length_v_in_rootBlock; - } - } - - node mf_bT_opt = G.chooseNode(); //= G.chooseNode() only to get rid of warning - int mf_ell_opt = 0; - mf_maximumFaceRec(rootBlockNode, mf_bT_opt, mf_ell_opt); - - /****************************************************************************/ - /* MIN DEPTH + MAX FACE */ - /****************************************************************************/ - //compute bT_opt: - mdmf_edgeLength.init(pBCTree->auxiliaryGraph(), MDMFLengthAttribute(0, 1)); - mdmf_nodeLength.init(pBCTree->auxiliaryGraph(), MDMFLengthAttribute(0, 0)); - int d_opt = maxint; - int ell_opt = -1; - node bT_opt; - node bT; - forall_nodes(bT, pBCTree->bcTree()) - { - if (pBCTree->typeOfBNode(bT) != BCTree::BComp) - continue; - if ( md_minDepth[bT] < d_opt - || (md_minDepth[bT] == d_opt && mf_maxFaceSize[bT] > ell_opt)) - { - d_opt = md_minDepth[bT]; - ell_opt = mf_maxFaceSize[bT]; - bT_opt = bT; - } - } - - //============================================================================ - // Second step: Embed G by expanding a maximum face in bT_opt - //============================================================================ - newOrder.init(G); - treeNodeTreated.init(pBCTree->bcTree(), false); - //reset md_nodeLength and set them during embedBlock call, because they are - //calculated for starting embedding with rootBlockNode, which is not - //guarenteed - md_nodeLength.fill(0); - embedBlock(bT_opt); - - forall_nodes(n, G) - G.sort(n, newOrder[n]); - - delete pBCTree; -} - - -int EmbedderMinDepthMaxFace::md_bottomUpTraversal(const node& bT, const node& cH) -{ - int m_B = 0; //max_{c \in B} m_B(c) - List M_B; //{c \in B | m_B(c) = m_B} - - //Recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - //node c_in_bT = pBCTree->cutVertex(cT, bT); - - //set length of c in block graph of root block node: - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e == e_cT_bT2) - continue; - - node bT2 = e_cT_bT2->source(); - node c_in_bT2 = pBCTree->cutVertex(cT, bT2); - md_m_cB[e_cT_bT2] = md_bottomUpTraversal(bT2, c_in_bT2); - - //update m_B and M_B: - if (m_B < md_m_cB[e_cT_bT2]) - { - node cV_in_bT = pBCTree->cutVertex(cT, bT); - m_B = md_m_cB[e_cT_bT2]; - M_B.clear(); - M_B.pushBack(cV_in_bT); - } - else if ( m_B == md_m_cB[e_cT_bT2] && M_B.search(pBCTree->cutVertex(cT, bT)) == -1) - { - node cV_in_bT = pBCTree->cutVertex(cT, bT); - M_B.pushBack(cV_in_bT); - } - } - } - - //set vertex length for all vertices in bH to 1 if vertex is in M_B: - for (ListIterator iterator = M_B.begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - - //generate block graph of bT: - Graph blockGraph_bT; - node cInBlockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, cH, - cInBlockGraph_bT, md_nodeLength, nodeLengthSG); - - //leafs of BC-tree: - if (M_B.size() == 0) - return 1; - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockGraph_bT, 0); - - //compute maximum external face of block graph and get its size: - int cstrLength_B_c - = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph_bT, cInBlockGraph_bT, nodeLengthSG, edgeLength); - - if (cstrLength_B_c == M_B.size()) - return m_B; - //else: - return m_B + 2; -} - - -void EmbedderMinDepthMaxFace::md_topDownTraversal(const node& bT) -{ - //m_B(c) = max {0} \cup {m_{c, B'} | c \in B', B' \neq B} - int m_B = 0; //max_{c \in B} m_B(c) - - //Compute m_B and M_B: - node cT_parent = 0; - edge e_bT_cT; - { - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->source() == bT) - cT_parent = e_bT_cT->target(); - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_cT_bT2 == e_bT_cT) - continue; - - //update m_B and M_B: - if (m_B < md_m_cB[e_cT_bT2]) - { - m_B = md_m_cB[e_cT_bT2]; - md_M_B[bT].clear(); - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m_B == md_m_cB[e_cT_bT2] && md_M_B[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - } - //set vertex length for all vertices in bH to 1 if vertex is in M_B: - NodeArray m_nodeLength(pBCTree->auxiliaryGraph(), 0); - for (ListIterator iterator = md_M_B[bT].begin(); iterator.valid(); iterator++) - { - md_nodeLength[*iterator] = 1; - m_nodeLength[*iterator] = 1; - } - - //generate block graph of bT: - Graph blockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - NodeArray nG_to_nSG; - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, - (*(pBCTree->hEdges(bT).begin()))->source(), - m_nodeLength, nodeLengthSG, nG_to_nSG); - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLengthBlock(blockGraph_bT, 0); - - //compute size of a maximum external face of block graph: - StaticSPQRTree* spqrTree = 0; - if ( !blockGraph_bT.empty() - && blockGraph_bT.numberOfNodes() != 1 - && blockGraph_bT.numberOfEdges() > 2) - { - spqrTree = new StaticSPQRTree(blockGraph_bT); - } - NodeArray< EdgeArray > edgeLengthSkel; - int cstrLength_B_c = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph_bT, nodeLengthSG, edgeLengthBlock, *spqrTree, edgeLengthSkel); - - //Prepare recursion by setting m_{c, B} for all edges {B, c} \in bcTree: - if (md_M_B[bT].size() > 0) - { - node cT1 = pBCTree->bcproper(pBCTree->original(*(md_M_B[bT].begin()))); - bool calculateNewNodeLengths; - if (md_M_B[bT].size() == 1 && cT1 == cT_parent) - calculateNewNodeLengths = true; - else - calculateNewNodeLengths = false; - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - node cT = e_bT_cT->source(); - node cH = pBCTree->cutVertex(cT, bT); - - if (md_M_B[bT].size() == 1 && cT1 == cT) - { - //Compute new vertex lengths according to - //m2 = max_{v \in V_B, v != c} m_B(v) and - //M2 = {c \in V_B \ {v} | m_B(c) = m2}. - int m2 = 0; - - //Compute m2 and M2: - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < md_m_cB[e_cT2_bT2]) - { - m2 = md_m_cB[e_cT2_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == md_m_cB[e_cT2_bT2] && md_M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - - //set vertex length for all vertices in bH to 1 if vertex is in M2 and - //0 otherwise: - md_nodeLength[*(md_M_B[bT].begin())] = 0; - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - - Graph blockGraph_bT; - node cInBlockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, cH, - cInBlockGraph_bT, md_nodeLength, nodeLengthSG); - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockGraph_bT, 0); - - //compute a maximum external face size of a face containing c in block graph: - int maxFaceSize = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph_bT, - cInBlockGraph_bT, - nodeLengthSG, - edgeLength); - if (md_M2[bT].size() == 0) - md_m_cB[e_bT_cT] = 1; - else - { - if (maxFaceSize == md_M2[bT].size()) - md_m_cB[e_bT_cT] = m2; - else - md_m_cB[e_bT_cT] = m2 + 2; - } - - if (calculateNewNodeLengths) - calculateNewNodeLengths = false; - else - { - //reset node lengths: - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 0; - md_nodeLength[*(md_M_B[bT].begin())] = 1; - } - } - else //M_B.size() != 1 - { - //compute a maximum external face size of a face containing c in block graph: - node cInBlockGraph_bT = nG_to_nSG[cH]; - int maxFaceSize = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph_bT, - cInBlockGraph_bT, - nodeLengthSG, - edgeLengthBlock, - *spqrTree, - edgeLengthSkel); - if (md_M_B[bT].size() == 0) - md_m_cB[e_bT_cT] = 1; - else - { - if (maxFaceSize == md_M_B[bT].size()) - md_m_cB[e_bT_cT] = m_B; - else - md_m_cB[e_bT_cT] = m_B + 2; - } - } - }//forall_adj_edges(e_bT_cT, bT) - - if (calculateNewNodeLengths) - { - //Compute new vertex lengths according to - //m2 = max_{v \in V_B, v != c} m_B(v) and - //M2 = {c \in V_B \ {v} | m_B(c) = m2}. - int m2 = 0; - - //Compute m2 and M2: - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < md_m_cB[e_cT2_bT2]) - { - m2 = md_m_cB[e_cT2_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == md_m_cB[e_cT2_bT2] && md_M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - - //set vertex length for all vertices in bH to 1 if vertex is in M2 and - //0 otherwise: - md_nodeLength[*(md_M_B[bT].begin())] = 0; - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - } //if (calculateNewNodeLengths - else if (md_M_B[bT].size() == 1) - { - //Compute M2 = {c \in V_B \ {v} | m_B(c) = m2} with - //m2 = max_{v \in V_B, v != c} m_B(v). - int m2 = 0; - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < md_m_cB[e_cT2_bT2]) - { - m2 = md_m_cB[e_cT2_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == md_m_cB[e_cT2_bT2] && md_M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - } - } - - //Recursion: - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - - node cT = e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_cT_bT2 == e_bT_cT) - continue; - - md_topDownTraversal(e_cT_bT2->source()); - } - } - - //Compute M_B and M2 for embedBlock-function: - { - md_M_B[bT].clear(); - md_M2[bT].clear(); - m_B = 0; - int m2 = 0; - forall_adj_edges(e_bT_cT, bT) - { - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_bT_cT == e_cT_bT2) - continue; - - //update m_B and M_B: - if (m_B < md_m_cB[e_cT_bT2]) - { - m_B = md_m_cB[e_cT_bT2]; - md_M_B[bT].clear(); - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m_B == md_m_cB[e_cT_bT2] && md_M_B[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - - if (md_M_B[bT].size() == 1) - { - node cT1 = pBCTree->bcproper(pBCTree->original(*(md_M_B[bT].begin()))); - forall_adj_edges(e_bT_cT, bT) - { - node cT2 = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - if (cT1 == cT2) - continue; - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - //update m2 and M2: - if (m2 < md_m_cB[e_cT_bT2]) - { - m2 = md_m_cB[e_cT_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m2 == md_m_cB[e_cT_bT2] - && md_M2[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - } - } - - if (cstrLength_B_c == md_M_B[bT].size()) - md_minDepth[bT] = m_B; - else - md_minDepth[bT] = m_B + 2; - - delete spqrTree; -} - - -int EmbedderMinDepthMaxFace::mf_constraintMaxFace(const node& bT, const node& cH) -{ - //forall (v \in B, v \neq c) do: - // length_B(v) := \sum_{(v, B') \in B} ConstraintMaxFace(B', v); - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node vT = e->source(); - node vH = pBCTree->cutVertex(vT, bT); - - //set length of vertex v in block graph of bT: - int length_v_in_block = 0; - edge e2; - forall_adj_edges(e2, vT) - { - //check if edge is an incoming edge: - if (e2->target() != vT) - continue; - - node bT2 = e2->source(); - node cutVertex = pBCTree->cutVertex(vT, bT2); - length_v_in_block += mf_constraintMaxFace(bT2, cutVertex); - } - mf_nodeLength[vH] = length_v_in_block; - } - - mf_nodeLength[cH] = 0; - Graph blockGraph; - node cInBlockGraph; - NodeArray nodeLengthSG(blockGraph); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph, cH, cInBlockGraph, - mf_nodeLength, nodeLengthSG); - EdgeArray edgeLengthSG(blockGraph, 1); - int cstrLengthBc = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph, cInBlockGraph, nodeLengthSG, edgeLengthSG); - mf_cstrLength[cH] = cstrLengthBc; - return cstrLengthBc; -} - - -void EmbedderMinDepthMaxFace::mf_maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt) -{ - //(B*, \ell*) := (B, size of a maximum face in B): - node m_bT_opt = bT; - Graph blockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - NodeArray nG_to_nSG; - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, - (*(pBCTree->hEdges(bT).begin()))->source(), mf_nodeLength, nodeLengthSG, nG_to_nSG); - EdgeArray edgeLengthSG(blockGraph_bT, 1); - StaticSPQRTree* spqrTree = 0; - if ( !blockGraph_bT.empty() - && blockGraph_bT.numberOfNodes() != 1 - && blockGraph_bT.numberOfEdges() > 2) - { - spqrTree = new StaticSPQRTree(blockGraph_bT); - } - NodeArray< EdgeArray > edgeLengthSkel; - int m_ell_opt = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph_bT, nodeLengthSG, edgeLengthSG, *spqrTree, edgeLengthSkel); - mf_maxFaceSize[bT] = m_ell_opt; - - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, bT); - - //cstrLengthBc := size of a maximum face in B containing c: - node cInBlockGraph_bT = nG_to_nSG[cH]; - mf_cstrLength[cH] - = EmbedderMaxFaceBiconnectedGraphs::computeSize( - blockGraph_bT, cInBlockGraph_bT, nodeLengthSG, edgeLengthSG, *spqrTree, edgeLengthSkel); - - //L := \sum_{(B', c) \in bcTree} cstrLength(B', c) - int L = 0; - edge e2; - { - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->source() != cT) - continue; - - //get partner vertex of c in the block graph of B'=e->target() and add - //cstrLength(B', c) to L: - L += mf_cstrLength[pBCTree->cutVertex(cT, e2->target())]; - } - } - - forall_adj_edges(e2, cT) - { - //check if edge is an outgoing edge or the edge from bT to cT: - if (e2->target() != cT || e2->source() == bT) - continue; - - //get partner vertex of c in the block graph of B'=e->source(): - node partnerV = pBCTree->cutVertex(cT, e2->source()); - mf_nodeLength[partnerV] = L - mf_cstrLength[partnerV]; - - //pBCTree->originalGraph().chooseNode() just to get rid of warning: - node thisbT_opt = pBCTree->originalGraph().chooseNode(); - int thisell_opt = 0; - mf_maximumFaceRec(e2->source(), thisbT_opt, thisell_opt); - if (thisell_opt > m_ell_opt) - { - m_bT_opt = thisbT_opt; - m_ell_opt = thisell_opt; - } - } - } - - //return (B*, \ell*): - bT_opt = m_bT_opt; - ell_opt = m_ell_opt; - - //if ( !blockGraph_bT.empty() - // && blockGraph_bT.numberOfNodes() != 1 - // && blockGraph_bT.numberOfEdges() != 1) - //{ - delete spqrTree; - //} -} - - -void EmbedderMinDepthMaxFace::embedBlock(const node& bT) -{ - ListIterator after; - node cT = 0; - embedBlock(bT, cT, after); -} - - -void EmbedderMinDepthMaxFace::embedBlock( - const node& bT, - const node& cT, - ListIterator& after) -{ - treeNodeTreated[bT] = true; - node nSG; - node cH = 0; - if (!(cT == 0)) - cH = pBCTree->cutVertex(cT, bT); - - //*************************************************************************** - // 1. Compute MinDepth node lengths depending on M_B, M2 and cT - //*************************************************************************** - if (!(cT == 0) && md_M_B[bT].size() == 1 && *(md_M_B[bT].begin()) == cH) - { - //set node length to 1 if node is in M2 and 0 otherwise - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - } - else - { - //set node length to 1 if node is in M_B and 0 otherwise - for (ListIterator iterator = md_M_B[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - } - - //*************************************************************************** - // 2. Set MinDepthMaxFace node lengths - //*************************************************************************** - //create subgraph (block bT): - node nodeInBlock = cH; - if (nodeInBlock == 0) - nodeInBlock = (*(pBCTree->hEdges(bT).begin()))->source(); - Graph SG; - NodeArray nodeLengthSG; - EdgeArray edgeLengthSG; - NodeArray nSG_to_nG; - EdgeArray eSG_to_eG; - node nodeInBlockSG; - ConnectedSubgraph::call( - pBCTree->auxiliaryGraph(), SG, - nodeInBlock, nodeInBlockSG, - nSG_to_nG, eSG_to_eG, - mdmf_nodeLength, nodeLengthSG, - mdmf_edgeLength, edgeLengthSG); - - //copy (0, 1)-min depth node lengths into nodeLengthSG d component and max - //face sice node lengths into l component: - forall_nodes(nSG, SG) - { - nodeLengthSG[nSG].d = md_nodeLength[nSG_to_nG[nSG]]; - nodeLengthSG[nSG].l = mf_nodeLength[nSG_to_nG[nSG]]; - } - - //*************************************************************************** - // 3. Compute embedding of block - //*************************************************************************** - adjEntry m_adjExternal = 0; - if (cH == 0) - EmbedderMaxFaceBiconnectedGraphs::embed( - SG, m_adjExternal, nodeLengthSG, edgeLengthSG); - else - EmbedderMaxFaceBiconnectedGraphs::embed( - SG, m_adjExternal, nodeLengthSG, edgeLengthSG, nodeInBlockSG); - - //*************************************************************************** - // 4. Copy block embedding into graph embedding and call recursively - // embedBlock for all cut vertices in bT - //*************************************************************************** - CombinatorialEmbedding CE(SG); - face f = CE.leftFace(m_adjExternal); - - if (*pAdjExternal == 0) - { - node on = pBCTree->original(nSG_to_nG[m_adjExternal->theNode()]); - adjEntry ae1 = on->firstAdj(); - for (adjEntry ae = ae1; ae; ae = ae->succ()) - { - if (ae->theEdge() == pBCTree->original(eSG_to_eG[m_adjExternal->theEdge()])) - { - *pAdjExternal = ae->twin(); - break; - } - } - } - - forall_nodes(nSG, SG) - { - node nH = nSG_to_nG[nSG]; - node nG = pBCTree->original(nH); - adjEntry ae = nSG->firstAdj(); - ListIterator* pAfter; - if (pBCTree->bcproper(nG) == cT) - pAfter = &after; - else - pAfter = new ListIterator(); - - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node cT2 = pBCTree->bcproper(nG); - bool no_recursion = false; - if (cT2 == cT) - { - node parent_bT_of_cT2; - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - if (e_cT2_to_bT2->source() == cT2) - { - parent_bT_of_cT2 = e_cT2_to_bT2->target(); - break; - } - } - if (treeNodeTreated[parent_bT_of_cT2]) - no_recursion = true; - } - - if (no_recursion) - { - //find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - } - else //!no_recursion - { - //(if exists) find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - node bT2; - if (e_cT2_to_bT2->source() == cT2) - bT2 = e_cT2_to_bT2->target(); - else - bT2 = e_cT2_to_bT2->source(); - if (!treeNodeTreated[bT2]) - embedBlock(bT2, cT2, *pAfter); - } - } - } - - //embed all edges of block bT: - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : nSG->firstAdj()) - { - edge eG = pBCTree->original(eSG_to_eG[aeNode->theEdge()]); - if (nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjSource()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjSource(), *pAfter); - } - else //!(nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjTarget()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - - if (!(*pAfter == after)) - delete pAfter; - } //forall_nodes(nSG, SG) -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/EmbedderMinDepthMaxFaceLayers.cpp b/ext/OGDF/src/planarity/EmbedderMinDepthMaxFaceLayers.cpp deleted file mode 100644 index 870808424..000000000 --- a/ext/OGDF/src/planarity/EmbedderMinDepthMaxFaceLayers.cpp +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * $Revision: 2566 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Computes an embedding of a graph with minimum depth and - * maximum external face. - * - * See the paper "Graph Embedding with Minimum - * Depth and Maximum External Face" by C. Gutwenger and P. Mutzel - * (2004) for details. - * The algorithm for minimum depth and maximum external face is - * combined with the algorithm for maximum external layers which - * defines how to embed blocks into inner faces. See diploma thesis - * "Algorithmen zur Bestimmung von guten Graph-Einbettungen für - * orthogonale Zeichnungen" (in german) by Thorsten Kerkhof (2007) - * for details. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void EmbedderMinDepthMaxFaceLayers::call(Graph& G, adjEntry& adjExternal) -{ - edge e; - node n; - int maxint = 0xFFFFFF; - - adjExternal = 0; - pAdjExternal = &adjExternal; - - //simple base cases: - if (G.numberOfNodes() <= 1) - return; - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - //HINT: Edges are directed from child to parent in BC-trees - pBCTree = new BCTree(G); - - //base case of biconnected graph: - if (pBCTree->bcTree().numberOfNodes() == 1) - { - NodeArray m_nodeLength(G, 0); - EdgeArray m_edgeLength(G, 1); - adjEntry m_adjExternal; - EmbedderMaxFaceBiconnectedGraphsLayers::embed( - G, m_adjExternal, m_nodeLength, m_edgeLength); - adjExternal = m_adjExternal->twin(); - - delete pBCTree; - return; - } - - - //============================================================================ - // First step: calculate min depth and node lengths - //============================================================================ - //Find root Block (only node with out-degree of 0): - node rootBlockNode; - forall_nodes(n, pBCTree->bcTree()) - { - if (n->outdeg() == 0) - { - rootBlockNode = n; - break; - } - } - - /****************************************************************************/ - /* MIN DEPTH */ - /****************************************************************************/ - //Node lengths of block graph: - md_nodeLength.init(pBCTree->auxiliaryGraph(), 0); - - //Edge lengths of BC-tree, values m_{c, B} for all (c, B) \in bcTree: - md_m_cB.init(pBCTree->bcTree(), 0); - - //Bottom-up traversal: (set m_cB for all {c, B} \in bcTree) - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - //node cH = pBCTree->cutVertex(cT, rootBlockNode); - - //set length of c in block graph of root block node: - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - - //Start recursion: - md_m_cB[e2] = md_bottomUpTraversal(blockNode, cutVertex); - } - } - - //Top-down traversal: (set m_cB for all {B, c} \in bcTree and get min depth - //for each block) - md_nodeLength.fill(0); - md_minDepth.init(pBCTree->bcTree(), maxint); - md_M_B.init(pBCTree->bcTree()); - md_M2.init(pBCTree->bcTree()); - md_topDownTraversal(rootBlockNode); - - /****************************************************************************/ - /* MAX FACE */ - /****************************************************************************/ - mf_cstrLength.init(pBCTree->auxiliaryGraph(), 0); - mf_nodeLength.init(pBCTree->auxiliaryGraph(), 0); - mf_maxFaceSize.init(pBCTree->bcTree(), 0); - - //Bottom-Up-Traversal: - { - forall_adj_edges(e, rootBlockNode) - { - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, rootBlockNode); - - //set length of v in block graph of root block node: - int length_v_in_rootBlock = 0; - edge e2; - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->target() != cT) - continue; - - node blockNode = e2->source(); - node cutVertex = pBCTree->cutVertex(cT, blockNode); - length_v_in_rootBlock += mf_constraintMaxFace(blockNode, cutVertex); - } - mf_nodeLength[cH] = length_v_in_rootBlock; - } - } - - node mf_bT_opt = G.chooseNode(); //= G.chooseNode() only to get rid of warning - int mf_ell_opt = 0; - mf_maximumFaceRec(rootBlockNode, mf_bT_opt, mf_ell_opt); - - /****************************************************************************/ - /* MIN DEPTH + MAX FACE */ - /****************************************************************************/ - //compute bT_opt: - mdmf_edgeLength.init(pBCTree->auxiliaryGraph(), MDMFLengthAttribute(0, 1)); - mdmf_nodeLength.init(pBCTree->auxiliaryGraph(), MDMFLengthAttribute(0, 0)); - int d_opt = maxint; - int ell_opt = -1; - node bT_opt; - node bT; - forall_nodes(bT, pBCTree->bcTree()) - { - if (pBCTree->typeOfBNode(bT) != BCTree::BComp) - continue; - if ( md_minDepth[bT] < d_opt || (md_minDepth[bT] == d_opt && mf_maxFaceSize[bT] > ell_opt)) - { - d_opt = md_minDepth[bT]; - ell_opt = mf_maxFaceSize[bT]; - bT_opt = bT; - } - } - - //============================================================================ - // Second step: Embed G by expanding a maximum face in bT_opt - //============================================================================ - newOrder.init(G); - treeNodeTreated.init(pBCTree->bcTree(), false); - //reset md_nodeLength and set them during embedBlock call, because they are - //calculated for starting embedding with rootBlockNode, which is not - //guarenteed - md_nodeLength.fill(0); - embedBlock(bT_opt); - - forall_nodes(n, G) - G.sort(n, newOrder[n]); - - delete pBCTree; -} - - -int EmbedderMinDepthMaxFaceLayers::md_bottomUpTraversal(const node& bT, const node& cH) -{ - int m_B = 0; //max_{c \in B} m_B(c) - List M_B; //{c \in B | m_B(c) = m_B} - - //Recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - //node c_in_bT = pBCTree->cutVertex(cT, bT); - - //set length of c in block graph of root block node: - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e == e_cT_bT2) - continue; - - node bT2 = e_cT_bT2->source(); - node c_in_bT2 = pBCTree->cutVertex(cT, bT2); - md_m_cB[e_cT_bT2] = md_bottomUpTraversal(bT2, c_in_bT2); - - //update m_B and M_B: - if (m_B < md_m_cB[e_cT_bT2]) - { - node cV_in_bT = pBCTree->cutVertex(cT, bT); - m_B = md_m_cB[e_cT_bT2]; - M_B.clear(); - M_B.pushBack(cV_in_bT); - } - else if ( m_B == md_m_cB[e_cT_bT2] && M_B.search(pBCTree->cutVertex(cT, bT)) == -1) - { - node cV_in_bT = pBCTree->cutVertex(cT, bT); - M_B.pushBack(cV_in_bT); - } - } - } - - //set vertex length for all vertices in bH to 1 if vertex is in M_B: - for (ListIterator iterator = M_B.begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - - //generate block graph of bT: - Graph blockGraph_bT; - node cInBlockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, cH, - cInBlockGraph_bT, md_nodeLength, nodeLengthSG); - - //leafs of BC-tree: - if (M_B.size() == 0) - return 1; - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockGraph_bT, 0); - - //compute maximum external face of block graph and get its size: - int cstrLength_B_c = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph_bT, - cInBlockGraph_bT, - nodeLengthSG, - edgeLength); - - if (cstrLength_B_c == M_B.size()) - return m_B; - //else: - return m_B + 2; -} - - -void EmbedderMinDepthMaxFaceLayers::md_topDownTraversal(const node& bT) -{ - //m_B(c) = max {0} \cup {m_{c, B'} | c \in B', B' \neq B} - int m_B = 0; //max_{c \in B} m_B(c) - - //Compute m_B and M_B: - node cT_parent = 0; - edge e_bT_cT; - { - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->source() == bT) - cT_parent = e_bT_cT->target(); - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_cT_bT2 == e_bT_cT) - continue; - - //update m_B and M_B: - if (m_B < md_m_cB[e_cT_bT2]) - { - m_B = md_m_cB[e_cT_bT2]; - md_M_B[bT].clear(); - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m_B == md_m_cB[e_cT_bT2] && md_M_B[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - } - //set vertex length for all vertices in bH to 1 if vertex is in M_B: - NodeArray m_nodeLength(pBCTree->auxiliaryGraph(), 0); - for (ListIterator iterator = md_M_B[bT].begin(); iterator.valid(); iterator++) - { - md_nodeLength[*iterator] = 1; - m_nodeLength[*iterator] = 1; - } - - //generate block graph of bT: - Graph blockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - NodeArray nG_to_nSG; - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, - (*(pBCTree->hEdges(bT).begin()))->source(), - m_nodeLength, nodeLengthSG, nG_to_nSG); - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLengthBlock(blockGraph_bT, 0); - - //compute size of a maximum external face of block graph: - StaticSPQRTree* spqrTree = 0; - if ( !blockGraph_bT.empty() - && blockGraph_bT.numberOfNodes() != 1 - && blockGraph_bT.numberOfEdges() > 2) - { - spqrTree = new StaticSPQRTree(blockGraph_bT); - } - NodeArray< EdgeArray > edgeLengthSkel; - int cstrLength_B_c = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph_bT, nodeLengthSG, edgeLengthBlock, *spqrTree, edgeLengthSkel); - - //Prepare recursion by setting m_{c, B} for all edges {B, c} \in bcTree: - if (md_M_B[bT].size() > 0) - { - node cT1 = pBCTree->bcproper(pBCTree->original(*(md_M_B[bT].begin()))); - bool calculateNewNodeLengths; - if (md_M_B[bT].size() == 1 && cT1 == cT_parent) - calculateNewNodeLengths = true; - else - calculateNewNodeLengths = false; - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - node cT = e_bT_cT->source(); - node cH = pBCTree->cutVertex(cT, bT); - - if (md_M_B[bT].size() == 1 && cT1 == cT) - { - //Compute new vertex lengths according to - //m2 = max_{v \in V_B, v != c} m_B(v) and - //M2 = {c \in V_B \ {v} | m_B(c) = m2}. - int m2 = 0; - - //Compute m2 and M2: - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < md_m_cB[e_cT2_bT2]) - { - m2 = md_m_cB[e_cT2_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == md_m_cB[e_cT2_bT2] && md_M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - - //set vertex length for all vertices in bH to 1 if vertex is in M2 and - //0 otherwise: - md_nodeLength[*(md_M_B[bT].begin())] = 0; - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - - Graph blockGraph_bT; - node cInBlockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph_bT, cH, - cInBlockGraph_bT, md_nodeLength, nodeLengthSG); - - //set edge length for all edges in block graph to 0: - EdgeArray edgeLength(blockGraph_bT, 0); - - //compute a maximum external face size of a face containing c in block graph: - int maxFaceSize = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph_bT, cInBlockGraph_bT, nodeLengthSG, edgeLength); - if (md_M2[bT].size() == 0) - md_m_cB[e_bT_cT] = 1; - else - { - if (maxFaceSize == md_M2[bT].size()) - md_m_cB[e_bT_cT] = m2; - else - md_m_cB[e_bT_cT] = m2 + 2; - } - - if (calculateNewNodeLengths) - calculateNewNodeLengths = false; - else - { - //reset node lengths: - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 0; - md_nodeLength[*(md_M_B[bT].begin())] = 1; - } - } - else //M_B.size() != 1 - { - //compute a maximum external face size of a face containing c in block graph: - node cInBlockGraph_bT = nG_to_nSG[cH]; - int maxFaceSize = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph_bT, cInBlockGraph_bT, nodeLengthSG, edgeLengthBlock, *spqrTree, edgeLengthSkel); - if (md_M_B[bT].size() == 0) - md_m_cB[e_bT_cT] = 1; - else - { - if (maxFaceSize == md_M_B[bT].size()) - md_m_cB[e_bT_cT] = m_B; - else - md_m_cB[e_bT_cT] = m_B + 2; - } - } - }//forall_adj_edges(e_bT_cT, bT) - - if (calculateNewNodeLengths) - { - //Compute new vertex lengths according to - //m2 = max_{v \in V_B, v != c} m_B(v) and - //M2 = {c \in V_B \ {v} | m_B(c) = m2}. - int m2 = 0; - - //Compute m2 and M2: - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < md_m_cB[e_cT2_bT2]) - { - m2 = md_m_cB[e_cT2_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == md_m_cB[e_cT2_bT2] && md_M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - - //set vertex length for all vertices in bH to 1 if vertex is in M2 and - //0 otherwise: - md_nodeLength[*(md_M_B[bT].begin())] = 0; - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - } //if (calculateNewNodeLengths - else if (md_M_B[bT].size() == 1) - { - //Compute M2 = {c \in V_B \ {v} | m_B(c) = m2} with - //m2 = max_{v \in V_B, v != c} m_B(v). - int m2 = 0; - edge e_bT_cT2; - forall_adj_edges(e_bT_cT2, bT) - { - node cT2 = (e_bT_cT2->source() == bT) ? e_bT_cT2->target() : e_bT_cT2->source(); - if (cT1 == cT2) - continue; - edge e_cT2_bT2; - forall_adj_edges(e_cT2_bT2, cT2) - { - if (e_cT2_bT2 == e_bT_cT2) - continue; - - //update m_B and M_B: - if (m2 < md_m_cB[e_cT2_bT2]) - { - m2 = md_m_cB[e_cT2_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - else if ( m2 == md_m_cB[e_cT2_bT2] && md_M2[bT].search(pBCTree->cutVertex(cT2, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT2, bT)); - } - }//forall_adj_edges(e_cT2_bT2, cT2) - }//forall_adj_edges(e_bT_cT2, bT) - } - } - - //Recursion: - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - - node cT = e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_cT_bT2 == e_bT_cT) - continue; - - md_topDownTraversal(e_cT_bT2->source()); - } - } - - //Compute M_B and M2 for embedBlock-function: - { - md_M_B[bT].clear(); - md_M2[bT].clear(); - m_B = 0; - int m2 = 0; - forall_adj_edges(e_bT_cT, bT) - { - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - if (e_bT_cT == e_cT_bT2) - continue; - - //update m_B and M_B: - if (m_B < md_m_cB[e_cT_bT2]) - { - m_B = md_m_cB[e_cT_bT2]; - md_M_B[bT].clear(); - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m_B == md_m_cB[e_cT_bT2] && md_M_B[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - md_M_B[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - - if (md_M_B[bT].size() == 1) - { - node cT1 = pBCTree->bcproper(pBCTree->original(*(md_M_B[bT].begin()))); - forall_adj_edges(e_bT_cT, bT) - { - node cT2 = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - if (cT1 == cT2) - continue; - node cT = (e_bT_cT->source() == bT) ? e_bT_cT->target() : e_bT_cT->source(); - edge e_cT_bT2; - forall_adj_edges(e_cT_bT2, cT) - { - //update m2 and M2: - if (m2 < md_m_cB[e_cT_bT2]) - { - m2 = md_m_cB[e_cT_bT2]; - md_M2[bT].clear(); - md_M2[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - else if ( m2 == md_m_cB[e_cT_bT2] - && md_M2[bT].search(pBCTree->cutVertex(cT, bT)) == -1) - { - md_M2[bT].pushBack(pBCTree->cutVertex(cT, bT)); - } - }//forall_adj_edges(e_cT_bT2, cT) - }//forall_adj_edges(e_bT_cT, bT) - } - } - - if (cstrLength_B_c == md_M_B[bT].size()) - md_minDepth[bT] = m_B; - else - md_minDepth[bT] = m_B + 2; - - delete spqrTree; -} - - -int EmbedderMinDepthMaxFaceLayers::mf_constraintMaxFace(const node& bT, const node& cH) -{ - //forall (v \in B, v \neq c) do: - // length_B(v) := \sum_{(v, B') \in B} ConstraintMaxFace(B', v); - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node vT = e->source(); - node vH = pBCTree->cutVertex(vT, bT); - - //set length of vertex v in block graph of bT: - int length_v_in_block = 0; - edge e2; - forall_adj_edges(e2, vT) - { - //check if edge is an incoming edge: - if (e2->target() != vT) - continue; - - node bT2 = e2->source(); - node cutVertex = pBCTree->cutVertex(vT, bT2); - length_v_in_block += mf_constraintMaxFace(bT2, cutVertex); - } - mf_nodeLength[vH] = length_v_in_block; - } - - mf_nodeLength[cH] = 0; - Graph blockGraph; - node cInBlockGraph; - NodeArray nodeLengthSG(blockGraph); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockGraph, cH, cInBlockGraph, - mf_nodeLength, nodeLengthSG); - EdgeArray edgeLengthSG(blockGraph, 1); - int cstrLengthBc = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph, cInBlockGraph, nodeLengthSG, edgeLengthSG); - mf_cstrLength[cH] = cstrLengthBc; - return cstrLengthBc; -} - - -void EmbedderMinDepthMaxFaceLayers::mf_maximumFaceRec(const node& bT, node& bT_opt, int& ell_opt) -{ - //(B*, \ell*) := (B, size of a maximum face in B): - node m_bT_opt = bT; - Graph blockGraph_bT; - NodeArray nodeLengthSG(blockGraph_bT); - NodeArray nG_to_nSG; - ConnectedSubgraph::call( - pBCTree->auxiliaryGraph(), blockGraph_bT, - (*(pBCTree->hEdges(bT).begin()))->source(), - mf_nodeLength, nodeLengthSG, nG_to_nSG); - EdgeArray edgeLengthSG(blockGraph_bT, 1); - StaticSPQRTree* spqrTree = 0; - if ( !blockGraph_bT.empty() - && blockGraph_bT.numberOfNodes() != 1 - && blockGraph_bT.numberOfEdges() > 2) - { - spqrTree = new StaticSPQRTree(blockGraph_bT); - } - NodeArray< EdgeArray > edgeLengthSkel; - int m_ell_opt = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph_bT, nodeLengthSG, edgeLengthSG, *spqrTree, edgeLengthSkel); - mf_maxFaceSize[bT] = m_ell_opt; - - edge e; - forall_adj_edges(e, bT) - { - if (e->target() != bT) - continue; - node cT = e->source(); - node cH = pBCTree->cutVertex(cT, bT); - - //cstrLengthBc := size of a maximum face in B containing c: - node cInBlockGraph_bT = nG_to_nSG[cH]; - mf_cstrLength[cH] = EmbedderMaxFaceBiconnectedGraphsLayers::computeSize( - blockGraph_bT, cInBlockGraph_bT, nodeLengthSG, edgeLengthSG, *spqrTree, edgeLengthSkel); - - //L := \sum_{(B', c) \in bcTree} cstrLength(B', c) - int L = 0; - edge e2; - { - forall_adj_edges(e2, cT) - { - //check if edge is an incoming edge: - if (e2->source() != cT) - continue; - - //get partner vertex of c in the block graph of B'=e->target() and add - //cstrLength(B', c) to L: - L += mf_cstrLength[pBCTree->cutVertex(cT, e2->target())]; - } - } - - forall_adj_edges(e2, cT) - { - //check if edge is an outgoing edge or the edge from bT to cT: - if (e2->target() != cT || e2->source() == bT) - continue; - - //get partner vertex of c in the block graph of B'=e->source(): - node partnerV = pBCTree->cutVertex(cT, e2->source()); - mf_nodeLength[partnerV] = L - mf_cstrLength[partnerV]; - - //pBCTree->originalGraph().chooseNode() just to get rid of warning: - node thisbT_opt = pBCTree->originalGraph().chooseNode(); - int thisell_opt = 0; - mf_maximumFaceRec(e2->source(), thisbT_opt, thisell_opt); - if (thisell_opt > m_ell_opt) - { - m_bT_opt = thisbT_opt; - m_ell_opt = thisell_opt; - } - } - } - - //return (B*, \ell*): - bT_opt = m_bT_opt; - ell_opt = m_ell_opt; - - delete spqrTree; -} - - -void EmbedderMinDepthMaxFaceLayers::embedBlock(const node& bT) -{ - ListIterator after; - node cT = 0; - embedBlock(bT, cT, after); -} - - -void EmbedderMinDepthMaxFaceLayers::embedBlock( - const node& bT, - const node& cT, - ListIterator& after) -{ - treeNodeTreated[bT] = true; - node nSG; - node cH = 0; - if (!(cT == 0)) - cH = pBCTree->cutVertex(cT, bT); - - //*************************************************************************** - // 1. Compute MinDepth node lengths depending on M_B, M2 and cT - //*************************************************************************** - if (!(cT == 0) && md_M_B[bT].size() == 1 && *(md_M_B[bT].begin()) == cH) - { - //set node length to 1 if node is in M2 and 0 otherwise - for (ListIterator iterator = md_M2[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - } - else - { - //set node length to 1 if node is in M_B and 0 otherwise - for (ListIterator iterator = md_M_B[bT].begin(); iterator.valid(); iterator++) - md_nodeLength[*iterator] = 1; - } - - //*************************************************************************** - // 2. Set MinDepthMaxFace node lengths - //*************************************************************************** - //create subgraph (block bT): - node nodeInBlock = cH; - if (nodeInBlock == 0) - nodeInBlock = (*(pBCTree->hEdges(bT).begin()))->source(); - Graph SG; - NodeArray nodeLengthSG; - EdgeArray edgeLengthSG; - NodeArray nSG_to_nG; - EdgeArray eSG_to_eG; - node nodeInBlockSG; - ConnectedSubgraph::call( - pBCTree->auxiliaryGraph(), SG, - nodeInBlock, nodeInBlockSG, - nSG_to_nG, eSG_to_eG, - mdmf_nodeLength, nodeLengthSG, - mdmf_edgeLength, edgeLengthSG); - - //copy (0, 1)-min depth node lengths into nodeLengthSG d component and max - //face sice node lengths into l component: - forall_nodes(nSG, SG) - { - nodeLengthSG[nSG].d = md_nodeLength[nSG_to_nG[nSG]]; - nodeLengthSG[nSG].l = mf_nodeLength[nSG_to_nG[nSG]]; - } - - - //*************************************************************************** - // 3. Compute embedding of block - //*************************************************************************** - adjEntry m_adjExternal = 0; - if (cH == 0) - EmbedderMaxFaceBiconnectedGraphsLayers::embed( - SG, m_adjExternal, nodeLengthSG, edgeLengthSG); - else - EmbedderMaxFaceBiconnectedGraphsLayers::embed( - SG, m_adjExternal, nodeLengthSG, edgeLengthSG, nodeInBlockSG); - - //*************************************************************************** - // 4. Copy block embedding into graph embedding and call recursively - // embedBlock for all cut vertices in bT - //*************************************************************************** - CombinatorialEmbedding CE(SG); - face f = CE.leftFace(m_adjExternal); - - if (*pAdjExternal == 0) - { - node on = pBCTree->original(nSG_to_nG[m_adjExternal->theNode()]); - adjEntry ae1 = on->firstAdj(); - for (adjEntry ae = ae1; ae; ae = ae->succ()) - { - if (ae->theEdge() == pBCTree->original(eSG_to_eG[m_adjExternal->theEdge()])) - { - *pAdjExternal = ae->twin(); - break; - } - } - } - - bool DGcomputed = false; - int extFaceID = 0; - Graph* p_DG; - List* p_fPG_to_nDG; - NodeArray* p_nDG_to_fPG; - NodeArray< List >* p_adjacencyList; - List< List >* p_faces; - NodeArray* p_distances; - - forall_nodes(nSG, SG) - { - node nH = nSG_to_nG[nSG]; - node nG = pBCTree->original(nH); - adjEntry ae = nSG->firstAdj(); - ListIterator* pAfter; - if (pBCTree->bcproper(nG) == cT) - pAfter = &after; - else - pAfter = new ListIterator(); - - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node cT2 = pBCTree->bcproper(nG); - bool no_recursion = false; - if (cT2 == cT) - { - node parent_bT_of_cT2; - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - if (e_cT2_to_bT2->source() == cT2) - { - parent_bT_of_cT2 = e_cT2_to_bT2->target(); - break; - } - } - if (treeNodeTreated[parent_bT_of_cT2]) - no_recursion = true; - } - - if (no_recursion) - { - //find adjacency entry of nSG which lies on external face f: - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - } - else //!no_recursion - { - //(if exists) find adjacency entry of nSG which lies on external face f: - bool aeExtExists = false; - adjEntry aeFace = f->firstAdj(); - do - { - if (aeFace->theNode() == nSG) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nSG->firstAdj(); - aeExtExists = true; - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f->firstAdj()); - - if (!aeExtExists) - { - if (!DGcomputed) - { - p_DG = new Graph(); - p_fPG_to_nDG = OGDF_NEW List(); - p_nDG_to_fPG = OGDF_NEW NodeArray(); - p_adjacencyList = OGDF_NEW NodeArray< List >(); - p_faces = OGDF_NEW List< List >; - p_distances = OGDF_NEW NodeArray; - DGcomputed = true; - - //compute dual graph of skeleton graph: - p_adjacencyList->init(SG); - node nBG; - forall_nodes(nBG, SG) - { - adjEntry ae_nBG; - forall_adj(ae_nBG, nBG) - (*p_adjacencyList)[nBG].pushBack(ae_nBG); - } - - NodeArray< List > adjEntryTreated(SG); - forall_nodes(nBG, SG) - { - adjEntry adj; - forall_adj(adj, nBG) - { - if (adjEntryTreated[nBG].search(adj) != -1) - continue; - - List newFace; - adjEntry adj2 = adj; - do - { - newFace.pushBack(adj2); - adjEntryTreated[adj2->theNode()].pushBack(adj2); - node tn = adj2->twinNode(); - int idx = (*p_adjacencyList)[tn].search(adj2->twin()); - if (idx - 1 < 0) - idx = (*p_adjacencyList)[tn].size() - 1; - else - idx -= 1; - adj2 = *((*p_adjacencyList)[tn].get(idx)); - } while (adj2 != adj); - p_faces->pushBack(newFace); - } - } //forall_nodes(nBG, blockG[bT]) - - p_nDG_to_fPG->init(*p_DG); - - for (ListIterator< List > it = p_faces->begin(); it.valid(); it++) - { - node nn = p_DG->newNode(); - (*p_nDG_to_fPG)[nn] = p_fPG_to_nDG->search(*(p_fPG_to_nDG->pushBack(nn))); - } - - NodeArray< List > adjFaces(*p_DG); - int i = 0; - for (ListIterator< List > it = p_faces->begin(); it.valid(); it++) - { - int f1_id = i; - for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - { - int f2_id = 0; - int j = 0; - for (ListIterator< List > it3 = p_faces->begin(); it3.valid(); it3++) - { - bool do_break = false; - for (ListIterator it4 = (*it3).begin(); it4.valid(); it4++) - { - if ((*it4) == (*it2)->twin()) - { - f2_id = j; - do_break = true; - break; - } - } - if (do_break) - break; - j++; - } - - if ( f1_id != f2_id - && adjFaces[*(p_fPG_to_nDG->get(f1_id))].search(*(p_fPG_to_nDG->get(f2_id))) == -1 - && adjFaces[*(p_fPG_to_nDG->get(f2_id))].search(*(p_fPG_to_nDG->get(f1_id))) == -1) - { - adjFaces[*(p_fPG_to_nDG->get(f1_id))].pushBack(*(p_fPG_to_nDG->get(f2_id))); - p_DG->newEdge(*(p_fPG_to_nDG->get(f1_id)), *(p_fPG_to_nDG->get(f2_id))); - } - - if (*it2 == f->firstAdj()) - extFaceID = f1_id; - } //for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - i++; - } //for (ListIterator< List > it = faces.begin(); it.valid(); it++) - - //compute shortest path from every face to the external face: - List DG_edges; - p_DG->allEdges(DG_edges); - for (ListIterator it_e = DG_edges.begin(); it_e.valid(); it_e++) - { - node s = (*it_e)->source(); - node t = (*it_e)->target(); - p_DG->newEdge(t, s); - } - ShortestPathWithBFM shortestPath; - node efDG = *(p_fPG_to_nDG->get(extFaceID)); - EdgeArray el(*p_DG, 1); - p_distances->init(*p_DG); - NodeArray pi(*p_DG); - shortestPath.call(*p_DG, efDG, el, *p_distances, pi); - } //if (!DGcomputed) - - //choose face with minimal shortest path: - List optFace; - int optFaceDist = -1; - for (int fID = 0; fID < p_faces->size(); fID++) - { - List theFace = *(p_faces->get(fID)); - adjEntry ae_nSG; - bool contains_nSG = false; - for (ListIterator it_ae = theFace.begin(); it_ae.valid(); it_ae++) - { - if ((*it_ae)->theNode() == nSG) - { - contains_nSG = true; - ae_nSG = *it_ae; - break; - } - } - - if (contains_nSG) - { - int thisDist = (*p_distances)[*p_fPG_to_nDG->get(fID)]; - if (optFaceDist == -1 || optFaceDist > thisDist) - { - optFace = theFace; - optFaceDist = thisDist; - if (ae_nSG->succ()) - ae = ae_nSG->succ(); - else - ae = nSG->firstAdj(); - } - } - } //for (int fID = 0; fID < faces.size(); fID++) - } //if (!aeExtExists) - - edge e_cT2_to_bT2; - forall_adj_edges(e_cT2_to_bT2, cT2) - { - node bT2; - if (e_cT2_to_bT2->source() == cT2) - bT2 = e_cT2_to_bT2->target(); - else - bT2 = e_cT2_to_bT2->source(); - if (!treeNodeTreated[bT2]) - embedBlock(bT2, cT2, *pAfter); - } - } - } - - //embed all edges of block bT: - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : nSG->firstAdj()) - { - edge eG = pBCTree->original(eSG_to_eG[aeNode->theEdge()]); - if (nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjSource()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjSource(), *pAfter); - } - else //!(nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder[nG].pushBack(eG->adjTarget()); - else - *pAfter = newOrder[nG].insertAfter(eG->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - - if (!(*pAfter == after)) - delete pAfter; - } //forall_nodes(nSG, SG) - - if (DGcomputed) - { - delete p_DG; - delete p_fPG_to_nDG; - delete p_nDG_to_fPG; - delete p_adjacencyList; - delete p_faces; - delete p_distances; - } -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/EmbedderMinDepthPiTa.cpp b/ext/OGDF/src/planarity/EmbedderMinDepthPiTa.cpp deleted file mode 100644 index e45b861e7..000000000 --- a/ext/OGDF/src/planarity/EmbedderMinDepthPiTa.cpp +++ /dev/null @@ -1,1558 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief The algorithm computes a planar embedding with minimum - * depth if the embedding for all blocks of the graph is given. - * For details see the paper "Minimum Depth Graph Drawing" by - * M. Pizzonia and R. Tamassia. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf { - -void EmbedderMinDepthPiTa::call(Graph& G, adjEntry& adjExternal) -{ - adjExternal = 0; - pAdjExternal = &adjExternal; - node n; - edge e; - - //simple base cases: - if (G.numberOfNodes() <= 1) - return; - - if (G.numberOfEdges() == 1) - { - edge e = G.firstEdge(); - adjExternal = e->adjSource(); - return; - } - - if(useExtendedDepthDefinition()) { - dummyNodes.clear(); - pBCTree = new BCTree(G); - if (pBCTree->bcTree().numberOfNodes() != 1) - { - node bT; - forall_nodes(bT, pBCTree->bcTree()) - { - if (pBCTree->typeOfBNode(bT) != BCTree::BComp) - continue; - - node cT = bT->firstAdj()->twinNode(); - node cH = pBCTree->cutVertex(cT, bT); - Graph SG; - NodeArray nSG_to_nG; - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), SG, cH, nSG_to_nG); - if (SG.numberOfEdges() == 1) - { - node dummyNodePG = G.newNode(); - dummyNodes.pushBack(dummyNodePG); - node SGnode1 = SG.chooseEdge()->source(); - node PGnode1 = pBCTree->original(nSG_to_nG[SGnode1]); - node SGnode2 = SG.chooseEdge()->target(); - node PGnode2 = pBCTree->original(nSG_to_nG[SGnode2]); - G.newEdge(PGnode1, dummyNodePG); - G.newEdge(PGnode2, dummyNodePG); - } - } - } - delete pBCTree; - } - - //HINT: Edges are directed from child to parent in BC-trees - pBCTree = new BCTree(G); - - //base case of biconnected graph: - if (pBCTree->bcTree().numberOfNodes() == 1) - { - planarEmbed(G); - CombinatorialEmbedding CE(G); - adjExternal = CE.chooseFace()->firstAdj(); - deleteDummyNodes(G, adjExternal); - - delete pBCTree; - return; - } - - - //***************************************************************************/ - //First step: embed all blocks - //***************************************************************************/ - newOrder.init(G); - nodeLength.init(pBCTree->bcTree()); - oneEdgeBlockNodes.clear(); - - //Find root Block (only node with out-degree of 0): - node rootBlockNode; - forall_nodes(n, pBCTree->bcTree()) - { - if (n->outdeg() == 0) - { - rootBlockNode = n; - break; - } - } - - blockG.init(pBCTree->bcTree()); - nBlockEmbedding_to_nH.init(pBCTree->bcTree()); - eBlockEmbedding_to_eH.init(pBCTree->bcTree()); - nH_to_nBlockEmbedding.init(pBCTree->bcTree()); - eH_to_eBlockEmbedding.init(pBCTree->bcTree()); - embedBlocks(rootBlockNode, 0); - - //***************************************************************************/ - //Second step: Constrained Minimization - //***************************************************************************/ - node vT = rootBlockNode->firstAdj()->twinNode(); - bcTreePG.clear(); - nBCTree_to_npBCTree.init(bcTreePG); - npBCTree_to_nBCTree.init(pBCTree->bcTree()); - forall_nodes(n, pBCTree->bcTree()) - { - node m = bcTreePG.newNode(); - nBCTree_to_npBCTree[m] = n; - npBCTree_to_nBCTree[n] = m; - } - forall_edges(e, pBCTree->bcTree()) - { - if (e->source() == vT) - bcTreePG.newEdge(npBCTree_to_nBCTree[e->target()], npBCTree_to_nBCTree[vT]); - else - bcTreePG.newEdge(npBCTree_to_nBCTree[e->source()], npBCTree_to_nBCTree[e->target()]); - } - - G_nT.init(pBCTree->bcTree()); - nG_nT_to_nPG.init(pBCTree->bcTree()); - nPG_to_nG_nT.init(pBCTree->bcTree()); - eG_nT_to_ePG.init(pBCTree->bcTree()); - ePG_to_eG_nT.init(pBCTree->bcTree()); - Gamma_adjExt_nT.init(pBCTree->bcTree()); - - tmpAdjExtFace = 0; - embedCutVertex(npBCTree_to_nBCTree[vT], true); - forall_nodes(n, G) - G.sort(n, newOrder[n]); - - //adjExternal = tmpAdjExtFace; - //deleteDummyNodes(G, adjExternal); - //return; - - //***************************************************************************/ - //Fourth step: Find the knot of the block cutface tree of the embedding and, - //if needed, modify it into a minimum diameter embedding. - //***************************************************************************/ - //a) Compute dual graph: - NodeArray< List > adjacencyList(G); - forall_nodes(n, G) - { - adjEntry ae; - forall_adj(ae, n) - adjacencyList[n].pushBack(ae); - } - - NodeArray< List > adjEntryTreated(G); - faces.clear(); - forall_nodes(n, G) - { - adjEntry adj; - forall_adj(adj, n) - { - if (adjEntryTreated[n].search(adj) != -1) - continue; - - List newFace; - adjEntry adj2 = adj; - do - { - newFace.pushBack(adj2); - adjEntryTreated[adj2->theNode()].pushBack(adj2); - node tn = adj2->twinNode(); - int idx = adjacencyList[tn].search(adj2->twin()); - if (idx - 1 < 0) - idx = adjacencyList[tn].size() - 1; - else - idx -= 1; - adj2 = *(adjacencyList[tn].get(idx)); - } while (adj2 != adj); - faces.pushBack(newFace); - } - } - - Graph DG; - fPG_to_nDG.clear(); - nDG_to_fPG.init(DG); - - for (ListIterator< List > it = faces.begin(); it.valid(); it++) - { - node nn = DG.newNode(); - nDG_to_fPG[nn] = fPG_to_nDG.search(*(fPG_to_nDG.pushBack(nn))); - } - - int extFaceID = 0; - NodeArray< List > adjFaces(DG); - int i = 0; - for (ListIterator< List > it = faces.begin(); it.valid(); it++) - { - int f1_id = i; - for (ListIterator it2 = (*it).begin(); it2.valid(); it2++) - { - int f2_id = 0; - int j = 0; - for (ListIterator< List > it3 = faces.begin(); it3.valid(); it3++) - { - bool do_break = false; - for (ListIterator it4 = (*it3).begin(); it4.valid(); it4++) - { - if ((*it4) == (*it2)->twin()) - { - f2_id = j; - do_break = true; - break; - } - } - if (do_break) - break; - j++; - } - - if ( f1_id != f2_id - && adjFaces[*(fPG_to_nDG.get(f1_id))].search(*(fPG_to_nDG.get(f2_id))) == -1 - && adjFaces[*(fPG_to_nDG.get(f2_id))].search(*(fPG_to_nDG.get(f1_id))) == -1) - { - adjFaces[*(fPG_to_nDG.get(f1_id))].pushBack(*(fPG_to_nDG.get(f2_id))); - DG.newEdge(*(fPG_to_nDG.get(f1_id)), *(fPG_to_nDG.get(f2_id))); - } - - if (*it2 == tmpAdjExtFace) - extFaceID = f1_id; - } - i++; - } - - //b) compute block-cutface tree, its diametral tree Tdiam and find the knot. - pm_blockCutfaceTree = new BCTree(DG); - BCTree& m_blockCutfaceTree = *pm_blockCutfaceTree; - - //if graph has only one cutface, return computed embedding with - //this cutface as external face: - if (m_blockCutfaceTree.numberOfCComps() == 0) - { - if (pBCTree->numberOfBComps() == 1) - adjExternal = tmpAdjExtFace; - else - { - node bT = rootBlockNode; - if (blockG[rootBlockNode].numberOfEdges() != 1) - { - adjEntry ae_cT = bT->firstAdj()->twin(); - adjEntry ae_cT2 = ae_cT->succ(); - if (!ae_cT2) - ae_cT2 = ae_cT->theNode()->firstAdj(); - bT = ae_cT2->twinNode(); - } - edge eB = blockG[bT].chooseEdge(); - edge ePG = pBCTree->original(eBlockEmbedding_to_eH[bT][eB]); - adjExternal = ePG->adjSource(); - } - - delete pBCTree; - delete pm_blockCutfaceTree; - deleteDummyNodes(G, adjExternal); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - return;//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - } - - node m_rootOfBlockCutfaceTree; - forall_nodes(n, m_blockCutfaceTree.bcTree()) - { - if (n->outdeg() == 0) - { - m_rootOfBlockCutfaceTree = n; - break; - } - } - - //if only one cutface exists, this face is the optimum external face: - if (m_blockCutfaceTree.numberOfCComps() == 1) - { - node nr = m_rootOfBlockCutfaceTree->firstAdj()->twinNode(); - node cv = m_blockCutfaceTree.cutVertex(nr, nr); - node ocv = m_blockCutfaceTree.original(cv); - int cfid = nDG_to_fPG[ocv]; - adjExternal = (*((*(faces.get(cfid))).begin())); - delete pBCTree; - delete pm_blockCutfaceTree; - deleteDummyNodes(G, adjExternal); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - return;//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - } - - blockCutfaceTree.clear(); - nBlockCutfaceTree_to_nm_blockCutfaceTree.init(blockCutfaceTree); - nm_blockCutfaceTree_to_nBlockCutfaceTree.init(m_blockCutfaceTree.bcTree()); - forall_nodes(n, m_blockCutfaceTree.bcTree()) - { - node m = blockCutfaceTree.newNode(); - nBlockCutfaceTree_to_nm_blockCutfaceTree[m] = n; - nm_blockCutfaceTree_to_nBlockCutfaceTree[n] = m; - } - forall_edges(e, m_blockCutfaceTree.bcTree()) - blockCutfaceTree.newEdge(nm_blockCutfaceTree_to_nBlockCutfaceTree[e->source()], - nm_blockCutfaceTree_to_nBlockCutfaceTree[e->target()]); - - //Root tree at external face. If external face is not a cutface in the - //block-cutface tree, choose an arbitrary cutface as root, because - //current external face cannot be the optimum external face. - node rDG = *(fPG_to_nDG.get(extFaceID)); - node rmBCFT = m_blockCutfaceTree.bcproper(rDG); - if (m_blockCutfaceTree.typeOfBNode(rmBCFT) != BCTree::CComp) - { - rmBCFT = m_rootOfBlockCutfaceTree->firstAdj()->twinNode(); - - //adjExternal = *((*(faces.get(nDG_to_fPG[m_blockCutfaceTree.original(m_blockCutfaceTree.cutVertex(m_rootOfBlockCutfaceTree->firstAdj()->twinNode(), m_rootOfBlockCutfaceTree->firstAdj()->twinNode()))]))).begin()); - //return; - } - - node rootOfBlockCutfaceTree = nm_blockCutfaceTree_to_nBlockCutfaceTree[rmBCFT]; - invertPath(blockCutfaceTree, rootOfBlockCutfaceTree, 0); - - edgeLength_blockCutfaceTree.init(blockCutfaceTree); - computeBlockCutfaceTreeEdgeLengths(rootOfBlockCutfaceTree); - nBlockCutfaceTree_to_nTdiam.init(blockCutfaceTree); - nTdiam_to_nBlockCutfaceTree.init(Tdiam); - Tdiam_initialized = false; - computeTdiam(rootOfBlockCutfaceTree); - - //if Tdiam is empty, following steps are not necessary: - if (Tdiam_initialized) - { - node knot = nTdiam_to_nBlockCutfaceTree[knotTdiam]; - node m_knot = nBlockCutfaceTree_to_nm_blockCutfaceTree[knot]; - - //d) compute mapping bDG_to_bPG and bPG_to_bDG - bDG_to_bPG.init(blockCutfaceTree); - bPG_to_bDG.init(pBCTree->bcTree()); - edge e_root_to_nbDG; - forall_adj_edges(e_root_to_nbDG, rootOfBlockCutfaceTree) - { - node nbDG = e_root_to_nbDG->source(); - List tmpBlocksNodes; - List tmpChildBlocks; - node bPG = computeBlockMapping(nbDG, rootOfBlockCutfaceTree, tmpBlocksNodes, tmpChildBlocks); - bDG_to_bPG[nbDG] = bPG; - bPG_to_bDG[bPG] = nbDG; - } - - //c) if needed, modify the embedding into a minimum depth diameter embedding - if ( m_blockCutfaceTree.typeOfBNode(m_knot) == BCTree::BComp - && rootOfBlockCutfaceTree != knotTdiam) - { - //node bT = bDG_to_bPG[knot]; - List childrenOfKnot; - List childrenOfKnot_bT; - List childrenOfKnotInBCTree; - edge e_kBC_to_cBC; - { - forall_adj_edges(e_kBC_to_cBC, bDG_to_bPG[knot]) - { - if (e_kBC_to_cBC->target() != bDG_to_bPG[knot]) - continue; - - childrenOfKnotInBCTree.pushBack(e_kBC_to_cBC->source()); - } - } - edge e_knot_to_w; - forall_adj_edges(e_knot_to_w, knotTdiam) - { - if (e_knot_to_w->target() != knotTdiam) - continue; - - node child = nTdiam_to_nBlockCutfaceTree[e_knot_to_w->source()]; - node childBCFTree = nBlockCutfaceTree_to_nm_blockCutfaceTree[child]; - edge e_childBCFTree_to_b; - forall_adj_edges(e_childBCFTree_to_b, childBCFTree) - { - if (e_childBCFTree_to_b->target() != childBCFTree) - continue; - - node bT = e_childBCFTree_to_b->target(); - node bBCTree = bDG_to_bPG[bT]; - node connectingNode = 0; - while (connectingNode == 0) - { - node parent_bBCTree; - edge eParent; - forall_adj_edges(eParent, bBCTree) - { - if (eParent->source() == bBCTree) - { - parent_bBCTree = eParent->target(); - break; - } - } - if (childrenOfKnotInBCTree.search(parent_bBCTree) != -1) - { - connectingNode = parent_bBCTree; - childrenOfKnot_bT.pushBack(bBCTree); - } - else - { - forall_adj_edges(eParent, parent_bBCTree) - { - if (eParent->source() == parent_bBCTree) - { - bBCTree = eParent->target(); - break; - } - } - } - } - childrenOfKnot.pushBack(pBCTree->original(connectingNode)); - } - } - CombinatorialEmbedding CE(blockG[bDG_to_bPG[m_knot]]); - face f; - forall_faces(f, CE) - { - int numOfEntriesFromList = 0; - adjEntry ae; - forall_face_adj(ae, f) - { - node orgNode = pBCTree->original(nBlockEmbedding_to_nH[bDG_to_bPG[m_knot]] [ae->theNode()]); - if (childrenOfKnot.search(orgNode) != -1) - numOfEntriesFromList++; - } - if (numOfEntriesFromList == childrenOfKnot.size()) - { - //i) remove embedding of blocks - NodeArray< NodeArray< List > > adjList(pBCTree->bcTree(), G); - for (ListIterator it = childrenOfKnot.begin(); it.valid(); it++) - { - node nG = *it; - node bT = *(childrenOfKnot_bT.get(childrenOfKnot.search(*it))); - List nodeList; - blockG[bT].allNodes(nodeList); - ListIterator it_ae; - for (it_ae = newOrder[nG].begin(); it_ae.valid(); it_ae++) - { - node otherNode = (*it_ae)->twinNode(); - if (nodeList.search(otherNode) != -1) - { - ListIterator pred_it = it_ae.pred(); - adjList[bT][nG].pushBack(*it_ae); - newOrder[nG].del(it_ae); - if (pred_it.valid()) - it_ae = pred_it; - else - it_ae = newOrder[nG].begin(); - } - } - } - - //ii) embed blocks into f - for (ListIterator it = childrenOfKnot.begin(); it.valid(); it++) - { - node nG = *it; - node bT = *(childrenOfKnot_bT.get(childrenOfKnot.search(*it))); - //find adjEntry of nG in f - adjEntry ae; - forall_face_adj(ae, f) - { - if (pBCTree->original(nBlockEmbedding_to_nH[bT][ae->theNode()]) == nG) - { - break; - } - } - ListIterator after = newOrder[nG].get(newOrder[nG].search(ae)); - for (ListIterator it_cpy = adjList[bT][nG].begin(); it_cpy.valid(); it_cpy++) - after = newOrder[nG].insertAfter(*it_cpy, after); - } - - //done: - break; - } - } - - forall_nodes(n, G) - G.sort(n, newOrder[n]); - } - } - - //***************************************************************************/ - //Fifth step: Select face with minimum eccentricity in the block-cutface tree - //as external face. - //***************************************************************************/ - - eccentricity.init(blockCutfaceTree, 0); - eccentricity_alt.init(blockCutfaceTree, 0); - eccentricityBottomUp(rootOfBlockCutfaceTree); - eccentricityTopDown(rootOfBlockCutfaceTree); - node cf_opt; - int ecc_opt = -1; - node nBCFT; - forall_nodes(nBCFT, blockCutfaceTree) - { - node n_mBCFT = nBlockCutfaceTree_to_nm_blockCutfaceTree[nBCFT]; - if (m_blockCutfaceTree.typeOfBNode(n_mBCFT) != BCTree::CComp) - continue; - - if (eccentricity[nBCFT] < ecc_opt || ecc_opt == -1) - { - ecc_opt = eccentricity[nBCFT]; - cf_opt = nBCFT; - } - } - node cf_opt_mBCFT = nBlockCutfaceTree_to_nm_blockCutfaceTree[cf_opt]; - node cf_opt_H = m_blockCutfaceTree.cutVertex(cf_opt_mBCFT, cf_opt_mBCFT); - node cf_opt_DG = m_blockCutfaceTree.original(cf_opt_H); - adjExternal = *((*(faces.get(nDG_to_fPG[cf_opt_DG]))).begin()); - - delete pBCTree; - delete pm_blockCutfaceTree; - deleteDummyNodes(G, adjExternal); -} - - -int EmbedderMinDepthPiTa::eccentricityBottomUp(const node& nT) -{ - int thisEccentricity[2] = {0, 0}; - edge e_nT_to_mT; - forall_adj_edges(e_nT_to_mT, nT) - { - if (e_nT_to_mT->target() != nT) - continue; - - node mT = e_nT_to_mT->source(); - int mT_eccentricity = eccentricityBottomUp(mT) + 1; - if (mT_eccentricity > thisEccentricity[0]) - { - thisEccentricity[1] = thisEccentricity[0]; - thisEccentricity[0] = mT_eccentricity; - } - else if (mT_eccentricity > thisEccentricity[1]) - thisEccentricity[1] = mT_eccentricity; - } - - eccentricity[nT] = thisEccentricity[0]; - eccentricity_alt[nT] = thisEccentricity[1]; - return thisEccentricity[0]; -} - - -void EmbedderMinDepthPiTa::eccentricityTopDown(const node& nT) -{ - int thisEccentricity = eccentricity[nT]; - int thisEccentricity_alt = eccentricity_alt[nT]; - edge e_nT_to_mT; - forall_adj_edges(e_nT_to_mT, nT) - { - if (e_nT_to_mT->source() != nT) - continue; - - node mT = e_nT_to_mT->target(); - if (eccentricity[mT] == thisEccentricity + 1 && eccentricity_alt[mT] + 1 >= thisEccentricity) - { - thisEccentricity_alt = thisEccentricity; - thisEccentricity = eccentricity_alt[mT] + 1; - } - else if (eccentricity[mT] != thisEccentricity + 1 && eccentricity[mT] + 1 > thisEccentricity) - { - thisEccentricity_alt = thisEccentricity; - thisEccentricity = eccentricity[mT] + 1; - } - else if (eccentricity_alt[mT] + 1 > thisEccentricity_alt) - thisEccentricity_alt = eccentricity_alt[mT] + 1; - } - eccentricity[nT] = thisEccentricity; - eccentricity_alt[nT] = thisEccentricity_alt; - - { - forall_adj_edges(e_nT_to_mT, nT) - { - if (e_nT_to_mT->target() != nT) - continue; - - node mT = e_nT_to_mT->source(); - eccentricityTopDown(mT); - } - } -} - - -node EmbedderMinDepthPiTa::computeBlockMapping( - const node& bDG, - const node& parent, - List& blocksNodes, - List& childBlocks) -{ - List childNodes; - edge e_bDG_to_cDG; - forall_adj_edges(e_bDG_to_cDG, bDG) - { - if (e_bDG_to_cDG->target() != bDG) - continue; - - node cf = e_bDG_to_cDG->source(); - edge e_cf_to_bDG2; - forall_adj_edges(e_cf_to_bDG2, cf) - { - if (e_cf_to_bDG2->target() != cf) - continue; - - node bDG2 = e_cf_to_bDG2->source(); - - //recursion: - List thisBlocksNodes; - List thisChildBlocks; - node bDG2_map = computeBlockMapping(bDG2, cf, thisBlocksNodes, thisChildBlocks); - childBlocks.conc(thisChildBlocks); - childBlocks.pushBack(bDG2_map); - bDG_to_bPG[bDG2] = bDG2_map; - bPG_to_bDG[bDG2_map] = bDG2; - childNodes.conc(thisBlocksNodes); - } - - List m_childNodes = childNodes; - for (ListIterator it = m_childNodes.begin(); it.valid(); it++) - { - node n = *it; - bool delete_node = false; - - if (n->degree() == 1) - { - //node of one-edge-block - delete_node = true; - } - else if (pBCTree->typeOfGNode(n) != BCTree::CutVertex) - { - //node is a non-cutvertex node of another block - delete_node = true; - } - else if (n->degree() == 2) - { - //node of one-edge-block - delete_node = true; - } - else - { - //test if cutvertex does not connect current block with - //child (in block-cutface tree) (mapped) block - int numOfBlocksInList = 0; - node cH = pBCTree->bcproper(n); - node cT = pBCTree->cutVertex(cH, cH); - edge e_cT_bT; - forall_adj_edges(e_cT_bT, cT) - { - node bT = (e_cT_bT->source() == cT) ? e_cT_bT->target() : e_cT_bT->source(); - if (childBlocks.search(bT) != -1) - numOfBlocksInList++; - } - if (numOfBlocksInList == cT->degree()) - delete_node = true; - } - - if (delete_node) - childNodes.del(childNodes.get(childNodes.search(n))); - } - } - - node parentT = nBlockCutfaceTree_to_nm_blockCutfaceTree[parent]; - node bDGT = nBlockCutfaceTree_to_nm_blockCutfaceTree[bDG]; - node parentH = pm_blockCutfaceTree->cutVertex(parentT, bDGT); - Graph SG; - NodeArray nSG_to_nH; - ConnectedSubgraph::call(pm_blockCutfaceTree->auxiliaryGraph(), - SG, parentH, nSG_to_nH); - - List blockNodesDG; - node nSG; - forall_nodes(nSG, SG) - { - if (parentH == nSG_to_nH[nSG]) - continue; - - int faceID_PG = nDG_to_fPG[pm_blockCutfaceTree->original(nSG_to_nH[nSG])]; - ListIterator beginIt = (*(faces.get(faceID_PG))).begin(); - for (ListIterator it = beginIt; it.valid(); it++) - { - node nPG = (*it)->theNode(); - if (childNodes.search(nPG) == -1 - && blockNodesDG.search(nPG) == -1 - && oneEdgeBlockNodes.search(nPG) == -1) - { - blockNodesDG.pushBack(nPG); - } - } - } - - node bT; - forall_nodes(bT, pBCTree->bcTree()) - { - if (pBCTree->typeOfBNode(bT) != BCTree::BComp) - continue; - - bool isSearchedBlock = true; - node n; - forall_nodes(n, blockG[bT]) - { - if (blockNodesDG.search(pBCTree->original(nBlockEmbedding_to_nH[bT][n])) == -1) - { - isSearchedBlock = false; - break; - } - } - if (isSearchedBlock) - { - node nChild; - forall_nodes(nChild, blockG[bT]) - blocksNodes.pushBack(pBCTree->original(nBlockEmbedding_to_nH[bT][nChild])); - return bT; - } - } - - //ohoh... - return 0; -} - - -void EmbedderMinDepthPiTa::invertPath(Graph& G, const node& n, const edge& e) -{ - edge e2; - forall_adj_edges(e2, n) - { - if (e != e2 && e2->source() == n) - { - invertPath(G, e2->target(), e2); - G.reverseEdge(e2); - } - } -} - - -void EmbedderMinDepthPiTa::computeTdiam(const node& n) -{ - if (n->indeg() == 0) - return; - - int maxEdgeLength = -1; - int numEdgesWithMaxLength = 0; - edge e_n_to_m; - { - forall_adj_edges(e_n_to_m, n) - { - if (e_n_to_m->target() != n) - continue; - int thisEdgeLength = edgeLength_blockCutfaceTree[e_n_to_m]; - if (thisEdgeLength > maxEdgeLength) - { - maxEdgeLength = thisEdgeLength; - numEdgesWithMaxLength = 1; - } - else if (thisEdgeLength == maxEdgeLength) - numEdgesWithMaxLength++; - } - } - - forall_adj_edges(e_n_to_m, n) - { - if (e_n_to_m->target() != n) - continue; - - if (edgeLength_blockCutfaceTree[e_n_to_m] < maxEdgeLength) - continue; - - node m = e_n_to_m->source(); - bool Tdiam_was_initialized = Tdiam_initialized; - if (numEdgesWithMaxLength > 1 && !Tdiam_initialized) - { - node nTdiam = Tdiam.newNode(); - nBlockCutfaceTree_to_nTdiam[n] = nTdiam; - nTdiam_to_nBlockCutfaceTree[nTdiam] = n; - knotTdiam = nTdiam; - Tdiam_initialized = true; - } - - if (Tdiam_was_initialized || numEdgesWithMaxLength > 1) - { - node mTdiam = Tdiam.newNode(); - nBlockCutfaceTree_to_nTdiam[m] = mTdiam; - nTdiam_to_nBlockCutfaceTree[mTdiam] = m; - node source_nTdiam = nBlockCutfaceTree_to_nTdiam[n]; - node target_nTdiam = mTdiam; - Tdiam.newEdge(source_nTdiam, target_nTdiam); - } - - computeTdiam(m); - } -} - - -int EmbedderMinDepthPiTa::computeBlockCutfaceTreeEdgeLengths(const node& n) -{ - if (n->indeg() == 0) - return 0; - - int maxChildrenEdgeLength = 0; - edge e_n_to_m; - forall_adj_edges(e_n_to_m, n) - { - if (e_n_to_m->target() != n) - continue; - - node m = e_n_to_m->source(); - edgeLength_blockCutfaceTree[e_n_to_m] = computeBlockCutfaceTreeEdgeLengths(m); - if (edgeLength_blockCutfaceTree[e_n_to_m] > maxChildrenEdgeLength) - maxChildrenEdgeLength = edgeLength_blockCutfaceTree[e_n_to_m]; - } - return maxChildrenEdgeLength + 1; -} - - -void EmbedderMinDepthPiTa::embedBlocks(const node& bT, const node& cH) -{ - //recursion: - edge e; - forall_adj_edges(e, bT) - { - if (e->source() == bT) - continue; - - node cT = e->source(); - edge e2; - forall_adj_edges(e2, cT) - { - if (e2->source() == cT) - continue; - node cH2 = pBCTree->cutVertex(cT, e2->source()); - embedBlocks(e2->source(), cH2); - } - } - - //embed block bT: - node m_cH = cH; - if (m_cH == 0) - m_cH = pBCTree->cutVertex(bT->firstAdj()->twinNode(), bT); - ConnectedSubgraph::call(pBCTree->auxiliaryGraph(), blockG[bT], m_cH, - nBlockEmbedding_to_nH[bT], eBlockEmbedding_to_eH[bT], - nH_to_nBlockEmbedding[bT], eH_to_eBlockEmbedding[bT]); - planarEmbed(blockG[bT]); - nodeLength[bT].init(blockG[bT], 0); - - if(!useExtendedDepthDefinition()) - { - if (blockG[bT].numberOfEdges() == 1) - { - node n; - forall_nodes(n, blockG[bT]) - { - node nOrg = pBCTree->original(nBlockEmbedding_to_nH[bT][n]); - if (nOrg->degree() == 1) - oneEdgeBlockNodes.pushBack(nOrg); - } - } - } -} - - -void EmbedderMinDepthPiTa::embedCutVertex(const node& vT, bool root /*= false*/) -{ - node vTp = nBCTree_to_npBCTree[vT]; - nG_nT_to_nPG[vTp].init(G_nT[vTp]); - nPG_to_nG_nT[vTp].init(pBCTree->originalGraph()); - eG_nT_to_ePG[vTp].init(G_nT[vTp]); - ePG_to_eG_nT[vTp].init(pBCTree->originalGraph()); - - node vG_nT = G_nT[vTp].newNode(); - node adj_bT = vT->firstAdj()->twinNode(); - node vH = pBCTree->cutVertex(vTp, nBCTree_to_npBCTree[adj_bT]); - node vG = pBCTree->original(vH); - nG_nT_to_nPG[vTp][vG_nT] = vG; - nPG_to_nG_nT[vTp][vG] = vG_nT; - Gamma_adjExt_nT[vTp] = 0; - - //add Gamma(b) of children b of vT into Gamma(vT): - edge e_vT_bT; - forall_adj_edges(e_vT_bT, vT) - { - if (e_vT_bT->target() != vT) - continue; - - node bT = e_vT_bT->source(); - node bTp = nBCTree_to_npBCTree[bT]; - //node vH = pBCTree->cutVertex(vTp, bTp); - if (bT->indeg() == 0) //leaf - { - //Let \Gamma(B) be the prescribed embedding of block B, with external face - //equal to one of the candidate cutfaces of (B, v). - nG_nT_to_nPG[bTp].init(G_nT[bTp]); - eG_nT_to_ePG[bTp].init(G_nT[bTp]); - nPG_to_nG_nT[bTp].init(pBCTree->originalGraph()); - ePG_to_eG_nT[bTp].init(pBCTree->originalGraph()); - - node vBG; - forall_nodes(vBG, blockG[bTp]) - { - node noG = pBCTree->original(nBlockEmbedding_to_nH[bTp][vBG]); - node noG_bT = G_nT[bTp].newNode(); - nG_nT_to_nPG[bTp][noG_bT] = noG; - nPG_to_nG_nT[bTp][noG] = noG_bT; - } - - edge eBG; - forall_edges(eBG, blockG[bTp]) - { - edge edG = pBCTree->original(eBlockEmbedding_to_eH[bTp][eBG]); - node edG_bT_source = nPG_to_nG_nT[bTp][edG->source()]; - node edG_bT_target = nPG_to_nG_nT[bTp][edG->target()]; - edge edG_bT = G_nT[bTp].newEdge(edG_bT_source, edG_bT_target); - ePG_to_eG_nT[bTp][edG] = edG_bT; - eG_nT_to_ePG[bTp][edG_bT] = edG; - } - - Gamma_adjExt_nT[bTp] = nPG_to_nG_nT[bTp][vG]->firstAdj(); - - //copy adjacency entry orderings: - NodeArray< List > newOrder_G_bTp(G_nT[bTp]); - node nB; - forall_nodes(nB, blockG[bTp]) - { - node nG = pBCTree->original(nBlockEmbedding_to_nH[bTp][nB]); - ListIterator after; - for (adjEntry aeNode = nB->firstAdj(); aeNode; aeNode = aeNode->succ()) - { - edge eG = pBCTree->original(eBlockEmbedding_to_eH[bTp][aeNode->theEdge()]); - edge eG_bT = ePG_to_eG_nT[bTp][eG]; - node nG_bT = nPG_to_nG_nT[bTp][nG]; - if (nG == eG->source()) - { - if (!after.valid()) - after = newOrder_G_bTp[nG_bT].pushBack(eG_bT->adjSource()); - else - after = newOrder_G_bTp[nG_bT].insertAfter(eG_bT->adjSource(), after); - } - else //!(nG == eG->source()) - { - if (!after.valid()) - after = newOrder_G_bTp[nG_bT].pushBack(eG_bT->adjTarget()); - else - after = newOrder_G_bTp[nG_bT].insertAfter(eG_bT->adjTarget(), after); - } - } //for (adjEntry aeNode = nB->firstAdj(); aeNode; aeNode = aeNode->succ()) - } //forall_nodes(nB, blockG[bTp]) - - forall_nodes(nB, G_nT[bTp]) - G_nT[bTp].sort(nB, newOrder_G_bTp[nB]); - } - else //if not leaf - { - //Let \Gamma(B) = embed(B) - embedBlockVertex(bT, vT); - } - - //add all nodes and edges of Gamma(bT) to Gamma(vT): - node n_Gamma_bT; - forall_nodes(n_Gamma_bT, G_nT[bTp]) - { - node nPG = nG_nT_to_nPG[bTp][n_Gamma_bT]; - if (nPG != vG) - { - node n_G_vT = G_nT[vTp].newNode(); - nG_nT_to_nPG[vTp][n_G_vT] = nPG; - nPG_to_nG_nT[vTp][nPG] = n_G_vT; - } - } - edge e_Gamma_bT; - forall_edges(e_Gamma_bT, G_nT[bTp]) - { - edge ePG = eG_nT_to_ePG[bTp][e_Gamma_bT]; - node n_G_vT_source = nPG_to_nG_nT[vTp][ePG->source()]; - node n_G_vT_target = nPG_to_nG_nT[vTp][ePG->target()]; - edge e_G_vT = G_nT[vTp].newEdge(n_G_vT_source, n_G_vT_target); - eG_nT_to_ePG[vTp][e_G_vT] = ePG; - ePG_to_eG_nT[vTp][ePG] = e_G_vT; - } - - //set adjacency entry of external face for Gamma(vT), if not already assigned: - if (Gamma_adjExt_nT[vTp] == 0) - { - // TESTCODE - // BUG (actually occurs below): graph of v is wrong - //node v = Gamma_adjExt_nT[bTp]->theNode(); // graphOf: ??? - //NodeArray &na = nG_nT_to_nPG[bTp]; // graphOf: G_nT[bTp] - //node xxx = na[v]; // BUG - // END TESTCODE - - node nodeG = nG_nT_to_nPG[bTp][Gamma_adjExt_nT[bTp]->theNode()]; - node nodeG_vT = nPG_to_nG_nT[vTp][nodeG]; - node twinG = nG_nT_to_nPG[bTp][Gamma_adjExt_nT[bTp]->twinNode()]; - node twinG_vT = nPG_to_nG_nT[vTp][twinG]; - adjEntry ae; - forall_adj(ae, nodeG_vT) - { - if (ae->twinNode() == twinG_vT) - { - Gamma_adjExt_nT[vTp] = ae; - break; - } - } - } - - if (root) - { - //set adjacency entry of external face for G, if not already assigned: - if (tmpAdjExtFace == 0) - { - node nodeG = nG_nT_to_nPG[bTp][Gamma_adjExt_nT[bTp]->theNode()]; - node twinG = nG_nT_to_nPG[bTp][Gamma_adjExt_nT[bTp]->twinNode()]; - adjEntry ae; - forall_adj(ae, nodeG) - { - if (ae->twinNode() == twinG) - { - tmpAdjExtFace = ae->twin(); - break; - } - } - } - } - } //forall_adj_edges(e_vT_bT, vT) - - ListIterator after; - NodeArray< List > newOrder_G_vT(G_nT[vTp]); - { - forall_adj_edges(e_vT_bT, vT) - { - if (e_vT_bT->target() != vT) - continue; - - node bT = e_vT_bT->source(); - node bTp = nBCTree_to_npBCTree[bT]; - //node vH = pBCTree->cutVertex(vTp, bTp); - - //compute new order: - node nB; - forall_nodes(nB, G_nT[bTp]) - { - node nG = nG_nT_to_nPG[bTp][nB]; - adjEntry ae = nB->firstAdj(); - ListIterator* pAfter; - if (nG == vG) - { - pAfter = &after; - - //find adjacency entry of nB which lies on external face, if it exists: - adjEntry aeFace = Gamma_adjExt_nT[bTp]; - do - { - if (aeFace->theNode() == nB) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = nB->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != Gamma_adjExt_nT[bTp]); - } - else - pAfter = OGDF_NEW ListIterator(); - - //embed all edges of Gamma(B): - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : nB->firstAdj()) - { - edge eG = eG_nT_to_ePG[bTp][aeNode->theEdge()]; - edge eG_vT = ePG_to_eG_nT[vTp][eG]; - node nG_vT = nPG_to_nG_nT[vTp][nG]; - if (nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder_G_vT[nG_vT].pushBack(eG_vT->adjSource()); - else - *pAfter = newOrder_G_vT[nG_vT].insertAfter(eG_vT->adjSource(), *pAfter); - } - else //!(nG == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder_G_vT[nG_vT].pushBack(eG_vT->adjTarget()); - else - *pAfter = newOrder_G_vT[nG_vT].insertAfter(eG_vT->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; ... - - if (nG != vG) - delete pAfter; - } //forall_nodes(nB, G_nT[bTp]) - } //forall_adj_edges(e_vT_bT, vT) - } - - //apply new order: - node n_G_vT; - forall_nodes(n_G_vT, G_nT[vTp]) - G_nT[vTp].sort(n_G_vT, newOrder_G_vT[n_G_vT]); - - if (root) - { - node n; - forall_nodes(n, pBCTree->originalGraph()) - { - newOrder[n].clear(); - node nG_vT = nPG_to_nG_nT[vTp][n]; - for (ListIterator it = newOrder_G_vT[nG_vT].begin(); it.valid(); it++) - { - node twinPGnode = nG_nT_to_nPG[vTp][(*it)->twinNode()]; - adjEntry ae_n; - forall_adj(ae_n, n) - { - if (ae_n->twinNode() == twinPGnode) - { - newOrder[n].pushBack(ae_n); - break; - } - } - } - } - } -} - - -void EmbedderMinDepthPiTa::embedBlockVertex(const node& bT, const node& parent_cT) -{ - node bTp = nBCTree_to_npBCTree[bT]; - - //compute Gamma(v) for all children of bT in the BC-tree: - edge e_bT_to_cT; - forall_adj_edges(e_bT_to_cT, bT) - { - if (e_bT_to_cT->target() != bT) - continue; - - node cT = e_bT_to_cT->source(); - embedCutVertex(cT); - } - - //compute all candidate cutfaces of (bT, cT): - List candidateCutfaces; - CombinatorialEmbedding CE(blockG[bTp]); - node nParentH = pBCTree->cutVertex(nBCTree_to_npBCTree[parent_cT], bTp); - node parent_cB = nH_to_nBlockEmbedding[bTp][nParentH]; - adjEntry ae_parent_cB; - forall_adj(ae_parent_cB, parent_cB) - { - face lf = CE.leftFace(ae_parent_cB); - if (candidateCutfaces.search(lf) == -1) - candidateCutfaces.pushBack(lf); - - face rf = CE.rightFace(ae_parent_cB); - if (candidateCutfaces.search(rf) == -1) - candidateCutfaces.pushBack(rf); - } - - //For all candidate cutfaces f of (bT, cT) compute - //delta(f) = max_{v \in T, v \in f} (depth(Gamma(v))) - //and f_B = face with max delta(f) and maximum number of cutvertices with deepest embedding. - face f_B = *(candidateCutfaces.begin()); - int max_delta_f = 0; - for (ListIterator it_f = candidateCutfaces.begin(); it_f.valid(); it_f++) - { - face f = *it_f; - int maxDepth = 0; - adjEntry ae_f = f->firstAdj(); - do - { - node nB = ae_f->theNode(); - node nH = nBlockEmbedding_to_nH[bTp][nB]; - node nG = pBCTree->original(nH); - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node nTp = pBCTree->bcproper(nG); - node nT = npBCTree_to_nBCTree[nTp]; - if (nT != parent_cT) - { - int depth_nT = depthCutvertex(nT); - if (depth_nT > maxDepth) - { - maxDepth = depth_nT; - } - } - } - - ae_f = ae_f->faceCycleSucc(); - } while(ae_f != f->firstAdj()); - - if (maxDepth > max_delta_f) - { - f_B = f; - max_delta_f = maxDepth; - } - } - - //embed all cutvertices incident to f_B into f_B and all other cutvertices - //into an arbitrary cutface: - Gamma_adjExt_nT[bTp] = f_B->firstAdj(); - - //G_nT[bT] = blockG[bT]: - nG_nT_to_nPG[bTp].init(G_nT[bTp]); - nPG_to_nG_nT[bTp].init(pBCTree->originalGraph()); - eG_nT_to_ePG[bTp].init(G_nT[bTp]); - ePG_to_eG_nT[bTp].init(pBCTree->originalGraph()); - node n_blockG_bT; - forall_nodes(n_blockG_bT, blockG[bTp]) - { - node nH = nBlockEmbedding_to_nH[bTp][n_blockG_bT]; - node nPG = pBCTree->original(nH); - node n_G_bT = G_nT[bTp].newNode(); - nG_nT_to_nPG[bTp][n_G_bT] = nPG; - nPG_to_nG_nT[bTp][nPG] = n_G_bT; - } - edge e_blockG_bT; - forall_edges(e_blockG_bT, blockG[bTp]) - { - edge eH = eBlockEmbedding_to_eH[bTp][e_blockG_bT]; - edge ePG = pBCTree->original(eH); - node n_G_bT_source = nPG_to_nG_nT[bTp][ePG->source()]; - node n_G_bT_target = nPG_to_nG_nT[bTp][ePG->target()]; - edge e_G_bT = G_nT[bTp].newEdge(n_G_bT_source, n_G_bT_target); - eG_nT_to_ePG[bTp][e_G_bT] = ePG; - ePG_to_eG_nT[bTp][ePG] = e_G_bT; - } - - //add nodes and edges of Gamma(cT) for all children cT of bT: - { - forall_adj_edges(e_bT_to_cT, bT) - { - if (e_bT_to_cT->target() != bT) - continue; - - node cT = e_bT_to_cT->source(); - node cTp = nBCTree_to_npBCTree[cT]; - node cPG = pBCTree->original(pBCTree->cutVertex(cTp, bTp)); - node n_G_cT; - forall_nodes(n_G_cT, G_nT[cTp]) - { - node nPG = nG_nT_to_nPG[cTp][n_G_cT]; - if (nPG != cPG) - { - node n_G_bT = G_nT[bTp].newNode(); - nG_nT_to_nPG[bTp][n_G_bT] = nPG; - nPG_to_nG_nT[bTp][nPG] = n_G_bT; - } - } - edge e_G_cT; - forall_edges(e_G_cT, G_nT[cTp]) - { - edge ePG = eG_nT_to_ePG[cTp][e_G_cT]; - node n_G_bT_source = nPG_to_nG_nT[bTp][ePG->source()]; - node n_G_bT_target = nPG_to_nG_nT[bTp][ePG->target()]; - edge e_G_bT = G_nT[bTp].newEdge(n_G_bT_source, n_G_bT_target); - eG_nT_to_ePG[bTp][e_G_bT] = ePG; - ePG_to_eG_nT[bTp][ePG] = e_G_bT; - } - } - } - - //compute new order of adjacency edges for all nodes depending on Gamma(v) - //for all children v of bT and the given embedding for block bT: - NodeArray< List > newOrder_bT(G_nT[bTp]); - forall_nodes(n_blockG_bT, blockG[bTp]) - { - node nH = nBlockEmbedding_to_nH[bTp][n_blockG_bT]; - node nG = pBCTree->original(nH); - adjEntry ae = n_blockG_bT->firstAdj(); - ListIterator after; - - if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - { - node cTp = pBCTree->bcproper(nG); - if (cTp != nBCTree_to_npBCTree[parent_cT]) - { - //find adjacency entry of n_blockG_bT which lies on external face of G_nT[cTp]: - adjEntry ae_G_cT; - adjEntry aeFace = Gamma_adjExt_nT[cTp]; - do - { - if (nG_nT_to_nPG[cTp][aeFace->theNode()] == nG) - { - if (aeFace->succ()) - ae_G_cT = aeFace->succ(); - else - ae_G_cT = aeFace->theNode()->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != Gamma_adjExt_nT[cTp]); - - //embed all edges of Gamma(cT): - node n_G_cT; - forall_nodes(n_G_cT, G_nT[cTp]) - { - node nG2 = nG_nT_to_nPG[cTp][n_G_cT]; - - adjEntry ae; - ListIterator* pAfter; - if (nG2 == nG) - { - ae = ae_G_cT; - pAfter = &after; - } - else - { - ae = n_G_cT->firstAdj(); - pAfter = OGDF_NEW ListIterator(); - } - - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : n_G_cT->firstAdj()) - { - edge eG = eG_nT_to_ePG[cTp][aeNode->theEdge()]; - edge e_G_bT = ePG_to_eG_nT[bTp][eG]; - node n_G_bT2 = nPG_to_nG_nT[bTp][nG2]; - if (nG2 == eG->source()) - { - if (!pAfter->valid()) - *pAfter = newOrder_bT[n_G_bT2].pushBack(e_G_bT->adjSource()); - else - *pAfter = newOrder_bT[n_G_bT2].insertAfter(e_G_bT->adjSource(), *pAfter); - } - else - { - if (!pAfter->valid()) - *pAfter = newOrder_bT[n_G_bT2].pushBack(e_G_bT->adjTarget()); - else - *pAfter = newOrder_bT[n_G_bT2].insertAfter(e_G_bT->adjTarget(), *pAfter); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - - if (nG2 != nG) - delete pAfter; - } //forall_nodes(n_G_cT, G_nT[cT]) - - //find adjacency entry of n_blockG_bT which lies on face f_B: - aeFace = f_B->firstAdj(); - do - { - if (aeFace->theNode() == n_blockG_bT) - { - if (aeFace->succ()) - ae = aeFace->succ(); - else - ae = n_blockG_bT->firstAdj(); - break; - } - aeFace = aeFace->faceCycleSucc(); - } while(aeFace != f_B->firstAdj()); - } //if (cT != parent_cT) - } //if (pBCTree->typeOfGNode(nG) == BCTree::CutVertex) - - //embed all edges of block bT: - bool after_ae = true; - for (adjEntry aeNode = ae; - after_ae || aeNode != ae; - after_ae = (!after_ae || !aeNode->succ()) ? false : true, - aeNode = aeNode->succ() ? aeNode->succ() : n_blockG_bT->firstAdj()) - { - edge eG = pBCTree->original(eBlockEmbedding_to_eH[bTp][aeNode->theEdge()]); - edge e_G_bT = ePG_to_eG_nT[bTp][eG]; - node n_G_bT = nPG_to_nG_nT[bTp][nG]; - if (nG == eG->source()) - { - if (!after.valid()) - after = newOrder_bT[n_G_bT].pushBack(e_G_bT->adjSource()); - else - after = newOrder_bT[n_G_bT].insertAfter(e_G_bT->adjSource(), after); - } - else - { - if (!after.valid()) - after = newOrder_bT[n_G_bT].pushBack(e_G_bT->adjTarget()); - else - after = newOrder_bT[n_G_bT].insertAfter(e_G_bT->adjTarget(), after); - } - } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ()) - } //forall_nodes(nSG, blockG[bT]) - - //apply new order: - node n_G_bT; - forall_nodes(n_G_bT, G_nT[bTp]) - G_nT[bTp].sort(n_G_bT, newOrder_bT[n_G_bT]); -} - - -int EmbedderMinDepthPiTa::depthBlock(const node& bT/*, const node& parent_cT*/) -{ - node bTp = nBCTree_to_npBCTree[bT]; - //node parent_cTp = nBCTree_to_npBCTree[parent_cT]; - //node parent_cH = pBCTree->cutVertex(parent_cTp, bTp); - //node parent_cPG = pBCTree->original(parent_cH); - //node parent_cG_nT = nPG_to_nG_nT[bTp][parent_cPG]; - - int dP = 0; - int dNP = 0; - - //compute dP = max_{v incident to f_B} depth(Gamma(v)), f_B = extFace, and - //dNP = 2 + max_{v not incident to f_B} depth(Gamma(v)): - int maxDepth_dP = 0; - int maxDepth_dNP = 0; - edge e_bT_cT; - forall_adj_edges(e_bT_cT, bT) - { - if (e_bT_cT->target() != bT) - continue; - - node cT = e_bT_cT->source(); - node cTp = nBCTree_to_npBCTree[cT]; - node cH = pBCTree->cutVertex(cTp, bTp); - node cPG = pBCTree->original(cH); - node cG_nT = nPG_to_nG_nT[bTp][cPG]; - - bool v_incident_to_fB = false; - adjEntry ae = Gamma_adjExt_nT[bTp]; - do - { - if (ae->theNode() == cG_nT) - { - v_incident_to_fB = true; - break; - } - ae = ae->faceCycleSucc(); - } while (ae != Gamma_adjExt_nT[bTp]); - - int depth_Gamma_cT = depthCutvertex(cT); - if (v_incident_to_fB) - { - if (depth_Gamma_cT > maxDepth_dP) - maxDepth_dP = depth_Gamma_cT; - } - else - { - if (depth_Gamma_cT > maxDepth_dNP) - maxDepth_dNP = depth_Gamma_cT; - } - } - - if (dP > 2 + dNP) - return dP; - //else: - return 2 + dNP; -} - - -int EmbedderMinDepthPiTa::depthCutvertex(const node& cT) -{ - //return max_{B \in children(v)} depth(Gamma(B)) - int maxDepth = 0; - - edge e_cT_bT; - forall_adj_edges(e_cT_bT, cT) - { - if (e_cT_bT->target() != cT) - continue; - - node bT = e_cT_bT->source(); - int thisDepth = depthBlock(bT/*, cT*/); - if (thisDepth > maxDepth) - maxDepth = thisDepth; - } - - return maxDepth; -} - - -void EmbedderMinDepthPiTa::deleteDummyNodes(Graph& G, adjEntry& adjExternal) -{ - if(!useExtendedDepthDefinition()) - return; - - node adjExtNode = adjExternal->theNode(); - node adjExtTwinNode = adjExternal->twinNode(); - if (dummyNodes.search(adjExtNode) != -1) - { - adjEntry succ = adjExternal->succ(); - if (!succ) - succ = adjExtNode->firstAdj(); - node succTwinNode = succ->twinNode(); - - //find edge between adjExtTwinNode and succTwinNode: - adjEntry ae; - forall_adj(ae, adjExtTwinNode) - { - if (ae->twinNode() == succTwinNode) - { - adjExternal = ae; - break; - } - } - } - else if (dummyNodes.search(adjExtTwinNode) != -1) - { - adjEntry succ = adjExternal->twin()->succ(); - if (!succ) - succ = adjExtTwinNode->firstAdj(); - node succTwinNode = succ->twinNode(); - - //find edge between adjExtNode and succTwinNode: - adjEntry ae; - forall_adj(ae, adjExtNode) - { - if (ae->twinNode() == succTwinNode) - { - adjExternal = ae; - break; - } - } - } - - for (ListIterator it = dummyNodes.begin(); it.valid(); it++) - G.delNode(*it); -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/ExtractKuratowskis.cpp b/ext/OGDF/src/planarity/ExtractKuratowskis.cpp deleted file mode 100644 index 6a2254efe..000000000 --- a/ext/OGDF/src/planarity/ExtractKuratowskis.cpp +++ /dev/null @@ -1,1847 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of the class ExtractKuratowskis - * - * \author Jens Schmidt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - -// reinitializes backtracking. all paths will be traversed again. startedges are -// either startInclude or not startExclude, all startedges have to contain the flag -// startFlag -void DynamicBacktrack::init( - const node start, - const node end, - const bool less, - const int flag, - const int startFlag = 0, - const edge startInclude = NULL, - const edge startExlude = NULL) -{ - OGDF_ASSERT(start!=NULL && end!=NULL); - this->start = start; - this->end = end; - this->less = less; - this->flag = flag; - - // init stack - stack.clear(); - adjEntry adj; - if (startInclude == NULL) { - forall_adj(adj,start) { - if (((m_flags[adj->theEdge()] & startFlag) == startFlag) && - adj->theEdge() != startExlude) { - stack.push(NULL); - stack.push(adj); - } - } - } else { - forall_adj(adj,start) { - if (adj->theEdge() == startInclude && - (m_flags[adj->theEdge()] & startFlag) == startFlag) { - stack.push(NULL); - stack.push(adj); - } - } - } - - // init array parent - if (!stack.empty()) { - m_parent.fill(NULL); - m_parent[start] = stack.top(); - } -} - -// returns the next possible path from start to endnode, if exists. -// endnode returns the last traversed node. -bool DynamicBacktrack::addNextPath(SListPure& list, node& endnode) { - adjEntry adj; - node v = NULL; - node temp; - - while (!stack.empty()) { - // backtrack - adj = stack.pop(); - - // return from a child node: delete parent - if (adj==NULL) { - // go to parent and delete visited flag - temp = v; - v = m_parent[temp]->theNode(); - m_parent[temp] = NULL; - continue; - } - - // get and mark node - v = adj->twinNode(); - m_parent[v] = adj; - - // path found - if ((less && m_dfi[v]theEdge()); - while(adj->theNode() != start) { - adj = m_parent[adj->theNode()]; - list.pushBack(adj->theEdge()); - } - - // in a following call of this method we'll have to reconstruct the actual - // state, therefore delete the last NULLs and visited flags on stack - while (!stack.empty() && stack.top()==NULL) { - stack.pop(); - temp = v; - v = m_parent[temp]->theNode(); - m_parent[temp] = NULL; - } - - // return bool, if path found - return true; - } - - // push all possible child-nodes - forall_adj(adj,v) { - // if edge is signed and target node was not visited before - if ((m_flags[adj->theEdge()] & flag) && (m_parent[adj->twinNode()]==NULL)) { - stack.push(NULL); - stack.push(adj); - } - } - } - return false; -} - -// returns the next possible path from start to endnode, if exists. -// endnode returns the last traversed node. all paths avoid "exclude"-nodes, except if -// on an edge with flag "exceptOnEdge". only the part of the path, that doesn't -// contain "exclude"-nodes is finally added. Here also the startedges computed in init() -// are considered to match these conditions. -bool DynamicBacktrack::addNextPathExclude( - SListPure& list, - node& endnode, - const NodeArray& nodeflags, - int exclude, - int exceptOnEdge) { - adjEntry adj; - node v = NULL; - node temp; - - while (!stack.empty()) { - // backtrack - adj = stack.pop(); - - // return from a child node: delete parent - if (adj==NULL) { - // go to parent and delete visited flag - temp = v; - v = m_parent[temp]->theNode(); - m_parent[temp] = NULL; - continue; - } - - // get and mark node - v = adj->twinNode(); - - // check if startedges computed in init() match th conditions - if (nodeflags[v]==exclude && !(m_flags[adj->theEdge()] & exceptOnEdge)) { - OGDF_ASSERT(stack.top()==NULL); - stack.pop(); - continue; - } - m_parent[v] = adj; - - // path found - if ((less && m_dfi[v] < m_dfi[end]) || (!less && v==end)) - { - // extract path vice versa until the startnode or an exclude-node is found - endnode = v; - list.clear(); - OGDF_ASSERT(nodeflags[v] != exclude); - list.pushBack(adj->theEdge()); - while (adj->theNode() != start && nodeflags[adj->theNode()] != exclude) { - adj = m_parent[adj->theNode()]; - list.pushBack(adj->theEdge()); - } - - // in a following call of this method we'll have to reconstruct the actual - // state, therefore delete the last NULLs and visited flags on stack - while (!stack.empty() && stack.top()==NULL) { - stack.pop(); - temp = v; - v = m_parent[temp]->theNode(); - m_parent[temp] = NULL; - } - - // return bool, if path found - return true; - } - - // push all possible child-nodes - forall_adj(adj,v) { - node x = adj->twinNode(); - edge e = adj->theEdge(); - // if edge is signed and target node was not visited before - if ((m_flags[e] & flag) && m_parent[x]==NULL) - { - // don't allow exclude-nodes, if not on an except-edge - if ((nodeflags[x] != exclude) || (m_flags[e] & exceptOnEdge)) - { - stack.push(NULL); - stack.push(adj); - } - } - } - } - return false; -} - -// class ExtractKuratowski -ExtractKuratowskis::ExtractKuratowskis(BoyerMyrvoldPlanar& bm) : - BMP(bm), - m_g(bm.m_g), - m_embeddingGrade(bm.m_embeddingGrade), - m_avoidE2Minors(bm.m_avoidE2Minors), - - m_wasHere(m_g,0), - - // initialize Members of BoyerMyrvoldPlanar - m_dfi(bm.m_dfi), - m_nodeFromDFI(bm.m_nodeFromDFI), - m_adjParent(bm.m_adjParent) -{ - OGDF_ASSERT(m_embeddingGrade == BoyerMyrvoldPlanar::doFindUnlimited || - m_embeddingGrade > 0); - // if only structures are limited, subdivisions must not be limited - if (bm.m_limitStructures) m_embeddingGrade = BoyerMyrvoldPlanar::doFindUnlimited; - m_nodeMarker = 0; - - // flip Graph and merge virtual with real nodes, if not already done - bm.flipBicomp(1,-1,m_wasHere,true,true); -} - -// returns the type of Kuratowski subdivision in list (none, K33 or K5) -int ExtractKuratowskis::whichKuratowski( - const Graph& m_g, - const NodeArray& /*m_dfi*/, - const SListPure& list) { - OGDF_ASSERT(!list.empty()); - EdgeArray edgenumber(m_g,0); - - // count edges - SListConstIterator it; - for (it = list.begin(); it.valid(); ++it) { - edge e = *it; - if (edgenumber[e] == 1) { - return ExtractKuratowskis::none; - } - edgenumber[e] = 1; - } - - return whichKuratowskiArray(m_g,/*m_dfi,*/edgenumber); -} - -// returns the type of Kuratowski subdivision in list (none, K33 or K5) -// the edgenumber has to be 1 for used edges, otherwise 0 -int ExtractKuratowskis::whichKuratowskiArray( - const Graph& m_g, - //const NodeArray& /* m_dfi */, - EdgeArray& edgenumber) -{ - edge e,ed; - node v; - NodeArray nodenumber(m_g,0); - int K33Partition[6] = {0,-1,-1,-1,-1,-1}; - bool K33Links[6][6] = {{0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0}, - {0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0}}; - - node K33Nodes[6]; - node K5Nodes[5]; - - #ifdef OGDF_DEBUG - forall_edges(e,m_g) OGDF_ASSERT(edgenumber[e] == 0 || edgenumber[e] == 1); - #endif - - // count incident nodes - SListConstIterator it; - int allEdges = 0; - forall_edges(e,m_g) { - if (edgenumber[e] == 1) { - ++allEdges; - ++nodenumber[e->source()]; - ++nodenumber[e->target()]; - } - } - if (allEdges < 9) { - return ExtractKuratowskis::none; - } - - int degree3nodes = 0; - int degree4nodes = 0; - forall_nodes(v,m_g) { - if (nodenumber[v] > 4 || nodenumber[v] == 1) { - return ExtractKuratowskis::none; - } - if (nodenumber[v]==3) { - K33Nodes[degree3nodes] = v; - ++degree3nodes; - } else if (nodenumber[v]==4) { - K5Nodes[degree4nodes] = v; - ++degree4nodes; - } - } - - // check on K3,3 - int paths = 0; - if (degree3nodes == 6) { - if (degree4nodes > 0) { - return ExtractKuratowskis::none; - } - for (int i=0; i<6; ++i) { - forall_adj_edges(e,K33Nodes[i]) { - if (edgenumber[e] > 0) { // not visited - edgenumber[e] = -2; // visited - v = e->opposite(K33Nodes[i]); - // traverse nodedegree-2 path until degree-3 node found - while (nodenumber[v] != 3) { - nodenumber[v] = -2; // visited - forall_adj_edges(ed,v) if (edgenumber[ed] > 0) break; - OGDF_ASSERT(edgenumber[ed] > 0); - edgenumber[ed] = -2; // visited - v = ed->opposite(v); - } - int ii; - for (ii=0; ii<6; ++ii) if (K33Nodes[ii]==v) break; - OGDF_ASSERT(ii>=0 && ii<=5); - if (K33Partition[i] != K33Partition[ii]) { - ++paths; - if (K33Partition[ii]==-1) K33Partition[ii] = !K33Partition[i]; - if (!K33Links[i][ii]) { - K33Links[i][ii] = true; - } else { - return ExtractKuratowskis::none; - } - } else { - return ExtractKuratowskis::none; - } - } - } - } - if (paths==9) { - return ExtractKuratowskis::K33; - } else { - return ExtractKuratowskis::none; - } - } else if (degree4nodes == 5) { - // check on K5 - if (degree3nodes > 0) { - return ExtractKuratowskis::none; - } - for (int i=0; i<5; ++i) { - forall_adj_edges(e,K5Nodes[i]) { - if (edgenumber[e] > 0) { // not visited - edgenumber[e] = -2; // visited - v = e->opposite(K5Nodes[i]); - // traverse nodedegree-2 path until degree-4 node found - while (nodenumber[v] != 4) { - nodenumber[v] = -2; // visited - forall_adj_edges(ed,v) if (edgenumber[ed] > 0) break; - if (edgenumber[ed] <= 0) break; - edgenumber[ed] = -2; // visited - v = ed->opposite(v); - } - if (nodenumber[v] == 4) ++paths; - } - } - } - if (paths==10) { - return ExtractKuratowskis::K5; - } else { - return ExtractKuratowskis::none; - } - } else { - return ExtractKuratowskis::none; - } -} - -// returns true, if kuratowski EdgeArray isn't already contained in output -bool ExtractKuratowskis::isANewKuratowski( - //const Graph& g, - const EdgeArray& test, - const SList& output) -{ - SListConstIterator itW; - SListConstIterator it; - for (itW = output.begin(); itW.valid(); ++itW) { - bool differentEdgeFound = false; - for (it = (*itW).edgeList.begin(); it.valid(); ++it) { - if (!test[*it]) { - differentEdgeFound = true; - break; - } - } - if (!differentEdgeFound) { - cerr << "\nERROR: Kuratowski is already in list as subdivisiontype " - << (*itW).subdivisionType << "\n"; - return false; - } - } - return true; -} - -// returns true, if kuratowski edgelist isn't already contained in output -bool ExtractKuratowskis::isANewKuratowski( - const Graph& g, - const SListPure& kuratowski, - const SList& output) -{ - EdgeArray test(g,0); - SListConstIterator it; - for (it = kuratowski.begin(); it.valid(); ++it) test[*it] = 1; - return isANewKuratowski(/*g,*/test,output); -} - -// returns adjEntry of the edge between node high and that node -// with the lowest DFI not less than the DFI of low -inline adjEntry ExtractKuratowskis::adjToLowestNodeBelow(node high, int low) { - adjEntry adj; - int result = 0; - int temp; - adjEntry resultAdj = NULL; - forall_adj(adj,high) { - temp = m_dfi[adj->twinNode()]; - if (temp >= low && (result==0 || temp < result)) { - result = temp; - resultAdj = adj->twin(); - } - } - if (result==0) { - return NULL; - } else return resultAdj; -} - -// add DFS-path from node bottom to node top to edgelist -// each virtual node has to be merged -inline void ExtractKuratowskis::addDFSPath( - SListPure& list, - node bottom, - node top) { - if (bottom == top) return; - adjEntry adj = m_adjParent[bottom]; - list.pushBack(adj->theEdge()); - while (adj->theNode() != top) { - adj = m_adjParent[adj->theNode()]; - list.pushBack(adj->theEdge()); - } -} - -// the same as above but list is reversed -inline void ExtractKuratowskis::addDFSPathReverse( - SListPure& list, - node bottom, - node top) { - if (bottom == top) return; - adjEntry adj = m_adjParent[bottom]; - list.pushFront(adj->theEdge()); - while (adj->theNode() != top) { - adj = m_adjParent[adj->theNode()]; - list.pushFront(adj->theEdge()); - } -} - -// separate list1 from edges already contained in list2 -inline void ExtractKuratowskis::truncateEdgelist( - SListPure& list1, - const SListPure& list2) -{ - SListConstIterator it = list2.begin(); - while (!list1.empty() && it.valid() && list1.front() == *it) { - list1.popFront(); - ++it; - } -} - -// extracts a type A minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorA( - SList& output, - const KuratowskiStructure& k, - //const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - OGDF_ASSERT(k.RReal != k.V); - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper A; - - // add all external face edges - addExternalFacePath(A.edgeList,k.externalFacePath); - - // add the path from v to u, this is only possible after computation of pathX and pathY - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - addDFSPath(A.edgeList,k.V,endnodeX); - } else addDFSPath(A.edgeList,k.V,endnodeY); - - // copy other paths to subdivision - SListConstIterator it; - for(it = pathX.begin(); it.valid(); ++it) A.edgeList.pushBack(*it); - for(it = pathY.begin(); it.valid(); ++it) A.edgeList.pushBack(*it); - for(it = pathW.begin(); it.valid(); ++it) A.edgeList.pushBack(*it); - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,A.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,A.edgeList,output)); - A.subdivisionType = KuratowskiWrapper::A; - A.V = k.V; - output.pushBack(A); -} - -// extracts a type B minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorB( - SList& output, - //NodeArray& nodeflags, - //const int nodemarker, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper B; - - // find ExternE-struct suitable for wNode - SListIterator itExternW; - for (itExternW = info.externEStart; (*itExternW).theNode != info.w; ++itExternW) - ; - OGDF_ASSERT(itExternW.valid() && (*itExternW).theNode == info.w); - ExternE& externE(*itExternW); - OGDF_ASSERT(externE.theNode == pathW.front()->source() || - externE.theNode == pathW.front()->target()); - - // check, if a external path sharing the first pathW-edge exists - SListIterator itStart; - SListIterator itEnd = externE.endnodes.begin(); - SListIterator > itPath = externE.externalPaths.begin(); - SListIterator itEdge; - for (itStart = externE.startnodes.begin(); itStart.valid(); ++itStart) { - if (*itStart != m_dfi[pathW.front()->opposite(info.w)]) { - ++itEnd; - ++itPath; - continue; - } - - // if path was preprocessed, copy path - node endnodeWExtern = *itEnd; - if (!(*itPath).empty()) { - B.edgeList = (*itPath); - } else { - // else traverse external Path starting with z. forbid edges starting at W, - // that are different from the edge w->z. - adjEntry adj = adjToLowestNodeBelow(endnodeWExtern,*itStart); - B.edgeList.pushFront(adj->theEdge()); - addDFSPathReverse(B.edgeList,adj->theNode(),info.w); - - // copy list - *itPath = B.edgeList; - } - - // truncate pathZ from edges already contained in pathW - OGDF_ASSERT(B.edgeList.front() == pathW.front()); - truncateEdgelist(B.edgeList,pathW); - - // add external face edges - addExternalFacePath(B.edgeList,k.externalFacePath); - - // compute dfi-minimum and maximum of all three paths to node Ancestor u - // add the dfs-path from minimum to maximum - node min,max; - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - min = endnodeX; - max = endnodeY; - } else { - min = endnodeY; - max = endnodeX; - } - if (m_dfi[endnodeWExtern] < m_dfi[min]) { - min = endnodeWExtern; - } else { - if (m_dfi[endnodeWExtern] > m_dfi[max]) max = endnodeWExtern; - } - addDFSPath(B.edgeList,max,min); - - // copy other paths to subdivision - SListConstIterator it; - for (it = pathX.begin(); it.valid(); ++it) B.edgeList.pushBack(*it); - for (it = pathY.begin(); it.valid(); ++it) B.edgeList.pushBack(*it); - for (it = pathW.begin(); it.valid(); ++it) B.edgeList.pushBack(*it); - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,B.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,B.edgeList,output)); - if (info.minorType & WInfo::A) { - B.subdivisionType = KuratowskiWrapper::AB; - } else B.subdivisionType = KuratowskiWrapper::B; - B.V = k.V; - output.pushBack(B); - B.edgeList.clear(); - -// break; - } -} - -// extracts a type B minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorBBundles( - SList& output, - NodeArray& nodeflags, - const int nodemarker, - const KuratowskiStructure& k, - EdgeArray& flags, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - KuratowskiWrapper B; - OGDF_ASSERT(flags[pathW.back()] & DynamicBacktrack::pertinentPath); - - // check, if pertinent pathW (w->u) traverses node z - if (!(flags[pathW.back()] & DynamicBacktrack::externalPath)) return; - - // mark single pathW in flags, so that pathW and the externalPath - // don't interfere later - SListConstIterator itE; - for (itE = pathW.begin(); itE.valid(); ++itE) { - flags[*itE] |= DynamicBacktrack::singlePath; - nodeflags[(*itE)->source()] = nodemarker; - nodeflags[(*itE)->target()] = nodemarker; - } - - // traverse all possible external Paths out of z. forbid edges starting at W, - // that are different from the edge w->z - node endnodeWExtern; - DynamicBacktrack backtrackExtern(m_g,m_dfi,flags); - backtrackExtern.init(info.w,k.V,true,DynamicBacktrack::externalPath, - DynamicBacktrack::externalPath,pathW.back(),NULL); - while (backtrackExtern.addNextPathExclude(B.edgeList,endnodeWExtern,nodeflags, - nodemarker,DynamicBacktrack::singlePath)) { - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - break; - - // add external face edges - addExternalFacePath(B.edgeList,k.externalFacePath); - - // compute dfi-minimum and maximum of all three paths to node Ancestor u - // add the dfs-path from minimum to maximum - node min,max; - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - min = endnodeX; - max = endnodeY; - } else { - min = endnodeY; - max = endnodeX; - } - if (m_dfi[endnodeWExtern] < m_dfi[min]) min = endnodeWExtern; - else if (m_dfi[endnodeWExtern] > m_dfi[max]) max = endnodeWExtern; - addDFSPath(B.edgeList,max,min); - - // copy other paths to subdivision - SListConstIterator it; - for (it = pathX.begin(); it.valid(); ++it) B.edgeList.pushBack(*it); - for (it = pathY.begin(); it.valid(); ++it) B.edgeList.pushBack(*it); - for (it = pathW.begin(); it.valid(); ++it) B.edgeList.pushBack(*it); - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,B.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,B.edgeList,output)); - if (info.minorType & WInfo::A) { - B.subdivisionType = KuratowskiWrapper::AB; - } else B.subdivisionType = KuratowskiWrapper::B; - B.V = k.V; - output.pushBack(B); - B.edgeList.clear(); - } - - // delete marked single pathW - for (itE = pathW.begin(); itE.valid(); ++itE) { - flags[*itE] &= ~DynamicBacktrack::singlePath; - } -} - -// extracts a type C minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorC( - SList& output, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper C; - SListPure tempC; - - // the case, that px is above stopX - OGDF_ASSERT(info.pxAboveStopX || info.pyAboveStopY); - SListConstIterator itE; - - // add the path from v to u, this is only possible after computation - // of pathX and pathY - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - addDFSPath(tempC,k.V,endnodeX); - } else addDFSPath(tempC,k.V,endnodeY); - - // add highestFacePath of wNode - OGDF_ASSERT(info.highestXYPath->size() >= 2); - for (itE=info.highestXYPath->begin().succ(); itE.valid(); ++itE) { - tempC.pushBack((*itE)->theEdge()); - } - - // the case, that px is above stopX - if (info.pxAboveStopX) { - C.edgeList = tempC; - - // add the external face path edges except the path from py/stopY to R - node end; - if (info.pyAboveStopY) { - end = info.highestXYPath->back()->theNode(); - } else end = k.stopY; - for (itE=k.externalFacePath.begin(); itE.valid(); ++itE) { - C.edgeList.pushBack((*itE)->theEdge()); - if ((*itE)->theNode() == end) break; - } - - // copy other paths to subdivision - SListConstIterator it; - for (it = pathX.begin(); it.valid(); ++it) C.edgeList.pushBack(*it); - for (it = pathY.begin(); it.valid(); ++it) C.edgeList.pushBack(*it); - for (it = pathW.begin(); it.valid(); ++it) C.edgeList.pushBack(*it); - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,C.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,C.edgeList,output)); - if (info.minorType & WInfo::A) { - C.subdivisionType = KuratowskiWrapper::AC; - } else C.subdivisionType = KuratowskiWrapper::C; - C.V = k.V; - output.pushBack(C); - C.edgeList.clear(); - } - - // the case, that py is above stopY - if (info.pyAboveStopY) { - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - C.edgeList = tempC; - - // add the external face path edges except the path from px/stopX to R - node start; - if (info.pxAboveStopX) { - start = info.highestXYPath->front()->theNode(); - } else start = k.stopX; - bool after = false; - for (itE=k.externalFacePath.begin(); itE.valid(); ++itE) { - if (after) { - C.edgeList.pushBack((*itE)->theEdge()); - } else if ((*itE)->theNode() == start) after = true; - } - - // copy other paths to subdivision - SListConstIterator it; - for (it = pathX.begin(); it.valid(); ++it) C.edgeList.pushBack(*it); - for (it = pathY.begin(); it.valid(); ++it) C.edgeList.pushBack(*it); - for (it = pathW.begin(); it.valid(); ++it) C.edgeList.pushBack(*it); - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,C.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,C.edgeList,output)); - if (info.minorType & WInfo::A) { - C.subdivisionType = KuratowskiWrapper::AC; - } else C.subdivisionType = KuratowskiWrapper::C; - C.V = k.V; - output.pushBack(C); - } -} - -// extracts a type D minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorD( - SList& output, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper D; - - // add the path from v to u, this is only possible after computation of pathX and pathY - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - addDFSPath(D.edgeList,k.V,endnodeX); - } else addDFSPath(D.edgeList,k.V,endnodeY); - - // add the external face path edges except the part from R to the nearest of - // the two nodes stopX and px resp. the part to stopY/py - node start; - if (info.pxAboveStopX) { - start = info.highestXYPath->front()->theNode(); - } else start = k.stopX; - node end; - if (info.pyAboveStopY) { - end = info.highestXYPath->back()->theNode(); - } else end = k.stopY; - node temp; - SListConstIterator itE; - bool between = false; - for (itE=k.externalFacePath.begin(); itE.valid(); ++itE) { - temp = (*itE)->theNode(); - if (between) D.edgeList.pushBack((*itE)->theEdge()); - if (temp == start) { - between = true; - } else if (temp == end) between = false; - } - - // add highestFacePath of wNode - OGDF_ASSERT(info.highestXYPath->size() >= 2); - for (itE=info.highestXYPath->begin().succ(); itE.valid(); ++itE) { - D.edgeList.pushBack((*itE)->theEdge()); - } - - // add path from first zNode to R - OGDF_ASSERT(!info.zPath->empty()); - for (itE=info.zPath->begin().succ(); itE.valid(); ++itE) { - D.edgeList.pushBack((*itE)->theEdge()); - } - - // copy other paths to subdivision - SListConstIterator it; - for (it = pathX.begin(); it.valid(); ++it) D.edgeList.pushBack(*it); - for (it = pathY.begin(); it.valid(); ++it) D.edgeList.pushBack(*it); - for (it = pathW.begin(); it.valid(); ++it) D.edgeList.pushBack(*it); - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,D.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,D.edgeList,output)); - if (info.minorType & WInfo::A) { - D.subdivisionType = KuratowskiWrapper::AD; - } else D.subdivisionType = KuratowskiWrapper::D; - D.V = k.V; - output.pushBack(D); -} - -// extracts a subtype E1 minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorE1( - SList& output, - int before, - //const node z, - const node px, - const node py, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - OGDF_ASSERT(before == -1 || before == 1); - KuratowskiWrapper E1; - SListConstIterator itE; - - // add highestFacePath of wNode - SListConstIterator it; - for (it=info.highestXYPath->begin().succ(); it.valid(); ++it) - E1.edgeList.pushBack((*it)->theEdge()); - - if (before == -1) { - // z is before w on external face path - - // add pathY - for (itE = pathY.begin(); itE.valid(); ++itE) E1.edgeList.pushBack(*itE); - - // add the path from v to u, this is only possible after computation of - // pathX and pathY - if (m_dfi[endnodeZ] < m_dfi[endnodeY]) { - addDFSPath(E1.edgeList,k.V,endnodeZ); - } else addDFSPath(E1.edgeList,k.V,endnodeY); - - // add the external face path edges except the part from stopY/py to R - node stop; - if (info.pyAboveStopY) { - stop = py; - } else stop = k.stopY; - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - E1.edgeList.pushBack((*it)->theEdge()); - if ((*it)->theNode() == stop) break; - } - } else { - // z is after w on external face path - - // if minor A occurs, add the dfs-path from node RReal to V, that isn't anymore - // involved because of removing pathY - if (k.RReal != k.V) addDFSPath(E1.edgeList,k.RReal,k.V); - - // add pathX - for (itE = pathX.begin(); itE.valid(); ++itE) E1.edgeList.pushBack(*itE); - - // add the path from v to u, this is only possible after computation of - // pathX and pathY - if (m_dfi[endnodeZ] < m_dfi[endnodeX]) { - addDFSPath(E1.edgeList,k.V,endnodeZ); - } else addDFSPath(E1.edgeList,k.V,endnodeX); - - // add the external face path edges except the part from stopX/px to R - node start; - if (info.pxAboveStopX) { - start = px; - } else start = k.stopX; - bool after = false; - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - if (after) { - E1.edgeList.pushBack((*it)->theEdge()); - } else if ((*it)->theNode() == start) after = true; - } - } - - // add pathW and pathZ - for (itE = pathW.begin(); itE.valid(); ++itE) E1.edgeList.pushBack(*itE); - for (itE = pathZ.begin(); itE.valid(); ++itE) E1.edgeList.pushBack(*itE); - // push this subdivision to kuratowskilist - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,E1.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,E1.edgeList,output)); - if (info.minorType & WInfo::A) { - E1.subdivisionType = KuratowskiWrapper::AE1; - } else E1.subdivisionType = KuratowskiWrapper::E1; - E1.V = k.V; - output.pushBack(E1); -} - -// extracts a subtype E2 minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorE2( - SList& output, - /*int before, - const node z, - const node px, - const node py,*/ - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - //const SListPure& pathW, - const SListPure& pathZ/*, - const node endnodeZ*/ - ) -{ - OGDF_ASSERT(!m_avoidE2Minors); - - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper E2; - - // add the path from v to u - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - addDFSPath(E2.edgeList,k.V,endnodeX); - } else addDFSPath(E2.edgeList,k.V,endnodeY); - - // add the external face path edges - SListConstIterator it; - for (it=k.externalFacePath.begin(); it.valid(); ++it) - E2.edgeList.pushBack((*it)->theEdge()); - - // add pathX, pathY and pathZ - SListConstIterator itE; - for (itE = pathX.begin(); itE.valid(); ++itE) E2.edgeList.pushBack(*itE); - for (itE = pathY.begin(); itE.valid(); ++itE) E2.edgeList.pushBack(*itE); - for (itE = pathZ.begin(); itE.valid(); ++itE) E2.edgeList.pushBack(*itE); - // push this subdivision to kuratowskilist - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,E2.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,E2.edgeList,output)); - if (info.minorType & WInfo::A) { - E2.subdivisionType = KuratowskiWrapper::AE2; - } else E2.subdivisionType = KuratowskiWrapper::E2; - E2.V = k.V; - output.pushBack(E2); -} - -// extracts a subtype E3 minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorE3( - SList& output, - int before, - const node z, - const node px, - const node py, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper E3; - OGDF_ASSERT(endnodeX != endnodeY); - - // add pathZ - SListConstIterator itE; - for (itE = pathZ.begin(); itE.valid(); ++itE) E3.edgeList.pushBack(*itE); - - // add highestFacePath px <-> py - SListConstIterator it; - for (it=info.highestXYPath->begin().succ(); it.valid(); ++it) - E3.edgeList.pushBack((*it)->theEdge()); - - // check, if endnodeX or endnodeY is descendant - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - OGDF_ASSERT(m_dfi[endnodeZ] < m_dfi[endnodeY]); - - // add the path from v to u - if (m_dfi[endnodeX] < m_dfi[endnodeZ]) { - addDFSPath(E3.edgeList,k.V,endnodeX); - } else addDFSPath(E3.edgeList,k.V,endnodeZ); - - // add the external face path edges except max(px,stopX)<->min(z,w) and v<->nearest(py,stopY) - node temp,start1,end1,start2; - if (info.pxAboveStopX) { - start1 = k.stopX; - } else start1 = px; - if (before<=0) { - end1 = z; - } else end1 = info.w; - if (info.pyAboveStopY) { - start2 = py; - } else start2 = k.stopY; - bool between = false; - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - temp = (*it)->theNode(); - if (!between) E3.edgeList.pushBack((*it)->theEdge()); - if (temp == start1) between = true; - else if (temp == start2) break; - else if (temp == end1) between = false; - } - } else { - OGDF_ASSERT(m_dfi[endnodeZ] < m_dfi[endnodeX]); - - // add the path from v to u - if (m_dfi[endnodeY] < m_dfi[endnodeZ]) { - addDFSPath(E3.edgeList,k.V,endnodeY); - } else addDFSPath(E3.edgeList,k.V,endnodeZ); - - // add the external face path edges except v<->min(px,stopX) and max(w,z)<->nearest(py,stopY) - node temp,end1,start2,end2; - if (info.pxAboveStopX) { - end1 = px; - } else end1 = k.stopX; - if (before>0) { - start2 = z; - } else start2 = info.w; - if (info.pyAboveStopY) { - end2 = k.stopY; - } else end2 = py; - bool between = true; - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - temp = (*it)->theNode(); - if (!between) E3.edgeList.pushBack((*it)->theEdge()); - if (temp == end1) between = false; - else if (temp == start2) between = true; - else if (temp == end2) between = false; - } - } - - // add pathX, pathY and pathW - for (itE = pathX.begin(); itE.valid(); ++itE) E3.edgeList.pushBack(*itE); - for (itE = pathY.begin(); itE.valid(); ++itE) E3.edgeList.pushBack(*itE); - for (itE = pathW.begin(); itE.valid(); ++itE) E3.edgeList.pushBack(*itE); - // push this subdivision to kuratowskilist - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,E3.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,E3.edgeList,output)); - if (info.minorType & WInfo::A) { - E3.subdivisionType = KuratowskiWrapper::AE3; - } else E3.subdivisionType = KuratowskiWrapper::E3; - E3.V = k.V; - output.pushBack(E3); -} - -// extracts a subtype E4 minor. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorE4( - SList& output, - int before, - const node z, - const node px, - const node py, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper E4; - SListPure tempE4; - OGDF_ASSERT((px != k.stopX && !info.pxAboveStopX) || - (py != k.stopY && !info.pyAboveStopY)); - - // add pathZ - SListConstIterator itE; - for (itE = pathZ.begin(); itE.valid(); ++itE) tempE4.pushBack(*itE); - - // add highestFacePath px <-> py - SListConstIterator it; - for (it = info.highestXYPath->begin().succ(); it.valid(); ++it) - tempE4.pushBack((*it)->theEdge()); - - // compute dfi-minimum and maximum of all three paths to node Ancestor u - // add the dfs-path from minimum to maximum - node min,max; - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - min = endnodeX; - max = endnodeY; - } else { - min = endnodeY; - max = endnodeX; - } - if (m_dfi[endnodeZ] < m_dfi[min]) min = endnodeZ; - else if (m_dfi[endnodeZ] > m_dfi[max]) max = endnodeZ; - addDFSPath(tempE4,max,min); - - if (px != k.stopX && !info.pxAboveStopX) { - E4.edgeList = tempE4; - - // add the external face path edges except max(w,z)<->min(py,stopY) - node temp,start,end; - if (before<=0) { - start = info.w; - } else start = z; - if (info.pyAboveStopY) { - end = k.stopY; - } else end = py; - bool between = false; - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - temp = (*it)->theNode(); - if (!between) E4.edgeList.pushBack((*it)->theEdge()); - if (temp == start) between = true; - else if (temp == end) between = false; - } - - // add pathX, pathY and pathW - for (itE = pathX.begin(); itE.valid(); ++itE) E4.edgeList.pushBack(*itE); - for (itE = pathY.begin(); itE.valid(); ++itE) E4.edgeList.pushBack(*itE); - for (itE = pathW.begin(); itE.valid(); ++itE) E4.edgeList.pushBack(*itE); - // push this subdivision to kuratowski-list - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,E4.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,E4.edgeList,output)); - if (info.minorType & WInfo::A) { - E4.subdivisionType = KuratowskiWrapper::AE4; - } else E4.subdivisionType = KuratowskiWrapper::E4; - E4.V = k.V; - output.pushBack(E4); - } - - if (py != k.stopY && !info.pyAboveStopY) { - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - E4.edgeList = tempE4; - - // add the external face path edges except max(px,stopX)<->min(w,z) - node temp,start,end; - if (info.pxAboveStopX) { - start = k.stopX; - } else start = px; - if (before <= 0) { - end = z; - } else end = info.w; - - bool between = false; - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - temp = (*it)->theNode(); - if (!between) E4.edgeList.pushBack((*it)->theEdge()); - if (temp == start) between = true; - else if (temp == end) between = false; - } - - // add pathX, pathY and pathW - for (itE = pathX.begin(); itE.valid(); ++itE) E4.edgeList.pushBack(*itE); - for (itE = pathY.begin(); itE.valid(); ++itE) E4.edgeList.pushBack(*itE); - for (itE = pathW.begin(); itE.valid(); ++itE) E4.edgeList.pushBack(*itE); - // push this subdivision to kuratowski-list - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,E4.edgeList) == ExtractKuratowskis::K33); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,E4.edgeList,output)); - if (info.minorType & WInfo::A) { - E4.subdivisionType = KuratowskiWrapper::AE4; - } else E4.subdivisionType = KuratowskiWrapper::E4; - E4.V = k.V; - output.pushBack(E4); - } -} - -// extracts a subtype E5 minor (the only minortype which represents a K5). -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorE5( - SList& output, - /*int before, - const node z, - const node px, - const node py,*/ - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW, - const SListPure& pathZ, - const node endnodeZ) -{ - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - - KuratowskiWrapper E5; - //OGDF_ASSERT(px==k.stopX && py==k.stopY && z==info.w && k.V == k.RReal); - OGDF_ASSERT((endnodeX == endnodeY && m_dfi[endnodeZ] <= m_dfi[endnodeX]) || - (endnodeX == endnodeZ && m_dfi[endnodeY] <= m_dfi[endnodeX]) || - (endnodeY == endnodeZ && m_dfi[endnodeX] <= m_dfi[endnodeY])); - - // compute dfi-minimum of all three paths to node Ancestor u and - // add the dfs-path from minimum to V - node min; - if (m_dfi[endnodeX] < m_dfi[endnodeY]) { - min = endnodeX; - } else if (m_dfi[endnodeY] < m_dfi[endnodeZ]) { - min = endnodeY; - } else { - min = endnodeZ; - } - addDFSPath(E5.edgeList,k.V,min); - - // add pathZ - SListConstIterator itE; - for (itE = pathZ.begin(); itE.valid(); ++itE) E5.edgeList.pushBack(*itE); - - // add highestFacePath px <-> py - SListConstIterator it; - for (it=info.highestXYPath->begin().succ(); it.valid(); ++it) - E5.edgeList.pushBack((*it)->theEdge()); - - // add the external face path edges - for (it=k.externalFacePath.begin(); it.valid(); ++it) { - E5.edgeList.pushBack((*it)->theEdge()); - } - - // add pathX, pathY and pathW - for (itE = pathX.begin(); itE.valid(); ++itE) E5.edgeList.pushBack(*itE); - for (itE = pathY.begin(); itE.valid(); ++itE) E5.edgeList.pushBack(*itE); - for (itE = pathW.begin(); itE.valid(); ++itE) E5.edgeList.pushBack(*itE); - // push this subdivision to kuratowski-list - OGDF_ASSERT(whichKuratowski(m_g,m_dfi,E5.edgeList) == ExtractKuratowskis::K5); - OGDF_ASSERT(!m_avoidE2Minors || isANewKuratowski(m_g,E5.edgeList,output)); - E5.subdivisionType = KuratowskiWrapper::E5; - E5.V = k.V; - output.pushBack(E5); -} - -// extracts a type E minor through splitting in different subtypes. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorE( - SList& output, - bool firstXPath, - bool firstYPath, - bool firstWPath, - bool firstWOnHighestXY, - const KuratowskiStructure& k, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - // find external paths for each extern node z on the lower external face - OGDF_ASSERT(info.externEStart.valid() && info.externEEnd.valid()); - - int before = -1; // -1= before, 0=equal, 1=after - SListConstIterator itW; - SListConstIterator it; - node px = info.highestXYPath->front()->theNode(); - node py = info.highestXYPath->back()->theNode(); - - adjEntry temp; - node z; - SListPure pathZ; - node endnodeZ; - SListConstIterator itZEndnode; - SListConstIterator itZStartnode; - SListConstIterator > itEPath; - - // consider only the nodes between px and py - for (it = info.externEStart; it.valid(); ++it) { - const ExternE& externE(*it); - z = externE.theNode; - - if (z == info.w) { - OGDF_ASSERT(z == pathW.front()->source() || z == pathW.front()->target()); - // z = wNode - before = 0; - - itZStartnode = externE.startnodes.begin(); - itEPath = externE.externalPaths.begin(); - for (itZEndnode = externE.endnodes.begin(); itZEndnode.valid(); - ++itZEndnode,++itZStartnode,++itEPath) { - endnodeZ = *itZEndnode; - SListPure& externalPath(const_cast& >(*itEPath)); - - if (!externalPath.empty()) { - // get preprocessed path - pathZ = externalPath; - } else { - temp = adjToLowestNodeBelow(endnodeZ,*itZStartnode); - pathZ.clear(); - pathZ.pushFront(temp->theEdge()); - addDFSPathReverse(pathZ,temp->theNode(),z); - - // copy path - externalPath = pathZ; - } - - // minortype E2 on z=wNode - if (!m_avoidE2Minors && firstWPath && firstWOnHighestXY && - m_dfi[endnodeZ] > m_dfi[endnodeX] && - m_dfi[endnodeZ] > m_dfi[endnodeY]) { - extractMinorE2(output,/*before,z,px,py,*/k,info,pathX, - endnodeX,pathY,endnodeY,/*pathW,*/pathZ/*,endnodeZ*/); - } - - // truncate pathZ from edges already contained in pathW - truncateEdgelist(pathZ,pathW); - - // minortype E3 on z=wNode - if (endnodeX != endnodeY && - (m_dfi[endnodeX] > m_dfi[endnodeZ] || m_dfi[endnodeY] > m_dfi[endnodeZ])) { - extractMinorE3(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E4 on z=wNode - if ((px != k.stopX && !info.pxAboveStopX) || - (py != k.stopY && !info.pyAboveStopY)) { - extractMinorE4(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - - // minortype E5 (K5) - if (px == k.stopX && py == k.stopY && k.V == k.RReal && - ((endnodeX == endnodeY && m_dfi[endnodeZ] <= m_dfi[endnodeX]) || - (endnodeX == endnodeZ && m_dfi[endnodeY] <= m_dfi[endnodeX]) || - (endnodeY == endnodeZ && m_dfi[endnodeX] <= m_dfi[endnodeY]))) { - // check, if pathZ shares no edge with pathW - if (*itZStartnode != m_dfi[pathW.front()->opposite(z)]) { - extractMinorE5(output,/*before,z,px,py,*/k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - } - } - } else { - // z != wNode, check position of node z - if (z == info.firstExternEAfterW) before = 1; - OGDF_ASSERT(before != 0); - OGDF_ASSERT(z != pathW.front()->source() && z != pathW.front()->target()); - - itZStartnode = externE.startnodes.begin(); - for (itZEndnode = externE.endnodes.begin(); itZEndnode.valid(); - ++itZEndnode,++itZStartnode) { - endnodeZ = *itZEndnode; - - temp = adjToLowestNodeBelow(endnodeZ,*itZStartnode); - pathZ.clear(); - pathZ.pushFront(temp->theEdge()); - addDFSPathReverse(pathZ,temp->theNode(),z); - - // split in minorE-subtypes - - // minortype E1 - if ((before == -1 && firstXPath) || (before == 1 && firstYPath)) { - extractMinorE1(output,before,/*z,*/px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E2 - if (!m_avoidE2Minors && firstWPath && firstWOnHighestXY - && m_dfi[endnodeZ] > m_dfi[endnodeX] - && m_dfi[endnodeZ] > m_dfi[endnodeY]) { - extractMinorE2(output,/*before,z,px,py,*/k,info,pathX, - endnodeX,pathY,endnodeY,/*pathW,*/pathZ/*,endnodeZ*/); - } - // minortype E3 - if (endnodeX != endnodeY && (m_dfi[endnodeX] > m_dfi[endnodeZ] || - m_dfi[endnodeY] > m_dfi[endnodeZ])) { - extractMinorE3(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E4 - if ((px != k.stopX && !info.pxAboveStopX) || - (py != k.stopY && !info.pyAboveStopY)) { - extractMinorE4(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - } - } - - // check if last node was reached - if (it == info.externEEnd) break; - } -} - -// extracts a type E minor through splitting in different subtypes. -// each virtual node has to be merged into its real counterpart. -void ExtractKuratowskis::extractMinorEBundles( - SList& output, - bool firstXPath, - bool firstYPath, - bool firstWPath, - bool firstWOnHighestXY, - NodeArray& nodeflags, - const int nodemarker, - const KuratowskiStructure& k, - EdgeArray& flags, - const WInfo& info, - const SListPure& pathX, - const node endnodeX, - const SListPure& pathY, - const node endnodeY, - const SListPure& pathW) -{ - // perform backtracking for each extern node z on the lower external face - OGDF_ASSERT(info.externEStart.valid() && info.externEEnd.valid()); - SListPure pathZ; - node z; - node endnodeZ; - int before = -1; // -1= before, 0=equal to wNode, 1=after - SListConstIterator itW; - SListConstIterator it; - node px = info.highestXYPath->front()->theNode(); - node py = info.highestXYPath->back()->theNode(); - DynamicBacktrack backtrackZ(m_g,m_dfi,flags); - - // mark all nodes of the single pathW in flags, so that pathW and - // the externalPath don't interfere later - for (itW = pathW.begin(); itW.valid(); ++itW) { - flags[*itW] |= DynamicBacktrack::singlePath; - nodeflags[(*itW)->source()] = nodemarker; - nodeflags[(*itW)->target()] = nodemarker; - } - - // consider only the nodes between px and py - for (it = info.externEStart; it.valid(); ++it) { - z = (*it).theNode; - - if (z == info.w) { - OGDF_ASSERT(z == pathW.back()->source() || z == pathW.back()->target()); - // z = wNode - before = 0; - - // minortype E2 on z=wNode - // on the first pathW: consider all pathsZ - if (!m_avoidE2Minors && firstWPath && firstWOnHighestXY) { - backtrackZ.init(z,k.V,true,DynamicBacktrack::externalPath, - DynamicBacktrack::externalPath,NULL,NULL); - while (backtrackZ.addNextPath(pathZ,endnodeZ)) { - if (m_dfi[endnodeZ] > m_dfi[endnodeX] && - m_dfi[endnodeZ] > m_dfi[endnodeY]) { - extractMinorE2(output,/*before,z,px,py,*/k,info,pathX, - endnodeX,pathY,endnodeY/*,pathW*/,pathZ/*,endnodeZ*/); - } - } - } - - backtrackZ.init(z,k.V,true,DynamicBacktrack::externalPath, - DynamicBacktrack::externalPath,NULL,NULL); - while (backtrackZ.addNextPathExclude(pathZ,endnodeZ, - nodeflags,nodemarker,DynamicBacktrack::singlePath)) { - // minortype E3 on z=wNode - if (endnodeX != endnodeY && (m_dfi[endnodeX] > m_dfi[endnodeZ] || - m_dfi[endnodeY] > m_dfi[endnodeZ])) { - extractMinorE3(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E4 on z=wNode - if ((px != k.stopX && !info.pxAboveStopX) || - (py != k.stopY && !info.pyAboveStopY)) { - extractMinorE4(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E5 (K5) - if (px == k.stopX && py == k.stopY && k.V == k.RReal && - ((endnodeX == endnodeY && m_dfi[endnodeZ] <= m_dfi[endnodeX]) || - (endnodeX == endnodeZ && m_dfi[endnodeY] <= m_dfi[endnodeX]) || - (endnodeY == endnodeZ && m_dfi[endnodeX] <= m_dfi[endnodeY]))) { - // instead of slower code: - //backtrackZ.init(z,k.V,true,DynamicBacktrack::externalPath, - // DynamicBacktrack::externalPath,NULL,pathW.back()); - //while (backtrackZ.addNextPathExclude(pathZ,endnodeZ,nodeflags,nodemarker,0)) { - if (pathZ.back() != pathW.back() && - (pathZ.back()->source() == z || pathZ.back()->target() == z)) { - extractMinorE5(output,/*before,z,px,py,*/k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - } - } - } else { - // z != wNode, check position of node z - if (z == info.firstExternEAfterW) before = 1; - OGDF_ASSERT(before != 0); - OGDF_ASSERT(z != pathW.back()->source() && z != pathW.back()->target()); - - backtrackZ.init(z,k.V,true,DynamicBacktrack::externalPath, - DynamicBacktrack::externalPath,NULL,NULL); - while (backtrackZ.addNextPath(pathZ,endnodeZ)) { - // split in minorE-subtypes - - // minortype E1 - if ((before == -1 && firstXPath) || (before == 1 && firstYPath)) { - extractMinorE1(output,before,/*z,*/px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E2 - if (!m_avoidE2Minors && firstWPath && firstWOnHighestXY - && m_dfi[endnodeZ] > m_dfi[endnodeX] - && m_dfi[endnodeZ] > m_dfi[endnodeY]) { - extractMinorE2(output,/*before,z,px,py,*/k,info,pathX, - endnodeX,pathY,endnodeY,/*pathW,*/pathZ/*,endnodeZ*/); - } - // minortype E3 - if (endnodeX != endnodeY && (m_dfi[endnodeX] > m_dfi[endnodeZ] || - m_dfi[endnodeY] > m_dfi[endnodeZ])) { - extractMinorE3(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - // minortype E4 - if ((px != k.stopX && !info.pxAboveStopX) || - (py != k.stopY && !info.pyAboveStopY)) { - extractMinorE4(output,before,z,px,py,k,info,pathX, - endnodeX,pathY,endnodeY,pathW,pathZ,endnodeZ); - } - } - } - - // check if last node was reached - if (it == info.externEEnd) break; - - // check, if we have found enough subdivisions - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - break; - } - - // delete marked single pathW - for (itW = pathW.begin(); itW.valid(); ++itW) { - flags[*itW] &= ~DynamicBacktrack::singlePath; - } -} - -// extracts all kuratowski subdivisions and adds them to output -void ExtractKuratowskis::extract( - const SListPure& allKuratowskis, - SList& output) -{ - SListConstIterator itAll; - SListConstIterator itInfo; - SListConstIterator itS; - SListConstIterator > itL; - - SListPure pathX,pathY; - node endnodeX,endnodeY; - adjEntry temp; - - SListConstIterator itXEndnode; - SListConstIterator itYEndnode; - SListConstIterator itXStartnode; - SListConstIterator itYStartnode; - - // consider all different kuratowski structures - for (itAll=allKuratowskis.begin(); itAll.valid(); ++itAll) { - const KuratowskiStructure& k(*itAll); - - // compute all possible external paths of stopX and stopY (pathX,pathY) - bool firstXPath = true; - itXStartnode = k.stopXStartnodes.begin(); - for (itXEndnode = k.stopXEndnodes.begin(); itXEndnode.valid(); ++itXEndnode) { - endnodeX = *itXEndnode; - pathX.clear(); - temp = adjToLowestNodeBelow(endnodeX,*(itXStartnode++)); - pathX.pushBack(temp->theEdge()); - addDFSPath(pathX,temp->theNode(),k.stopX); - - bool firstYPath = true; - itYStartnode = k.stopYStartnodes.begin(); - for (itYEndnode = k.stopYEndnodes.begin(); itYEndnode.valid(); ++itYEndnode) { - endnodeY = *itYEndnode; - pathY.clear(); - temp = adjToLowestNodeBelow(endnodeY,*(itYStartnode++)); - pathY.pushBack(temp->theEdge()); - addDFSPath(pathY,temp->theNode(),k.stopY); - - // if minor A occurs, other minortypes are possible with adding - // the dfs-path from node RReal to V - if (k.RReal != k.V) addDFSPath(pathY,k.RReal,k.V); - - // consider all possible wNodes - SListPure* oldHighestXYPath = NULL; - for (itInfo = k.wNodes.begin(); itInfo.valid(); ++itInfo) { - const WInfo& info(*itInfo); - - // compute all possible internal paths of this wNode - bool firstWPath = true; // avoid multiple identical subdivisions in E2 - for (itL = info.pertinentPaths.begin(); itL.valid(); ++itL) { - const SListPure& pathW(*itL); - OGDF_ASSERT(!pathX.empty() && !pathY.empty() && !pathW.empty()); - - // extract minor A - if (info.minorType & WInfo::A) - extractMinorA(output,k,/*info,*/pathX,endnodeX,pathY, - endnodeY,pathW); - - // extract minor B - if (info.minorType & WInfo::B) { - ++m_nodeMarker; - extractMinorB(output,/*m_wasHere,++m_nodeMarker,*/k, - info,pathX,endnodeX,pathY,endnodeY,pathW); - } - - // extract minor C - if (info.minorType & WInfo::C) - extractMinorC(output,k,info,pathX,endnodeX,pathY, - endnodeY,pathW); - - // extract minor D - if (info.minorType & WInfo::D) - extractMinorD(output,k,info,pathX,endnodeX,pathY, - endnodeY,pathW); - - // extract minor E including all subtypes - if (info.minorType & WInfo::E) { - extractMinorE(output,firstXPath,firstYPath,firstWPath, - oldHighestXYPath!=info.highestXYPath,k,info, - pathX,endnodeX,pathY,endnodeY,pathW); - } - - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - firstWPath = false; - // break; - } - oldHighestXYPath = info.highestXYPath; - } - firstYPath = false; - // break; - } - firstXPath = false; - // break; - } - } -} - -// extracts all kuratowski subdivisions and adds them to output -void ExtractKuratowskis::extractBundles( - const SListPure& allKuratowskis, - SList& output) -{ - SListConstIterator itAll; - SListConstIterator itInfo; - SListConstIterator itS; - - SListPure pathX,pathY,pathW; - node endnodeX,endnodeY; - - EdgeArray flags(m_g,0); - DynamicBacktrack backtrackX(m_g,m_dfi,flags); - DynamicBacktrack backtrackY(m_g,m_dfi,flags); - DynamicBacktrack backtrackW(m_g,m_dfi,flags); - - // consider all different kuratowski structures - for (itAll=allKuratowskis.begin(); itAll.valid(); ++itAll) { - const KuratowskiStructure& k(*itAll); - - // create pertinent and external flags - for (itS = k.pertinentSubgraph.begin(); itS.valid(); ++itS) - flags[*itS] |= DynamicBacktrack::pertinentPath; - for (itS = k.externalSubgraph.begin(); itS.valid(); ++itS) - flags[*itS] |= DynamicBacktrack::externalPath; - - // compute all possible external paths of stopX and stopY (pathX,pathY) - bool firstXPath = true; - backtrackX.init(k.stopX,k.V,true,DynamicBacktrack::externalPath, - DynamicBacktrack::externalPath,NULL,NULL); - while (backtrackX.addNextPath(pathX,endnodeX)) { - bool firstYPath = true; - backtrackY.init(k.stopY,k.V,true,DynamicBacktrack::externalPath, - DynamicBacktrack::externalPath,NULL,NULL); - while (backtrackY.addNextPath(pathY,endnodeY)) { - - // if minor A occurs, other minortypes are possible with adding - // the dfs-path from node RReal to V - if (k.RReal != k.V) addDFSPath(pathY,k.RReal,k.V); - - // consider all possible wNodes - SListPure* oldHighestXYPath = NULL; - for (itInfo = k.wNodes.begin(); itInfo.valid(); ++itInfo) { - const WInfo& info(*itInfo); - - // compute all possible internal paths of this wNode - bool firstWPath = true; // avoid multiple identical subdivisions in E2 - backtrackW.init(info.w,k.V,false,DynamicBacktrack::pertinentPath, - DynamicBacktrack::pertinentPath,NULL,NULL); - node dummy; - while (backtrackW.addNextPath(pathW,dummy)) { - OGDF_ASSERT(!pathX.empty() && !pathY.empty() && !pathW.empty()); - - // extract minor A - if (info.minorType & WInfo::A) - extractMinorA(output,k,/*info,*/pathX,endnodeX,pathY, - endnodeY,pathW); - - // extract minor B - if (info.minorType & WInfo::B) - extractMinorBBundles(output,m_wasHere,++m_nodeMarker,k,flags, - info,pathX,endnodeX,pathY,endnodeY,pathW); - - // extract minor C - if (info.minorType & WInfo::C) - extractMinorC(output,k,info,pathX,endnodeX,pathY, - endnodeY,pathW); - - // extract minor D - if (info.minorType & WInfo::D) - extractMinorD(output,k,info,pathX,endnodeX,pathY, - endnodeY,pathW); - - // extract minor E including all subtypes - if (info.minorType & WInfo::E) { - extractMinorEBundles(output,firstXPath,firstYPath,firstWPath, - oldHighestXYPath!=info.highestXYPath, - m_wasHere,++m_nodeMarker,k,flags,info, - pathX,endnodeX,pathY,endnodeY,pathW); - } - - if (m_embeddingGrade > BoyerMyrvoldPlanar::doFindUnlimited && - output.size() >= m_embeddingGrade) - return; - firstWPath = false; - // break; - } - oldHighestXYPath = info.highestXYPath; - } - firstYPath = false; - // break; - } - firstXPath = false; - // break; - } - - // delete pertinent and external flags - for (itS = k.pertinentSubgraph.begin(); itS.valid(); ++itS) - flags[*itS] = 0; - for (itS = k.externalSubgraph.begin(); itS.valid(); ++itS) - flags[*itS] = 0; - } -} - - -} diff --git a/ext/OGDF/src/planarity/FastPlanarSubgraph.cpp b/ext/OGDF/src/planarity/FastPlanarSubgraph.cpp deleted file mode 100644 index 965f0baa8..000000000 --- a/ext/OGDF/src/planarity/FastPlanarSubgraph.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the FastPlanarSubgraph. - * - * Class is derived from base class PlanarSubgraphModule - * and implements the interface for the Planarization algorithm - * based on PQ-trees. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf{ - -// Prepares the planarity test and the planar embedding -Module::ReturnType FastPlanarSubgraph::doCall( - const Graph &G, - const List & /*preferedEdges*/, - List &delEdges, - const EdgeArray *pCost, - bool /*preferedImplyPlanar*/) -{ - - delEdges.clear(); - - if (G.numberOfEdges() < 9) - return retOptimal; - - - node v; - NodeArray tableNodes(G,0); - EdgeArray tableEdges(G,0); - NodeArray mark(G,0); - - EdgeArray componentID(G); - - - // Determine Biconnected Components - int bcCount = biconnectedComponents(G,componentID); - - // Determine edges per biconnected component - Array > blockEdges(0,bcCount-1); - edge e; - forall_edges(e,G) - { - if (!e->isSelfLoop()) - blockEdges[componentID[e]].pushFront(e); - } - - // Determine nodes per biconnected component. - Array > blockNodes(0,bcCount-1); - int i; - for (i = 0; i < bcCount; i++) - { - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - if (!mark[e->source()]) - { - blockNodes[i].pushBack(e->source()); - mark[e->source()] = true; - } - if (!mark[e->target()]) - { - blockNodes[i].pushBack(e->target()); - mark[e->target()] = true; - } - } - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++itn) - mark[*itn] = false; - } - - - // Perform Planarization for every biconnected component - - if (bcCount == 1) { - if (G.numberOfEdges() > 4) - computeDelEdges(G,pCost,0,delEdges); - - } else { - for (i = 0; i < bcCount; i++) - { - Graph C; - - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - { - v = *itn; - node w = C.newNode(); - tableNodes[v] = w; - } - - - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - edge f = C.newEdge(tableNodes[e->source()],tableNodes[e->target()]); - tableEdges[e] = f; - } - - // Construct a translation table for the edges. - // Necessary, since edges are deleted in a new graph. - // that represents the biconnectedcomponent of the original graph. - EdgeArray backTableEdges(C,0); - for (it = blockEdges[i].begin(); it.valid(); ++it) - backTableEdges[tableEdges[*it]] = *it; - - // gets the deletec Edges of the biconnected component - List delEdgesOfBC; - - - if (C.numberOfEdges() > 4) - computeDelEdges(C,pCost,&backTableEdges,delEdgesOfBC); - - // get the original edges that are deleted and - // put them on the list delEdges. - while (!delEdgesOfBC.empty()) - delEdges.pushBack(backTableEdges[delEdgesOfBC.popFrontRet()]); - - } - } - - return retFeasible; -} - - -void FastPlanarSubgraph::computeDelEdges( - const Graph &G, - const EdgeArray *pCost, - const EdgeArray *backTableEdges, - List &delEdges) -{ - if (m_nRuns <= 0) - { - // Compute st-numbering - NodeArray numbering(G,0); - stNumber(G,numbering); - - planarize(G,numbering,delEdges); - - } else { - int bestSolution = INT_MAX; - - for(int i = 1; i <= m_nRuns && bestSolution > 1; ++i) - { - List currentDelEdges; - - // Compute (randomized) st-numbering - NodeArray numbering(G,0); - stNumber(G,numbering,0,0,true); - - planarize(G,numbering,currentDelEdges); - - if(pCost == 0) - { - int currentSolution = currentDelEdges.size(); - - if(currentSolution < bestSolution) { - bestSolution = currentSolution; - delEdges.clear(); - delEdges.conc(currentDelEdges); - } - - } else { - int currentSolution = 0; - ListConstIterator it; - for(it = currentDelEdges.begin(); it.valid(); ++it) - if(backTableEdges != 0) - currentSolution += (*pCost)[(*backTableEdges)[*it]]; - else - currentSolution += (*pCost)[*it]; - - if(currentSolution < bestSolution) { - bestSolution = currentSolution; - delEdges.clear(); - delEdges.conc(currentDelEdges); - - } - } - } - } -} - - - -// Performs a planarity test on a biconnected component -// of G. numbering contains an st-numbering of the component. -void FastPlanarSubgraph::planarize( - const Graph &G, - NodeArray &numbering, - List &delEdges) -{ - node v; - - NodeArray* > > inLeaves(G); - NodeArray* > > outLeaves(G); - Array table(G.numberOfNodes()+1); - - forall_nodes(v,G) - { - edge e; - forall_adj_edges(e,v) - { - if (numbering[e->opposite(v)] > numbering[v]) - // sideeffect: ignores selfloops - { - PlanarLeafKey* L = OGDF_NEW PlanarLeafKey(e); - inLeaves[v].pushFront(L); - } - } - table[numbering[v]] = v; - } - - forall_nodes(v,G) - { - SListIterator* > it; - for (it = inLeaves[v].begin(); it.valid(); ++it) - { - PlanarLeafKey* L = *it; - outLeaves[L->userStructKey()->opposite(v)].pushFront(L); - } - } - - SList*> totalEliminatedKeys; - - PlanarSubgraphPQTree T; - T.Initialize(inLeaves[table[1]]); - for (int i = 2; i < G.numberOfNodes(); i++) - { - SList*> eliminatedKeys; - T.Reduction(outLeaves[table[i]],eliminatedKeys); - - totalEliminatedKeys.conc(eliminatedKeys); - T.ReplaceRoot(inLeaves[table[i]]); - T.emptyAllPertinentNodes(); - } - - - SListIterator* > it; - for (it = totalEliminatedKeys.begin(); it.valid(); ++it) - { - edge e = (*it)->userStructKey(); - delEdges.pushBack(e); - } - - //cleanup - forall_nodes(v,G) - { - while (!inLeaves[v].empty()) - { - PlanarLeafKey* L = inLeaves[v].popFrontRet(); - delete L; - } - } - - T.Cleanup(); // Explicit call for destructor necessary. This allows to call virtual - // funtion CleanNode for freeing node information class. -} - - -} diff --git a/ext/OGDF/src/planarity/FindKuratowskis.cpp b/ext/OGDF/src/planarity/FindKuratowskis.cpp deleted file mode 100644 index e5a1c0fdf..000000000 --- a/ext/OGDF/src/planarity/FindKuratowskis.cpp +++ /dev/null @@ -1,790 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of the class FindKuratowskis - * - * \author Jens Schmidt - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - -// copy pointer of class Kuratowski -void KuratowskiStructure::copyPointer(const KuratowskiStructure& orig, SListPure& list) { - SListConstIterator > itHighOrig=orig.highestXYPaths.begin(); - SListIterator > itHigh=highestXYPaths.begin(); - SListConstIterator > itZOrig=orig.zPaths.begin(); - SListIterator > itZ=zPaths.begin(); - SListConstIterator itExternStartOrig=orig.externE.begin(); - SListIterator itExternStart=externE.begin(); - SListConstIterator itExternEndOrig=orig.externE.begin(); - SListIterator itExternEnd=externE.begin(); - SListIterator it; - for (it=list.begin(); it.valid(); ++it) { - WInfo& info(*it); - if (info.highestXYPath!=NULL) { - // go to referenced object - while (info.highestXYPath != &(*itHighOrig)) { - ++itHigh; - ++itHighOrig; - } - OGDF_ASSERT(itHigh.valid() && itHighOrig.valid()); - info.highestXYPath=&(*itHigh); - } - if (info.zPath!=NULL) { - // go to referenced object - while (info.zPath != &(*itZOrig)) { - ++itZ; - ++itZOrig; - } - OGDF_ASSERT(itZ.valid() && itZOrig.valid()); - info.zPath=&(*itZ); - } - if (info.externEStart.valid()) { - // go to referenced object - while ((*info.externEStart).theNode != (*itExternStartOrig).theNode) { - ++itExternStartOrig; - ++itExternStart; - } - OGDF_ASSERT(itExternStartOrig.valid() && itExternStart.valid()); - info.externEStart = itExternStart; - } - if (info.externEEnd.valid()) { - // go to referenced object - while ((*info.externEEnd).theNode != (*itExternEndOrig).theNode) { - ++itExternEndOrig; - ++itExternEnd; - } - OGDF_ASSERT(itExternEndOrig.valid() && itExternEnd.valid()); - info.externEEnd = itExternEnd; - } - } -} - -// copy class Kuratowski -void KuratowskiStructure::copy(const KuratowskiStructure& orig) { - V = orig.V; - V_DFI = orig.V_DFI; - R = orig.R; - RReal = orig.RReal; - stopX = orig.stopX; - stopY = orig.stopY; - - wNodes = orig.wNodes; - highestFacePath = orig.highestFacePath; - highestXYPaths = orig.highestXYPaths; - externalFacePath = orig.externalFacePath; - externalSubgraph = orig.externalSubgraph; - pertinentSubgraph = orig.pertinentSubgraph; - zPaths = orig.zPaths; - externE = orig.externE; - stopXStartnodes = orig.stopXStartnodes; - stopYStartnodes = orig.stopYStartnodes; - stopXEndnodes = orig.stopXEndnodes; - stopYEndnodes = orig.stopYEndnodes; - - // copy pointer - copyPointer(orig,wNodes); -} - - -// clears members -void KuratowskiStructure::clear() -{ - V=R=RReal=stopX=stopY=NULL; - V_DFI = 0; - wNodes.clear(); - highestFacePath.clear(); - highestXYPaths.clear(); - externalFacePath.clear(); - externalSubgraph.clear(); - pertinentSubgraph.clear(); - zPaths.clear(); - externE.clear(); - stopXStartnodes.clear(); - stopYStartnodes.clear(); - stopXEndnodes.clear(); - stopYEndnodes.clear(); -} - -// class FindKuratowski -FindKuratowskis::FindKuratowskis(BoyerMyrvoldPlanar* bm) : - pBM(bm), - m_g(bm->m_g), - m_embeddingGrade(bm->m_embeddingGrade), - - m_bundles(bm->m_bundles), - - // initialize Members of BoyerMyrvoldPlanar - m_realVertex(bm->m_realVertex), - m_dfi(bm->m_dfi), - m_nodeFromDFI(bm->m_nodeFromDFI), - m_link(bm->m_link), - m_adjParent(bm->m_adjParent), - m_leastAncestor(bm->m_leastAncestor), - m_edgeType(bm->m_edgeType), - m_lowPoint(bm->m_lowPoint), - m_highestSubtreeDFI(bm->m_highestSubtreeDFI), - m_separatedDFSChildList(bm->m_separatedDFSChildList), - m_pointsToRoot(bm->m_pointsToRoot), - m_visitedWithBackedge(bm->m_visitedWithBackedge), - m_backedgeFlags(bm->m_backedgeFlags), - m_pertinentRoots(bm->m_pertinentRoots) -{ - OGDF_ASSERT(bm != NULL); - m_nodeMarker = 0; -} - -// finds root node of the bicomp containing the stopping node stopX -node FindKuratowskis::findRoot(node stopX) { - int dir = CCW; - while (m_realVertex[stopX]==NULL) - stopX = pBM->successorWithoutShortCircuit(stopX,dir); - return stopX; -} - -// extracts highest face path (contains all highest xy-paths) -void FindKuratowskis::extractHighestFacePath( - ListPure& highestFacePath, - int marker) { - adjEntry adj = pBM->beforeShortCircuitEdge(k.R,CCW); - adjEntry end = pBM->beforeShortCircuitEdge(k.R,CW); - node x,target; - while (adj != end->twin()) { - x = adj->theNode(); - - if (m_wasHere[x] >= marker) { - // node is already visited on facepath: pop until duplicate node found - OGDF_ASSERT(!highestFacePath.empty()); - while (highestFacePath.back()->theNode()!=x) highestFacePath.popBack(); - // sign cut-vertex with marker+1 - m_wasHere[x] = marker+1; - } else { - highestFacePath.pushBack(adj); - // sign visited nodes with marker - m_wasHere[x] = marker; - } - - do { - adj = adj->cyclicSucc(); - target = adj->twinNode(); - if (target == k.R) m_wasHere[x] = marker+1; - } while (adj != end && - (m_edgeType[adj->theEdge()] == EDGE_BACK_DELETED || - m_dfi[target] <= m_dfi[k.R])); - adj = adj->twin(); - } -} - -// extract external facepath in direction CCW and split the highest facepath -// in highest xy-paths. marker marks the node, highMarker is used to check, -// whether the node was visited before by the highest facepath traversal. -// highMarker+1 identifies the nodes that are zNodes. -void FindKuratowskis::extractExternalFacePath( - SListPure& externalFacePath, - const ListPure& highestFacePath, - int marker, - int highMarker) -{ - int dir = CCW; - // x traverses the external facepath - node x = pBM->successorWithoutShortCircuit(k.R,dir); - externalFacePath.pushBack(pBM->beforeShortCircuitEdge(k.R,CCW)); - m_wasHere[k.R] = marker; - while (x != k.R) { - // set visited sign on nodes that are both on the highest and external facepath - if (m_wasHere[x]>=highMarker) m_wasHere[x] = marker; - externalFacePath.pushBack(pBM->beforeShortCircuitEdge(x,dir)); - x = pBM->successorWithoutShortCircuit(x,dir); - } - - dir = CCW; - x = pBM->successorWithoutShortCircuit(k.R,dir); - ListConstIterator highIt = highestFacePath.begin(); - OGDF_ASSERT(x == (*highIt)->theNode()); - SListPure XYPathList; - SListPure zList; - WInfo info; - adjEntry adj = pBM->beforeShortCircuitEdge(k.R,CCW); - adjEntry temp; - while (x != k.R) { - // go along the highest face path until next visited sign - OGDF_ASSERT(adj->theNode()==x); - if (m_wasHere[x] == marker) { - XYPathList.clear(); - zList.clear(); - info.w = NULL; - info.minorType = 0; - info.highestXYPath = NULL; - info.zPath = NULL; - info.pxAboveStopX = false; - info.pyAboveStopY = false; - info.externEStart = NULL; - info.externEEnd = NULL; - info.firstExternEAfterW = NULL; - } - - // push in wNodes-list - if (pBM->pertinent(x)) { - info.w = x; - k.wNodes.pushBack(info); - } - - // compute next highestXYPath - if (m_wasHere[x] == marker && - m_wasHere[pBM->constSuccessorWithoutShortCircuit(x,dir)] != marker) { - // traverse highFacePath to x - while ((*highIt)->theNode() != x) ++highIt; - OGDF_ASSERT(highIt.valid()); - XYPathList.pushBack(adj); - OGDF_ASSERT((*highIt.succ())->theNode() != - pBM->constSuccessorWithoutShortCircuit(x,dir)); - - // traverse highFacePath to next marker - do { - ++highIt; - if (!highIt.valid()) break; - temp = *highIt; - XYPathList.pushBack(temp); - // check, if node is z-node and push one single z-node - if (m_wasHere[temp->theNode()]==highMarker+1 && zList.empty()) - zList.pushBack(temp); - } while (m_wasHere[temp->theNode()] != marker); - - // save highestXY-Path - OGDF_ASSERT(!XYPathList.empty()); - k.highestXYPaths.pushBack(XYPathList); - info.highestXYPath = &k.highestXYPaths.back(); - - // compute path from zNode to V and save it - if (!zList.empty()) { - OGDF_ASSERT(zList.size()==1); // just one zNode for now - temp = zList.back(); - do { - do { - temp = temp->cyclicSucc(); - OGDF_ASSERT(m_dfi[temp->twinNode()]==m_dfi[k.R] || - m_dfi[temp->twinNode()]>=m_dfi[k.RReal]); - } while (m_edgeType[temp->theEdge()]==EDGE_BACK_DELETED); - temp = temp->twin(); - zList.pushBack(temp); - } while (temp->theNode() != k.R); - k.zPaths.pushBack(zList); - info.zPath = &k.zPaths.back(); - } - } - - // go on - adj = pBM->beforeShortCircuitEdge(x,dir); - x = pBM->successorWithoutShortCircuit(x,dir); - } -} - -// separate pertinent nodes in the lists of possible different minor-types -void FindKuratowskis::splitInMinorTypes( - const SListPure& externalFacePath, - int marker) -{ - // mark nodes, which are before stopX or behind stopY in CCW-traversal and add - // all extern nodes strictly between stopX and stopY to list - // externE for minor E (pertinent nodes are considered because of the - // position of z left or right of w) - SListConstIterator itExtern; - SListIterator it = k.wNodes.begin(); - node x; - bool between = false; - SListPure infoList; - SListIterator itList; - ExternE externEdummy; - // compute list of externE nodes - for (itExtern=externalFacePath.begin(); itExtern.valid(); ++itExtern) { - x = (*itExtern)->theNode(); - if (x==k.stopX || x==k.stopY) { - between = (between==false) ? true : false; - } else { - if (!between) { - m_wasHere[x]=marker; - } else { - if (pBM->externallyActive(x,k.V_DFI)) { - externEdummy.theNode = x; - - // check minor type B and save extern linkage - if (it.valid() && (*it).w==x && - !m_pertinentRoots[x].empty() && - m_lowPoint[m_nodeFromDFI[-m_dfi[m_pertinentRoots[x].back()]]] - < k.V_DFI) { - WInfo& info(*it); - - // checking minor type B - info.minorType |= WInfo::B; - // mark extern node for later extraction - externEdummy.startnodes.pushBack(0); - // create externE-list - k.externE.pushBack(externEdummy); - // save extern linkage - info.externEStart = k.externE.rbegin(); - info.externEEnd = k.externE.rbegin(); - } else { - // create externE-list - externEdummy.startnodes.clear(); - k.externE.pushBack(externEdummy); - } - - // save for each wNode the first externally active successor - // on the external face - for (itList = infoList.begin(); itList.valid(); ++itList) - (*itList)->firstExternEAfterW = x; - infoList.clear(); - - - } - - // get appropriate WInfo - if (it.valid() && (*it).w==x) { - infoList.pushBack(&(*it)); - ++it; - } - } - } - } - - // divide wNodes in different minor types - // avoids multiple computation of the externE range - itExtern = externalFacePath.begin(); - SListIterator itExternE = k.externE.begin(); - WInfo* oldInfo = NULL; - for (it=k.wNodes.begin(); it.valid(); ++it) { - WInfo& info(*it); - - // checking minor type A - if (k.RReal!=k.V) info.minorType |= WInfo::A; - - // if a XYPath exists - if (info.highestXYPath!=NULL) { - if (m_wasHere[info.highestXYPath->front()->theNode()]==marker) - info.pxAboveStopX = true; - if (m_wasHere[info.highestXYPath->back()->theNode()]==marker) - info.pyAboveStopY = true; - - // checking minor type C - if (info.pxAboveStopX || info.pyAboveStopY) - info.minorType |= WInfo::C; - - // checking minor type D - if (info.zPath!=NULL) info.minorType |= WInfo::D; - - // checking minor type E - if (!k.externE.empty()) { - node t; - - // compute valid range of externE-nodes in linear time - if (oldInfo!=NULL && info.highestXYPath==oldInfo->highestXYPath) { - // found the same highestXYPath as before - info.externEStart = oldInfo->externEStart; - info.externEEnd = oldInfo->externEEnd; - if (oldInfo->minorType & WInfo::E) info.minorType |= WInfo::E; - } else { - // compute range of a new highestXYPath - node px; - if (info.pxAboveStopX) px = k.stopX; - else px = info.highestXYPath->front()->theNode(); - node py; - if (info.pyAboveStopY) py = k.stopY; - else py = info.highestXYPath->back()->theNode(); - while ((*itExtern)->theNode() != px) ++itExtern; - t = (*(++itExtern))->theNode(); - node start = NULL; - node end = NULL; - while (t != py) { - if (pBM->externallyActive(t,k.V_DFI)) { - if (start==NULL) start = t; - end = t; - } - t = (*(++itExtern))->theNode(); - } - if (start != NULL) { - while ((*itExternE).theNode != start) ++itExternE; - info.externEStart = itExternE; - // mark node to extract external subgraph later - (*itExternE).startnodes.pushBack(0); - node temp = start; - while (temp != end) { - temp = (*++itExternE).theNode; - // mark node to extract external subgraph later - (*itExternE).startnodes.pushBack(0); - } - info.externEEnd = itExternE; - info.minorType |= WInfo::E; - } - oldInfo = &info; - } - } - } - - /* - // use this to find special kuratowski-structures - if ((info.minorType & (WInfo::A|WInfo::B|WInfo::C|WInfo::D|WInfo::E)) == - (WInfo::A|WInfo::B|WInfo::C|WInfo::D|WInfo::E)) { - char t; cin >> t; - } - */ - } - - // extract the externalSubgraph of all saved externally active nodes - // exclude the already extracted minor b-types - #ifdef OGDF_DEBUG - int visited = m_nodeMarker+1; - #endif - for (itExternE=k.externE.begin(); itExternE.valid(); ++itExternE) { - if ((*itExternE).startnodes.empty()) continue; - - ExternE& externE(*itExternE); - externE.startnodes.clear(); - if (m_bundles) { - OGDF_ASSERT(m_wasHere[externE.theNode] < visited); - extractExternalSubgraphBundles(externE.theNode,k.V_DFI, - k.externalSubgraph,++m_nodeMarker); - } else { - extractExternalSubgraph(externE.theNode,k.V_DFI,externE.startnodes, - externE.endnodes); - SListIterator itInt; - SListPure dummy; - for (itInt = externE.startnodes.begin(); itInt.valid(); ++itInt) - externE.externalPaths.pushBack(dummy); - } - } -} - -// extracts and adds external subgraph from stopnode to ancestors of the node with dfi root -// to edgelist, nodeMarker is used as a visited flag. returns the endnode with lowest dfi. -void FindKuratowskis::extractExternalSubgraph( - const node stop, - int root, - SListPure& externalStartnodes, - SListPure& externalEndnodes) -{ - int lowpoint; - ListConstIterator it; - - if (m_leastAncestor[stop] < root) { - externalStartnodes.pushBack(m_dfi[stop]); - externalEndnodes.pushBack(m_nodeFromDFI[m_leastAncestor[stop]]); - } - - // descent to external active child bicomps of stopnode - node temp; - for (it = m_separatedDFSChildList[stop].begin(); it.valid(); ++it) { - temp = *it; - lowpoint = m_lowPoint[temp]; - if (lowpoint >= root) break; - - externalStartnodes.pushBack(m_dfi[temp]); - externalEndnodes.pushBack(m_nodeFromDFI[lowpoint]); - } -} - -// extract and add external subgraph from stopnode to ancestors of the node with dfi root -// to edgelist, nodeMarker is used as a visited flag. returns the endnode with lowest dfi. -void FindKuratowskis::extractExternalSubgraphBundles( - const node stop, - int root, - SListPure& externalSubgraph, - int nodeMarker) -{ - node v,temp; - adjEntry adj; - - #ifdef OGDF_DEBUG - forall_nodes(v,m_g) OGDF_ASSERT(m_wasHere[v]!=nodeMarker); - #endif - - StackPure stack; // stack for dfs-traversal - ListConstIterator it; - stack.push(stop); - while (!stack.empty()) { - v = stack.pop(); - if (m_wasHere[v]==nodeMarker) continue; - // mark visited nodes - m_wasHere[v]=nodeMarker; - - // search for unvisited nodes and add them to stack - forall_adj(adj,v) { - temp = adj->twinNode(); - if (m_edgeType[adj->theEdge()]==EDGE_BACK_DELETED) continue; - - // go along backedges to ancestor (ignore virtual nodes) - if (m_dfi[temp] < root && m_dfi[temp] > 0) { - OGDF_ASSERT(m_edgeType[adj->theEdge()]==EDGE_BACK); - externalSubgraph.pushBack(adj->theEdge()); - } else if (v != stop && m_dfi[temp]>=m_dfi[v]) { - // set flag and push unvisited nodes - OGDF_ASSERT(m_edgeType[adj->theEdge()]==EDGE_BACK || - m_edgeType[adj->theEdge()]==EDGE_DFS || - m_edgeType[adj->theEdge()]==EDGE_BACK_DELETED); - externalSubgraph.pushBack(adj->theEdge()); - if (m_wasHere[temp] != nodeMarker) stack.push(temp); - } - } - - // descent to external active child bicomps - for (it = m_separatedDFSChildList[v].begin(); it.valid(); ++it) { - temp = *it; - if (m_lowPoint[temp] >= root) break; - stack.push(m_nodeFromDFI[-m_dfi[temp]]); - } - } -} - -// extract pertinent paths from all w-nodes to k.V to edgelist -void FindKuratowskis::extractPertinentSubgraph( - SListPure& W_All/*, - const node V*/) -{ - SListPure path; - SListIterator it; - adjEntry adj; - int minDFI = -m_dfi[k.R]; - int maxDFI = m_highestSubtreeDFI[m_nodeFromDFI[minDFI]]; - int targetDFI; - node target; - edge e; - - // create links from pertinent nodes to WInfo - for (it = W_All.begin(); it.valid(); ++it) - m_getWInfo[(*it).w] = &(*it); - - // add all pertinent paths to WInfo - forall_adj(adj,k.V) { - if (m_edgeType[adj->theEdge()]==EDGE_BACK_DELETED) continue; - targetDFI = m_dfi[adj->twinNode()]; - if (targetDFI >= minDFI && targetDFI <= maxDFI) { - // target node is in subtree of a pertinent node - - // delete last edge and backedgeFlags - target = adj->twinNode(); - e = adj->theEdge(); - path.pushFront(e); - OGDF_ASSERT(!m_backedgeFlags[target].empty()); - m_backedgeFlags[target].clear(); - m_edgeType[e] = EDGE_BACK_DELETED; - // delete backedge-counter on virtual root node - --m_visitedWithBackedge[m_pointsToRoot[e]]; - OGDF_ASSERT(m_visitedWithBackedge[m_pointsToRoot[e]] >= 0); - - // go up along the DFS-path - while (m_getWInfo[target] == NULL) { - path.pushFront(m_adjParent[target]->theEdge()); - target = m_adjParent[target]->theNode(); - if (m_realVertex[target] != NULL) { - target = m_realVertex[target]; - m_pertinentRoots[target].clear(); - } - } - - // save path - m_getWInfo[target]->pertinentPaths.pushBack(path); - path.clear(); - } - } - - // delete links from pertinent nodes to WInfo - for (it = W_All.begin(); it.valid(); ++it) - m_getWInfo[(*it).w] = NULL; -} - - -// extract and add pertinent subgraph from all w-nodes to v to edgelist -void FindKuratowskis::extractPertinentSubgraphBundles( - const SListPure& W_All, - const node V, - SListPure& pertinentSubgraph, - int nodeMarker) -{ - node w,x; - adjEntry adj; - edge e; - - #ifdef OGDF_DEBUG - forall_nodes(w,m_g) OGDF_ASSERT(m_wasHere[w]!=nodeMarker); - #endif - - StackPure stack; // stack for dfs-traversal - SListIterator it; - SListConstIterator itt; - // for all w-nodes - for (itt = W_All.begin(); itt.valid(); ++itt) { - node currentWNode = (*itt).w; - stack.push(currentWNode); - - // until stack is empty, do dfs-traversal in bicomps and descent to - // pertinent child bicomps - while (!stack.empty()) { - w = stack.pop(); - if (m_wasHere[w]==nodeMarker) continue; - // mark visited nodes - m_wasHere[w]=nodeMarker; - - // search for unvisited nodes and add them to stack - forall_adj(adj,w) { - e = adj->theEdge(); - if (m_edgeType[e]==EDGE_BACK_DELETED) continue; - x = adj->twinNode(); - - // go along pertinent backedges to V (ignore virtual nodes) - if (x==V && m_edgeType[e]!=EDGE_BACK_DELETED) { - OGDF_ASSERT(m_edgeType[e]==EDGE_BACK); - // delete edge and delete backedgeFlags - m_edgeType[e] = EDGE_BACK_DELETED; - m_backedgeFlags[w].clear(); - // delete backedge-counter on virtual root node - --m_visitedWithBackedge[m_pointsToRoot[e]]; - OGDF_ASSERT(m_visitedWithBackedge[m_pointsToRoot[e]]>=0); - pertinentSubgraph.pushBack(e); - - } else if (w != currentWNode && m_dfi[x] >= m_dfi[w]) { - OGDF_ASSERT(m_edgeType[adj->theEdge()]==EDGE_DFS || - m_edgeType[adj->theEdge()]==EDGE_BACK || - m_edgeType[adj->theEdge()]==EDGE_BACK_DELETED); - // set flag and push unvisited nodes - pertinentSubgraph.pushBack(e); - if (m_wasHere[x] != nodeMarker) stack.push(x); - } - } - - // descent to pertinent child bicomps - for (it = m_pertinentRoots[w].begin(); it.valid(); ++it) { - stack.push(*it); - } - // delete all pertinentRoots-lists, since there are no pertinent backedges any more - m_pertinentRoots[w].clear(); - } - } -} - -// add Kuratowski structure on current node V -void FindKuratowskis::addKuratowskiStructure( - const node currentNode, - const node root, - const node stopx, - const node stopy) -{ - OGDF_ASSERT(currentNode!=NULL && root!=NULL && stopx!=NULL && stopy!=NULL); - OGDF_ASSERT(stopx!=stopy && currentNode!=stopx && currentNode!=stopy && m_dfi[root]<0); - OGDF_ASSERT(!pBM->pertinent(stopx) && - pBM->externallyActive(stopx,m_dfi[currentNode])); - OGDF_ASSERT(!pBM->pertinent(stopy) && - pBM->externallyActive(stopy,m_dfi[currentNode])); - OGDF_ASSERT(findRoot(stopx)==root); // check root - OGDF_ASSERT(pBM->wNodesExist(root,stopx,stopy)); - OGDF_ASSERT(isSimpleUndirected(m_g)); // Graph has to be simple - OGDF_ASSERT(m_embeddingGrade > BoyerMyrvoldPlanar::doNotFind); - // check, if we have found enough kuratowski structures - OGDF_ASSERT(m_embeddingGrade <= 0 || allKuratowskis.size() < m_embeddingGrade); - - // init NodeArrays in first invocation - if (!m_wasHere.valid()) { - if (!m_bundles) { - OGDF_ASSERT(!m_getWInfo.valid() && m_getWInfo.graphOf()==NULL); - m_getWInfo.init(m_g,NULL); - } - OGDF_ASSERT(m_wasHere.graphOf()==NULL); - m_wasHere.init(m_g,0); - } - - // delete old KuratowskiStruture and initialize new structure - k.clear(); - k.V = currentNode; - k.V_DFI = m_dfi[currentNode]; - k.stopX = stopx; - k.stopY = stopy; - k.R = root; - k.RReal = m_realVertex[k.R]; - - // flip bicomp with root R with or without reversed flipping. changes the embedding - // process completely. - pBM->flipBicomp(-m_dfi[k.R],++m_nodeMarker,m_wasHere,false,true); - // pBM->flipBicomp(-m_dfi[k.R],++m_nodeMarker,m_wasHere,false,false); - - // extract highest facepath (contains all highest xy-paths) - extractHighestFacePath(k.highestFacePath,++m_nodeMarker); - ++m_nodeMarker; - - // extract external facepath in direction CCW and split the highest facepath in - // highest xy-paths - ++m_nodeMarker; - extractExternalFacePath(k.externalFacePath,k.highestFacePath,m_nodeMarker, - m_nodeMarker-2); - - // extract external subgraph from stopX and stopY to ancestors of R - if (m_bundles) { - extractExternalSubgraphBundles(k.stopX,k.V_DFI,k.externalSubgraph,++m_nodeMarker); - } else { - extractExternalSubgraph(k.stopX,k.V_DFI,k.stopXStartnodes,k.stopXEndnodes); - } - - if (m_bundles) { - extractExternalSubgraphBundles(k.stopY,k.V_DFI,k.externalSubgraph,++m_nodeMarker); - } else { - extractExternalSubgraph(k.stopY,k.V_DFI,k.stopYStartnodes,k.stopYEndnodes); - } - - // pass pertinent nodes in the lists of possible different minor-types - splitInMinorTypes(k.externalFacePath,++m_nodeMarker); - - // extract pertinent subgraphs from all w-nodes to k.V - if (m_bundles) { - extractPertinentSubgraphBundles(k.wNodes,k.V,k.pertinentSubgraph,++m_nodeMarker); - } else { - extractPertinentSubgraph(k.wNodes/*,k.V*/); - } - - // add Kuratowski to KuratowskisOnNode - allKuratowskis.pushBack(k); - - // reverse flipping -// pBM->flipBicomp(-m_dfi[k.R],++m_nodeMarker,m_wasHere,false,false); - - OGDF_ASSERT(m_bundles || k.pertinentSubgraph.empty()); -} - - -} diff --git a/ext/OGDF/src/planarity/FixedEmbeddingInserter.cpp b/ext/OGDF/src/planarity/FixedEmbeddingInserter.cpp deleted file mode 100644 index a944116e9..000000000 --- a/ext/OGDF/src/planarity/FixedEmbeddingInserter.cpp +++ /dev/null @@ -1,862 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of FixedEmbeddingInserter class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// constructor -// sets default values for options -// -FixedEmbeddingInserter::FixedEmbeddingInserter() -{ - m_rrOption = rrNone; - m_percentMostCrossed = 25; - m_keepEmbedding = false; - m_runsPostprocessing = 0; -} - - -//--------------------------------------------------------- -// FEICrossingsBucket -// bucket function for sorting edges by decreasing number -// of crossings -class FEICrossingsBucket : public BucketFunc -{ - const PlanRep *m_pPG; - -public: - FEICrossingsBucket(const PlanRep *pPG) : - m_pPG(pPG) { } - - int getBucket(const edge &e) { - return -m_pPG->chain(e).size(); - } -}; - - - -//--------------------------------------------------------- -// actual call (called by all variations of call) -// crossing of generalizations is forbidden if forbidCrossingGens = true -// edge costs are obeyed if costOrig != 0 -// -Module::ReturnType FixedEmbeddingInserter::doCall( - PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig, - const EdgeArray *edgeSubGraph) -{ - - double T; - usedTime(T); - - ReturnType retValue = retFeasible; - m_runsPostprocessing = 0; - - if(!m_keepEmbedding) PG.embed(); - OGDF_ASSERT(PG.representsCombEmbedding() == true); - - if (origEdges.size() == 0) - return retOptimal; // nothing to do - - // initialization - CombinatorialEmbedding E(PG); // embedding of PG - - m_dual.clear(); - m_primalAdj.init(m_dual); - m_nodeOf.init(E); - - // construct dual graph - m_primalIsGen.init(m_dual,false); - - OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0); - - if(forbidCrossingGens) - constructDualForbidCrossingGens((const PlanRepUML&)PG,E); - else - constructDual(PG,E,forbiddenEdgeOrig); - - // m_delFaces and m_newFaces are used by removeEdge() - // if we can't allocate memory for them, we throw an exception - if (removeReinsert() != rrNone) { - m_delFaces = new FaceSetSimple(E); - if (m_delFaces == 0) - OGDF_THROW(InsufficientMemoryException); - - m_newFaces = new FaceSetPure(E); - if (m_newFaces == 0) { - delete m_delFaces; - OGDF_THROW(InsufficientMemoryException); - } - - // no postprocessing -> no removeEdge() - } else { - m_delFaces = 0; - m_newFaces = 0; - } - - SListPure currentOrigEdges; - if(removeReinsert() == rrIncremental) { - edge e; - forall_edges(e,PG) - currentOrigEdges.pushBack(PG.original(e)); - } - - // insertion of edges - ListConstIterator it; - for(it = origEdges.begin(); it.valid(); ++it) - { - edge eOrig = *it; - - int eSubGraph = 0; // edgeSubGraph-data of eOrig - if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig]; - - SList crossed; - if(costOrig != 0) { - findShortestPath(PG, E, *costOrig, - PG.copy(eOrig->source()),PG.copy(eOrig->target()), - forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, - crossed, edgeSubGraph, eSubGraph); - } else { - findShortestPath(E, - PG.copy(eOrig->source()),PG.copy(eOrig->target()), - forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, - crossed); - } - - insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig); - - if(removeReinsert() == rrIncremental || removeReinsert() == rrIncInserted) { - currentOrigEdges.pushBack(eOrig); - - bool improved; - do { - ++m_runsPostprocessing; - improved = false; - - SListConstIterator itRR; - for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR) - { - edge eOrigRR = *itRR; - - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph); - else - pathLength = PG.chain(eOrigRR).size() - 1; - if (pathLength == 0) continue; // cannot improve - - removeEdge(PG,E,eOrigRR,forbidCrossingGens,forbiddenEdgeOrig); - - // try to find a better insertion path - SList crossed; - if(costOrig != 0) { - int eSubGraph = 0; // edgeSubGraph-data of eOrig - if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrigRR]; - - findShortestPath(PG, E, *costOrig, - PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()), - forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association, - crossed, edgeSubGraph, eSubGraph); - } else { - findShortestPath(E, - PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()), - forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association, - crossed); - } - - // re-insert edge (insertion path cannot be longer) - insertEdge(PG,E,eOrigRR,crossed,forbidCrossingGens,forbiddenEdgeOrig); - - int newPathLength = (costOrig != 0) ? costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrigRR).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - } - } - - const Graph &G = PG.original(); - if(removeReinsert() != rrIncremental && removeReinsert() != rrIncInserted) { - // postprocessing (remove-reinsert heuristc) - SListPure rrEdges; - - switch(removeReinsert()) - { - case rrAll: - case rrMostCrossed: { - const List &origInCC = PG.nodesInCC(); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - rrEdges.pushBack(eG); - } - } - } - break; - - case rrInserted: - for(ListConstIterator it = origEdges.begin(); it.valid(); ++it) - rrEdges.pushBack(*it); - break; - - case rrNone: - case rrIncremental: - case rrIncInserted: - break; - } - - // marks the end of the interval of rrEdges over which we iterate - // initially set to invalid iterator which means all edges - SListConstIterator itStop; - - bool improved; - do { - // abort postprocessing if time limit reached - if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) { - retValue = retTimeoutFeasible; - break; - } - - ++m_runsPostprocessing; - improved = false; - - if(removeReinsert() == rrMostCrossed) - { - FEICrossingsBucket bucket(&PG); - rrEdges.bucketSort(bucket); - - const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); - itStop = rrEdges.get(num); - } - - SListConstIterator it; - for(it = rrEdges.begin(); it != itStop; ++it) - { - edge eOrig = *it; - - // remove only if crossings on edge; - // in especially: forbidden edges are never handled by postprocessing - // since there are no crossings on such edges - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrig,PG,*costOrig,edgeSubGraph); - else - pathLength = PG.chain(eOrig).size() - 1; - if (pathLength == 0) continue; // cannot improve - - removeEdge(PG,E,eOrig,forbidCrossingGens,forbiddenEdgeOrig); - - // try to find a better insertion path - SList crossed; - if(costOrig != 0) { - int eSubGraph = 0; // edgeSubGraph-data of eOrig - if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig]; - - findShortestPath(PG, E, *costOrig, - PG.copy(eOrig->source()),PG.copy(eOrig->target()), - forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, - crossed, edgeSubGraph, eSubGraph); - } else { - findShortestPath(E, - PG.copy(eOrig->source()),PG.copy(eOrig->target()), - forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, - crossed); - } - - // re-insert edge (insertion path cannot be longer) - insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig); - - int newPathLength = (costOrig != 0) ? costCrossed(eOrig,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrig).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while(improved); // iterate as long as we improve - } - - // verify computed planarization - OGDF_ASSERT(PG.representsCombEmbedding()); - OGDF_ASSERT(forbidCrossingGens == false || checkCrossingGens((const PlanRepUML&)PG) == true); - - // free resources - delete m_newFaces; - delete m_delFaces; - - m_primalIsGen.init(); - m_nodeOf.init(); - m_primalAdj.init(); - m_dual.clear(); - - return retValue; -} - -edge FixedEmbeddingInserter::crossedEdge(adjEntry adj) const -{ - edge e = adj->theEdge(); - - adj = adj->cyclicSucc(); - while(adj->theEdge() == e) - adj = adj->cyclicSucc(); - - return adj->theEdge(); -} - - -int FixedEmbeddingInserter::costCrossed(edge eOrig, - const PlanRep &PG, - const EdgeArray &costOrig, - const EdgeArray *subgraphs) const -{ - int c = 0; - - const List &L = PG.chain(eOrig); - - ListConstIterator it = L.begin(); - for(++it; it.valid(); ++it) { - edge e = PG.original(crossedEdge((*it)->adjSource())); - if(subgraphs!=0) { - int subgraphCounter = 0; - for(int i=0; i<32; i++) - if((((*subgraphs)[e] & (1<theEdge()) == Graph::generalization) - m_primalIsGen[e] = true; - } - } - - // Augment the dual graph by two new vertices. These are used temporarily - // when searching for a shortest path in the dual graph. - m_vS = m_dual.newNode(); - m_vT = m_dual.newNode(); -} - - - -//--------------------------------------------------------- -// construct dual graph -// assumes that m_pDual, m_primalAdj and m_nodeOf are already constructed -// -void FixedEmbeddingInserter::constructDual( - const GraphCopy &GC, - const CombinatorialEmbedding &E, - const EdgeArray *forbiddenEdgeOrig) -{ - // insert a node in the dual graph for each face in E - face f; - forall_faces(f,E) - m_nodeOf[f] = m_dual.newNode(); - - - // Insert an edge into the dual graph for each adjacency entry in E. - // The edges are directed from the left face to the right face. - node v; - forall_nodes(v,GC) - { - adjEntry adj; - forall_adj(adj,v) - { - // Do not insert edges into dual if crossing the original edge - // is forbidden - if(forbiddenEdgeOrig && (*forbiddenEdgeOrig)[GC.original(adj->theEdge())] == true) - continue; - - node vLeft = m_nodeOf[E.leftFace (adj)]; - node vRight = m_nodeOf[E.rightFace(adj)]; - - m_primalAdj[m_dual.newEdge(vLeft,vRight)] = adj; - } - } - - // Augment the dual graph by two new vertices. These are used temporarily - // when searching for a shortest path in the dual graph. - m_vS = m_dual.newNode(); - m_vT = m_dual.newNode(); -} - - - -//--------------------------------------------------------- -// finds a shortest path in the dual graph augmented by s and t (represented -// by m_vS and m_vT); returns list of crossed adjacency entries (corresponding -// to used edges in the dual) in crossed. -// -void FixedEmbeddingInserter::findShortestPath( - const CombinatorialEmbedding &E, - node s, - node t, - Graph::EdgeType eType, - SList &crossed) -{ - OGDF_ASSERT(s != t); - - NodeArray spPred(m_dual,0); - QueuePure queue; - int oldIdCount = m_dual.maxEdgeIndex(); - - // augment dual by edges from s to all adjacent faces of s ... - adjEntry adj; - forall_adj(adj,s) { - // starting edges of bfs-search are all edges leaving s - edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]); - m_primalAdj[eDual] = adj; - queue.append(eDual); - } - - // ... and from all adjacent faces of t to t - forall_adj(adj,t) { - edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT); - m_primalAdj[eDual] = adj; - } - - // actual search (using bfs on directed dual) - for( ; ;) - { - // next candidate edge - edge eCand = queue.pop(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == m_vT) - { - // ... then search is done. - // constructed list of used edges (translated to crossed - // adjacency entries in PG) from t back to s (including first - // and last!) - - do { - edge eDual = spPred[v]; - crossed.pushFront(m_primalAdj[eDual]); - v = eDual->source(); - } while(v != m_vS); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if (v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - queue.append(e); - } - } - } - } - - - // remove augmented edges again - while ((adj = m_vS->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - while ((adj = m_vT->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - m_dual.resetEdgeIdCount(oldIdCount); -} - - - -inline int getCost(const PlanRep &PG, const EdgeArray &cost, edge e, const EdgeArray *edgeSubGraph, int stSubGraph) -{ - edge eOrig = PG.original(e); - if(edgeSubGraph==0) - return (eOrig == 0) ? 0 : cost[eOrig]; - - int edgeCost = 0; - if(eOrig!=0) { - for(int i=0; i<32; i++) { - if((((*edgeSubGraph)[eOrig] & (1 << i)) != 0) && ((stSubGraph & (1 << i)) != 0)) - edgeCost++; - } - edgeCost *= cost[eOrig]; - edgeCost *= 10000; - if(edgeCost == 0) - edgeCost = 1; - } - return edgeCost; -} - - -//--------------------------------------------------------- -// finds a weighted shortest path in the dual graph augmented by s and t -// (represented by m_vS and m_vT) using edges weights given by costOrig; -// returns list of crossed adjacency entries (corresponding -// to used edges in the dual) in crossed. -// -// running time: O(|dual| + L + C), -// where L ist the weighted length of the insertion path and C the -// maximum cost of an edge -// -void FixedEmbeddingInserter::findShortestPath( - const PlanRep &PG, - const CombinatorialEmbedding &E, - const EdgeArray &costOrig, - node s, - node t, - Graph::EdgeType eType, - SList &crossed, - const EdgeArray *edgeSubGraph, - int eSubGraph) -{ - - OGDF_ASSERT(s != t); - - EdgeArray costDual(m_dual, 0); - int maxCost = 0; - edge eDual; - forall_edges(eDual, m_dual) { - int c = getCost(PG,costOrig, m_primalAdj[eDual]->theEdge(), edgeSubGraph, eSubGraph); - costDual[eDual] = c; - if (c > maxCost) - maxCost = c; - } - - ++maxCost; - Array > nodesAtDist(maxCost); - - NodeArray spPred(m_dual,0); - - int oldIdCount = m_dual.maxEdgeIndex(); - - // augment dual by edges from s to all adjacent faces of s ... - adjEntry adj; - forall_adj(adj,s) { - // starting edges of bfs-search are all edges leaving s - edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]); - m_primalAdj[eDual] = adj; - nodesAtDist[0].pushBack(eDual); - } - - // ... and from all adjacent faces of t to t - forall_adj(adj,t) { - edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT); - m_primalAdj[eDual] = adj; - } - - // actual search (using extended bfs on directed dual) - int currentDist = 0; - - for( ; ; ) - { - // next candidate edge - while(nodesAtDist[currentDist % maxCost].empty()) - ++currentDist; - - edge eCand = nodesAtDist[currentDist % maxCost].popFrontRet(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == m_vT) - { - // ... then search is done. - // constructed list of used edges (translated to crossed - // adjacency entries in PG) from t back to s (including first - // and last!) - - do { - edge eDual = spPred[v]; - crossed.pushFront(m_primalAdj[eDual]); - v = eDual->source(); - } while(v != m_vS); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if (v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - int listPos = (currentDist + costDual[e]) % maxCost; - nodesAtDist[listPos].pushBack(e); - } - } - } - } - - - // remove augmented edges again - while ((adj = m_vS->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - while ((adj = m_vT->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - m_dual.resetEdgeIdCount(oldIdCount); -} - - - -//--------------------------------------------------------- -// inserts edge e according to insertion path crossed. -// updates embeding and dual graph -// -void FixedEmbeddingInserter::insertEdge( - PlanRep &PG, - CombinatorialEmbedding &E, - edge eOrig, - const SList &crossed, - bool forbidCrossingGens, - const EdgeArray *forbiddenEdgeOrig) -{ - // remove dual nodes on insertion path - SListConstIterator it; - for(it = crossed.begin(); it != crossed.rbegin(); ++it) { - m_dual.delNode(m_nodeOf[E.rightFace(*it)]); - } - - // update primal - PG.insertEdgePathEmbedded(eOrig,E,crossed); - - - // insert new face nodes into dual - const List &path = PG.chain(eOrig); - ListConstIterator itEdge; - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adj = (*itEdge)->adjSource(); - m_nodeOf[E.leftFace (adj)] = m_dual.newNode(); - m_nodeOf[E.rightFace(adj)] = m_dual.newNode(); - } - - // insert new edges into dual - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adjSrc = (*itEdge)->adjSource(); - face f = E.rightFace(adjSrc); // face to the right of adj in loop - node vRight = m_nodeOf[f]; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - if(forbiddenEdgeOrig && (*forbiddenEdgeOrig)[PG.original(adj->theEdge())] == true) - continue; - - node vLeft = m_nodeOf[E.leftFace(adj)]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_primalAdj[eLR] = adj; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_primalAdj[eRL] = adj->twin(); - - if(forbidCrossingGens && - ((const PlanRepUML&)PG).typeOf(adj->theEdge()) == Graph::generalization) - { - m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - - // the other face adjacent to *itEdge ... - f = E.rightFace(adjSrc->twin()); - vRight = m_nodeOf[f]; - - adj1 = f->firstAdj(); - adj = adj1; - do { - if(forbiddenEdgeOrig && (*forbiddenEdgeOrig)[PG.original(adj->theEdge())] == true) - continue; - - node vLeft = m_nodeOf[E.leftFace(adj)]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_primalAdj[eLR] = adj; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_primalAdj[eRL] = adj->twin(); - - if(forbidCrossingGens && - ((const PlanRepUML&)PG).typeOf(adj->theEdge()) == Graph::generalization) - { - m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - } -} - - -//--------------------------------------------------------- -// removes edge eOrig; updates embedding and dual graph -// -void FixedEmbeddingInserter::removeEdge( - PlanRep &PG, - CombinatorialEmbedding &E, - edge eOrig, - bool forbidCrossingGens, - const EdgeArray *forbiddenEdgeOrig) -{ - const List &path = PG.chain(eOrig); - ListConstIterator itEdge; - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adj = (*itEdge)->adjSource(); - m_delFaces->insert(E.leftFace (adj)); - m_delFaces->insert(E.rightFace (adj)); - } - - // delete all corresponding nodes in dual - SListConstIterator itsF; - for(itsF = m_delFaces->faces().begin(); itsF.valid(); ++itsF) - m_dual.delNode(m_nodeOf[*itsF]); - - m_delFaces->clear(); - - // remove edge path from PG - PG.removeEdgePathEmbedded(E,eOrig,*m_newFaces); - - // update dual - // insert new nodes - ListConstIterator itF; - for(itF = m_newFaces->faces().begin(); itF.valid(); ++itF) { - m_nodeOf[*itF] = m_dual.newNode(); - } - - // insert new edges into dual - for(itF = m_newFaces->faces().begin(); itF.valid(); ++itF) - { - face f = *itF; // face to the right of adj in loop - node vRight = m_nodeOf[f]; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - if(forbiddenEdgeOrig && (*forbiddenEdgeOrig)[PG.original(adj->theEdge())] == true) - continue; - - node vLeft = m_nodeOf[E.leftFace(adj)]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_primalAdj[eLR] = adj; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_primalAdj[eRL] = adj->twin(); - - if(forbidCrossingGens && - ((const PlanRepUML&)PG).typeOf(adj->theEdge()) == Graph::generalization) - { - m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - } - - m_newFaces->clear(); - -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/GraphReduction.cpp b/ext/OGDF/src/planarity/GraphReduction.cpp deleted file mode 100644 index 02d5f3c57..000000000 --- a/ext/OGDF/src/planarity/GraphReduction.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class GraphReduction. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf { - -GraphReduction::GraphReduction(const Graph &G) : m_pGraph(&G), -m_vOrig(), m_eOrig(), m_vReduction(), m_eReduction() { - Graph::construct(*m_pGraph,m_vReduction,m_eReduction); - - int d; - node v,ov; - edge e1,e2; - - m_vOrig.init(*this); - m_eOrig.init(*this); - forall_nodes(v, *m_pGraph) - m_vOrig[m_vReduction[v]] = v; - - forall_edges(e1, *m_pGraph) - m_eOrig[m_eReduction[e1]].pushBack(e1); - - // remove selfloops - forall_edges(e1, *this) { - if(e1->isSelfLoop()) { - m_eReduction[e1] = NULL; - this->delEdge(e1); - } - } - - List next; - forall_nodes(v, *m_pGraph) - next.pushBack(v); - while(next.size()) { - ov = next.front(); - next.popFront(); - v = m_vReduction[ov]; - if( v && (d=v->degree()) < 3) { - if(d == 2) { - e1 = v->firstAdj()->theEdge(); - e2 = v->lastAdj()->theEdge(); - - if( e1->source() == v) { - if(e2->source() == v) m_eOrig[e2].reverse(); - this->moveSource(e1, e2->opposite(v)); - for(ListConstIterator it = m_eOrig[e2].rbegin(); it.valid(); --it) { - m_eReduction[*it] = e1; - m_eOrig[e1].pushFront( *it ); - } - } else { - if(e2->target() == v) m_eOrig[e2].reverse(); - this->moveTarget(e1, e2->opposite(v)); - for(ListConstIterator it = m_eOrig[e2].begin(); it.valid(); ++it) { - m_eReduction[*it] = e1; - m_eOrig[e1].pushBack( *it ); - } - } - m_eOrig[e2].clear(); - this->delEdge(e2); - } else if(d == 1) { - e1 = v->firstAdj()->theEdge(); - const List& el = m_eOrig[e1]; - node nv; - if(el.size() == 1) - nv = el.front()->opposite(ov); - else { - bool front_e1 = el.front()->source() == ov || el.front()->target() == ov; - edge e3; - if(front_e1) { - e2 = el.back(); - e3 = *(el.rbegin().pred()); - } else { - e2 = el.front(); - e3 = *(el.begin().succ()); - } - nv = (e2->source() == e3->source() || e2->source() == e3->target()) ? e2->target() : e2->source(); - } - next.pushBack(nv); - - for(ListIterator it = m_eOrig[e1].begin(); it.valid(); it++) - m_eReduction[*it] = 0; - this->delEdge(e1); - } - m_vReduction[ ov ] = 0; - this->delNode(v); - } - } - -#ifdef OGDF_DEBUG - edge em; - forall_edges(em, *this) { - node t = 0; - OGDF_ASSERT( original(em).front()->source() == original(em->source()) ); - for(ListConstIterator it = original(em).begin(); it.valid(); ++it) { - if(t) { - OGDF_ASSERT( (*it)->source() == t); - } - } - OGDF_ASSERT( original(em).back()->target() == original(em->target()) ); - } -#endif - -} - -} diff --git a/ext/OGDF/src/planarity/Layout.cpp b/ext/OGDF/src/planarity/Layout.cpp deleted file mode 100644 index 0e03b6004..000000000 --- a/ext/OGDF/src/planarity/Layout.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of class Layout - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - - -namespace ogdf { - - -void Layout::computePolyline(GraphCopy &GC, edge eOrig, DPolyline &dpl) const -{ - dpl.clear(); - - const List &edgePath = GC.chain(eOrig); - - // The corresponding edge path in the copy must contain at least 1 edge! - OGDF_ASSERT(edgePath.size() >= 1); - - // iterate over all edges in the corresponding edge path in the copy - ListConstIterator it; - edge e; - bool firstTime = true; - for(it = edgePath.begin(); it.valid(); ++it) { - e = *it; - node v = e->source(); - - // append point of source node of e ... - if (!firstTime) - dpl.pushBack(DPoint(m_x[v],m_y[v])); - else - firstTime = false; - - // ... and polyline of e - const DPolyline &segment = m_bends[e]; - ListConstIterator itSeg; - - for(itSeg = segment.begin(); itSeg.valid(); ++itSeg) - dpl.pushBack(*itSeg); - } -} - - -// faster version of computePolylineClear -// clears the list of bend points of all edges in the edge path -// in the copy corresponding to eOrig! -void Layout::computePolylineClear(PlanRep &PG, edge eOrig, DPolyline &dpl) -{ - dpl.clear(); - - const List &edgePath = PG.chain(eOrig); - - // The corresponding edge path in the copy must contain at least 1 edge! - OGDF_ASSERT(edgePath.size() >= 1); - - // iterate over all edges in the corresponding edge path in the copy - ListConstIterator it; - edge e; - bool firstTime = true; - for(it = edgePath.begin(); it.valid(); ++it) { - e = *it; - node v = e->source(); - - // append point of source node of e ... - if (!firstTime) - dpl.pushBack(DPoint(m_x[v],m_y[v])); - else - firstTime = false; - - // ... and polyline of e - dpl.conc(m_bends[e]); - } - node w = e->target(); - if (PG.typeOf(w) == Graph::generalizationExpander) - dpl.pushBack(DPoint(m_x[w],m_y[w])); -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/LayoutPlanRepModule.cpp b/ext/OGDF/src/planarity/LayoutPlanRepModule.cpp deleted file mode 100644 index 13a842355..000000000 --- a/ext/OGDF/src/planarity/LayoutPlanRepModule.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of class LayoutPlanRepModule - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void LayoutPlanRepModule::setBoundingBox(PlanRepUML &PG, Layout &drawing) -{ - double maxWidth = 0; - double maxHeight = 0; - - // check rightmost and uppermost extension of all (original) nodes - const List &origInCC = PG.nodesInCC(PG.currentCC()); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - - double maxX = drawing.x(PG.copy(vG)) + PG.widthOrig(vG)/2; - if (maxX > maxWidth ) maxWidth = maxX; - - double maxY = drawing.y(PG.copy(vG)) + PG.heightOrig(vG)/2; - if (maxY > maxHeight) maxHeight = maxY; - - // check polylines of all (original) edges - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - const List &path = PG.chain(eG); - - ListConstIterator itPath; - for(itPath = path.begin(); itPath.valid(); ++itPath) - { - edge e = *itPath; - - // we have to check (only) all interior points, i.e., we can - // omitt the first and last point since it lies in the box of - // the source or target node. - // This version checks also the first for simplicity of the loop. - node v = e->source(); - if (drawing.x(v) > maxWidth ) maxWidth = drawing.x(v); - if (drawing.y(v) > maxHeight) maxHeight = drawing.y(v); - - const DPolyline &dpl = drawing.bends(e); - - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - { - const DPoint &dp = *it; - if (dp.m_x > maxWidth ) maxWidth = dp.m_x; - if (dp.m_y > maxHeight) maxHeight = dp.m_y; - } - } - } - } - - - m_boundingBox = DPoint(maxWidth,maxHeight); -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/MDMFLengthAttribute.cpp b/ext/OGDF/src/planarity/MDMFLengthAttribute.cpp deleted file mode 100644 index cb349ea47..000000000 --- a/ext/OGDF/src/planarity/MDMFLengthAttribute.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Length attribute used in EmbedderMinDepthMaxFace. - * It contains two components (d, l) and a linear order is defined by: - * (d, l) > (d', l') iff d > d' or (d = d' and l > l') - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -MDMFLengthAttribute MDMFLengthAttribute::operator=(const MDMFLengthAttribute& x) -{ - this->d = x.d; - this->l = x.l; - return *this; -} - -MDMFLengthAttribute MDMFLengthAttribute::operator=(const int& x) -{ - this->d = x; - this->l = 0; - return *this; -} - -bool MDMFLengthAttribute::operator==(const MDMFLengthAttribute& x) -{ - return (this->d == x.d && this->l == x.l); -} - -bool MDMFLengthAttribute::operator!=(const MDMFLengthAttribute& x) -{ - return !(*this == x); -} - -bool MDMFLengthAttribute::operator>(const MDMFLengthAttribute& x) -{ - return (this->d > x.d || (this->d == x.d && this->l > x.l)); -} - -bool MDMFLengthAttribute::operator<(const MDMFLengthAttribute& x) -{ - return !(*this >= x); -} - -bool MDMFLengthAttribute::operator>=(const MDMFLengthAttribute& x) -{ - return (*this == x) || (*this > x); -} - -bool MDMFLengthAttribute::operator<=(const MDMFLengthAttribute& x) -{ - return (*this == x) || (*this < x); -} - -MDMFLengthAttribute MDMFLengthAttribute::operator+(const MDMFLengthAttribute& x) -{ - return MDMFLengthAttribute(this->d + x.d, this->l + x.l); -} - -MDMFLengthAttribute MDMFLengthAttribute::operator-(const MDMFLengthAttribute& x) -{ - return MDMFLengthAttribute(this->d - x.d, this->l - x.l); -} - -MDMFLengthAttribute MDMFLengthAttribute::operator+=(const MDMFLengthAttribute& x) -{ - this->d += x.d; - this->l += x.l; - return *this; -} - -MDMFLengthAttribute MDMFLengthAttribute::operator-=(const MDMFLengthAttribute& x) -{ - this->d -= x.d; - this->l -= x.l; - return *this; -} - -bool operator==(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return (x.d == y.d && x.l == y.l); -} - -bool operator!=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return !(x == y); -} - -bool operator>(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return (x.d > y.d || (x.d == y.d && x.l > y.l)); -} - -bool operator<(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return y > x; -} - -bool operator>=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return (x == y) || (x > y); -} - -bool operator<=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return (x == y) || (x < y); -} - -MDMFLengthAttribute operator+(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return MDMFLengthAttribute(x.d + y.d, x.l + y.l); -} - -MDMFLengthAttribute operator-(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return MDMFLengthAttribute(x.d - y.d, x.l - y.l); -} - -MDMFLengthAttribute operator+=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return MDMFLengthAttribute(x.d + y.d, x.l + y.l); -} - -MDMFLengthAttribute operator-=(const MDMFLengthAttribute& x, const MDMFLengthAttribute& y) -{ - return MDMFLengthAttribute(x.d - y.d, x.l - y.l); -} - -ostream& operator<<(ostream& s, const MDMFLengthAttribute& x) -{ - s << x.d << ", " << x.l; - return s; -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/MMCrossingMinimizationModule.cpp b/ext/OGDF/src/planarity/MMCrossingMinimizationModule.cpp deleted file mode 100644 index 27f27e43c..000000000 --- a/ext/OGDF/src/planarity/MMCrossingMinimizationModule.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class MMCrossingMinimizationModule. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - - -namespace ogdf { - - -Module::ReturnType MMCrossingMinimizationModule::call( - const Graph &G, - const List &splittableNodes, - int &cr, - const EdgeArray *forbid) -{ - cr = 0; m_nodeSplits = 0; m_splittedNodes = 0; - - NodeArray splittable(G,false); - ListConstIterator itV; - for(itV = splittableNodes.begin(); itV.valid(); ++itV) - splittable[*itV] = true; - - EdgeArray comp(G,-1); - int c = biconnectedComponents(G, comp); - - Array > edges(c); - edge e; - forall_edges(e,G) { - edges[comp[e]].pushBack(e); - } - - NodeArray map(G,0); - - for(int i = 0; i < c; ++i) - { - if(edges[i].size() < 9) - continue; - - Graph B; - List nodes; - List splittableNodesB; - - EdgeArray *forbidB = 0; - if(forbid) forbidB = new EdgeArray(B, false); - - ListConstIterator it; - for(it = edges[i].begin(); it.valid(); ++it) - { - edge e = *it; - node v = e->source(), w = e->target(); - - if(map[v] == 0) { - map[v] = B.newNode(); - nodes.pushBack(v); - if(splittable[v]) - splittableNodesB.pushBack(map[v]); - } - if(map[w] == 0) { - map[w] = B.newNode(); - nodes.pushBack(w); - if(splittable[w]) - splittableNodesB.pushBack(map[w]); - } - - edge eB = B.newEdge(map[v],map[w]); - if(forbidB) - (*forbidB)[eB] = (*forbid)[e]; - } - - PlanRepExpansion PG(B,splittableNodesB); - - int crcc, numNS = 0, numSN = 0; - ReturnType ret = doCall(PG,0,forbidB,crcc,numNS,numSN); - delete forbidB; - if(isSolution(ret) == false) - return ret; - cr += crcc; - m_nodeSplits += numNS; - m_splittedNodes += numSN; - - ListConstIterator itV; - for(itV = nodes.begin(); itV.valid(); ++itV) - map[*itV] = 0; - } - - return retFeasible; -} - - -Module::ReturnType MMCrossingMinimizationModule::call( - const Graph &G, - int &cr, - const EdgeArray *forbid) -{ - cr = 0; m_nodeSplits = 0; m_splittedNodes = 0; - - EdgeArray comp(G,-1); - int c = biconnectedComponents(G, comp); - - Array > edges(c); - edge e; - forall_edges(e,G) { - edges[comp[e]].pushBack(e); - } - - NodeArray map(G,0); - - for(int i = 0; i < c; ++i) - { - if(edges[i].size() < 9) - continue; - - Graph B; - List nodes; - - ListConstIterator it; - for(it = edges[i].begin(); it.valid(); ++it) - { - edge e = *it; - node v = e->source(), w = e->target(); - - if(map[v] == 0) { - map[v] = B.newNode(); - nodes.pushBack(v); - } - if(map[w] == 0) { - map[w] = B.newNode(); - nodes.pushBack(w); - } - - B.newEdge(map[v],map[w]); - } - - PlanRepExpansion PG(B); - - int crcc, numNS = 0, numSN = 0; - ReturnType ret = doCall(PG,0,forbid,crcc,numNS,numSN); - if(isSolution(ret) == false) - return ret; - cr += crcc; - m_nodeSplits += numNS; - m_splittedNodes += numSN; - - ListConstIterator itV; - for(itV = nodes.begin(); itV.valid(); ++itV) - map[*itV] = 0; - } - - return retFeasible; -} - - -} // namspace ogdf - diff --git a/ext/OGDF/src/planarity/MMFixedEmbeddingInserter.cpp b/ext/OGDF/src/planarity/MMFixedEmbeddingInserter.cpp deleted file mode 100644 index 9c90a6ab3..000000000 --- a/ext/OGDF/src/planarity/MMFixedEmbeddingInserter.cpp +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of MMFixedEmbeddingInserter class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - static int globalCounter = 0; - -//--------------------------------------------------------- -// constructor -// sets default values for options -// -MMFixedEmbeddingInserter::MMFixedEmbeddingInserter() -{ - m_rrOption = rrNone; - m_percentMostCrossed = 25; -} - - -//--------------------------------------------------------- -// FEICrossingsBucket -// bucket function for sorting edges by decreasing number -// of crossings -class FEICrossingsBucket : public BucketFunc -{ - const PlanRepExpansion *m_pPG; - -public: - FEICrossingsBucket(const PlanRepExpansion *pPG) : - m_pPG(pPG) { } - - int getBucket(const edge &e) { - return -m_pPG->chain(e).size(); - } -}; - - -/* -static void draw( - const PlanRepExpansion &PG, - const EdgeArray *forbiddenEdgeOrig) -{ - static int num = 1; - - GraphAttributes GA(PG, - GraphAttributes::nodeGraphics | GraphAttributes::edgeGraphics | GraphAttributes::nodeLabel | GraphAttributes::edgeColor | GraphAttributes::nodeColor); - char buffer[128]; - - node v; - forall_nodes(v, PG) { - node vOrig = PG.original(v); - if(vOrig != 0) { - sprintf(buffer, 128, "%d | %d", v->index(), vOrig->index()); - GA.colorNode(v) = "#ffffff"; - } else { - sprintf(buffer, 128, "%d", v->index()); - GA.colorNode(v) = "#22ff22"; - } - GA.labelNode(v) = buffer; - GA.width(v) = 60; - GA.height(v) = 20; - } - - if(forbiddenEdgeOrig) { - edge e; - forall_edges(e, PG) { - edge eOrig = PG.originalEdge(e); - if (eOrig && (*forbiddenEdgeOrig)[eOrig] == true) - GA.colorEdge(e) = "#ff0000"; - } - } - - PlanarStraightLayout pl; - pl.separation(40); - pl.callFixEmbed(GA, PG.firstEdge()->adjSource()); - - sprintf(buffer, 128, "layout-%d.gml", num++); - GA.writeGML(buffer); -} -*/ - -void MMFixedEmbeddingInserter::drawDual( - const PlanRepExpansion &PG, - const EdgeArray *forbiddenEdgeOrig) -{ - GraphAttributes GA(m_dual, - GraphAttributes::nodeGraphics | GraphAttributes::edgeGraphics | GraphAttributes::nodeLabel | GraphAttributes::edgeColor | GraphAttributes::nodeColor); - - char buffer[128]; - - node v; - forall_nodes(v, m_dual) { - if(m_primalNode[v]) { - sprintf(buffer, 128, "v%d: %d", m_primalNode[v]->index(), v->index()); - GA.colorNode(v) = "#ffffff"; - } else { - sprintf(buffer, 128, "f: %d", v->index()); - GA.colorNode(v) = "#22ff22"; - } - GA.labelNode(v) = buffer; - GA.width(v) = 50; - GA.height(v) = 20; - } - - edge e; - forall_edges(e, m_dual) { - if(origOfDualForbidden(e, PG, forbiddenEdgeOrig) == true) - GA.colorEdge(e) = "#ff0000"; - else - GA.colorEdge(e) = "#000000"; - } - - GA.writeGML("dual.gml"); -} - - -//--------------------------------------------------------- -// actual call (called by all variations of call) -// crossing of generalizations is forbidden if forbidCrossingGens = true -// edge costs are obeyed if costOrig != 0 -// -Module::ReturnType MMFixedEmbeddingInserter::doCall( - PlanRepExpansion &PG, - const List &origEdges, - const EdgeArray *forbiddenEdgeOrig) -{ - ReturnType retValue = retFeasible; - - //cout << "orig edges: "; - //ListConstIterator itE; - //for(itE = origEdges.begin(); itE.valid(); ++itE) - // cout << *itE << " "; - //cout << endl; - - PG.embed(); - OGDF_ASSERT(PG.representsCombEmbedding() == true); - - if (origEdges.size() == 0) - return retOptimal; // nothing to do - - // initialization - CombinatorialEmbedding E(PG); // embedding of PG - - // construct dual graph - m_primalAdj.init(m_dual); - m_dualEdge.init(PG,0); - m_dualOfFace.init(E); - m_dualOfNode.init(PG,0); - m_primalNode.init(m_dual,0); - m_dualCost.init(m_dual,0); - - constructDual(PG,E); - OGDF_ASSERT(checkDualGraph(PG,E)); - - //draw(PG, forbiddenEdgeOrig); - - //if(forbiddenEdgeOrig) { - // cout << "forbidden edges: "; - // edge e;; - // forall_edges(e, PG.original()) - // if((*forbiddenEdgeOrig)[e]) cout << e << " "; - // cout << endl; - //} - - m_delFaces = new FaceSetSimple(E); - - // m_newFaces and m_mergedNodes are used by removeEdge() - m_newFaces = 0; - m_mergedNodes = 0; - if (removeReinsert() != rrNone) { - m_newFaces = new FaceSetPure(E); - m_mergedNodes = new NodeSetPure(PG); - } - - SListPure currentOrigEdges; - if(removeReinsert() == rrIncremental) { - edge e; - forall_edges(e,PG) - currentOrigEdges.pushBack(PG.originalEdge(e)); - } - - NodeSet sources(PG), targets(PG); - - // insertion of edges - ListConstIterator it; - for(it = origEdges.begin(); it.valid(); ++it) - { - edge eOrig = *it; - node srcOrig = eOrig->source(); - node tgtOrig = eOrig->target(); - - node oldSrc = (PG.splittableOrig(srcOrig) && PG.expansion(srcOrig).size() == 1) ? - PG.expansion(srcOrig).front() : 0; - node oldTgt = (PG.splittableOrig(tgtOrig) && PG.expansion(tgtOrig).size() == 1) ? - PG.expansion(tgtOrig).front() : 0; - - anchorNodes(eOrig->source(), sources, PG); - anchorNodes(eOrig->target(), targets, PG); - - List > crossed; - findShortestPath(PG, E, sources.nodes(), targets.nodes(), crossed, forbiddenEdgeOrig); - sources.clear(); targets.clear(); - - insertEdge(PG,E,eOrig,eOrig->source(),eOrig->target(),0,crossed); - - if(oldSrc != 0 && PG.expansion(srcOrig).size() > 1) - contractSplitIfReq(PG,E,oldSrc); - if(oldTgt != 0 && PG.expansion(tgtOrig).size() > 1) - contractSplitIfReq(PG,E,oldTgt); - - //draw(PG, forbiddenEdgeOrig); - - // THIS OPTION IS NOT YET IMPLEMENTED! - if(removeReinsert() == rrIncremental) - { - currentOrigEdges.pushBack(eOrig); - - bool improved; - do { - improved = false; - - SListConstIterator itRR; - for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR) - { - edge eOrigRR = *itRR; - - int pathLength = PG.chain(eOrigRR).size() - 1; - if (pathLength == 0) continue; // cannot improve - - node oldSrc, oldTgt; - removeEdge(PG,E,eOrigRR,0,oldSrc,oldTgt); - - // try to find a better insertion path - List > crossed; - findShortestPath(PG, E, - PG.expansion(eOrigRR->source()), PG.expansion(eOrigRR->target()), - crossed, forbiddenEdgeOrig); - - // re-insert edge (insertion path cannot be longer) - insertEdge(PG,E,eOrigRR,eOrigRR->source(),eOrigRR->target(),0,crossed); - - int newPathLength = PG.chain(eOrigRR).size() - 1; - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - } - OGDF_ASSERT(checkSplitDeg(PG)); - } - - OGDF_ASSERT(E.consistencyCheck()); - OGDF_ASSERT(PG.consistencyCheck()); - OGDF_ASSERT(checkDualGraph(PG,E)); - OGDF_ASSERT(checkSplitDeg(PG)); - - const Graph &G = PG.original(); - if(removeReinsert() != rrIncremental) { - // postprocessing (remove-reinsert heuristc) - SListPure rrEdges; - - switch(removeReinsert()) - { - case rrAll: - case rrMostCrossed: { - const List &origInCC = PG.nodesInCC(); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - rrEdges.pushBack(eG); - } - } - } - break; - - case rrInserted: - for(ListConstIterator it = origEdges.begin(); it.valid(); ++it) - rrEdges.pushBack(*it); - break; - - case rrNone: - case rrIncremental: - break; - } - - // marks the end of the interval of rrEdges over which we iterate - // initially set to invalid iterator which means all edges - SListConstIterator itStop; - - bool improved; - do { - improved = false; - - if(removeReinsert() == rrMostCrossed) - { - FEICrossingsBucket bucket(&PG); - rrEdges.bucketSort(bucket); - - const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); - itStop = rrEdges.get(num); - } - - SListConstIterator it; - for(it = rrEdges.begin(); it != itStop; ++it) - { - edge eOrig = *it; - - int pathLength; - pathLength = PG.chain(eOrig).size() - 1; - if (pathLength == 0) continue; // cannot improve - - node oldSrc = 0, oldTgt = 0; - removeEdge(PG,E,eOrig,0,oldSrc,oldTgt); - //draw(PG, forbiddenEdgeOrig); - - // try to find a better insertion path - anchorNodes(eOrig->source(), sources, PG); - anchorNodes(eOrig->target(), targets, PG); - - List > crossed; - findShortestPath(PG, E, sources.nodes(), targets.nodes(), crossed, forbiddenEdgeOrig); - sources.clear(); targets.clear(); - - // re-insert edge (insertion path cannot be longer) - insertEdge(PG,E,eOrig,eOrig->source(),eOrig->target(),0,crossed); - - if(PG.splittable(oldSrc)) - contractSplitIfReq(PG,E,oldSrc); - if(PG.splittable(oldTgt)) - contractSplitIfReq(PG,E,oldTgt); - - int newPathLength = PG.chain(eOrig).size() - 1; - int saved = pathLength - newPathLength; - OGDF_ASSERT(saved >= 0); - - if(saved > 0) - improved = true; - } - - if(removeReinsert() == rrAll) - { - // process all node splits - int nsCount = PG.nodeSplits().size(); - ListIterator itS, itSNext; - for(itS = PG.nodeSplits().begin(); itS.valid() && nsCount > 0; itS = itSNext, --nsCount) - { - ++globalCounter; - PlanRepExpansion::NodeSplit *ns = &(*itS); - - int pathLength; - pathLength = ns->m_path.size() - 1; - if (pathLength == 0) continue; // cannot improve - - node vOrig = PG.original(ns->source()); - - node oldSrc = 0, oldTgt = 0; - removeEdge(PG,E,0,ns,oldSrc,oldTgt); - - // try to find a better insertion path - findSourcesAndTargets(oldSrc,oldTgt,sources,targets,PG); - - List > crossed; - findShortestPath(PG, E, sources.nodes(), targets.nodes(), crossed, forbiddenEdgeOrig); - - node vCommon = commonDummy(sources,targets); - sources.clear(); targets.clear(); - - if(vCommon == 0) - { - // re-insert edge (insertion path cannot be longer) - insertEdge(PG,E,0,vOrig,vOrig,ns,crossed); - - if(PG.splittable(oldSrc)) - contractSplitIfReq(PG,E,oldSrc,ns); - if(PG.splittable(oldTgt)) - contractSplitIfReq(PG,E,oldTgt,ns); - - int newPathLength = ns->m_path.size() - 1; - int saved = pathLength - newPathLength; - OGDF_ASSERT(saved >= 0); - - if(saved > 0) - improved = true; - - itSNext = itS.succ(); - if(newPathLength == 0) - contractSplit(PG,E,ns); - - } else { - improved = true; - itSNext = itS.succ(); - - convertDummy(PG,E,vCommon,vOrig,ns); - } - - } - } - - OGDF_ASSERT(PG.consistencyCheck()); - OGDF_ASSERT(E.consistencyCheck()); - OGDF_ASSERT(checkDualGraph(PG,E)); - OGDF_ASSERT(checkSplitDeg(PG)); - - } while(improved); // iterate as long as we improve - } - - - // free resources - delete m_newFaces; - delete m_delFaces; - delete m_mergedNodes; - - m_dualOfFace.init(); - m_dualOfNode.init(); - m_primalNode.init(); - m_primalAdj.init(); - m_dualEdge.init(); - m_dualCost.init(); - m_dual.clear(); - - return retValue; -} - - -//--------------------------------------------------------- -// construct dual graph -// -void MMFixedEmbeddingInserter::constructDual( - const PlanRepExpansion &PG, - const CombinatorialEmbedding &E) -{ - // insert a node in the dual graph for each face in E - face f; - forall_faces(f,E) { - m_dualOfFace[f] = m_dual.newNode(); - //cout << "dual of face " << f->index() << ": " << m_dualOfFace[f] << endl; - } - - // insert a node in the dual graph for each splittable node in PG - node v; - forall_nodes(v,PG) { - if(PG.splittable(v) && v->degree() >= 4) { - m_primalNode[m_dualOfNode[v] = m_dual.newNode()] = v; - //cout << "dual of node " << v << " :" << m_dualOfNode[v] << endl; - } - } - - // Insert an edge into the dual graph for each adjacency entry in E. - // The edges are directed from the left face to the right face. - forall_nodes(v,PG) - { - node vDual = m_dualOfNode[v]; - - adjEntry adj; - forall_adj(adj,v) - { - node vLeft = m_dualOfFace[E.leftFace (adj)]; - node vRight = m_dualOfFace[E.rightFace(adj)]; - - if(vLeft != vRight) { - edge e = m_dual.newEdge(vLeft,vRight); - //cout << "dual edge " << e << endl; - m_dualEdge[m_primalAdj[e] = adj] = e; - m_dualCost[e] = 1; - } - - if(vDual) { - edge eOut = m_dual.newEdge(vDual,vLeft); - //cout << "dual edge " << eOut << endl; - m_primalAdj[eOut] = adj; - m_dualCost[eOut] = 0; - - edge eIn = m_dual.newEdge(vLeft,vDual); - //cout << "dual edge " << eIn << endl; - m_primalAdj[eIn] = adj; - m_dualCost[eIn] = 1; - } - } - } - - // Augment the dual graph by two new vertices. These are used temporarily - // when searching for a shortest path in the dual graph. - m_vS = m_dual.newNode(); - m_vT = m_dual.newNode(); - - m_maxCost = 2; // we just have 0/1 edge costs at the moment; maximum has - // to be adjusted when we have more general costs -} - - -//--------------------------------------------------------- -// finds a weighted shortest path in the dual graph augmented by s and t -// (represented by m_vS and m_vT) using edges weights given by costOrig; -// returns list of crossed adjacency entries (corresponding -// to used edges in the dual) in crossed. -// -// running time: O(|dual| + L + C), -// where L ist the weighted length of the insertion path and C the -// maximum cost of an edge -// -void MMFixedEmbeddingInserter::findShortestPath( - const PlanRepExpansion &PG, - const CombinatorialEmbedding &E, - const List &sources, - const List &targets, - List > &crossed, - const EdgeArray *forbiddenEdgeOrig) -{ - //static int count = 1; - //cout << "==> " << count++ << endl; - //cout << "Insert:" << endl; - //cout << " sources: "; - //ListConstIterator itV; - //for(itV = sources.begin(); itV.valid(); ++itV) - // cout << *itV << " "; - //cout << "\n targets: "; - //for(itV = targets.begin(); itV.valid(); ++itV) - // cout << *itV << " "; - //cout << endl; - //drawDual(PG, forbiddenEdgeOrig); - - //cout << "forbidden dual edges: "; - //edge ed; - //forall_edges(ed,m_dual) { - // if(origOfDualForbidden(ed,PG,forbiddenEdgeOrig) == true) - // cout << ed << " "; - //} - //cout << endl; - Array > nodesAtDist(m_maxCost); - NodeArray spPred(m_dual,0); - - int oldIdCount = m_dual.maxEdgeIndex(); - - adjEntry adj; - ListConstIterator itV; - - // augment dual by edges from m_vS to all adjacent faces of sources ... - for(itV = sources.begin(); itV.valid(); ++itV) { - forall_adj(adj,*itV) { - // starting edges of bfs-search are all edges leaving s - edge eDual = m_dual.newEdge(m_vS, m_dualOfFace[E.rightFace(adj)]); - m_primalAdj[eDual] = adj; - nodesAtDist[0].pushBack(eDual); - } - } - - // ... and from all adjacent faces of targets to m_vT - for(itV = targets.begin(); itV.valid(); ++itV) { - forall_adj(adj,*itV) { - edge eDual = m_dual.newEdge(m_dualOfFace[E.rightFace(adj)], m_vT); - m_primalAdj[eDual] = adj; - } - } - - //cout << "start nodes: "; - //forall_adj(adj, m_vS) - // cout << adj->twinNode() << " "; - //cout << "\ntarget nodes: "; - //forall_adj(adj, m_vT) - // cout << adj->twinNode() << " "; - //cout << endl; - - // actual search (using extended bfs on directed dual) - int currentDist = 0; - - for( ; ; ) - { - // next candidate edge - while(nodesAtDist[currentDist % m_maxCost].empty()) - ++currentDist; - - edge eCand = nodesAtDist[currentDist % m_maxCost].popFrontRet(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == m_vT) - { - // ... then search is done. - // constructed list of used edges (translated to crossed - // adjacency entries in PG) from t back to s (including first - // and last!) - - do { - edge eDual = spPred[v]; - node w = eDual->source(); - - if(m_primalNode[w] == 0) - // w is a face node - crossed.pushFront(Tuple2(m_primalAdj[eDual],0)); - else { - edge eDual2 = spPred[w]; - w = eDual2->source(); - crossed.pushFront(Tuple2(m_primalAdj[eDual2],m_primalAdj[eDual])); - } - - v = w; - } while(v != m_vS); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if (v != e->source()) continue; - if(origOfDualForbidden(e, PG, forbiddenEdgeOrig)) continue; - - int listPos = (currentDist + m_dualCost[e]) % m_maxCost; - nodesAtDist[listPos].pushBack(e); - } - } - } - - // remove augmented edges again - while ((adj = m_vS->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - while ((adj = m_vT->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - m_dual.resetEdgeIdCount(oldIdCount); -} - - -void MMFixedEmbeddingInserter::prepareAnchorNode( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - adjEntry &adjStart, - node srcOrig) -{ - adjEntry adj = adjStart; - face f = E.rightFace(adjStart); - - edge eStraight; - PlanRepExpansion::NodeSplit *nsStraight; - List *pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - - node vStraight = pathStraight->front()->source(); - if(PG.original(vStraight) != srcOrig) { - vStraight = pathStraight->back()->target(); - if(PG.original(vStraight) != srcOrig) { - adj = adj->cyclicSucc(); - pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - vStraight = pathStraight->front()->source(); - if(PG.original(vStraight) != srcOrig) { - vStraight = pathStraight->back()->target(); - } - } - } - OGDF_ASSERT(PG.original(vStraight) == srcOrig); - - if(PG.original(adj->twinNode()) == srcOrig) { - // No need for a split; can just directly go to a split node - adjStart = (adj == adjStart) ? adj->twin()->cyclicPred() : adj->twin(); - - } else { - edge eNew, e = adj->theEdge(); - if(nsStraight == 0) { - // We split a chain of an original edge - eNew = PG.enlargeSplit(vStraight, e, E); - - } else { - // We split a node split - eNew = PG.splitNodeSplit(e, E); - } - - adjEntry adj1 = eNew->adjSource(); - node vLeft = m_dualOfFace[E.leftFace (adj1)]; - node vRight = m_dualOfFace[E.rightFace(adj1)]; - - edge eDual1 = m_dual.newEdge(vLeft,vRight); - m_dualEdge[m_primalAdj[eDual1] = adj1] = eDual1; - m_dualCost[eDual1] = 1; - - adjEntry adj2 = e->adjTarget(); - edge eDual2 = m_dual.newEdge(vRight,vLeft); - m_dualEdge[m_primalAdj[eDual2] = adj2] = eDual2; - m_dualCost[eDual2] = 1; - - adjStart = (E.rightFace(adj1) == f) ? adj1 : adj2; - OGDF_ASSERT(E.rightFace(adjStart) == f); - } -} - - -void MMFixedEmbeddingInserter::preprocessInsertionPath( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - node srcOrig, - node tgtOrig, - //PlanRepExpansion::nodeSplit ns, - List > &crossed) -{ - adjEntry &adjStart = (*crossed.begin ()).x1(); - adjEntry &adjEnd = (*crossed.rbegin()).x1(); - - // Warning: Potential multi-edges are not considered here!!! - - if(PG.original(adjStart->theNode()) == 0) { - prepareAnchorNode(PG, E, adjStart, srcOrig); - } - - if(PG.original(adjEnd->theNode()) == 0) { - prepareAnchorNode(PG, E, adjEnd, tgtOrig); - } -} - - -//--------------------------------------------------------- -// inserts edge e according to insertion path crossed. -// updates embeding and dual graph -// -void MMFixedEmbeddingInserter::insertEdge( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - edge eOrig, - node srcOrig, - node tgtOrig, - PlanRepExpansion::NodeSplit *nodeSplit, - List > &crossed) -{ - preprocessInsertionPath(PG,E,srcOrig,tgtOrig,/*nodeSplit,*/crossed); - - // remove dual nodes of faces on insertion path - ListConstIterator > it; - for(it = crossed.begin(); it != crossed.rbegin(); ++it) { - adjEntry adj1 = (*it).x1(); - adjEntry adj2 = (*it).x2(); - if(adj2 == 0) { - m_dual.delNode(m_dualOfFace[E.rightFace(adj1)]); - } else { - OGDF_ASSERT(adj1->theNode() == adj2->theNode()); - m_dual.delNode(m_dualOfFace[E.leftFace(adj2)]); - } - } - - // update primal - PG.insertEdgePathEmbedded(eOrig,nodeSplit,E,crossed); - - // remove edges at vertices (to be split) on insertion path - // and insert a new vertex in dual for each split node - for(it = crossed.begin(); it != crossed.rbegin(); ++it) { - adjEntry adj1 = (*it).x1(); - adjEntry adj2 = (*it).x2(); - if(adj2 != 0) { - node v = adj1->theNode(); - node vDual = m_dualOfNode[v]; - if(v->degree() >= 4) { - while(vDual->firstAdj() != 0) - m_dual.delEdge(vDual->firstAdj()->theEdge()); - } else { - m_dual.delNode(vDual); - m_dualOfNode[v] = 0; - } - - node w = adj2->theNode(); - if(w->degree() >= 4) - m_primalNode[m_dualOfNode[w] = m_dual.newNode()] = w; - } - } - - // insert new face nodes into dual - const List &path = (eOrig) ? PG.chain(eOrig) : nodeSplit->m_path; - ListConstIterator itEdge; - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adj = (*itEdge)->adjSource(); - m_dualOfFace[E.leftFace (adj)] = m_dual.newNode(); - m_dualOfFace[E.rightFace(adj)] = m_dual.newNode(); - } - - // insert new edges into dual - for(itEdge = path.begin(), it = crossed.begin().succ(); - itEdge.valid(); ++itEdge, ++it) - { - adjEntry adjSrc = (*itEdge)->adjSource(); - face f = E.rightFace(adjSrc); // face to the right of adj in loop - node vRight = m_dualOfFace[f]; - m_delFaces->insert(f); - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - face fAdj = E.leftFace(adj); - if(!m_delFaces->isMember(fAdj)) // Don't insert edges twice - { - node vLeft = m_dualOfFace[fAdj]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_dualEdge[m_primalAdj[eLR] = adj] = eLR; - m_dualCost [eLR] = 1; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_dualEdge[m_primalAdj[eRL] = adj->twin()] = eRL; - m_dualCost [eRL] = 1; - - } else if(f == fAdj) - m_dualEdge[adj] = m_dualEdge[adj->twin()] = 0; - - node vDual = m_dualOfNode[adj->theNode()]; - if(vDual != 0) { - adjEntry adjSucc = adj->cyclicSucc(); - edge eOut = m_dual.newEdge(vDual,vRight); - m_primalAdj[eOut] = adjSucc; - m_dualCost[eOut] = 0; - - edge eIn = m_dual.newEdge(vRight,vDual); - m_primalAdj[eIn] = adjSucc; - m_dualCost[eIn] = 1; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - - // the other face adjacent to *itEdge ... - f = E.rightFace(adjSrc->twin()); - vRight = m_dualOfFace[f]; - m_delFaces->insert(f); - - adj1 = f->firstAdj(); - adj = adj1; - do { - face fAdj = E.leftFace(adj); - if(!m_delFaces->isMember(fAdj)) - { - node vLeft = m_dualOfFace[fAdj]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_dualEdge[m_primalAdj[eLR] = adj] = eLR; - m_dualCost [eLR] = 1; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_dualEdge[m_primalAdj[eRL] = adj->twin()] = eRL; - m_dualCost [eRL] = 1; - - } else if(f == fAdj) - m_dualEdge[adj] = m_dualEdge[adj->twin()] = 0; - - node vDual = m_dualOfNode[adj->theNode()]; - if(vDual != 0) { - adjEntry adjSucc = adj->cyclicSucc(); - edge eOut = m_dual.newEdge(vDual,vRight); - m_primalAdj[eOut] = adjSucc; - m_dualCost[eOut] = 0; - - edge eIn = m_dual.newEdge(vRight,vDual); - m_primalAdj[eIn] = adjSucc; - m_dualCost[eIn] = 1; - } - - adjEntry adjS1 = (*it).x1(); - adjEntry adjS2 = (*it).x2(); - - if(adjS2 != 0) { - node v = adjS1->theNode(); - node vDual = m_dualOfNode[v]; - if(vDual) { - face f1 = E.leftFace(adjS1); - face f2 = E.leftFace(adjS1->cyclicPred()); - - adjEntry adjE; - forall_adj(adjE,v) { - face fL = E.leftFace(adjE); - if(fL == f1 || fL == f2) continue; - - node vL = m_dualOfFace[fL]; - edge eOut = m_dual.newEdge(vDual,vL); - m_primalAdj[eOut] = adjE; - m_dualCost[eOut] = 0; - edge eIn = m_dual.newEdge(vL,vDual); - m_primalAdj[eIn] = adjE; - m_dualCost[eIn] = 1; - } - } - - v = adjS2->theNode(); - vDual = m_dualOfNode[v]; - if(vDual) { - face f1 = E.leftFace(adjS2); - face f2 = E.leftFace(adjS2->cyclicPred()); - - adjEntry adjE; - forall_adj(adjE,v) { - face fL = E.leftFace(adjE); - if(fL == f1 || fL == f2) continue; - - node vL = m_dualOfFace[fL]; - edge eOut = m_dual.newEdge(vDual,vL); - m_primalAdj[eOut] = adjE; - m_dualCost[eOut] = 0; - edge eIn = m_dual.newEdge(vL,vDual); - m_primalAdj[eIn] = adjE; - m_dualCost[eIn] = 1; - } - } - } - } - while((adj = adj->faceCycleSucc()) != adj1); - } - - node s = path.front()->source(); - if(s->degree() == 4 && PG.splittable(s)) { - m_primalNode[m_dualOfNode[s] = m_dual.newNode()] = s; - insertDualEdges(s,E); - } - - node t = path.back()->target(); - if(t->degree() == 4 && PG.splittable(t)) { - m_primalNode[m_dualOfNode[t] = m_dual.newNode()] = t; - insertDualEdges(t,E); - } - - m_delFaces->clear(); -} - - -void MMFixedEmbeddingInserter::insertDualEdge(node vDual, adjEntry adj, const CombinatorialEmbedding &E) -{ - node vLeft = m_dualOfFace[E.leftFace(adj)]; - - edge eOut = m_dual.newEdge(vDual,vLeft); - m_primalAdj[eOut] = adj; - m_dualCost[eOut] = 0; - - edge eIn = m_dual.newEdge(vLeft,vDual); - m_primalAdj[eIn] = adj; - m_dualCost[eIn] = 1; -} - - -void MMFixedEmbeddingInserter::insertDualEdges(node v, const CombinatorialEmbedding &E) -{ - node vDual = m_dualOfNode[v]; - if(vDual) { - adjEntry adj; - forall_adj(adj,v) - insertDualEdge(vDual,adj,E); - } -} - - -//--------------------------------------------------------- -// removes edge eOrig; updates embedding and dual graph -// -void MMFixedEmbeddingInserter::removeEdge( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - edge eOrig, - PlanRepExpansion::NodeSplit *nodeSplit, - node &oldSrc, node &oldTgt) -{ - const List &path = (eOrig) ? PG.chain(eOrig) : nodeSplit->m_path; - - ListConstIterator itEdge; - for(itEdge = path.begin(); itEdge.valid(); ++itEdge) - { - adjEntry adj = (*itEdge)->adjSource(); - m_delFaces->insert(E.leftFace (adj)); - m_delFaces->insert(E.rightFace (adj)); - - // remove dual of nodes that get merged - if(itEdge != path.begin()) { - node xl = adj->cyclicSucc()->twinNode(); - node xlDual = m_dualOfNode[xl]; - node xlOrig = PG.original(xl); - node xr = adj->cyclicPred()->twinNode(); - node xrDual = m_dualOfNode[xr]; - node xrOrig = PG.original(xr); - - if(xlOrig != 0 && xlOrig == xrOrig) { - if(xlDual) m_dual.delNode(xlDual); - if(xrDual) m_dual.delNode(xrDual); - m_dualOfNode[xl] = m_dualOfNode[xr] = 0; - } - } - } - - node vSrc = path.front()->source(); - if(m_dualOfNode[vSrc] != 0 && vSrc->degree() == 4) { - m_dual.delNode(m_dualOfNode[vSrc]); - m_dualOfNode[vSrc] = 0; - } - node vTgt = path.back()->target(); - if(m_dualOfNode[vTgt] != 0 && vTgt->degree() == 4) { - m_dual.delNode(m_dualOfNode[vTgt]); - m_dualOfNode[vTgt] = 0; - } - - // delete all corresponding nodes in dual - SListConstIterator itsF; - for(itsF = m_delFaces->faces().begin(); itsF.valid(); ++itsF) - m_dual.delNode(m_dualOfFace[*itsF]); - - m_delFaces->clear(); - - // remove edge path from PG - PG.removeEdgePathEmbedded(E,eOrig,nodeSplit,*m_newFaces,*m_mergedNodes, oldSrc, oldTgt); - - // insert dual nodes for merged nodes - ListConstIterator itV; - for(itV = m_mergedNodes->nodes().begin(); itV.valid(); ++itV) { - node v = *itV; - if(PG.splittable(v) && v->degree() >= 4) { - node vDual = m_dualOfNode[v] = m_dual.newNode(); - m_primalNode[vDual] = v; - - adjEntry adj; - forall_adj(adj,v) { - if(!m_newFaces->isMember(E.leftFace(adj))) // other edges are inserted below! - insertDualEdge(vDual,adj,E); - } - } - } - m_mergedNodes->clear(); - - // insert new nodes for new faces - ListConstIterator itF; - for(itF = m_newFaces->faces().begin(); itF.valid(); ++itF) { - m_dualOfFace[*itF] = m_dual.newNode(); - } - - // insert new edges into dual - for(itF = m_newFaces->faces().begin(); itF.valid(); ++itF) - { - face f = *itF; // face to the right of adj in loop - node vRight = m_dualOfFace[f]; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - face fAdj = E.leftFace(adj); - - if(m_newFaces->isMember(fAdj) == false || f->index() < fAdj->index()) - { - node vLeft = m_dualOfFace[E.leftFace(adj)]; - - edge eLR = m_dual.newEdge(vLeft,vRight); - m_dualEdge[m_primalAdj[eLR] = adj] = eLR; - m_dualCost [eLR] = 1; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_dualEdge[m_primalAdj[eRL] = adj->twin()] = eRL; - m_dualCost [eRL] = 1; - - } else if(f == fAdj) - m_dualEdge[adj] = m_dualEdge[adj->twin()] = 0; - - node vDual = m_dualOfNode[adj->theNode()]; - if(vDual != 0) { - adjEntry adjSucc = adj->cyclicSucc(); - edge eOut = m_dual.newEdge(vDual,vRight); - m_primalAdj[eOut] = adjSucc; - m_dualCost[eOut] = 0; - - edge eIn = m_dual.newEdge(vRight,vDual); - m_primalAdj[eIn] = adjSucc; - m_dualCost[eIn] = 1; - } - } - while((adj = adj->faceCycleSucc()) != adj1); - } - - m_newFaces->clear(); - -} - - -void MMFixedEmbeddingInserter::contractSplit( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - PlanRepExpansion::NodeSplit *nodeSplit) -{ - edge e = nodeSplit->m_path.front(); - node u = e->source(); - node v = e->target(); - - if(m_dualOfNode[u]) m_dual.delNode(m_dualOfNode[u]); - if(m_dualOfNode[v]) m_dual.delNode(m_dualOfNode[v]); - - // remove dual edges connecting dual node of left face of e - // with dual node of right face of e - node vl = m_dualOfFace[E.leftFace(e->adjSource())]; - adjEntry adj, adjNext; - for(adj = vl->firstAdj(); adj != 0; adj = adjNext) { - adjNext = adj->succ(); - - adjEntry padj = m_primalAdj[adj->theEdge()]; - if(padj == e->adjSource() || padj == e->adjTarget()) - m_dual.delEdge(adj->theEdge()); - } - - PG.contractSplit(nodeSplit,E); - OGDF_ASSERT(u->degree() >= 4); - - m_primalNode[m_dualOfNode[u] = m_dual.newNode()] = u; - insertDualEdges(u,E); -} - - -void MMFixedEmbeddingInserter::contractSplitIfReq( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - node u, - const PlanRepExpansion::nodeSplit nsCurrent) -{ - edge eContract = u->firstAdj()->theEdge(); - edge eExpand = u->lastAdj ()->theEdge(); - if(PG.nodeSplitOf(eContract) == 0) - swap(eContract,eExpand); - - if(u->degree() == 2 && PG.nodeSplitOf(eContract) != 0 && PG.nodeSplitOf(eContract) != nsCurrent) { - edge eDCS = m_dualEdge[eContract->adjSource()]; - if(eDCS) m_dual.delEdge(eDCS); - edge eDCT = m_dualEdge[eContract->adjTarget()]; - if(eDCT) m_dual.delEdge(eDCT); - edge eDES = m_dualEdge[eExpand ->adjSource()]; - if(eDES) m_dual.delEdge(eDES); - edge eDET = m_dualEdge[eExpand ->adjTarget()]; - if(eDET) m_dual.delEdge(eDET); - - edge e = PG.unsplitExpandNode(u,eContract,eExpand,E); - - if(e->isSelfLoop()) { - node u = e->source(); - adjEntry adj; - forall_adj(adj,u) { - if(e == adj->theEdge()) continue; - edge eDual = m_dualEdge[adj]; - if(eDual) m_dual.delEdge(eDual); - } - - PG.removeSelfLoop(e,E); - - } else { - adjEntry adj = e->adjSource(); - node vLeft = m_dualOfFace[E.leftFace (adj)]; - node vRight = m_dualOfFace[E.rightFace(adj)]; - - if(vLeft != vRight) - { - edge eLR = m_dual.newEdge(vLeft,vRight); - m_dualEdge[m_primalAdj[eLR] = adj] = eLR; - m_dualCost [eLR] = 1; - - edge eRL = m_dual.newEdge(vRight,vLeft); - m_dualEdge[m_primalAdj[eRL] = adj->twin()] = eRL; - m_dualCost [eRL] = 1; - } - } - } -} - - -void MMFixedEmbeddingInserter::collectAnchorNodes( - node v, - NodeSet &nodes, - const PlanRepExpansion::NodeSplit *nsParent, - const PlanRepExpansion &PG) const -{ - if(PG.original(v) != 0) - nodes.insert(v); - - adjEntry adj; - forall_adj(adj,v) { - edge e = adj->theEdge(); - const PlanRepExpansion::NodeSplit *ns = PG.nodeSplitOf(e); - if(ns == 0) { - // add dummy nodes of non-node-split edge - ListConstIterator it = PG.chain(PG.originalEdge(e)).begin(); - for(++it; it.valid(); ++it) - nodes.insert((*it)->source()); - - } else if(ns != nsParent) { - // add dummy nodes of node-split edge - ListConstIterator it = ns->m_path.begin(); - for(++it; it.valid(); ++it) - nodes.insert((*it)->source()); - - node w = (v == e->source()) ? ns->target() : ns->source(); - collectAnchorNodes(w, nodes, ns, PG); - } - } -} - - -void MMFixedEmbeddingInserter::findSourcesAndTargets( - node src, node tgt, - NodeSet &sources, - NodeSet &targets, - const PlanRepExpansion &PG) const -{ - collectAnchorNodes(src, sources, 0, PG); - collectAnchorNodes(tgt, targets, 0, PG); -} - -void MMFixedEmbeddingInserter::anchorNodes( - node vOrig, - NodeSet &nodes, - const PlanRepExpansion &PG) const -{ - node vFirst = PG.expansion(vOrig).front(); - if(PG.splittableOrig(vOrig) == true) - collectAnchorNodes(vFirst, nodes, 0, PG); - else - nodes.insert(vFirst); -} - - -node MMFixedEmbeddingInserter::commonDummy( - NodeSet &sources, - NodeSet &targets) -{ - ListConstIterator it; - for(it = sources.nodes().begin(); it.valid(); ++it) - if(targets.isMember(*it)) - return *it; - - return 0; -} - - -void MMFixedEmbeddingInserter::convertDummy( - PlanRepExpansion &PG, - CombinatorialEmbedding &E, - node u, - node vOrig, - PlanRepExpansion::nodeSplit ns_0) -{ - PlanRepExpansion::nodeSplit ns_1 = PG.convertDummy(u,vOrig,ns_0); - - m_primalNode[m_dualOfNode[u] = m_dual.newNode()] = u; - insertDualEdges(u,E); - - if(ns_0->m_path.size() == 1) - contractSplit(PG,E,ns_0); - if(ns_1->m_path.size() == 1) - contractSplit(PG,E,ns_1); -} - - -bool MMFixedEmbeddingInserter::checkSplitDeg( - PlanRepExpansion &PG) -{ - ListConstIterator it; - for(it = PG.nodeSplits().begin(); it.valid(); ++it) { - node src = (*it).source(); - if(src->degree() <= 2) - return false; - node tgt = (*it).target(); - if(tgt->degree() <= 2) - return false; - } - - return true; -} - - -bool MMFixedEmbeddingInserter::checkDualGraph( - PlanRepExpansion &PG, - const CombinatorialEmbedding &E) const -{ - NodeArray af(m_dual,0); - NodeArray av(m_dual,0); - - face f; - forall_faces(f,E) { - node u = m_dualOfFace[f]; - if(u == 0) - return false; - if(af[u] != 0 || av[u] != 0) - return false; - af[u] = f; - } - - node v; - forall_nodes(v,PG) { - if(PG.splittable(v) && v->degree() >= 4) { - node u = m_dualOfNode[v]; - if(u == 0) - return false; - if(af[u] != 0 || av[u] != 0) - return false; - av[u] = v; - } else { - if(m_dualOfNode[v] != 0) - return false; - } - } - - Array exists(0,m_dual.maxEdgeIndex(),false); - - edge e; - forall_edges(e,m_dual) - { - exists[e->index()] = true; - - node v = e->source(); - node w = e->target(); - adjEntry adj = m_primalAdj[e]; - - if(af[v] != 0 && af[w] != 0) { - if(af[v] != E.leftFace(adj)) - return false; - if(af[w] != E.rightFace(adj)) - return false; - if(m_dualEdge[adj] != e) - return false; - - } else if(af[v] != 0) { - if(adj->theNode() != av[w]) - return false; - if(af[v] != E.leftFace(adj)) - return false; - - } else if(af[w] != 0) { - if(adj->theNode() != av[v]) - return false; - if(af[w] != E.leftFace(adj)) - return false; - } else - return false; - } - - forall_edges(e,PG) - { - if(E.leftFace(e->adjSource()) == E.rightFace(e->adjSource())) { - if(m_dualEdge[e->adjSource()] != 0) - return false; - if(m_dualEdge[e->adjTarget()] != 0) - return false; - continue; - } - - edge eDual = m_dualEdge[e->adjSource()]; - node srcDual = eDual->source(); - node tgtDual = eDual->target(); - - if(af[srcDual] == 0) - return false; - if(af[tgtDual] == 0) - return false; - - if(E.leftFace(e->adjSource()) != af[srcDual]) - return false; - if(E.rightFace(e->adjSource()) != af[tgtDual]) - return false; - - if(exists[eDual->index()] == false) - return false; -#ifdef OGDF_DEBUG - if(eDual->graphOf() != &m_dual) - return false; - - eDual = m_dualEdge[e->adjTarget()]; - if(eDual->graphOf() != &m_dual) - return false; -#endif - } - - return true; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/MMSubgraphPlanarizer.cpp b/ext/OGDF/src/planarity/MMSubgraphPlanarizer.cpp deleted file mode 100644 index d18ec6a39..000000000 --- a/ext/OGDF/src/planarity/MMSubgraphPlanarizer.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class MMSubgraphPlanarizer. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - - -namespace ogdf { - - -MMSubgraphPlanarizer::MMSubgraphPlanarizer() -{ - FastPlanarSubgraph *s = new FastPlanarSubgraph(); - s->runs(100); - m_subgraph.set(s); - - MMFixedEmbeddingInserter *pInserter = new MMFixedEmbeddingInserter(); - pInserter->removeReinsert(MMEdgeInsertionModule::rrAll); - m_inserter.set(pInserter); - - m_permutations = 1; -} - - -Module::ReturnType MMSubgraphPlanarizer::doCall(PlanRepExpansion &PG, - int cc, - const EdgeArray *forbid, - int& crossingNumber, - int& numNS, - int& numSN) -{ - OGDF_ASSERT(m_permutations >= 1); - - List deletedEdges; - PG.initCC(cc); - - ReturnType retValue ; - - if(forbid != 0) { - List preferedEdges; - edge e; - forall_edges(e, PG) { - edge eOrig = PG.originalEdge(e); - if(eOrig && (*forbid)[eOrig]) - preferedEdges.pushBack(e); - } - - retValue = m_subgraph.get().call(PG, preferedEdges, deletedEdges, true); - - } else { - retValue = m_subgraph.get().call(PG, deletedEdges); - } - - if(isSolution(retValue) == false) - return retValue; - - for(ListIterator it = deletedEdges.begin(); it.valid(); ++it) - *it = PG.originalEdge(*it); - - int bestcr = -1; - - for(int i = 1; i <= m_permutations; ++i) - { - for(ListConstIterator it = deletedEdges.begin(); it.valid(); ++it) - PG.delCopy(PG.copy(*it)); - - deletedEdges.permute(); - - if(forbid != 0) - m_inserter.get().call(PG, deletedEdges, *forbid); - else - m_inserter.get().call(PG, deletedEdges); - - crossingNumber = PG.computeNumberOfCrossings(); - - if(i == 1 || crossingNumber < bestcr) { - bestcr = crossingNumber; - numNS = PG.numberOfNodeSplits(); - numSN = PG.numberOfSplittedNodes(); - } - - PG.initCC(cc); - } - - crossingNumber = bestcr; - - return retFeasible; -} - - -} // namspace ogdf diff --git a/ext/OGDF/src/planarity/MMVariableEmbeddingInserter.cpp b/ext/OGDF/src/planarity/MMVariableEmbeddingInserter.cpp deleted file mode 100644 index b7320cfc3..000000000 --- a/ext/OGDF/src/planarity/MMVariableEmbeddingInserter.cpp +++ /dev/null @@ -1,1893 +0,0 @@ -/* - * $Revision: 2616 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-16 15:34:43 +0200 (Mo, 16. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of MMVariableEmbeddingInserter class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include - - -//#define MMC_OUTPUT - -namespace ogdf { - - static int globalCounter = 0; - -//--------------------------------------------------------- -// constructor -// sets default values for options -// -MMVariableEmbeddingInserter::MMVariableEmbeddingInserter() -{ - m_rrOption = rrNone; - m_percentMostCrossed = 25; -} - - -//--------------------------------------------------------- -// VEICrossingsBucket -// bucket function for sorting edges by decreasing number -// of crossings -class VEICrossingsBucket : public BucketFunc -{ - const PlanRepExpansion *m_pPG; - -public: - VEICrossingsBucket(const PlanRepExpansion *pPG) : - m_pPG(pPG) { } - - int getBucket(const edge &e) { - return -m_pPG->chain(e).size(); - } -}; - -void outputPG(const PlanRepExpansion &PG, int i) -{ - GraphAttributes AG(PG, GraphAttributes::nodeLabel); - String label; - - node v; - forall_nodes(v,PG) { - label.sprintf("%d",v->index()); - AG.labelNode(v) = label; - } - - String str; - str.sprintf("PG_%d.gml", i); - AG.writeGML(str); -} - -void MMVariableEmbeddingInserter::writeEip(const List &eip) -{ - ListConstIterator it; - for(it = eip.begin(); it.valid(); ++it) { - const MMVariableEmbeddingInserter::Crossing &cr = *it; - - if(cr.m_adj == 0) { - cout << "nil {"; - cout << cr.m_partitionLeft; - cout << "} {"; - cout << cr.m_partitionRight; - cout << "}"; - - } else - cout << cr.m_adj; - cout << endl; - } -} - -//--------------------------------------------------------- -// actual call (called by all variations of call) -// crossing of generalizations is forbidden if forbidCrossingGens = true -// edge costs are obeyed if costOrig != 0 -// -Module::ReturnType MMVariableEmbeddingInserter::doCall( - PlanRepExpansion &PG, - const List &origEdges, - const EdgeArray *forbiddenEdgeOrig) -{ - ReturnType retValue = retFeasible; - - if (origEdges.size() == 0) - return retOptimal; // nothing to do - - m_pPG = &PG; - m_forbiddenEdgeOrig = forbiddenEdgeOrig; - - SListPure rrEdges; - if(removeReinsert() != rrNone) { - edge e; - forall_edges(e,PG) - rrEdges.pushBack(PG.originalEdge(e)); - - ListConstIterator itE; - for(itE = origEdges.begin(); itE.valid(); ++itE) - rrEdges.pushBack(*itE); - } - - m_pSources = new NodeSet(PG); - m_pTargets = new NodeSet(PG); - -#ifdef MMC_OUTPUT - outputPG(PG,0); - int ii = 0; -#endif - - // insertion of edges - ListConstIterator it; - for(it = origEdges.begin(); it.valid(); ++it) - { - edge eOrig = *it; - node srcOrig = eOrig->source(); - node tgtOrig = eOrig->target(); - -#ifdef MMC_OUTPUT - cout << "insert " << srcOrig << " -> " << tgtOrig << endl; -#endif - - node oldSrc = (PG.splittableOrig(srcOrig) && PG.expansion(srcOrig).size() == 1) ? - PG.expansion(srcOrig).front() : 0; - node oldTgt = (PG.splittableOrig(tgtOrig) && PG.expansion(tgtOrig).size() == 1) ? - PG.expansion(tgtOrig).front() : 0; - - anchorNodes(eOrig->source(), *m_pSources); - anchorNodes(eOrig->target(), *m_pTargets); - - node vDummy = commonDummy(*m_pSources, *m_pTargets); - node src, tgt; - edge eExtraSrc = 0, eExtraTgt = 0; - List eip; - - if(vDummy == 0) { - AnchorNodeInfo vStart, vEnd; - insert(eip, vStart, vEnd); - -#ifdef MMC_OUTPUT - writeEip(eip); -#endif - preprocessInsertionPath(vStart,vEnd,srcOrig,tgtOrig,src,tgt,eExtraSrc,eExtraTgt); - -#ifdef MMC_OUTPUT - cout << "from: " << src << " to: " << tgt << endl; -#endif - - } else { - insertWithCommonDummy(eOrig, vDummy, src, tgt); -#ifdef MMC_OUTPUT - cout << "(direct) from: " << src << " to: " << tgt << endl; -#endif - } - - PG.insertEdgePath(eOrig, 0, src, tgt, eip, eExtraSrc, eExtraTgt); - -#ifdef MMC_OUTPUT - ++ii; - cout << endl; - outputPG(PG,ii); -#endif - - m_pSources->clear(); - m_pTargets->clear(); - - if(oldSrc != 0 && PG.expansion(srcOrig).size() > 1) - contractSplitIfReq(oldSrc); - if(oldTgt != 0 && PG.expansion(tgtOrig).size() > 1) - contractSplitIfReq(oldTgt); - - //OGDF_ASSERT(PG.consistencyCheck()); - //OGDF_ASSERT(isPlanar(PG)); - } - - if(removeReinsert() != rrNone) { - // postprocessing (remove-reinsert heuristc) - //SListPure rrEdges; - - //switch(removeReinsert()) - //{ - //case rrAll: - //case rrMostCrossed: { - // const List &origInCC = PG.nodesInCC(); - // ListConstIterator itV; - - // for(itV = origInCC.begin(); itV.valid(); ++itV) { - // node vG = *itV; - // adjEntry adj; - // forall_adj(adj,vG) { - // if ((adj->index() & 1) == 0) continue; - // edge eG = adj->theEdge(); - // rrEdges.pushBack(eG); - // } - // } - // } - // break; - - //case rrInserted: { - // ListConstIterator it; - // for(it = origEdges.begin(); it.valid(); ++it) - // rrEdges.pushBack(*it); - // } - // break; - //} - - // marks the end of the interval of rrEdges over which we iterate - // initially set to invalid iterator which means all edges - //SListConstIterator itStop; - - bool improved; - do { - improved = false; - - //if(removeReinsert() == rrMostCrossed) - //{ - // VEICrossingsBucket bucket(&PG); - // rrEdges.bucketSort(bucket); - - // const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); - // itStop = rrEdges.get(num); - //} - - SListConstIterator it; - for(it = rrEdges.begin(); it.valid(); ++it) - { - globalCounter++; - edge eOrig = *it; - node srcOrig = eOrig->source(); - node tgtOrig = eOrig->target(); - - int oldCrossings = PG.chain(eOrig).size() - 1; - if (oldCrossings == 0) continue; // cannot improve - - node oldSrc = 0, oldTgt = 0; - PG.removeEdgePath(eOrig,0,oldSrc,oldTgt); - //OGDF_ASSERT(PG.consistencyCheck()); - - // try to find a better insertion path - anchorNodes(eOrig->source(), *m_pSources); - anchorNodes(eOrig->target(), *m_pTargets); - - node vDummy = commonDummy(*m_pSources, *m_pTargets); - node src, tgt; - edge eExtraSrc = 0, eExtraTgt = 0; - - List eip; - if(vDummy == 0) { - AnchorNodeInfo vStart, vEnd; - insert(eip, vStart, vEnd); - preprocessInsertionPath(vStart,vEnd,srcOrig,tgtOrig,src,tgt,eExtraSrc,eExtraTgt); - - } else { - insertWithCommonDummy(eOrig, vDummy, src, tgt); - } - - int newCrossings = eip.size(); - - OGDF_ASSERT(isPlanar(PG)); - PG.insertEdgePath(eOrig, 0, src, tgt, eip, eExtraSrc, eExtraTgt); - OGDF_ASSERT(PG.consistencyCheck()); - OGDF_ASSERT(isPlanar(PG)); - - m_pSources->clear(); - m_pTargets->clear(); - - if(PG.splittable(oldSrc)) - contractSplitIfReq(oldSrc); - if(PG.splittable(oldTgt)) - contractSplitIfReq(oldTgt); - - OGDF_ASSERT(PG.consistencyCheck()); - OGDF_ASSERT(isPlanar(PG)); - - //int newPathLength = PG.chain(eOrig).size() - 1; - int saved = oldCrossings - newCrossings; - OGDF_ASSERT(saved >= 0); - - if(saved > 0) - improved = true; - } - - if(removeReinsert() == rrAll) - { - // process all node splits - int nsCount = PG.nodeSplits().size(); - ListIterator itS, itSNext; - for(itS = PG.nodeSplits().begin(); itS.valid() && nsCount > 0; itS = itSNext, --nsCount) - { - globalCounter++; - PlanRepExpansion::NodeSplit *ns = &(*itS); - - int oldCrossings = ns->m_path.size() - 1; - if (oldCrossings == 0) { - itSNext = itS.succ(); - PG.contractSplit(ns); - continue; // cannot improve - } - - node vOrig = PG.original(ns->source()); - - node oldSrc = 0, oldTgt = 0; - PG.removeEdgePath(0,ns,oldSrc,oldTgt); - OGDF_ASSERT(PG.consistencyCheck()); - - // try to find a better insertion path - findSourcesAndTargets(oldSrc,oldTgt,*m_pSources,*m_pTargets); - - node vCommon = commonDummy(*m_pSources, *m_pTargets); - - if(vCommon == 0) { - node src, tgt; - edge eExtraSrc = 0, eExtraTgt = 0; - - List eip; - AnchorNodeInfo vStart, vEnd; - insert(eip, vStart, vEnd); - preprocessInsertionPath(vStart,vEnd,vOrig,vOrig,src,tgt,eExtraSrc,eExtraTgt); - PG.insertEdgePath(0, ns, src, tgt, eip, eExtraSrc, eExtraTgt); - - OGDF_ASSERT(PG.consistencyCheck()); - - m_pSources->clear(); - m_pTargets->clear(); - - if(PG.splittable(oldSrc)) - contractSplitIfReq(oldSrc); - if(PG.splittable(oldTgt)) - contractSplitIfReq(oldTgt); - - OGDF_ASSERT(PG.consistencyCheck()); - OGDF_ASSERT(isPlanar(PG)); - - //int newCrossings = ns->m_path.size() - 1; - int newCrossings = eip.size(); - int saved = oldCrossings - newCrossings; - OGDF_ASSERT(saved >= 0); - - if(saved > 0) - improved = true; - - itSNext = itS.succ(); - if(ns->m_path.size() == 1) - PG.contractSplit(ns); - - } else { - m_pSources->clear(); - m_pTargets->clear(); - - improved = true; - itSNext = itS.succ(); - - convertDummy(vCommon,vOrig,ns); - OGDF_ASSERT(PG.consistencyCheck()); - OGDF_ASSERT(isPlanar(PG)); - } - } - } - - } while(improved); - } - - delete m_pSources; - delete m_pTargets; - -#ifdef OGDF_DEBUG - bool isPlanar = -#endif - PG.embed(); - OGDF_ASSERT(isPlanar); - OGDF_ASSERT(PG.representsCombEmbedding()); - - return retValue; -} - - -void MMVariableEmbeddingInserter::insert( - List &eip, - AnchorNodeInfo &vStart, - AnchorNodeInfo &vEnd) -{ - PlanRepExpansion &PG = *m_pPG; - eip.clear(); - - // compute biconnected components of PG - EdgeArray compnum(PG); - int c = biconnectedComponents(PG,compnum); - - m_compV.init(PG); - m_nodeB.init(c); - - // edgeB[i] = list of edges in component i - m_edgeB.init(c); - edge e; - forall_edges(e,PG) - m_edgeB[compnum[e]].pushBack(e); - - // construct arrays compV and nodeB such that - // m_compV[v] = list of components containing v - // m_nodeB[i] = list of vertices in component i - NodeArray mark(PG,false); - - int i; - for(i = 0; i < c; ++i) { - SListConstIterator itEdge; - for(itEdge = m_edgeB[i].begin(); itEdge.valid(); ++itEdge) - { - edge e = *itEdge; - - if (!mark[e->source()]) { - mark[e->source()] = true; - m_nodeB[i].pushBack(e->source()); - } - if (!mark[e->target()]) { - mark[e->target()] = true; - m_nodeB[i].pushBack(e->target()); - } - } - - SListConstIterator itNode; - for(itNode = m_nodeB[i].begin(); itNode.valid(); ++itNode) - { - node v = *itNode; - m_compV[v].pushBack(i); - mark[v] = false; - } - } - - mark.init(); - m_GtoBC.init(PG,0); - - m_conFinished = false; - dfsVertex(m_pTargets->nodes().front(), -1, eip, vStart, vEnd); - - // deallocate resources used by insert() - m_GtoBC.init(); - m_edgeB.init(); - m_nodeB.init(); - m_compV.init(); -} - - -node MMVariableEmbeddingInserter::prepareAnchorNode( - const AnchorNodeInfo &anchor, - node vOrig, - bool isSrc, - edge &eExtra) -{ - PlanRepExpansion &PG = *m_pPG; - - adjEntry adj = 0; - node vStraight = 0; - - edge eStraight; - PlanRepExpansion::NodeSplit *nsStraight; - if(anchor.m_adj_2 != 0) { - adj = anchor.m_adj_1; - //if(PG.originalEdge(adj->theEdge()) == PG.originalEdge(anchor.m_adj_2->theEdge()) && - // PG.nodeSplitOf(adj->theEdge()) == PG.nodeSplitOf(anchor.m_adj_2->theEdge())) - //{ - // node u = adj->theNode(); - // forall_adj(adj,u) { - // List *pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - // vStraight = pathStraight->front()->source(); - // if(PG.original(vStraight) == vOrig) - // break; - // vStraight = pathStraight->back()->target(); - // if(PG.original(vStraight)== vOrig) - // break; - // } - // - // PG.removeCrossingReuseDummy(adj, vStraight); - - // return u; - //} - - List *pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - - vStraight = pathStraight->front()->source(); - if(PG.original(vStraight) != vOrig) { - vStraight = pathStraight->back()->target(); - if(PG.original(vStraight) != vOrig) { - adj = anchor.m_adj_2; - pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - vStraight = pathStraight->front()->source(); - if(PG.original(vStraight) != vOrig) { - vStraight = pathStraight->back()->target(); - } - } - } - - if(PG.original(vStraight) != vOrig) { - node u = adj->theNode(); - adjEntry adjA[2]; - int i = 0; - adjEntry adj_x; - forall_adj(adj_x,u) { - if(adj_x != anchor.m_adj_1 && adj_x != anchor.m_adj_2) - adjA[i++] = adj_x; - } - - List *pathStraight = &PG.setOrigs(adjA[0]->theEdge(), eStraight, nsStraight); - vStraight = pathStraight->front()->source(); - if(PG.original(vStraight) != vOrig) - vStraight = pathStraight->back()->target(); - OGDF_ASSERT(PG.original(vStraight) == vOrig); - - eExtra = PG.separateDummy(adjA[0], adjA[1], vStraight, isSrc); - return u; - } - - } else { - // Should be the correct adj... (case S-node, dummy) - adj = anchor.m_adj_1; - List *pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - - if((eStraight && eStraight->source() != vOrig && eStraight->target() != vOrig) || - (nsStraight && PG.original(nsStraight->source()) != vOrig)) - { - node vDummy = adj->theNode(); - edge eStraightOld = eStraight; - PlanRepExpansion::NodeSplit *nsStraightOld = nsStraight; - - forall_adj(adj,vDummy) { - pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight); - if((eStraightOld && eStraight != eStraightOld) || (nsStraightOld && nsStraight != nsStraightOld)) - break; - } - } - - vStraight = pathStraight->front()->source(); - if(PG.original(vStraight) != vOrig) - vStraight = pathStraight->back()->target(); - } - - OGDF_ASSERT(PG.original(vStraight) == vOrig); - eExtra = 0; - - if(PG.original(adj->twinNode()) == vOrig) { - // No need for a split; can just directly go to a split node - return adj->twinNode(); - - } else { - edge e = adj->theEdge(); - if(nsStraight == 0) { - // We split a chain of an original edge - PG.enlargeSplit(vStraight, e); - return e->target(); - - } else { - // We split a node split - PG.splitNodeSplit(e); - return e->target(); - } - } -} - -void MMVariableEmbeddingInserter::preprocessInsertionPath( - const AnchorNodeInfo &srcInfo, - const AnchorNodeInfo &tgtInfo, - node srcOrig, - node tgtOrig, - node &src, - node &tgt, - edge &eSrc, - edge &eTgt) -{ - PlanRepExpansion &PG = *m_pPG; - - src = srcInfo.m_adj_1->theNode(); - if(PG.original(src) == 0) - src = prepareAnchorNode(srcInfo,srcOrig,true,eSrc); - - tgt = tgtInfo.m_adj_1->theNode(); - if(PG.original(tgt) == 0) - tgt = prepareAnchorNode(tgtInfo,tgtOrig,false,eTgt); -} - - -node MMVariableEmbeddingInserter::preparePath( - node vAnchor, - adjEntry adjPath, - bool bOrigEdge, - node vOrig) -{ - PlanRepExpansion &PG = *m_pPG; - - if(PG.original(adjPath->twinNode()) == vOrig) { - // No need for a split; can just directly go to a split node - return adjPath->twinNode(); - - } else { - edge e = adjPath->theEdge(); - if(bOrigEdge) { - // We split a chain of an original edge - PG.enlargeSplit(vAnchor, e); - } else { - // We split a node split - PG.splitNodeSplit(e); - } - return e->target(); - } -} - - -void MMVariableEmbeddingInserter::findPseudos( - node vDummy, - adjEntry adjSrc, - AnchorNodeInfo &infoSrc, - SListPure &pseudos) -{ - PlanRepExpansion &PG = *m_pPG; - - ListConstIterator it = PG.position(adjSrc->theEdge()); - node w; - if((*it)->source() == vDummy) { - edge e = *it; - while(PG.isPseudoCrossing(w = e->target())) { - pseudos.pushBack(w); - ++it; e = *it; - } - - infoSrc.m_adj_1 = e->adjTarget(); - infoSrc.m_adj_2 = (adjSrc->cyclicSucc() == (*PG.position(adjSrc->theEdge()).pred())->adjTarget()) ? - infoSrc.m_adj_1->cyclicSucc() : infoSrc.m_adj_1->cyclicPred(); - - } else { - edge e = *it; - while(PG.isPseudoCrossing(w = e->source())) { - pseudos.pushBack(w); - --it; e = *it; - } - - infoSrc.m_adj_1 = e->adjSource(); - infoSrc.m_adj_2 = (adjSrc->cyclicPred() == (*PG.position(adjSrc->theEdge()).succ())->adjSource()) ? - infoSrc.m_adj_1->cyclicPred() : infoSrc.m_adj_1->cyclicSucc(); - } - -} - - -void MMVariableEmbeddingInserter::insertWithCommonDummy( - edge eOrig, - node vDummy, - node &src, - node &tgt) -{ - PlanRepExpansion &PG = *m_pPG; -#ifdef OGDF_DEBUG - bool isPlanar = -#endif - PG.embed(); - OGDF_ASSERT(isPlanar); - - node vSrc = 0, vTgt = 0; - adjEntry adjSrc = 0, adjTgt = 0; - bool bOrigEdgeSrc = true, bOrigEdgeTgt = true; - - adjEntry adj; - forall_adj(adj,vDummy) { - edge e = adj->theEdge(); - edge eStraight; - PlanRepExpansion::NodeSplit *nsStraight; - List &pathStraight = PG.setOrigs(e, eStraight, nsStraight); - - node vAnchor; - if(vDummy == e->source()) - vAnchor = pathStraight.back()->target(); - else - vAnchor = pathStraight.front()->source(); - - node vOrig = PG.original(vAnchor); - if(vOrig == eOrig->source()) { - vSrc = vAnchor; - adjSrc = adj; - bOrigEdgeSrc = (eStraight != 0); - } else if(vOrig == eOrig->target()) { - vTgt = vAnchor; - adjTgt = adj; - bOrigEdgeTgt = (eStraight != 0); - } - } - - OGDF_ASSERT(vSrc != 0 && vTgt != 0 && adjSrc != 0 && adjTgt != 0); - - if(adjSrc == adjTgt->cyclicPred() || adjSrc == adjTgt->cyclicSucc()) - { - src = preparePath(vSrc, adjSrc, bOrigEdgeSrc, eOrig->source()); - tgt = preparePath(vTgt, adjTgt, bOrigEdgeTgt, eOrig->target()); - - } else { - SListPure pseudos; - AnchorNodeInfo infoSrc; - AnchorNodeInfo infoTgt; - - findPseudos(vDummy,adjSrc,infoSrc,pseudos); - findPseudos(vDummy,adjTgt,infoTgt,pseudos); - - SListConstIterator it; - for(it = pseudos.begin(); it.valid(); ++it) - PG.resolvePseudoCrossing(*it); - - edge eExtra = 0; - src = infoSrc.m_adj_1->theNode(); - if(PG.original(src) == 0) - src = prepareAnchorNode(infoSrc,eOrig->source(),true,eExtra); - OGDF_ASSERT(eExtra == 0); - - tgt = infoTgt.m_adj_1->theNode(); - if(PG.original(tgt) == 0) - tgt = prepareAnchorNode(infoTgt,eOrig->target(),false,eExtra); - OGDF_ASSERT(eExtra == 0); - - - - //adjEntry adjTgt_2 = adjTgt->cyclicSucc()->cyclicSucc(); - //OGDF_ASSERT(PG.nodeSplitOf(adjTgt->theEdge()) == PG.nodeSplitOf(adjTgt_2->theEdge()) && - // PG.originalEdge(adjTgt->theEdge()) == PG.originalEdge(adjTgt_2->theEdge())); - - //edge e = PG.insertBySepDummy(eOrig, vSrc, vTgt, adjSrc, adjTgt, adjTgt_2); - // //separateDummy(adjTgt, adjTgt_2, vTgt, false); - //PG.assignOrig(e,eOrig); - } -} - -//------------------------------------------------------------------- -// Block represents a block of the original graph -//------------------------------------------------------------------- - -class MMVariableEmbeddingInserter::Block : public Graph -{ -public: - // constructor - Block(PlanRepExpansion &PG) : m_PG(PG) - { - m_adjBCtoG .init(*this,0); - m_forbidden .init(*this,false); - m_vBCtoG .init(*this,0); - m_isSource .init(*this,false); - m_isTarget .init(*this,false); - m_isSplittable.init(*this,false); - m_pT = 0; - } - - ~Block() { delete m_pT; } - - // avoid automatic generation of assignment operator - Block &operator=(const Block &); - - node containsSource(node v) const; - node containsTarget(node v) const; - - adjEntry containsSourceAdj(node v) const; - adjEntry containsTargetAdj(node v) const; - - PlanRepExpansion &m_PG; - StaticPlanarSPQRTree *m_pT; - - AdjEntryArray m_adjBCtoG; - EdgeArray m_forbidden; - NodeArray m_vBCtoG; - - NodeArray m_isSource; - NodeArray m_isTarget; - NodeArray m_isSplittable; -}; - - -node MMVariableEmbeddingInserter::Block::containsSource(node v) const -{ - const Skeleton &S = m_pT->skeleton(v); - const Graph &M = S.getGraph(); - - node w; - forall_nodes(w,M) { - node wOrig = S.original(w); - if(m_isSource[wOrig]) - return wOrig; - } - - return 0; -} - -node MMVariableEmbeddingInserter::Block::containsTarget(node v) const -{ - const Skeleton &S = m_pT->skeleton(v); - const Graph &M = S.getGraph(); - - node w; - forall_nodes(w,M) { - node wOrig = S.original(w); - if(m_isTarget[wOrig]) - return wOrig; - } - - return 0; -} - -adjEntry MMVariableEmbeddingInserter::Block::containsSourceAdj(node v) const -{ - const Skeleton &S = m_pT->skeleton(v); - const Graph &M = S.getGraph(); - - node w, wOrig = 0; - forall_nodes(w,M) { - wOrig = S.original(w); - if(m_isSource[wOrig]) - break; - } - - if(wOrig == 0) return 0; - - adjEntry adj; - forall_adj(adj,wOrig) { - if(m_pT->skeletonOfReal(adj->theEdge()).treeNode() == v) - return adj; - } - - return wOrig->firstAdj(); -} - -adjEntry MMVariableEmbeddingInserter::Block::containsTargetAdj(node v) const -{ - const Skeleton &S = m_pT->skeleton(v); - const Graph &M = S.getGraph(); - - node w, wOrig = 0; - forall_nodes(w,M) { - wOrig = S.original(w); - if(m_isTarget[wOrig]) - break; - } - - if(wOrig == 0) return 0; - - adjEntry adj; - forall_adj(adj,wOrig) { - if(m_pT->skeletonOfReal(adj->theEdge()).treeNode() == v) - return adj; - } - - return wOrig->firstAdj(); -} - - -//------------------------------------------------------------------- -// ExpandedSkeleton represents the (partially) expanded skeleton with -// its dual graph (search network) -//------------------------------------------------------------------- - -class MMVariableEmbeddingInserter::ExpandedSkeleton -{ - Block &m_BC; - - NodeArray m_GtoExp; - List m_nodesG; - Graph m_exp; // expanded graph - AdjEntryArray m_expToG; - edge m_eS, m_eT; // (virtual) edges in exp representing s and t (if any) - - ConstCombinatorialEmbedding m_E; //!< Embedding of expanded graph. - - Graph m_dual; //!< Search network of expanded skeleton. - NodeArray m_primalNode; //!< The node in PG corresponding to dual node (0 if face). - EdgeArray m_primalAdj; //!< The adjacency entry in primal graph corresponding to edge in dual. - EdgeArray m_dualCost; //!< The cost of an edge in the seach network. - - node m_startEdge; - node m_startSource; - node m_startTarget; - node m_endEdge; - node m_endSource; - node m_endTarget; - - -public: - ExpandedSkeleton(Block &BC) : - m_BC(BC), - m_GtoExp(BC.m_pT->originalGraph(),0), - m_expToG(m_exp,0), - m_primalNode(m_dual,0), - m_primalAdj(m_dual,0), - m_dualCost(m_dual,0) { } - - void expand(node v, edge eIn, edge eOut); - - void constructDual(bool bPathToEdge, bool bPathToSrc, bool bPathToTgt); - - void findShortestPath(bool &bPathToEdge, bool &bPathToSrc, bool &bPathToTgt, Paths &paths); - - // avoid automatic generation of assignment operator - ExpandedSkeleton &operator=(const ExpandedSkeleton &); - -private: - edge insertEdge(node vG, node wG, edge eG); - void expandSkeleton(node v, edge e1, edge e2); - - static void addOutgoingEdges(node v, SListPure &edges); - PathType reconstructInsertionPath( - node v, - AnchorNodeInfo &m_srcInfo, - AnchorNodeInfo &m_tgtInfo, - List &crossed, - SList &addLeft, - SList &addRight, - NodeArray &spPred); -}; - - -//------------------------------------------------------------------- -// build expanded graph (by expanding skeleton(v), edges eIn and eOut -// are the adjacent tree edges on the path from v1 to v2 -//------------------------------------------------------------------- - -void MMVariableEmbeddingInserter::ExpandedSkeleton::expand( - node v, edge eIn, edge eOut) -{ - m_exp.clear(); - - while (!m_nodesG.empty()) - m_GtoExp[m_nodesG.popBackRet()] = 0; - - const StaticSPQRTree &T = *m_BC.m_pT; - const Skeleton &S = T.skeleton(v); - - m_eS = 0; - if (eIn != 0) { - edge eInS = (v != eIn->source()) ? T.skeletonEdgeTgt(eIn) : - T.skeletonEdgeSrc(eIn); - node x = S.original(eInS->source()), y = S.original(eInS->target()); - m_eS = insertEdge(x,y,0); - } - - m_eT = 0; - if (eOut != 0) { - edge eOutS = (v != eOut->source()) ? T.skeletonEdgeTgt(eOut) : - T.skeletonEdgeSrc(eOut); - node x = S.original(eOutS->source()), y = S.original(eOutS->target()); - m_eT = insertEdge(x,y,0); - } - - expandSkeleton(v, eIn, eOut); - - planarEmbed(m_exp); - m_E.init(m_exp); -} - - -//------------------------------------------------------------------- -// insert edge in exp (from a node corresponding to vG in G to a node -// corresponding to wG) -//------------------------------------------------------------------- - -edge MMVariableEmbeddingInserter::ExpandedSkeleton::insertEdge( - node vG, node wG, edge eG) -{ - node &rVG = m_GtoExp[vG]; - node &rWG = m_GtoExp[wG]; - - if (rVG == 0) { - rVG = m_exp.newNode(); - m_nodesG.pushBack(vG); - } - if (rWG == 0) { - rWG = m_exp.newNode(); - m_nodesG.pushBack(wG); - } - - edge e1 = m_exp.newEdge(rVG,rWG); - - if(eG != 0) { - m_expToG[e1->adjSource()] = eG->adjSource(); - m_expToG[e1->adjTarget()] = eG->adjTarget(); - } else { - m_expToG[e1->adjSource()] = 0; - m_expToG[e1->adjTarget()] = 0; - } - - return e1; -} - - -//------------------------------------------------------------------- -// expand one skeleton (recursive construction) -//------------------------------------------------------------------- - -void MMVariableEmbeddingInserter::ExpandedSkeleton::expandSkeleton( - node v, edge e1, edge e2) -{ - const StaticSkeleton &S = *dynamic_cast(&m_BC.m_pT->skeleton(v)); - const Graph &M = S.getGraph(); - - edge e; - forall_edges(e,M) - { - edge eG = S.realEdge(e); - if (eG != 0) { - insertEdge(eG->source(),eG->target(),eG); - - } else { - edge eT = S.treeEdge(e); - - // do not expand virtual edges corresponding to tree edges e1 or e2 - if (eT != e1 && eT != e2) { - expandSkeleton((v == eT->source()) ? eT->target() : eT->source(), - eT,0); - } - } - } -} - - -//------------------------------------------------------------------- -// construct augmented dual graph (search network) -//------------------------------------------------------------------- - -void MMVariableEmbeddingInserter::ExpandedSkeleton::constructDual( - bool bPathToEdge, bool bPathToSrc, bool bPathToTgt) -{ - m_dual.clear(); - - // insert a node in the dual graph for each face in E - FaceArray dualOfFace(m_E); - - face f; - forall_faces(f,m_E) - dualOfFace[f] = m_dual.newNode(); - - SListPure sources, targets; - - // insert a node in the dual graph for each splittable node in PG - NodeArray dualOfNode(m_exp,0); - - ListConstIterator itV; - for(itV = m_nodesG.begin(); itV.valid(); ++itV) { - node vBC = *itV; - node v = m_GtoExp[vBC]; - - bool addDualNode = m_BC.m_isSplittable[vBC]; - - if(m_BC.m_isSource[vBC]) { - sources.pushBack(v); - addDualNode = true; - } - if(m_BC.m_isTarget[vBC]) { - targets.pushBack(v); - addDualNode = true; - } - - if(addDualNode) - m_primalNode[dualOfNode[v] = m_dual.newNode()] = v; - } - - // Insert an edge into the dual graph for each adjacency entry in E. - // The edges are directed from the left face to the right face. - node v; - forall_nodes(v,m_exp) - { - node vDual = dualOfNode[v]; - - adjEntry adj; - forall_adj(adj,v) - { - // cannot cross virtual edge representing sources / targets - adjEntry adjBC = m_expToG[adj]; - if(adjBC == 0) - continue; - - node vLeft = dualOfFace[m_E.leftFace (adj)]; - node vRight = dualOfFace[m_E.rightFace(adj)]; - - if(m_BC.m_forbidden[adjBC->theEdge()] == false) { - edge e = m_dual.newEdge(vLeft,vRight); - m_primalAdj[e] = adj; - m_dualCost [e] = 1; - } - - if(vDual) { - //if(m_eT == 0 || (v != m_eT->source() && v != m_eT->target())) { - edge eOut = m_dual.newEdge(vDual,vLeft); - m_primalAdj[eOut] = adj; - m_dualCost [eOut] = 0; - //} - - if(m_eS == 0 || - ((bPathToSrc == false || v != m_eS->source()) && (bPathToTgt == false || v != m_eS->target()))) - { - edge eIn = m_dual.newEdge(vLeft,vDual); - m_primalAdj[eIn] = adj; - m_dualCost [eIn] = 1; - } - } - } - } - - m_startEdge = (bPathToEdge) ? m_dual.newNode() : 0; - if(m_eS != 0) { - if(m_startEdge) { - m_dual.newEdge(m_startEdge, dualOfFace[m_E.rightFace(m_eS->adjSource())]); - m_dual.newEdge(m_startEdge, dualOfFace[m_E.rightFace(m_eS->adjTarget())]); - } - - m_startSource = (bPathToSrc) ? dualOfNode[m_eS->source()] : 0; - m_startTarget = (bPathToTgt) ? dualOfNode[m_eS->target()] : 0; - - } else { - m_startSource = m_startTarget = 0; - SListConstIterator it; - for(it = sources.begin(); it.valid(); ++it) - m_dual.newEdge(m_startEdge, dualOfNode[*it]); - } - - m_endEdge = m_dual.newNode(); - if(m_eT != 0) { - m_dual.newEdge(dualOfFace[m_E.rightFace(m_eT->adjSource())], m_endEdge); - m_dual.newEdge(dualOfFace[m_E.rightFace(m_eT->adjTarget())], m_endEdge); - - m_endSource = dualOfNode[m_eT->source()]; - m_endTarget = dualOfNode[m_eT->target()]; - - } else { - m_endSource = m_endTarget = 0; - SListConstIterator it; - for(it = targets.begin(); it.valid(); ++it) - m_dual.newEdge(dualOfNode[*it], m_endEdge); - } -} - - -//------------------------------------------------------------------- -// finds shortest paths in the search network -//------------------------------------------------------------------- - -void MMVariableEmbeddingInserter::ExpandedSkeleton::addOutgoingEdges( - node v, SListPure &edges) -{ - edge e; - forall_adj_edges(e,v) - if(e->target() != v) - edges.pushBack(e); -} - -MMVariableEmbeddingInserter::PathType - MMVariableEmbeddingInserter::ExpandedSkeleton::reconstructInsertionPath( - node v, - AnchorNodeInfo &srcInfo, - AnchorNodeInfo &tgtInfo, - List &crossed, - SList &addLeft, - SList &addRight, - NodeArray &spPred) -{ - // handle last node on path split first - if(v == m_endEdge) { - edge eDual = spPred[v]; - v = eDual->source(); - if(m_primalNode[v] != 0) { - eDual = spPred[v]; - // hier Ziel speichern: m_expToG[m_primalAdj[eDual]]->theNode() - //tgt = m_expToG[m_primalAdj[eDual]]->theNode(); - tgtInfo.m_adj_1 = m_expToG[m_primalAdj[eDual]]; - tgtInfo.m_adj_2 = m_expToG[m_primalAdj[eDual]->cyclicPred()]; - - OGDF_ASSERT(tgtInfo.m_adj_1 != 0); - - v = eDual->source(); - } - - } else { - edge eDual = spPred[v]; - - if(eDual != 0) { - adjEntry adj_1 = m_primalAdj[eDual]; - Crossing &cr = *crossed.pushFront(Crossing()); - - adjEntry adj; - for(adj = adj_1; adj->theEdge() != m_eT; adj = adj->cyclicSucc()) { - adjEntry adjBC = m_expToG[adj]; - if(adjBC != 0) - cr.m_partitionLeft.pushBack(adjBC); - //OGDF_ASSERT(m_expToG[adj] != 0); - } - for(adj = adj->cyclicSucc(); adj != adj_1; adj = adj->cyclicSucc()) { - adjEntry adjBC = m_expToG[adj]; - if(adjBC != 0) - cr.m_partitionRight.pushBack(adjBC); - //OGDF_ASSERT(m_expToG[adj] != 0); - } - - v = eDual->source(); - - } else { - node vExp = m_primalNode[v]; - OGDF_ASSERT(m_eS->source() == vExp || m_eS->target() == vExp); - OGDF_ASSERT(m_eT->source() == vExp || m_eT->target() == vExp); - adjEntry adjS = (m_eS->source() == vExp) ? m_eS->adjSource() : m_eS->adjTarget(); - adjEntry adjT = (m_eT->source() == vExp) ? m_eT->adjSource() : m_eT->adjTarget(); - OGDF_ASSERT(adjS->theNode() == vExp && adjT->theNode() == vExp); - - adjEntry adj; - for(adj = adjS->cyclicSucc(); adj != adjT; adj = adj->cyclicSucc()) { - addLeft.pushBack(m_expToG[adj]); - OGDF_ASSERT(m_expToG[adj] != 0); - } - for(adj = adj->cyclicSucc(); adj != adjS; adj = adj->cyclicSucc()) { - addRight.pushBack(m_expToG[adj]); - OGDF_ASSERT(m_expToG[adj] != 0); - } - } - } - - while(v != m_startEdge && v != m_startSource && v != m_startTarget) { - OGDF_ASSERT(m_primalNode[v] == 0); - - edge eDual = spPred[v]; - node w = eDual->source(); - - if(m_primalNode[w] == 0) { - // w is a face node - adjEntry adjExp = m_primalAdj[spPred[v]]; - if(adjExp != 0) - crossed.pushFront(Crossing(m_expToG[adjExp])); - - } else { - edge eDual2 = spPred[w]; - - if(eDual2 != 0) { - adjEntry adj_1 = m_primalAdj[eDual2]; - adjEntry adj_2 = m_primalAdj[eDual]; - - w = eDual2->source(); - if(adj_1 != 0) { - Crossing &cr = *crossed.pushFront(Crossing()); - - adjEntry adj; - for(adj = adj_1; adj != adj_2; adj = adj->cyclicSucc()) { - adjEntry adjBC = m_expToG[adj]; - if(adjBC != 0) - cr.m_partitionLeft.pushBack(adjBC); - //OGDF_ASSERT(m_expToG[adj] != 0); - } - for(; adj != adj_1; adj = adj->cyclicSucc()) { - adjEntry adjBC = m_expToG[adj]; - if(adjBC != 0) - cr.m_partitionRight.pushBack(adjBC); - //OGDF_ASSERT(m_expToG[adj] != 0); - } - - } else { - // speichere Startkonoten hier: - //src = m_expToG[m_primalAdj[eDual]]->theNode(); - srcInfo.m_adj_1 = m_expToG[m_primalAdj[eDual]]; - srcInfo.m_adj_2 = m_expToG[m_primalAdj[eDual]->cyclicPred()]; - - OGDF_ASSERT(srcInfo.m_adj_1 != 0); - } - - } else { - adjEntry adj_2 = m_primalAdj[eDual]; - - adjEntry adj; - for(adj = adj_2; adj->theEdge() != m_eS; adj = adj->cyclicSucc()) { - adjEntry adjBC = m_expToG[adj]; - if(adjBC != 0) - addLeft.pushBack(adjBC); - //OGDF_ASSERT(m_expToG[adj] != 0); - } - for(adj = adj->cyclicSucc(); adj != adj_2; adj = adj->cyclicSucc()) { - adjEntry adjBC = m_expToG[adj]; - if(adjBC != 0) - addRight.pushBack(adjBC); - //OGDF_ASSERT(m_expToG[adj] != 0); - } - } - } - - v = w; - } - - if(v == m_startEdge) - return pathToEdge; - else if (v == m_startSource) - return pathToSource; - else - return pathToTarget; -} - -void MMVariableEmbeddingInserter::ExpandedSkeleton::findShortestPath( - bool &bPathToEdge, - bool &bPathToSrc, - bool &bPathToTgt, - Paths &paths) -{ - const int maxCost = 2; - - Array > nodesAtDist(maxCost); - NodeArray spPred(m_dual,0); - - // start edges - if(m_startEdge) - addOutgoingEdges(m_startEdge, nodesAtDist[0]); - if(m_startSource) - addOutgoingEdges(m_startSource, nodesAtDist[0]); - if(m_startTarget) - addOutgoingEdges(m_startTarget, nodesAtDist[0]); - - bool vEdgeReached = false; - bool vSourceReached = (m_endSource == 0 || m_endSource == m_startSource || m_endSource == m_startTarget); - bool vTargetReached = (m_endTarget == 0 || m_endTarget == m_startSource || m_endTarget == m_startTarget); - - // actual search (using extended bfs on directed dual) - int currentDist = 0; - - for( ; ; ) - { - // next candidate edge - while(nodesAtDist[currentDist % maxCost].empty()) - ++currentDist; - - edge eCand = nodesAtDist[currentDist % maxCost].popFrontRet(); - node v = eCand->target(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - if(v == m_endEdge ) vEdgeReached = true; - if(v == m_endSource) vSourceReached = true; - if(v == m_endTarget) vTargetReached = true; - - // all targets reached? - if (vEdgeReached && vSourceReached && vTargetReached) - { - paths.m_pred[pathToEdge] = reconstructInsertionPath(m_endEdge, - paths.m_src[pathToEdge], paths.m_tgt[pathToEdge], - paths.m_paths[pathToEdge], - paths.m_addPartLeft[pathToEdge], paths.m_addPartRight[pathToEdge], - spPred); - if(m_endSource != 0) - paths.m_pred[pathToSource] = reconstructInsertionPath(m_endSource, - paths.m_src[pathToSource], paths.m_tgt[pathToSource], - paths.m_paths[pathToSource], - paths.m_addPartLeft[pathToSource], paths.m_addPartRight[pathToSource], - spPred); - if(m_endTarget != 0) - paths.m_pred[pathToTarget] = reconstructInsertionPath(m_endTarget, - paths.m_src[pathToTarget], paths.m_tgt[pathToTarget], - paths.m_paths[pathToTarget], - paths.m_addPartLeft[pathToTarget], paths.m_addPartRight[pathToTarget], - spPred); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - edge e; - forall_adj_edges(e,v) { - if (v != e->source()) continue; - - int listPos = (currentDist + m_dualCost[e]) % maxCost; - nodesAtDist[listPos].pushBack(e); - } - } - } - - int lenEdge = paths.m_paths[pathToEdge].size(); - int lenSrc = paths.m_paths[pathToSource].size(); - int lenTgt = paths.m_paths[pathToTarget].size(); - OGDF_ASSERT(m_endSource == 0 || lenSrc >= lenEdge); - OGDF_ASSERT(m_endTarget == 0 || lenTgt >= lenEdge); - - //bPathToEdge = ((m_endSource == 0 || lenEdge <= lenSrc) && (m_endTarget == 0 || lenEdge <= lenTgt)); - bPathToEdge = true; - bPathToSrc = (m_endSource != 0 && lenSrc == lenEdge); - bPathToTgt = (m_endTarget != 0 && lenTgt == lenEdge); -} - - -bool MMVariableEmbeddingInserter::dfsVertex( - node v, - int parent, - List &eip, - AnchorNodeInfo &vStart, - AnchorNodeInfo &vEnd) -{ - // forall biconnected components containing v (except predecessor parent) - SListConstIterator itI; - for(itI = m_compV[v].begin(); itI.valid(); ++itI) - { - int i = *itI; - - if (i == parent) continue; - - node repS; // representative of s in B(i) - if (dfsBlock(i,v,repS,eip,vStart,vEnd) == true) { // path found? - if(m_conFinished) return true; - - // build graph BC of biconnected component B(i) - SList nodesG; - Block BC(*m_pPG); - - SListConstIterator itE; - for(itE = m_edgeB[i].begin(); itE.valid(); ++itE) - { - edge e = *itE; - - node vSrc = e->source(); - if (m_GtoBC[vSrc] == 0) { - BC.m_vBCtoG[m_GtoBC[vSrc] = BC.newNode()] = vSrc; - nodesG.pushBack(vSrc); - if(m_pSources->isMember(vSrc) || vSrc == repS) - BC.m_isSource[m_GtoBC[vSrc]] = true; - if(m_pTargets->isMember(vSrc) || vSrc == v) - BC.m_isTarget[m_GtoBC[vSrc]] = true; - BC.m_isSplittable[m_GtoBC[vSrc]] = m_pPG->splittable(vSrc); - } - - node vTgt = e->target(); - if (m_GtoBC[vTgt] == 0) { - BC.m_vBCtoG[m_GtoBC[vTgt] = BC.newNode()] = vTgt; - nodesG.pushBack(vTgt); - if(m_pSources->isMember(vTgt) || vTgt == repS) - BC.m_isSource[m_GtoBC[vTgt]] = true; - if(m_pTargets->isMember(vTgt) || vTgt == v) - BC.m_isTarget[m_GtoBC[vTgt]] = true; - BC.m_isSplittable[m_GtoBC[vTgt]] = m_pPG->splittable(vTgt); - } - - edge eBC = BC.newEdge(m_GtoBC[vSrc],m_GtoBC[vTgt]); - BC.m_adjBCtoG[eBC->adjSource()] = e->adjSource(); - BC.m_adjBCtoG[eBC->adjTarget()] = e->adjTarget(); - - if(m_forbiddenEdgeOrig != 0) { - edge eOrig = m_pPG->originalEdge(e); - if(eOrig != 0) - BC.m_forbidden[eBC] = (*m_forbiddenEdgeOrig)[eOrig]; - } - } - - AnchorNodeInfo srcInfo = repS->firstAdj(); - AnchorNodeInfo tgtInfo = v->firstAdj(); - - // less than 3 nodes requires no crossings (cannot build SPQR-tree - // for a graph with less than 3 nodes!) - if (nodesG.size() >= 3) { - // call biconnected case - List L; - blockInsert(BC, L, srcInfo, tgtInfo); - - srcInfo.m_adj_1 = BC.m_adjBCtoG[srcInfo.m_adj_1]; - if(srcInfo.m_adj_2 != 0) - srcInfo.m_adj_2 = BC.m_adjBCtoG[srcInfo.m_adj_2]; - tgtInfo.m_adj_1 = BC.m_adjBCtoG[tgtInfo.m_adj_1]; - if(tgtInfo.m_adj_2 != 0) - tgtInfo.m_adj_2 = BC.m_adjBCtoG[tgtInfo.m_adj_2]; - - // transform crossed edges to edges in G - ListIterator it; - for(it = L.begin(); it.valid(); ++it) { - Crossing &cr = *it; - if(cr.m_adj != 0) cr.m_adj = BC.m_adjBCtoG[cr.m_adj]; - SListIterator itAdj; - for(itAdj = cr.m_partitionLeft.begin(); itAdj.valid(); ++itAdj) - *itAdj = BC.m_adjBCtoG[*itAdj]; - for(itAdj = cr.m_partitionRight.begin(); itAdj.valid(); ++itAdj) - *itAdj = BC.m_adjBCtoG[*itAdj]; - - //adjEntry adj1 = BC.m_BCtoG[(*it).m_adj1]; - //adjEntry adj2 = ((*it).m_adj1 == 0) ? 0 : BC.m_BCtoG[(*it).m_adj1]; - //eip.pushBack(Crossing(adj1,adj2)); - } - eip.conc(L); - } - - if(m_pSources->isMember(srcInfo.m_adj_1->theNode())) - vStart = srcInfo; - - if(m_pTargets->isMember(tgtInfo.m_adj_1->theNode())) { - vEnd = tgtInfo; - m_conFinished = true; - } - - // set entries of GtoBC back to nil (GtoBC allocated only once - // in insert()!) - SListConstIterator itV; - for(itV = nodesG.begin(); itV.valid(); ++itV) - m_GtoBC[*itV] = 0; - - return true; // path found - } - } - - return false; // path not found -} - - -bool MMVariableEmbeddingInserter::dfsBlock(int i, - node parent, - node &repS, - List &eip, - AnchorNodeInfo &vStart, - AnchorNodeInfo &vEnd) -{ - // forall nodes in biconected component B(i) (except predecessor parent) - SListConstIterator it; - for(it = m_nodeB[i].begin(); it.valid(); ++it) - { - repS = *it; - - if (repS == parent) continue; - if (m_pSources->isMember(repS) == true) { // s found? - return true; - } - - if (dfsVertex(repS,i,eip,vStart,vEnd) == true) { - return true; // path found - } - } - - return false; // path not found -} - - -//------------------------------------------------------------------- -// find optimal edge insertion path for biconnected graph G -//------------------------------------------------------------------- - -bool MMVariableEmbeddingInserter::pathSearch( - node v, - edge parent, - const Block &BC, - List &path) -{ - if(BC.containsTarget(v) != 0) - return true; - - edge e; - forall_adj_edges(e,v) { - if(e == parent) continue; - if(pathSearch(e->opposite(v),e,BC,path) == true) { - path.pushFront(e); - return true; - } - } - - return false; -} - -void MMVariableEmbeddingInserter::blockInsert( - Block &BC, - List &L, - AnchorNodeInfo &srcInfo, - AnchorNodeInfo &tgtInfo) -{ - L.clear(); - srcInfo = tgtInfo = AnchorNodeInfo(); - - // construct SPQR-tree - BC.m_pT = new StaticPlanarSPQRTree(BC); - const StaticSPQRTree &T = *BC.m_pT; - const Graph &tree = T.tree(); - - node v, v1 = 0, vx = 0; - forall_nodes(v,tree) { - if(BC.containsSource(v) != 0) { - if(v1 == 0) - v1 = v; - if(T.typeOf(v) == SPQRTree::RNode && BC.containsTarget(v) != 0) { - vx = v; break; - } - } - } - - List path; - if(vx == 0) { - // find path in tree connecting a nodes whose skeleton contains and - // source and a target, resp. - pathSearch(v1,0,BC,path); - - // remove unnecessary allocation nodes of sources from start of path - while(!path.empty() && BC.containsSource(v = path.front()->opposite(v1)) != 0) - { - v1 = v; - path.popFront(); - } - } else - v1 = vx; - - // call build_subpath for every R-node building the list of crossed edges/nodes - ExpandedSkeleton exp(BC); - - bool bPathToEdge = true; - bool bPathToSrc = false; - bool bPathToTgt = false; - Array pathsInSks(path.size()+1); - int i = 0; - - switch(T.typeOf(v1)) { - case SPQRTree::RNode: - buildSubpath(v1, 0, - (path.empty()) ? 0 : path.front(), - pathsInSks[i++], - bPathToEdge, - bPathToSrc, - bPathToTgt, - exp); - break; - - case SPQRTree::PNode: - break; - - case SPQRTree::SNode: - srcInfo.m_adj_1 = BC.containsSourceAdj(v1); - break; - } - - v = v1; - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) - { - edge e = *it; - v = e->opposite(v); - - switch(T.typeOf(v)) { - case SPQRTree::RNode: - buildSubpath(v, e, - (it.succ().valid() == false) ? 0 : *(it.succ()), - pathsInSks[i++], - bPathToEdge, - bPathToSrc, - bPathToTgt, - exp); - break; - - case SPQRTree::PNode: - break; - - case SPQRTree::SNode: - if(it.succ().valid()) { - edge eNext = *it.succ(); - - edge e_1 = (v == e ->target()) ? T.skeletonEdgeTgt(e ) : T.skeletonEdgeSrc(e ); - edge e_2 = (v == eNext->target()) ? T.skeletonEdgeTgt(eNext) : T.skeletonEdgeSrc(eNext); - - bool bPathToSrcOld = bPathToSrc; - bool bPathToTgtOld = bPathToTgt; - - Paths &p = pathsInSks[i]; - if(e_2->source() == e_1->source() && bPathToSrcOld) { - p.m_pred[pathToSource] = pathToSource; - bPathToSrc = true; - } else if (e_2->source() == e_1->target() && bPathToTgtOld) { - p.m_pred[pathToSource] = pathToTarget; - bPathToSrc = true; - } else - bPathToSrc = false; - - if(e_2->target() == e_1->target() && bPathToTgtOld) { - p.m_pred[pathToTarget] = pathToTarget; - bPathToTgt = true; - } else if (e_2->target() == e_1->source() && bPathToSrcOld) { - p.m_pred[pathToTarget] = pathToSource; - bPathToTgt = true; - } else - bPathToTgt = false; - - i++; - } - break; - } - } - - if(T.typeOf(v) == SPQRTree::SNode) - tgtInfo.m_adj_1 = BC.containsTargetAdj(v); - //tgtInfo.m_adj_1 = BC.containsTarget(v)->firstAdj(); - - if(i == 0) return; - - // construct list of crossings L - int currentPath = pathToEdge; - AnchorNodeInfo &x = pathsInSks[i-1].m_tgt[currentPath]; - if(x.m_adj_1 != 0) - tgtInfo = x; - SList *pAddLeft = 0; - SList *pAddRight = 0; - - while(--i >= 0) { - List &eip = pathsInSks[i].m_paths[currentPath]; - - if(currentPath > 0) { - if(eip.empty()) { - pathsInSks[i].m_addPartLeft [currentPath].conc(*pAddLeft ); - pathsInSks[i].m_addPartRight[currentPath].conc(*pAddRight); - - } else { - Crossing &cr = *eip.rbegin(); - cr.m_partitionLeft .conc(*pAddLeft ); - cr.m_partitionRight.conc(*pAddRight); - } - } - - L.concFront(eip); - - pAddLeft = &pathsInSks[i].m_addPartLeft [currentPath]; - pAddRight = &pathsInSks[i].m_addPartRight[currentPath]; - if(i == 0) { - AnchorNodeInfo &x = pathsInSks[0].m_src[currentPath]; - if(x.m_adj_1 != 0) - srcInfo = x; - OGDF_ASSERT(srcInfo.m_adj_1 != 0); - } - - currentPath = pathsInSks[i].m_pred[currentPath]; - } -} - - -//------------------------------------------------------------------- -// find the shortest path from represent. of s to represent. of t in -// the dual of the (partially) expanded skeleton of v -//------------------------------------------------------------------- - -void MMVariableEmbeddingInserter::buildSubpath( - node v, - edge eIn, - edge eOut, - Paths &paths, - bool &bPathToEdge, - bool &bPathToSrc, - bool &bPathToTgt, - ExpandedSkeleton &Exp) -{ - // build expanded graph Exp - Exp.expand(v,eIn,eOut); - - // construct augmented dual of expanded graph - Exp.constructDual(bPathToEdge,bPathToSrc,bPathToTgt); - - // find shortest path in augmented dual - Exp.findShortestPath(bPathToEdge, bPathToSrc, bPathToTgt, paths); -} - - -void MMVariableEmbeddingInserter::contractSplitIfReq(node u) -{ - if(u->degree() == 2) { - edge eContract = u->firstAdj()->theEdge(); - edge eExpand = u->lastAdj ()->theEdge(); - if(m_pPG->nodeSplitOf(eContract) == 0) - swap(eContract,eExpand); - - if(m_pPG->nodeSplitOf(eContract) != 0) { - edge e = m_pPG->unsplitExpandNode(u,eContract,eExpand); - - if(e->isSelfLoop()) - m_pPG->removeSelfLoop(e); - } - } -} - - -void MMVariableEmbeddingInserter::convertDummy( - node u, - node vOrig, - PlanRepExpansion::nodeSplit ns_0) -{ - PlanRepExpansion::nodeSplit ns_1 = m_pPG->convertDummy(u,vOrig,ns_0); - - if(ns_0->m_path.size() == 1) - m_pPG->contractSplit(ns_0); - if(ns_1->m_path.size() == 1) - m_pPG->contractSplit(ns_1); -} - - -void MMVariableEmbeddingInserter::collectAnchorNodes( - node v, - NodeSet &nodes, - const PlanRepExpansion::NodeSplit *nsParent) const -{ - if(m_pPG->original(v) != 0) - nodes.insert(v); - - adjEntry adj; - forall_adj(adj,v) { - edge e = adj->theEdge(); - const PlanRepExpansion::NodeSplit *ns = m_pPG->nodeSplitOf(e); - if(ns == 0) { - // add dummy nodes of non-node-split edge - ListConstIterator it = m_pPG->chain(m_pPG->originalEdge(e)).begin(); - for(++it; it.valid(); ++it) - nodes.insert((*it)->source()); - - } else if(ns != nsParent) { - // add dummy nodes of node-split edge - ListConstIterator it = ns->m_path.begin(); - for(++it; it.valid(); ++it) - nodes.insert((*it)->source()); - - node w = (v == e->source()) ? ns->target() : ns->source(); - collectAnchorNodes(w, nodes, ns); - } - } -} - - -void MMVariableEmbeddingInserter::findSourcesAndTargets( - node src, node tgt, - NodeSet &sources, - NodeSet &targets) const -{ - collectAnchorNodes(src, sources, 0); - collectAnchorNodes(tgt, targets, 0); -} - - -void MMVariableEmbeddingInserter::anchorNodes( - node vOrig, - NodeSet &nodes) const -{ - node vFirst = m_pPG->expansion(vOrig).front(); - if(m_pPG->splittableOrig(vOrig) == true) - collectAnchorNodes(vFirst, nodes, 0); - else - nodes.insert(vFirst); -} - - -node MMVariableEmbeddingInserter::commonDummy( - NodeSet &sources, - NodeSet &targets) -{ - ListConstIterator it; - for(it = sources.nodes().begin(); it.valid(); ++it) - if(targets.isMember(*it)) - return *it; - - return 0; -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/MaximalPlanarSubgraphSimple.cpp b/ext/OGDF/src/planarity/MaximalPlanarSubgraphSimple.cpp deleted file mode 100644 index 8cfded731..000000000 --- a/ext/OGDF/src/planarity/MaximalPlanarSubgraphSimple.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class MaximalPlanarSubgraphSimple. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include - - -namespace ogdf { - - -Module::ReturnType MaximalPlanarSubgraphSimple::doCall( - const Graph &G, - const List &preferedEdges, - List &delEdges, - const EdgeArray * /* pCost */, - bool preferedImplyPlanar) -{ - delEdges.clear(); - - Graph H; - NodeArray mapToH(G); - - node v; - forall_nodes(v,G) - mapToH[v] = H.newNode(); - - EdgeArray visited(G,false); - - ListConstIterator it; - for(it = preferedEdges.begin(); it.valid(); ++it) - { - edge eG = *it; - visited[eG] = true; - - edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); - - if (preferedImplyPlanar == false && isPlanar(H) == false) { - H.delEdge(eH); - delEdges.pushBack(eG); - } - } - - edge eG; - forall_edges(eG,G) - { - if(visited[eG] == true) - continue; - - edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); - - if (isPlanar(H) == false) { - H.delEdge(eH); - delEdges.pushBack(eG); - } - } - - return retFeasible; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/MaximumPlanarSubgraph.cpp b/ext/OGDF/src/planarity/MaximumPlanarSubgraph.cpp deleted file mode 100644 index c2616e0e1..000000000 --- a/ext/OGDF/src/planarity/MaximumPlanarSubgraph.cpp +++ /dev/null @@ -1,179 +0,0 @@ - /* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class MaximumPlanarSubgraph - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - #ifdef USE_ABACUS - - #include - #include - #include - #include - - namespace ogdf { - -Module::ReturnType MaximumPlanarSubgraph::doCall( - const Graph &G, - const List &preferedEdges, - List &delEdges, - const EdgeArray *pCost, - bool preferredImplyPlanar) -{ - if (G.numberOfEdges() < 9) - return retOptimal; - - //if the graph is planar, we don't have to do anything - if (isPlanar(G)) - return retOptimal; - - //--------- - //Exact ILP - MaximumCPlanarSubgraph mc; - List addEdges; - - delEdges.clear(); - - node v; - NodeArray tableNodes(G,0); - EdgeArray tableEdges(G,0); - NodeArray mark(G,0); - - EdgeArray componentID(G); - - // Determine biconnected components - int bcCount = biconnectedComponents(G,componentID); - - // Determine edges per biconnected component - Array > blockEdges(0,bcCount-1); - edge e; - forall_edges(e,G) - { - if (!e->isSelfLoop()) - blockEdges[componentID[e]].pushFront(e); - } - - // Determine nodes per biconnected component. - Array > blockNodes(0,bcCount-1); - int i; - for (i = 0; i < bcCount; i++) - { - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - if (!mark[e->source()]) - { - blockNodes[i].pushBack(e->source()); - mark[e->source()] = true; - } - if (!mark[e->target()]) - { - blockNodes[i].pushBack(e->target()); - mark[e->target()] = true; - } - } - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++itn) - mark[*itn] = false; - } - - - // Perform computation for every biconnected component - ReturnType mr; - - if (bcCount == 1) { - ClusterGraph CG(G); - mr = mc.call(CG, delEdges, addEdges); - - return mr; - } - else - { - for (i = 0; i < bcCount; i++) - { - Graph C; - - SListIterator itn; - for (itn = blockNodes[i].begin(); itn.valid(); ++ itn) - { - v = *itn; - node w = C.newNode(); - tableNodes[v] = w; - } - - - SListIterator it; - for (it = blockEdges[i].begin(); it.valid(); ++it) - { - e = *it; - edge f = C.newEdge(tableNodes[e->source()],tableNodes[e->target()]); - tableEdges[e] = f; - } - - // Construct a translation table for the edges. - // Necessary, since edges are deleted in a new graph - // that represents the current biconnected component - // of the original graph. - EdgeArray backTableEdges(C,0); - for (it = blockEdges[i].begin(); it.valid(); ++it) - backTableEdges[tableEdges[*it]] = *it; - - // The deleted edges of the biconnected component - List delEdgesOfBC; - - ClusterGraph CG(C); - mr = mc.call(CG, delEdgesOfBC, addEdges); - // Abort if no optimal solution found, i.e., feasible is also not allowed - if (mr != retOptimal) - return mr; - - // Get the original edges that are deleted and - // put them on the list delEdges. - while (!delEdgesOfBC.empty()) - delEdges.pushBack(backTableEdges[delEdgesOfBC.popFrontRet()]); - - } - } - return mr; -}//docall for graph - -} //end namespace ogdf - -#endif //USE_ABACUS diff --git a/ext/OGDF/src/planarity/MultiEdgeApproxInserter.cpp b/ext/OGDF/src/planarity/MultiEdgeApproxInserter.cpp deleted file mode 100644 index afabfcafa..000000000 --- a/ext/OGDF/src/planarity/MultiEdgeApproxInserter.cpp +++ /dev/null @@ -1,1743 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implements class MultiEdgeApproxInserter - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -MultiEdgeApproxInserter::PathDir MultiEdgeApproxInserter::s_oppDir[3] = { pdRight, pdLeft, pdNone }; - - -//--------------------------------------------------------- -// class EmbeddingPreference -// encodes an embedding preference -//--------------------------------------------------------- - -class MultiEdgeApproxInserter::EmbeddingPreference -{ -public: - enum Type { epNone, epRNode, epPNode }; - - // constructs an embedding preference of type none (= irrelevant) - EmbeddingPreference() : m_type(epNone) { } - - // constructs an embedding preference for an R-node - EmbeddingPreference(bool mirror) : m_type(epRNode), m_mirror(mirror) { } - - EmbeddingPreference(adjEntry a1, adjEntry a2) : m_type(epPNode), m_adj1(a1), m_adj2(a2) { } - // constructs an embedding preference for a P-node - - Type type() const { return m_type; } - bool isNull() const { return m_type == epNone; } - - bool mirror() const { return m_mirror; } - adjEntry adj1() const { return m_adj1; } - adjEntry adj2() const { return m_adj2; } - - // flip embedding preference - void flip() { - m_mirror = !m_mirror; - swap(m_adj1,m_adj2); - } - - static const EmbeddingPreference s_none; - - ostream &print(ostream &os) const { - switch(type()) { - case MultiEdgeApproxInserter::EmbeddingPreference::epNone: - os << "none"; - break; - case MultiEdgeApproxInserter::EmbeddingPreference::epPNode: - os << "PNode: " << adj1()->index() << "->" << adj2()->index(); - break; - case MultiEdgeApproxInserter::EmbeddingPreference::epRNode: - os << "RNode: " << mirror(); - break; - } - return os; - } - -private: - Type m_type; - bool m_mirror; // skeleton of an R-node must be mirrored (yes/no) - - adjEntry m_adj1, m_adj2; - // these two adj entries of first node in skeleton of a P-node must be in clockwise order adj1 -> adj2 -}; - -const MultiEdgeApproxInserter::EmbeddingPreference MultiEdgeApproxInserter::EmbeddingPreference::s_none; - - - -//--------------------------------------------------------- -// class Block -// maintains a block in the graph -//--------------------------------------------------------- - -class MultiEdgeApproxInserter::Block : public Graph -{ -public: - struct SPQRPath { - SPQRPath() : m_start(0) { } - node m_start; // first node in SPQR-tree (its skeleton contains v1) - List m_edges; // actual path (empty if v1 and v2 are in skeleton of m_start) - List m_prefs; // embeding preferences along the path - }; - - struct PathElement { - PathElement() : m_node(0), m_pref(&EmbeddingPreference::s_none) { } - - node m_node; - const EmbeddingPreference *m_pref; - }; - - - // constructor - Block() : m_spqr(0), m_embB(0), m_dualB(0), m_faceNodeB(0), m_primalAdjB(0), m_vS(0), m_vT(0) - { - m_BCtoG.init(*this); - m_cost .init(*this,1); - } - - // destructoe - ~Block() { - delete m_primalAdjB; - delete m_faceNodeB; - delete m_dualB; - delete m_embB; - delete m_spqr; - } - - // returns true iff block is just a bridge (in this case, there is no SPQR-tree!) - bool isBridge() const { return numberOfEdges() < 3; } - - int cost(edge e) const { return m_cost[e]; } - - // initialize SPQR-tree; compute allocation nodes - void initSPQR(int m); - - // returns SPQR-tree - const StaticPlanarSPQRTree &spqr() const { return *m_spqr; } - StaticPlanarSPQRTree &spqr() { return *m_spqr; } - - // compute traversing costs in skeleton of n; omit skeleton edges e1, e2 - void computeTraversingCosts(node n, edge e1, edge e2); - - int findShortestPath(node n, edge eRef); - - // compute costs of a subpath through skeleton(n) while connecting s with t - int costsSubpath(node n, edge eIn, edge eOut, node s, node t, PathDir &dirFrom, PathDir &dirTo); - - void pathToArray(int i, Array &path); - - bool embPrefAgree(node n, const EmbeddingPreference &p_pick, const EmbeddingPreference &p_e); - - bool switchingPair(node n, node m, - const EmbeddingPreference &p_pick_n, const EmbeddingPreference &p_n, - const EmbeddingPreference &p_pick_m, const EmbeddingPreference &p_m); - - int findBestFaces(node s, node t, adjEntry &adj_s, adjEntry &adj_t); - adjEntry findBestFace(node s, node t, int &len); - - AdjEntryArray m_BCtoG; // maps adjacency entries in block to original graph - EdgeArray m_cost; // costs of an edge (as given for edges in original graph) - NodeArray > m_allocNodes; // list of allocation nodes - Array m_pathSPQR; // insertion path in SPQR-tree - -private: - struct RNodeInfo { - RNodeInfo() : m_emb(0), m_dual(0), m_faceNode(0), m_primalAdj(0) { } - ~RNodeInfo() { - delete m_primalAdj; - delete m_faceNode; - delete m_dual; - delete m_emb; - } - - ConstCombinatorialEmbedding *m_emb; // combinatorial embedding of skeleton graph - Graph *m_dual; // dual graph - FaceArray *m_faceNode; // mapping dual node -> face - AdjEntryArray *m_primalAdj; // mapping dual adjEntry -> primal adjEntry - }; - - int recTC(node n, edge eRef); - void constructDual(node n); - -public: - void constructDualBlock(); -private: - - StaticPlanarSPQRTree *m_spqr; - NodeArray > m_tc; // traversing costs - - NodeArray m_info; // additional data for R-node skeletons - - ConstCombinatorialEmbedding *m_embB; - Graph *m_dualB; - FaceArray *m_faceNodeB; - AdjEntryArray *m_primalAdjB; - node m_vS, m_vT; -}; - - -void MultiEdgeApproxInserter::Block::pathToArray(int i, Array &path) -{ - SPQRPath &sp = m_pathSPQR[i]; - - if(sp.m_start == 0) { - path.init(); - return; - } - - path.init(1+sp.m_edges.size()); - - ListConstIterator itE = sp.m_edges.begin(); - ListConstIterator itP = sp.m_prefs.begin(); - - node n = sp.m_start; - - path[0].m_node = n; - if(m_spqr->typeOf(n) != SPQRTree::SNode) - path[0].m_pref = &(*itP++); - - int j; - for(j = 1; itE.valid(); ++j) - { - n = (*itE++)->opposite(n); - path[j].m_node = n; - - if(m_spqr->typeOf(n) != SPQRTree::SNode) - path[j].m_pref = &(*itP++); - } - - OGDF_ASSERT(j == path.size()); -} - - -bool MultiEdgeApproxInserter::Block::embPrefAgree(node n, const EmbeddingPreference &p_pick, const EmbeddingPreference &p_e) -{ - switch(m_spqr->typeOf(n)) { - case SPQRTree::RNode: - return p_pick.mirror() == p_e.mirror(); // check if mirroring is the same - - case SPQRTree::PNode: - if(!p_e.isNull()) { - // check if adj entries in (embedded) P-Node are in the right order - return p_e.adj1()->cyclicSucc() == p_e.adj2(); - } - - default: - return true; // any other case "agrees" - } -} - - -bool MultiEdgeApproxInserter::Block::switchingPair( - node n, node m, - const EmbeddingPreference &p_pick_n, const EmbeddingPreference &p_n, - const EmbeddingPreference &p_pick_m, const EmbeddingPreference &p_m) -{ - EmbeddingPreference p_n_f = p_n; - EmbeddingPreference p_m_f = p_m; - - p_n_f.flip(); - p_m_f.flip(); - - return - (embPrefAgree(n, p_pick_n, p_n) && embPrefAgree(m, p_pick_m, p_m_f)) || - (embPrefAgree(n, p_pick_n, p_n_f) && embPrefAgree(m, p_pick_m, p_m)); -} - - -//--------------------------------------------------------- -// create SPQR-tree and compute allocation nodes -//--------------------------------------------------------- - -void MultiEdgeApproxInserter::Block::initSPQR(int m) -{ - if(m_spqr == 0) { - m_spqr = new StaticPlanarSPQRTree(*this,true); - m_pathSPQR.init(m); - - const Graph &tree = m_spqr->tree(); - m_tc.init(tree); - m_info.init(tree); - - // compute allocation nodes - m_allocNodes.init(*this); - - node n; - forall_nodes(n,tree) - { - const Skeleton &S = m_spqr->skeleton(n); - const Graph &M = S.getGraph(); - - EdgeArray &tcS = m_tc[n]; - tcS.init(M,-1); - - node x; - forall_nodes(x,M) - m_allocNodes[S.original(x)].pushBack(n); - - edge e; - forall_edges(e,M) { - edge eOrig = S.realEdge(e); - if(eOrig != 0) tcS[e] = 1; - } - } - } -} - - -//--------------------------------------------------------- -// construct dual graph of skeleton of n -//--------------------------------------------------------- - -void MultiEdgeApproxInserter::Block::constructDual(node n) -{ - const StaticSkeleton &S = *dynamic_cast(&m_spqr->skeleton(n)); - const Graph &M = S.getGraph(); - - OGDF_ASSERT(m_info[n].m_dual == 0); - - ConstCombinatorialEmbedding *emb = m_info[n].m_emb = new ConstCombinatorialEmbedding(M); - Graph *dual = m_info[n].m_dual = new Graph; - FaceArray *faceNode = m_info[n].m_faceNode = new FaceArray(*emb); - AdjEntryArray *primalAdj = m_info[n].m_primalAdj = new AdjEntryArray(*dual); - - // constructs nodes (for faces in emb) - face f; - forall_faces(f,*emb) { - (*faceNode)[f] = dual->newNode(); - } - - // construct dual edges (for primal edges in M) - node v; - forall_nodes(v,M) - { - adjEntry adj; - forall_adj(adj,v) - { - if(adj->index() & 1) { - node vLeft = (*faceNode)[emb->leftFace (adj)]; - node vRight = (*faceNode)[emb->rightFace(adj)]; - - edge eDual = dual->newEdge(vLeft,vRight); - (*primalAdj)[eDual->adjSource()] = adj; - (*primalAdj)[eDual->adjTarget()] = adj->twin(); - } - } - } -} - - -void MultiEdgeApproxInserter::Block::constructDualBlock() -{ - m_embB = new ConstCombinatorialEmbedding(*this); - m_dualB = new Graph; - m_faceNodeB = new FaceArray(*m_embB); - m_primalAdjB = new AdjEntryArray(*m_dualB); - - // constructs nodes (for faces in m_embB) - face f; - forall_faces(f,*m_embB) { - (*m_faceNodeB)[f] = m_dualB->newNode(); - } - - // construct dual edges (for primal edges in block) - node v; - forall_nodes(v,*this) - { - adjEntry adj; - forall_adj(adj,v) - { - if(adj->index() & 1) { - node vLeft = (*m_faceNodeB)[m_embB->leftFace (adj)]; - node vRight = (*m_faceNodeB)[m_embB->rightFace(adj)]; - - edge eDual = m_dualB->newEdge(vLeft,vRight); - (*m_primalAdjB)[eDual->adjSource()] = adj; - (*m_primalAdjB)[eDual->adjTarget()] = adj->twin(); - } - } - } - - m_vS = m_dualB->newNode(); - m_vT = m_dualB->newNode(); -} - - -adjEntry MultiEdgeApproxInserter::Block::findBestFace(node s, node t, int &len) -{ - if(isBridge()) { - len = 0; - return s->firstAdj(); - } - - adjEntry adj_s, adj_t; - len = findBestFaces(s,t,adj_s,adj_t); - return adj_s; -} - - -int MultiEdgeApproxInserter::Block::findBestFaces( - node s, node t, adjEntry &adj_s, adjEntry &adj_t) -{ - if(m_dualB == 0) - constructDualBlock(); - - NodeArray spPred(*m_dualB, 0); - QueuePure queue; - int oldIdCount = m_dualB->maxEdgeIndex(); - - // augment dual by edges from s to all adjacent faces of s ... - adjEntry adj; - forall_adj(adj,s) { - // starting edges of bfs-search are all edges leaving s - edge eDual = m_dualB->newEdge(m_vS, (*m_faceNodeB)[m_embB->rightFace(adj)]); - (*m_primalAdjB)[eDual->adjSource()] = adj; - (*m_primalAdjB)[eDual->adjTarget()] = 0; - queue.append(eDual->adjSource()); - } - - // ... and from all adjacent faces of t to t - forall_adj(adj,t) { - edge eDual = m_dualB->newEdge((*m_faceNodeB)[m_embB->rightFace(adj)], m_vT); - (*m_primalAdjB)[eDual->adjSource()] = adj; - (*m_primalAdjB)[eDual->adjTarget()] = 0; - } - - // actual search (using bfs on directed dual) - int len = -2; - for( ; ;) - { - // next candidate edge - adjEntry adjCand = queue.pop(); - node v = adjCand->twinNode(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = adjCand; - - // have we reached t ... - if (v == m_vT) - { - // ... then search is done. - adj_t = (*m_primalAdjB)[adjCand]; - - adjEntry adj; - do { - adj = spPred[v]; - ++len; - v = adj->theNode(); - } while(v != m_vS); - adj_s = (*m_primalAdjB)[adj]; - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - adjEntry adj; - forall_adj(adj,v) { - if(adj->twinNode() != m_vS) - queue.append(adj); - } - } - } - - // remove augmented edges again - while ((adj = m_vS->firstAdj()) != 0) - m_dualB->delEdge(adj->theEdge()); - - while ((adj = m_vT->firstAdj()) != 0) - m_dualB->delEdge(adj->theEdge()); - - m_dualB->resetEdgeIdCount(oldIdCount); - - return len; -} - - -//--------------------------------------------------------- -// compute traversing costs in skelton -//--------------------------------------------------------- - -int MultiEdgeApproxInserter::Block::recTC(node n, edge eRef) -{ - const StaticSkeleton &S = *dynamic_cast(&m_spqr->skeleton(n)); - const Graph &M = S.getGraph(); - EdgeArray &tcS = m_tc[n]; - - edge e; - forall_edges(e,M) { - if(tcS[e] == -1 && e != eRef) { - edge eT = S.treeEdge(e); - - node nC; - edge eRefC; - if(n == eT->source()) { - nC = eT->target(); eRefC = m_spqr->skeletonEdgeTgt(eT); - } else { - nC = eT->source(); eRefC = m_spqr->skeletonEdgeSrc(eT); - } - - tcS[e] = recTC(nC,eRefC); - } - } - - int c = 1; - switch(m_spqr->typeOf(n)) - { - case SPQRTree::SNode: - c = INT_MAX; - forall_edges(e,M) - if(e != eRef) c = min(c, tcS[e]); - break; - - case SPQRTree::PNode: - c = 0; - forall_edges(e,M) - if(e != eRef) c += tcS[e]; - break; - - case SPQRTree::RNode: - if(m_info[n].m_dual == 0) - constructDual(n); - - c = findShortestPath(n, eRef); - break; - } - - return c; -} - -void MultiEdgeApproxInserter::Block::computeTraversingCosts(node n, edge e1, edge e2) -{ - const StaticSkeleton &S = *dynamic_cast(&m_spqr->skeleton(n)); - const Graph &M = S.getGraph(); - EdgeArray &tcS = m_tc[n]; - - edge e; - forall_edges(e,M) { - if(tcS[e] == -1 && e != e1 && e != e2) { - edge eT = S.treeEdge(e); - - node nC; - edge eRef; - if(n == eT->source()) { - nC = eT->target(); eRef = m_spqr->skeletonEdgeTgt(eT); - } else { - nC = eT->source(); eRef = m_spqr->skeletonEdgeSrc(eT); - } - - tcS[e] = recTC(nC,eRef); - } - } -} - - -int MultiEdgeApproxInserter::Block::findShortestPath(node n, edge eRef) -{ - const StaticSkeleton &S = *dynamic_cast(&m_spqr->skeleton(n)); - const Graph &M = S.getGraph(); - const EdgeArray &tcS = m_tc[n]; - - const Graph &dual = *m_info[n].m_dual; - const ConstCombinatorialEmbedding &emb = *m_info[n].m_emb; - const FaceArray faceNode = *m_info[n].m_faceNode; - const AdjEntryArray primalAdj = *m_info[n].m_primalAdj; - - int maxTC = 0; - edge e; - forall_edges(e,M) - maxTC = max(maxTC, tcS[e]); - - ++maxTC; - Array > nodesAtDist(maxTC); - - NodeArray spPred(dual,0); // predecessor in shortest path tree - - node vS = faceNode[emb.rightFace(eRef->adjSource())]; - node vT = faceNode[emb.rightFace(eRef->adjTarget())]; - - // start with all edges leaving from vS - adjEntry adj; - forall_adj(adj,vS) { - edge eOrig = primalAdj[adj]->theEdge(); - if(eOrig != eRef) - nodesAtDist[tcS[eOrig]].pushBack(adj); - } - - int currentDist = 0; - for( ; ; ) { - // next candidate edge - while(nodesAtDist[currentDist % maxTC].empty()) - ++currentDist; - - adjEntry adjCand = nodesAtDist[currentDist % maxTC].popFrontRet(); - node v = adjCand->twinNode(); - - // leads to an unvisited node ? - if (spPred[v] == 0) { - // yes, then we set v's predecessor in search tree - spPred[v] = adjCand; - - // have we reached t ... - if (v == vT) { - // ... then search is done. - return currentDist; - } - - // append next candidates to end of queue - forall_adj(adj,v) { - int listPos = (currentDist + tcS[primalAdj[adj]->theEdge()]) % maxTC; - nodesAtDist[listPos].pushBack(adj); - } - } - } -} - - -int MultiEdgeApproxInserter::Block::costsSubpath(node n, edge eIn, edge eOut, node s, node t, PathDir &dirFrom, PathDir &dirTo) -{ - if(m_info[n].m_dual == 0) - constructDual(n); - - const StaticSkeleton &S = *dynamic_cast(&m_spqr->skeleton(n)); - const Graph &M = S.getGraph(); - const EdgeArray &tcS = m_tc[n]; - - const Graph &dual = *m_info[n].m_dual; - const ConstCombinatorialEmbedding &emb = *m_info[n].m_emb; - const FaceArray faceNode = *m_info[n].m_faceNode; - const AdjEntryArray primalAdj = *m_info[n].m_primalAdj; - - node v1 = 0, v2 = 0; - if(eIn == 0 || eOut == 0) { - node v; - forall_nodes(v,M) { - node vOrig = S.original(v); - if(vOrig == s) v1 = v; - if(vOrig == t) v2 = v; - } - } - - edge e1 = (eIn == 0) ? 0 : ((n != eIn ->source()) ? m_spqr->skeletonEdgeTgt(eIn) : m_spqr->skeletonEdgeSrc(eIn)); - edge e2 = (eOut == 0) ? 0 : ((n != eOut->source()) ? m_spqr->skeletonEdgeTgt(eOut) : m_spqr->skeletonEdgeSrc(eOut)); - - computeTraversingCosts(n, e1, e2); - - int maxTC = 0; - edge e; - forall_edges(e,M) - maxTC = max(maxTC, tcS[e]); - - ++maxTC; - Array > > nodesAtDist(maxTC); - - // start vertices - if(e1 != 0) { - nodesAtDist[0].pushBack( Tuple2(faceNode[emb.rightFace(e1->adjSource())], 0) ); - nodesAtDist[0].pushBack( Tuple2(faceNode[emb.rightFace(e1->adjTarget())], 0) ); - } else { - adjEntry adj; - forall_adj(adj,v1) - nodesAtDist[0].pushBack( Tuple2(faceNode[emb.rightFace(adj)], 0) ); - } - - // stop vertices - NodeArray stopVertex(dual,false); - - if(e2 != 0) { - stopVertex[faceNode[emb.rightFace(e2->adjSource())]] = true; - stopVertex[faceNode[emb.rightFace(e2->adjTarget())]] = true; - } else { - adjEntry adj; - forall_adj(adj,v2) - stopVertex[faceNode[emb.rightFace(adj)]] = true; - } - - // actual shortest path search - NodeArray visited(dual,false); - NodeArray spPred(dual,0); - - int currentDist = 0; - for( ; ; ) { - // next candidate - while(nodesAtDist[currentDist % maxTC].empty()) - ++currentDist; - - Tuple2 pair = nodesAtDist[currentDist % maxTC].popFrontRet(); - node v = pair.x1(); - - // leads to an unvisited node ? - if (visited[v] == false) { - visited[v] = true; - spPred[v] = pair.x2(); - - // have we reached t ... - if (stopVertex[v]) { - // ... then search is done. - - // find start node w - node w = v; - while(spPred[w] != 0) - w = spPred[w]; - - // in which direction to we start - if(e1 == 0) - dirFrom = pdNone; // doesn't matter - else if(w == faceNode[emb.rightFace(e1->adjSource())]) - dirFrom = pdRight; // right face of eIn - else - dirFrom = pdLeft; // left face of eIn - - // from which direction to we enter - if(e2 == 0) - dirTo = pdNone; // doesn't matter - else if(v == faceNode[emb.rightFace(e2->adjSource())]) - dirTo = pdLeft; // right face of eOut (leaving to the right) - else - dirTo = pdRight; // left face of eOut (leaving to the left) - - return currentDist; - } - - // append next candidates to end of queue - adjEntry adj; - forall_adj(adj,v) { - edge eM = primalAdj[adj]->theEdge(); - if(eM != e1 && eM != e2) { - int listPos = (currentDist + tcS[eM]) % maxTC; - nodesAtDist[listPos].pushBack( - Tuple2(adj->twinNode(), v) ); - } - } - } - } -} - - -//--------------------------------------------------------- -// constructor -// sets default values for options -//--------------------------------------------------------- - -MultiEdgeApproxInserter::MultiEdgeApproxInserter() -{ - m_rrOptionFix = rrNone; - m_rrOptionVar = rrNone; - m_percentMostCrossedFix = 25; - m_percentMostCrossedVar = 25; - m_statistics = false; -} - - -//--------------------------------------------------------- -// construct graph of block i -// store mapping of original nodes to copies in blocks -//--------------------------------------------------------- - -MultiEdgeApproxInserter::Block *MultiEdgeApproxInserter::constructBlock(int i) -{ - Block *b = new Block; - SList nodesG; - - SListConstIterator itE; - for(itE = m_edgesB[i].begin(); itE.valid(); ++itE) - { - edge e = *itE; - - if (m_GtoBC[e->source()] == 0) { - m_GtoBC[e->source()] = b->newNode(); - nodesG.pushBack(e->source()); - } - if (m_GtoBC[e->target()] == 0) { - m_GtoBC[e->target()] = b->newNode(); - nodesG.pushBack(e->target()); - } - - edge eBC = b->newEdge(m_GtoBC[e->source()],m_GtoBC[e->target()]); - b->m_BCtoG[eBC->adjSource()] = e->adjSource(); - b->m_BCtoG[eBC->adjTarget()] = e->adjTarget(); - - edge eOrig = m_pPG->original(e); - if(m_costOrig != 0) - b->m_cost[eBC] = (eOrig == 0) ? 0 : (*m_costOrig)[eOrig]; - } - - // store mapping orginal nodes -> copy in blocks and reset entries of GtoBC - SListConstIterator itV; - for(itV = nodesG.begin(); itV.valid(); ++itV) { - node v = *itV; - m_copyInBlocks[v].pushBack(VertexBlock(m_GtoBC[v],i)); - m_GtoBC[v] = 0; - } - - planarEmbed(*b); - - return b; -} - - -//--------------------------------------------------------- -// returns copy of node vOrig in block b -//--------------------------------------------------------- - -node MultiEdgeApproxInserter::copy(node vOrig, int b) -{ - SListConstIterator it; - for(it = m_copyInBlocks[vOrig].begin(); it.valid(); ++it) { - if((*it).m_block == b) - return (*it).m_vertex; - } - - return 0; -} - - -//--------------------------------------------------------- -// DFS-traversal for computing insertion path in SPQR-tree -//--------------------------------------------------------- - -bool MultiEdgeApproxInserter::dfsPathSPQR(node v, node v2, edge eParent, List &path) -{ - if(v == v2) - return true; - - edge e; - forall_adj_edges(e,v) { - if(e == eParent) continue; - - if(dfsPathSPQR(e->opposite(v),v2,e,path) == true) { - path.pushFront(e); - return true; - } - } - - return false; -} - - -//--------------------------------------------------------- -// compute insertion path of edge edge k in SPQR-tree of block b -// from node vOrig to node wOrig -//--------------------------------------------------------- - -int MultiEdgeApproxInserter::computePathSPQR(int b, node vOrig, node wOrig, int k) -{ - Block &B = *m_block[b]; - - node v = copy(vOrig,b); - node w = copy(wOrig,b); - OGDF_ASSERT(v != 0 && w != 0); - - B.initSPQR(m_edge.size()); - - const SListPure &vAllocNodes = B.m_allocNodes[v]; - const SListPure &wAllocNodes = B.m_allocNodes[w]; - List &path = B.m_pathSPQR[k].m_edges; - - node v1 = vAllocNodes.front(); - node v2 = wAllocNodes.front(); - - dfsPathSPQR( v1, v2, 0, path ); - - node x; - while(!path.empty() && vAllocNodes.search(x = path.front()->opposite(v1)) >= 0) { - v1 = x; - path.popFront(); - } - - B.m_pathSPQR[k].m_start = v1; - - while(!path.empty() && wAllocNodes.search(x = path.back()->opposite(v2)) >= 0) { - v2 = x; - path.popBack(); - } - - // compute insertion costs - const StaticPlanarSPQRTree &spqr = B.spqr(); - List &prefs = B.m_pathSPQR[k].m_prefs; - - PathDir dirFrom, dirTo; - PathDir curDir = pdRight; - int c = 0; - - switch(spqr.typeOf(v1)) { - case SPQRTree::RNode: - c += B.costsSubpath(v1, 0, (path.empty()) ? 0 : path.front(), v, w, dirFrom, dirTo); - prefs.pushBack(EmbeddingPreference(false)); - curDir = dirTo; - break; - - case SPQRTree::PNode: - // in this case, the insertion path is a single P-node and we have no preference - prefs.pushBack(EmbeddingPreference()); - break; - - case SPQRTree::SNode: - break; // nothing to do - } - - node n = v1; - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) - { - edge e = *it; - n = e->opposite(n); - - switch(spqr.typeOf(n)) { - case SPQRTree::RNode: - c += B.costsSubpath(n, e, - (it.succ().valid() == false) ? 0 : *(it.succ()), v, w, - dirFrom, dirTo); - - // do we need to mirror embedding of R-node? - if(dirFrom == curDir) { - curDir = dirTo; - prefs.pushBack(EmbeddingPreference(false)); // no - } else { - curDir = s_oppDir[dirTo]; - prefs.pushBack(EmbeddingPreference(true)); // yes - } - break; - - case SPQRTree::PNode: - { - edge eIn = e; - edge eOut = *(it.succ()); - - edge e1 = (n != eIn ->source()) ? spqr.skeletonEdgeTgt(eIn) : spqr.skeletonEdgeSrc(eIn); - edge e2 = (n != eOut->source()) ? spqr.skeletonEdgeTgt(eOut) : spqr.skeletonEdgeSrc(eOut); - - const Graph &M = spqr.skeleton(n).getGraph(); - node v1 = M.firstNode(); - - adjEntry a1 = (e1->source() == v1) ? e1->adjSource() : e1->adjTarget(); - adjEntry a2 = (e2->source() == v1) ? e2->adjSource() : e2->adjTarget(); - - bool srcFits = (e1->source() == v1); - if( (curDir == pdLeft && srcFits) || (curDir == pdRight && !srcFits) ) - swap(a1,a2); - prefs.pushBack(EmbeddingPreference(a1,a2)); - - if(e1->source() != e2->source()) - curDir = s_oppDir[curDir]; - } - break; - - case SPQRTree::SNode: - if(it.succ().valid()) { - edge eIn = e; - edge eOut = *(it.succ()); - - edge e1 = (n != eIn ->source()) ? spqr.skeletonEdgeTgt(eIn) : spqr.skeletonEdgeSrc(eIn); - edge e2 = (n != eOut->source()) ? spqr.skeletonEdgeTgt(eOut) : spqr.skeletonEdgeSrc(eOut); - - adjEntry at = e1->adjSource(); - while(at->theEdge() != e2) - at = at->twin()->cyclicSucc(); - - if(at == e2->adjSource()) - curDir = s_oppDir[curDir]; - } - break; // nothing to do - } - } - - return c; -} - - -//--------------------------------------------------------- -// DFS-traversal for computing insertion path in BC-tree -// (case vertex v) -//--------------------------------------------------------- - -bool MultiEdgeApproxInserter::dfsPathVertex(node v, int parent, int k, node t) -{ - if(v == t) return true; - - SListConstIterator it; - for(it = m_compV[v].begin(); it.valid(); ++it) { - if(*it == parent) continue; - if(dfsPathBlock(*it,v,k,t)) return true; - } - return false; -} - - -//--------------------------------------------------------- -// DFS-traversal for computing insertion path in BC-tree -// (case block b) -//--------------------------------------------------------- - -bool MultiEdgeApproxInserter::dfsPathBlock(int b, node parent, int k, node t) -{ - SListConstIterator it; - for(it = m_verticesB[b].begin(); it.valid(); ++it) - { - node c = *it; - if(c == parent) continue; - if(dfsPathVertex(c,b,k,t)) { - m_pathBCs[k].pushFront(VertexBlock(parent,b)); - - if(!m_block[b]->isBridge()) - { - // find path from parent to c in block b and compute embedding preferences - m_insertionCosts[k] += computePathSPQR(b, parent, c, k); - } - - return true; - } - } - return false; -} - - -//--------------------------------------------------------- -// compute insertion path of edge edge k in BC-tree -//--------------------------------------------------------- - -void MultiEdgeApproxInserter::computePathBC(int k) -{ - node s = m_pPG->copy(m_edge[k]->source()); - node t = m_pPG->copy(m_edge[k]->target()); - - bool found = dfsPathVertex(s, -1, k, t); - if(!found) cout << "Could not find path in BC-tree!" << endl; -} - - -//--------------------------------------------------------- -// Embeds block b according to combined embedding -// preference s of the k insertion paths -//--------------------------------------------------------- - -void MultiEdgeApproxInserter::embedBlock(int b, int m) -{ - // Algorithm 3.7. - - Block &B = *m_block[b]; - if(B.isBridge()) - return; - StaticPlanarSPQRTree &spqr = B.spqr(); - - // A. --------------------------------------- - NodeArray pi_pick(spqr.tree()); - NodeArray visited(spqr.tree(), false); // mark nodes with embedding preferences - NodeArray markFlipped(spqr.tree(), false); // mark nodes on current path to get flipped - Array p; - - // B. --------------------------------------- - for(int i = 0; i < m; ++i) - { - // (a) - B.pathToArray(i, p); - const int len = p.size(); - if(len == 0) continue; // this path does not go through B - - int j = 0; - do { - node n = p[j].m_node; - - // (b) --------------------------------------- - bool newlySet = false; - if(pi_pick[n].isNull()) { - newlySet = true; - pi_pick[n] = *p[j].m_pref; - - if(spqr.typeOf(n) == SPQRTree::PNode) { - adjEntry a1 = pi_pick[n].adj1(); - adjEntry a2 = pi_pick[n].adj2(); - adjEntry adj = a1->cyclicSucc(); - - if(adj != a2) - spqr.swap(n,adj,a2); - - OGDF_ASSERT(a1->cyclicSucc() == a2); - } - } - - // (c) --------------------------------------- - - // determine non-S-node predecessor of n - int j_mu = -1; - if(j > 0) { - node x = p[j-1].m_node; - if(spqr.typeOf(x) != SPQRTree::SNode) - j_mu = j-1; - else if(j > 1) - j_mu = j-2; - } - - if(j_mu >= 0) - { - node mu = p[j_mu].m_node; - - // do we have a switching pair (mu,n)? - if(B.switchingPair(mu, n, pi_pick[mu], *p[j_mu].m_pref, pi_pick[n], *p[j].m_pref)) - markFlipped[mu] = true; // flip embedding at mu - } - - // (d) --------------------------------------- - if(!newlySet) { - // skip nodes in same embedding partition - while(j+1 < len && visited[p[j+1].m_node]) - ++j; - } - - // next node - if(++j >= len) - break; // end of insertion path - - // skip S-node (can only be one) - if(spqr.typeOf(p[j].m_node) == SPQRTree::SNode) - ++j; - - } while(j < len); - - // flip embedding preferences - bool flipping = false; - for(int j = len-1; j >= 0; --j) - { - node n = p[j].m_node; - if(markFlipped[n]) { - flipping = !flipping; - markFlipped[n] = false; - } - - if(flipping) { - pi_pick[n].flip(); - if(pi_pick[n].type() == EmbeddingPreference::epPNode) - spqr.reverse(n); - - if(visited[n]) { - node n_succ = (j+1 < len) ? p[j+1].m_node : 0; - node n_pred = (j-1 >= 0) ? p[j-1].m_node : 0; - - adjEntry adj; - forall_adj(adj,n) { - node x = adj->twinNode(); - if(x != n_succ && x != n_pred && visited[x]) - recFlipPref(adj->twin(), pi_pick, visited, spqr); - } - } - } - - visited[n] = true; - } - } - - // C. --------------------------------------- - node n; - forall_nodes(n,spqr.tree()) - { - const EmbeddingPreference &p = pi_pick[n]; - if(p.isNull()) - continue; - - switch(spqr.typeOf(n)) { - case SPQRTree::SNode: - break; // nothing to do - - case SPQRTree::PNode: - break; // already embedded as desired - - case SPQRTree::RNode: - if(p.mirror()) - spqr.reverse(n); - break; - } - } - - spqr.embed(B); -} - - -void MultiEdgeApproxInserter::recFlipPref( - adjEntry adjP, - NodeArray &pi_pick, - const NodeArray &visited, - StaticPlanarSPQRTree &spqr) -{ - node n = adjP->theNode(); - - EmbeddingPreference &pref = pi_pick[n]; - pref.flip(); - if(pref.type() == EmbeddingPreference::epPNode) - spqr.reverse(n); - - adjEntry adj; - forall_adj(adj,n) { - if(adj != adjP && visited[adj->twinNode()]) - recFlipPref(adj->twin(), pi_pick, visited, spqr); - } -} - - -//--------------------------------------------------------- -// actual call method -// currently not supported: -// frobidCrossingGens, forbiddenEdgeOrig, edgeSubGraph -//--------------------------------------------------------- - -const char *strType[] = { "S", "P", "R" }; -//#define MEAI_OUTPUT - -struct CutvertexPreference { - CutvertexPreference(node v1, int b1, node v2, int b2) - : m_v1(v1), m_v2(v2), m_b1(b1), m_b2(b2), m_len1(-1), m_len2(-1) { } - - node m_v1, m_v2; - int m_b1, m_b2; - int m_len1, m_len2; -}; - -void appendToList(SListPure &adjList, adjEntry adj1, - const AdjEntryArray &BCtoG, - AdjEntryArray > &pos) -{ - adjEntry adj = adj1; - do { - adj = adj->cyclicSucc(); - adjEntry adjG = BCtoG[adj]; - pos[adjG] = adjList.pushBack(adjG); - } while(adj != adj1); -} - -void insertAfterList(SListPure &adjList, SListIterator itBefore, adjEntry adj1, - const AdjEntryArray &BCtoG, - AdjEntryArray > &pos) -{ - adjEntry adj = adj1; - do { - adj = adj->cyclicSucc(); - adjEntry adjG = BCtoG[adj]; - itBefore = pos[adjG] = adjList.insertAfter(adjG, itBefore); - } while(adj != adj1); -} - -Module::ReturnType MultiEdgeApproxInserter::doCall( - PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig, - const EdgeArray *edgeSubGraph) -{ - m_pPG = &PG; - m_costOrig = costOrig; - const int m = origEdges.size(); - - m_edge.init(m); - m_pathBCs.init(m); - m_insertionCosts.init(0,m-1,0); - - int i = 0; - for(ListConstIterator it = origEdges.begin(); it.valid(); ++it) - m_edge[i++] = *it; - - // - // PHASE 1: Fix a good embedding - // - - // compute biconnected components of PG - EdgeArray compnum(PG); - int c = biconnectedComponents(PG,compnum); - - m_compV.init(PG); - m_verticesB.init(c); - - // edgesB[i] = list of edges in component i - m_edgesB.init(c); - edge e; - forall_edges(e,PG) - m_edgesB[compnum[e]].pushBack(e); - - // construct arrays compV and nodeB such that - // m_compV[v] = list of components containing v - // m_verticesB[i] = list of vertices in component i - NodeArray mark(PG,false); - - for(i = 0; i < c; ++i) { - SListConstIterator itEdge; - for(itEdge = m_edgesB[i].begin(); itEdge.valid(); ++itEdge) - { - edge e = *itEdge; - - if (!mark[e->source()]) { - mark[e->source()] = true; - m_verticesB[i].pushBack(e->source()); - } - if (!mark[e->target()]) { - mark[e->target()] = true; - m_verticesB[i].pushBack(e->target()); - } - } - - SListConstIterator itNode; - for(itNode = m_verticesB[i].begin(); itNode.valid(); ++itNode) - { - node v = *itNode; - m_compV[v].pushBack(i); - mark[v] = false; - } - } - mark.init(); - m_GtoBC.init(PG,0); - m_copyInBlocks.init(PG); - - m_block.init(c); - for(int i = 0; i < c; ++i) - m_block[i] = constructBlock(i); - - m_sumInsertionCosts = 0; - for(i = 0; i < m; ++i) { - computePathBC(i); - m_sumInsertionCosts += m_insertionCosts[i]; - -#ifdef MEAI_OUTPUT - cout << "(" << PG.copy(m_edge[i]->source()) << "," << PG.copy(m_edge[i]->target()) << ") c = " << m_insertionCosts[i] << ":\n"; - ListConstIterator it; - for(it = m_pathBCs[i].begin(); it.valid(); ++it) { - int b = (*it).m_block; - const StaticSPQRTree &spqr = m_block[b]->spqr(); - - cout << " [ " << "V_" << (*it).m_vertex << ", B_" << b << " ]\n"; - cout << " "; - if(m_block[b]->isBridge()) { - cout << "BRIDGE"; - } else { - node x = m_block[b]->m_pathSPQR[i].m_start; - SPQRTree::NodeType t = spqr.typeOf(x); - cout << strType[t] << "_" << x; - ListConstIterator itP = m_block[b]->m_pathSPQR[i].m_prefs.begin(); - if(t == SPQRTree::RNode) { - if((*itP).type() == EmbeddingPreference::epNone) - cout << " (NONE)"; - else if((*itP).mirror()) - cout << " (MIRROR)"; - else - cout << " (KEEP)"; - ++itP; - } else if(t == SPQRTree::PNode) { - if((*itP).type() == EmbeddingPreference::epNone) - cout << " (NONE)"; - else - cout << "(ADJ:" << (*itP).adj1()->index() << ";" << (*itP).adj2()->index() << ")"; - ++itP; - } - - ListConstIterator itE = m_block[b]->m_pathSPQR[i].m_edges.begin(); - for(; itE.valid(); ++itE) - { - node y = (*itE)->opposite(x); - SPQRTree::NodeType t = spqr.typeOf(y); - cout << " -> " << strType[t] << "_" << y; - - if(t == SPQRTree::RNode) { - if((*itP).type() == EmbeddingPreference::epNone) - cout << " (NONE)"; - else if((*itP).mirror()) - cout << " (MIRROR)"; - else - cout << " (KEEP)"; - ++itP; - } else if(t == SPQRTree::PNode) { - if((*itP).type() == EmbeddingPreference::epNone) - cout << " (NONE)"; - else - cout << "(ADJ:" << (*itP).adj1()->index() << ";" << (*itP).adj2()->index() << ")"; - ++itP; - } - - x = y; - } - } - cout << endl; - } -#endif - } - - // embed blocks - for(int i = 0; i < c; ++i) - embedBlock(i,m); - - - // find embedding preferences at cutvertices - NodeArray > cvPref(PG); - - for(i = 0; i < m; ++i) - { - const List &L = m_pathBCs[i]; - if(L.size() < 2) - continue; - - ListConstIterator it = L.begin(); - node last_v = (*it).m_vertex; - int last_b = (*it).m_block; - ++it; - do { - node v2 = (it.succ().valid()) ? (*it.succ()).m_vertex : PG.copy(m_edge[i]->target()); - cvPref[(*it).m_vertex].pushBack(CutvertexPreference(last_v,last_b,v2,(*it).m_block)); - - last_v = (*it).m_vertex; - last_b = (*it).m_block; - ++it; - } while(it.valid()); - } - - - // embedding graph - Array blockSet(0,c-1,false); - AdjEntryArray > pos(PG,0); - - node v; - forall_nodes(v,PG) - { - SListPure adjList; - SList &copies = m_copyInBlocks[v]; - - // not a cut vertex? - if(copies.size() == 1) { - OGDF_ASSERT(cvPref[v].empty()); - const Block &B = *m_block[copies.front().m_block]; - node vB = copies.front().m_vertex; - - adjEntry adj; - forall_adj(adj,vB) - adjList.pushBack(B.m_BCtoG[adj]); - - } else { - SList &prefs = cvPref[v]; - - SListIterator it; - if(!prefs.empty()) { - // always realize first cutvertex preference - it = prefs.begin(); - - int b1 = (*it).m_b1; - int b2 = (*it).m_b2; - blockSet[b1] = blockSet[b2] = true; - - adjEntry adj1 = m_block[b1]->findBestFace(copy(v,b1),copy((*it).m_v1,b1), (*it).m_len1); - appendToList(adjList, adj1, m_block[b1]->m_BCtoG, pos); - - adjEntry adj2 = m_block[b2]->findBestFace(copy(v,b2),copy((*it).m_v2,b2), (*it).m_len2); - appendToList(adjList, adj2, m_block[b2]->m_BCtoG, pos); - - for(++it; it.valid(); ++it) { - b1 = (*it).m_b1; - b2 = (*it).m_b2; - - if(!blockSet[b1] && !blockSet[b2]) { - // none of the two blocks set yet - adjEntry adj1 = m_block[b1]->findBestFace(copy(v,b1),copy((*it).m_v1,b1), (*it).m_len1); - appendToList(adjList, adj1, m_block[b1]->m_BCtoG, pos); - - adjEntry adj2 = m_block[b2]->findBestFace(copy(v,b2),copy((*it).m_v2,b2), (*it).m_len2); - appendToList(adjList, adj2, m_block[b2]->m_BCtoG, pos); - - blockSet[b1] = blockSet[b2] = true; - - } else if(!blockSet[b1]) { - // b2 is set, but b1 is not yet set - adjEntry adj1 = m_block[b1]->findBestFace(copy(v,b1),copy((*it).m_v1,b1), (*it).m_len1); - adjEntry adj2 = m_block[b2]->findBestFace(copy(v,b2),copy((*it).m_v2,b2), (*it).m_len2); - - insertAfterList(adjList, pos[m_block[b2]->m_BCtoG[adj2]], adj1, m_block[b1]->m_BCtoG, pos); - blockSet[b1] = true; - - } else if(!blockSet[b2]) { - // b1 is set, but b2 is not yet set - adjEntry adj1 = m_block[b1]->findBestFace(copy(v,b1),copy((*it).m_v1,b1), (*it).m_len1); - adjEntry adj2 = m_block[b2]->findBestFace(copy(v,b2),copy((*it).m_v2,b2), (*it).m_len2); - - insertAfterList(adjList, pos[m_block[b1]->m_BCtoG[adj1]], adj2, m_block[b2]->m_BCtoG, pos); - blockSet[b2] = true; - } - } - } - - // embed remaining blocks (if any) - SListConstIterator itVB; - for(itVB = copies.begin(); itVB.valid(); ++itVB) { - int b = (*itVB).m_block; - if(blockSet[b]) - continue; - appendToList(adjList, (*itVB).m_vertex->firstAdj(), m_block[b]->m_BCtoG, pos); - } - - // cleanup - for(it = prefs.begin(); it.valid(); ++it) { - blockSet[(*it).m_b1] = false; - blockSet[(*it).m_b2] = false; - } - - OGDF_ASSERT(adjList.size() == v->degree()); - } - - PG.sort(v, adjList); - } - - OGDF_ASSERT(PG.representsCombEmbedding()); - - // arbitrary embedding for testing - //planarEmbed(PG); - - // generate further statistic information - if(m_statistics) { - constructDual(PG); - - //cout << "\ncutvertex preferences:\n" << endl; - //forall_nodes(v,PG) - //{ - // SListConstIterator it = cvPref[v].begin(); - // if(!it.valid()) continue; - - // cout << v << ":\n"; - // for(; it.valid(); ++it) { - // const CutvertexPreference &p = *it; - - // int sp1 = findShortestPath(p.m_v1, v); - // int sp2 = findShortestPath(v, p.m_v2); - // cout << " ( v" << p.m_v1 << ", b" << p.m_b1 << "; v" << p.m_v2 << ", b" << p.m_b2 << " ) "; - // cout << "[ " << p.m_len1 << " / " << sp1 << " ; " << p.m_len2 << " / " << sp2 << " ]" << endl; - // } - //} - - m_sumFEInsertionCosts = 0; - for(i = 0; i < m; ++i) { - node s = PG.copy(m_edge[i]->source()); - node t = PG.copy(m_edge[i]->target()); - int len = findShortestPath(s,t); - m_sumFEInsertionCosts += len; - } - } else - m_sumFEInsertionCosts = -1; - - - // release no longer needed resources - - cleanup(); - - - // - // PHASE 2: Perform edge insertion with fixed emebdding - // - - FixedEmbeddingInserter fei; - fei.keepEmbedding(true); - fei.removeReinsert(m_rrOptionFix); - fei.percentMostCrossed(m_percentMostCrossedFix); - - fei.call( PG, origEdges ); - - if(m_rrOptionVar != rrNone && m_rrOptionVar != rrIncremental) { - VariableEmbeddingInserter vei; - vei.removeReinsert(m_rrOptionVar); - vei.percentMostCrossed(m_percentMostCrossedFix); - vei.callPostprocessing( PG, origEdges ); - } - - - return retFeasible; -} - - -//--------------------------------------------------------- -// cleanup: delete blocks, reset all auxiliary arrays -//--------------------------------------------------------- - -void MultiEdgeApproxInserter::cleanup() -{ - int c = m_block.size(); - for(int i = 0; i < c; ++i) - delete m_block[i]; - m_block.init(); - - m_GtoBC.init(); - m_edgesB.init(); - m_verticesB.init(); - m_compV.init(); - - m_edge.init(); - m_pathBCs.init(); - m_insertionCosts.init(); - m_copyInBlocks.init(); - - m_primalAdj.init(); - m_faceNode.init(); - m_E.init(); - m_dual.clear(); -} - - -//--------------------------------------------------------- -// just for testing and additional statistics -//--------------------------------------------------------- - -void MultiEdgeApproxInserter::constructDual(const PlanRep &PG) -{ - m_E.init(PG); - m_faceNode.init(m_E); - m_primalAdj.init(m_dual); - - // constructs nodes (for faces in m_embB) - face f; - forall_faces(f,m_E) { - m_faceNode[f] = m_dual.newNode(); - } - - // construct dual edges (for primal edges in block) - node v; - forall_nodes(v,PG) - { - adjEntry adj; - forall_adj(adj,v) - { - if(adj->index() & 1) { - node vLeft = m_faceNode[m_E.leftFace (adj)]; - node vRight = m_faceNode[m_E.rightFace(adj)]; - - edge eDual = m_dual.newEdge(vLeft,vRight); - m_primalAdj[eDual->adjSource()] = adj; - m_primalAdj[eDual->adjTarget()] = adj->twin(); - } - } - } - - m_vS = m_dual.newNode(); - m_vT = m_dual.newNode(); -} - - -int MultiEdgeApproxInserter::findShortestPath(node s, node t) -{ - NodeArray spPred(m_dual, 0); - QueuePure queue; - int oldIdCount = m_dual.maxEdgeIndex(); - - // augment dual by edges from s to all adjacent faces of s ... - adjEntry adj; - forall_adj(adj,s) { - // starting edges of bfs-search are all edges leaving s - edge eDual = m_dual.newEdge(m_vS, m_faceNode[m_E.rightFace(adj)]); - m_primalAdj[eDual->adjSource()] = adj; - m_primalAdj[eDual->adjTarget()] = 0; - queue.append(eDual->adjSource()); - } - - // ... and from all adjacent faces of t to t - forall_adj(adj,t) { - edge eDual = m_dual.newEdge(m_faceNode[m_E.rightFace(adj)], m_vT); - m_primalAdj[eDual->adjSource()] = adj; - m_primalAdj[eDual->adjTarget()] = 0; - } - - // actual search (using bfs on directed dual) - int len = -2; - for( ; ;) - { - // next candidate edge - adjEntry adjCand = queue.pop(); - node v = adjCand->twinNode(); - - // leads to an unvisited node? - if (spPred[v] == 0) - { - // yes, then we set v's predecessor in search tree - spPred[v] = adjCand; - - // have we reached t ... - if (v == m_vT) - { - // ... then search is done. - - adjEntry adj; - do { - adj = spPred[v]; - ++len; - v = adj->theNode(); - } while(v != m_vS); - - break; - } - - // append next candidate edges to queue - // (all edges leaving v) - adjEntry adj; - forall_adj(adj,v) { - if(adj->twinNode() != m_vS) - queue.append(adj); - } - } - } - - // remove augmented edges again - while ((adj = m_vS->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - while ((adj = m_vT->firstAdj()) != 0) - m_dual.delEdge(adj->theEdge()); - - m_dual.resetEdgeIdCount(oldIdCount); - - return len; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanRep.cpp b/ext/OGDF/src/planarity/PlanRep.cpp deleted file mode 100644 index 8c6b8b7b5..000000000 --- a/ext/OGDF/src/planarity/PlanRep.cpp +++ /dev/null @@ -1,972 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of PlanRep base class for planar rep. - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -#include - -#include - - -namespace ogdf { - -PlanRep::PlanRep(const Graph& AG) : - GraphCopy(), - m_pGraphAttributes(NULL), - m_boundaryAdj(AG, 0),//*this, 0), - m_oriEdgeTypes(AG, 0), - m_eAuxCopy(AG) - { - m_vType .init(*this, Graph::dummy); - m_nodeTypes .init(*this, 0); //the new node type info - m_expandedNode .init(*this, 0); - m_expandAdj .init(*this, 0); - m_expansionEdge.init(*this, 0); - m_eType .init(*this, Graph::association); //should be dummy or standard, but isnt checked correctly, - m_edgeTypes .init(*this, 0); //the new edge type info - - const Graph &G = AG; - - // special way of initializing GraphCopy; we start with an empty copy - // and add components by need - GraphCopy::createEmpty(G); - - // compute connected component of G - NodeArray component(G); - m_numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - m_nodesInCC.init(m_numCC); - - node v; - forall_nodes(v,G) - m_nodesInCC[component[v]].pushBack(v); - - m_currentCC = -1; // not yet initialized -} - - -PlanRep::PlanRep(const GraphAttributes& AG) : - GraphCopy(), - m_pGraphAttributes(&AG), - m_boundaryAdj(AG.constGraph(), 0), - m_oriEdgeTypes(AG.constGraph(), 0), - m_eAuxCopy(AG.constGraph()) -{ - m_vType .init(*this,Graph::dummy); - m_nodeTypes .init(*this, 0); //the new node type info - m_expandedNode .init(*this,0); - m_expandAdj .init(*this,0); - m_expansionEdge.init(*this, 0); - m_eType .init(*this, Graph::association); //should be dummy or standard, but isnt checked correctly, - m_edgeTypes .init(*this, 0); //the new edge type info - - const Graph &G = AG.constGraph(); - - // special way of initializing GraphCopy; we start with an empty copy - // and add components by need - GraphCopy::createEmpty(G); - - // compute connected component of G - NodeArray component(G); - m_numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - m_nodesInCC.init(m_numCC); - - node v; - forall_nodes(v,G) - m_nodesInCC[component[v]].pushBack(v); - - m_currentCC = -1; // not yet initialized -}//PlanRep - - -void PlanRep::initCC(int i) -{ - // delete copy / chain fields for originals of nodes in current cc - // (since we remove all these copies in initByNodes(...) - if (m_currentCC >= 0) - { - const List &origInCC = nodesInCC(i); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - - m_vCopy[vG] = 0; - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - m_eCopy[eG].clear(); - } - } - } - - m_currentCC = i; - GraphCopy::initByNodes(m_nodesInCC[i], m_eAuxCopy); - - // set type of edges (gen. or assoc.) in the current CC - edge e; - forall_edges(e,*this) - setCopyType(e, original(e)); - - if(m_pGraphAttributes == 0) - return; - - // The following part is only relevant with given graph attributes! - - node v; - forall_nodes(v,*this) - { - m_vType[v] = m_pGraphAttributes->type(original(v)); - if (m_pGraphAttributes->isAssociationClass(original(v))) { - OGDF_ASSERT(v->degree() == 1) - edge e = v->firstAdj()->theEdge(); - setAssClass(e); - } - } -}//initCC - - -//inserts Boundary for a given group of nodes -//can e.g. be used to split clique replacements from the rest of the graph -//precondition: is only applicable for planar embedded subgraphs -// -//void PlanRep::insertBoundary(List &group) -//{ -//TODO -//Difficulty: efficiently find the outgoing edges -//} -//special version for stars -//works on copy nodes -//precondition: center is the center of a star-like subgraph -//induced by the neighbours of center, subgraph has connection -//to the rest of the graph -//keeps the given embedding -void PlanRep::insertBoundary(node centerOrig, adjEntry& adjExternal)//, CombinatorialEmbedding &E) -{ - //we insert edges to represent the boundary - //by splitting the outgoing edges and connecting the - //split nodes - node center = copy(centerOrig); - OGDF_ASSERT(center) - - if (center->degree() < 1) return; - - OGDF_ASSERT(original(center)) - - //--------------------------- - //retrieve the outgoing edges - //we run over all nodes adjacent to center and add their - //adjacent edges - SList outAdj; - - adjEntry adj; - forall_adj(adj, center) - { - //-------------------------------------------------------------- - //check if external face was saved over adjEntry on center edges - - //we want to stay in the same (external) face, next adjEntry - //may get split later on, succ(succ) can never be within this clique - //(and split) because all clique node - clique node connections are deleted - //IFF the target node is connnected to some non-clique part of the graph - //the search in this case would loop if there is no connection to the rest of - //the graph - if (adjExternal == adj) //outgoing - { - if (adj->twinNode()->degree() == 1) - { - do { - adjExternal = adjExternal->faceCycleSucc(); - } while ( (adjExternal->theNode() == center) || - (adjExternal->twinNode() == center)); - }//if degree 1 - else - adjExternal = adjExternal->faceCycleSucc()->faceCycleSucc(); - } - if (adjExternal == adj->twin()) //incoming - { - if (adj->twinNode()->degree() == 1) - { - do { - adjExternal = adjExternal->faceCycleSucc(); - } while ( (adjExternal->theNode() == center) || - (adjExternal->twinNode() == center)); - }//if degree 1 - else - adjExternal = adjExternal->faceCyclePred()->faceCyclePred(); - } - adjEntry stopper = adj->twin(); - adjEntry runner = stopper->cyclicSucc(); - while (runner != stopper) - { - outAdj.pushBack(runner); - runner = runner->cyclicSucc(); - }//while - - }//foralladj of center - - //we do not insert a boundary if the subgraph is not - //connected to the rest of the graph - if (outAdj.empty()) return; - - //--------------------------------------- - //now split the edges and save adjEntries - //we maintain two lists of adjentries - List targetEntries, sourceEntries; - - //we need to find out if edge is outgoing - bool isOut = false; - SListIterator it = outAdj.begin(); - while (it.valid()) - { - //outgoing edges of clique nodes - adjEntry splitAdj = (*it); - - edge splitEdge = splitAdj->theEdge(); - - isOut = (splitAdj->theNode() == splitEdge->source()); - - //------------------------------------------------------- - //check if external face was saved over edges to be split - bool splitOuter = false; - bool splitInner = false; - if (adjExternal == splitAdj) - { - splitOuter = true; - //adjExternal = adjExternal->faceCycleSucc(); - } - if (adjExternal == splitAdj->twin()) - { - splitInner = true; - //adjExternal = adjExternal->faceCyclePred(); - } - - - //combinatorial version - //edge newEdge = E.split(splitEdge); - //simple version - edge newEdge = split(splitEdge); - setCrossingType(newEdge->source()); - - //store the adjEntries depending on in/out direction - if (isOut) - { - //splitresults "upper" edge to old target node is newEdge! - sourceEntries.pushBack(newEdge->adjSource()); - targetEntries.pushBack(splitEdge->adjTarget()); - if (splitOuter) adjExternal = newEdge->adjSource(); - if (splitInner) adjExternal = newEdge->adjTarget(); - }//if outgoing - else - { - sourceEntries.pushBack(splitEdge->adjTarget()); - targetEntries.pushBack(newEdge->adjSource()); - if (splitOuter) adjExternal = splitEdge->adjTarget(); - if (splitInner) adjExternal = splitEdge->adjSource(); - }//else outgoing - - //go on with next edge - it++; - - }//while outedges - - - //we need pairs of adjEntries - OGDF_ASSERT(targetEntries.size() == sourceEntries.size()); - //now flip first target entry to front - //should be nonempty - adjEntry flipper = targetEntries.popFrontRet(); - targetEntries.pushBack(flipper); - - edge e; - - //connect the new nodes to form the boundary - while (!targetEntries.empty()) - { - //combinatorial version - //edge e = E.splitFace(sourceEntries.popFrontRet(), targetEntries.popFrontRet()); - //simple version - e = newEdge(sourceEntries.popFrontRet(), targetEntries.popFrontRet()); - this->typeOf(e) = Graph::association; - setCliqueBoundary(e); - } - - //keep it simple: just assign the last adjEntry to boundaryAdj - //we have to save at the original, the copy may be replaced - OGDF_ASSERT(m_boundaryAdj[original(center)] == 0) - m_boundaryAdj[original(center)] = e->adjSource(); - -}//insertBoundary - - -//***************************************************************************** -//embedding and crossings - -bool PlanRep::embed() -{ - return planarEmbed(*this); -} - -void PlanRep::removeUnnecessaryCrossing( - adjEntry adjA1, - adjEntry adjA2, - adjEntry adjB1, - adjEntry adjB2) -{ - node v = adjA1->theNode(); - - if(adjA1->theEdge()->source() == v) - moveSource(adjA1->theEdge(), adjA2->twin(), before); - else - moveTarget(adjA1->theEdge(), adjA2->twin(), before); - - if(adjB1->theEdge()->source() == v) - moveSource(adjB1->theEdge(), adjB2->twin(), before); - else - moveTarget(adjB1->theEdge(), adjB2->twin(), before); - - edge eOrigA = original(adjA1->theEdge()); - edge eOrigB = original(adjB1->theEdge()); - - if (eOrigA != 0) - m_eCopy[eOrigA].del(m_eIterator[adjA2->theEdge()]); - if (eOrigB != 0) - m_eCopy[eOrigB].del(m_eIterator[adjB2->theEdge()]); - - delEdge(adjB2->theEdge()); - delEdge(adjA2->theEdge()); - - delNode(v); -} - -void PlanRep::removePseudoCrossings() -{ - node v, vSucc; - for(v = firstNode(); v != 0; v = vSucc) - { - vSucc = v->succ(); - - if (typeOf(v) != PlanRep::dummy || v->degree() != 4) - continue; - - adjEntry adj1 = v->firstAdj(); - adjEntry adj2 = adj1->succ(); - adjEntry adj3 = adj2->succ(); - adjEntry adj4 = adj3->succ(); - - if(original(adj1->theEdge()) == original(adj2->theEdge())) - removeUnnecessaryCrossing(adj1,adj2,adj3,adj4); - else if (original(adj2->theEdge()) == original(adj3->theEdge())) - removeUnnecessaryCrossing(adj2,adj3,adj4,adj1); - } -} - -void PlanRep::insertEdgePathEmbedded( - edge eOrig, - CombinatorialEmbedding &E, - const SList &crossedEdges) -{ - GraphCopy::insertEdgePathEmbedded(eOrig,E,crossedEdges); - Graph::EdgeType edgeType = m_pGraphAttributes ? - m_pGraphAttributes->type(eOrig) : Graph::association; - - long et = m_oriEdgeTypes[eOrig]; - - ListConstIterator it; - for(it = chain(eOrig).begin(); it.valid(); ++it) - { - m_eType[*it] = edgeType; - m_edgeTypes[*it] = et; - if (!original((*it)->target())) - { - OGDF_ASSERT((*it)->target()->degree() == 4) - OGDF_ASSERT(it != chain(eOrig).rbegin()) - setCrossingType((*it)->target()); - } - } -} - -void PlanRep::insertEdgePath( - edge eOrig, - const SList &crossedEdges) -{ - GraphCopy::insertEdgePath(eOrig,crossedEdges); - - //old types - Graph::EdgeType edgeType = m_pGraphAttributes ? - m_pGraphAttributes->type(eOrig) : Graph::association; - - //new types - long et = m_oriEdgeTypes[eOrig]; - - ListConstIterator it; - for(it = chain(eOrig).begin(); it.valid(); ++it) - { - m_eType[*it] = edgeType; - m_edgeTypes[*it] = et; - if (!original((*it)->target())) - { - OGDF_ASSERT((*it)->target()->degree() == 4) - setCrossingType((*it)->target()); - } - } -} - -edge PlanRep::insertCrossing( - edge &crossingEdge, - edge crossedEdge, - bool topDown) -{ - EdgeType eTypi = m_eType[crossingEdge]; - EdgeType eTypd = m_eType[crossedEdge]; - edgeType eTypsi = m_edgeTypes[crossingEdge]; - edgeType eTypsd = m_edgeTypes[crossedEdge]; - - edge newCopy = GraphCopy::insertCrossing(crossingEdge, crossedEdge, topDown); - - //Do not use original types, they may differ from the copy - //type due to conflict resolution in preprocessing (expand crossings) - m_eType[crossingEdge] = eTypi; - m_eType[newCopy] = eTypd; - m_edgeTypes[crossingEdge] = eTypsi; - m_edgeTypes[newCopy] = eTypsd; - - setCrossingType(newCopy->source()); - OGDF_ASSERT(isCrossingType(newCopy->source())) - - //TODO: hier sollte man die NodeTypes setzen, d.h. crossing - - return newCopy; - -} - - -void PlanRep::removeCrossing(node v) -{ - OGDF_ASSERT(v->degree() == 4) - OGDF_ASSERT(isCrossingType(v)) - - adjEntry a1 = v->firstAdj(); - adjEntry b1 = a1->cyclicSucc(); - adjEntry a2 = b1->cyclicSucc(); - adjEntry b2 = a2->cyclicSucc(); - - removeUnnecessaryCrossing(a1, a2, b1, b2); - - -}//removeCrossing - - - -void PlanRep::expand(bool lowDegreeExpand) -{ - node v; - forall_nodes(v,*this) - { - - // Replace vertices with high degree by cages and - // replace degree 4 vertices with two generalizations - // adjacent in the embedding list by a cage. - if ((v->degree() > 4) && (typeOf(v) != Graph::dummy) && !lowDegreeExpand) - { - edge e; - - //Set the type of the node v. It remains in the graph - // as one of the nodes of the expanded face. - typeOf(v) = Graph::highDegreeExpander; - - // Scan the list of edges of v to find the adjacent edges of v - // according to the planar embedding. All except one edge - // will get a new adjacent node - SList adjEdges; - {forall_adj_edges(e,v) - adjEdges.pushBack(e); - } - - //The first edge remains at v. remove it from the list. - e = adjEdges.popFrontRet(); - - // Create the list of high degree expanders - // We need degree(v)-1 of them to construct a face. - // and set expanded Node to v - setExpandedNode(v, v); - SListPure expander; - for (int i = 0; i < v->degree()-1; i++) - { - node u = newNode(); - typeOf(u) = Graph::highDegreeExpander; - setExpandedNode(u, v); - expander.pushBack(u); - } - - // We move the target node of each ingoing generalization of v to a new - // node stored in expander. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - SListConstIterator itn; - - NodeArray ar(*this); - - itn = expander.begin(); - - for (it = adjEdges.begin(); it.valid(); it++) - { - // Did we allocate enough dummy nodes? - OGDF_ASSERT(itn.valid()); - - if ((*it)->source() == v) - moveSource(*it,*itn); - else - moveTarget(*it,*itn); - ar[*itn] = (*itn)->firstAdj(); - itn++; - } - ar[v] = v->firstAdj(); - - // Now introduce the circular list of new edges - // forming the border of the merge face. Keep the embedding. - adjEntry adjPrev = v->firstAdj(); - -// cout <firstAdj() << endl; - e = Graph::newEdge(adjPrev,(*itn)->firstAdj()); - setExpansionEdge(e, 2);//can be removed if edgetypes work properly - - setExpansion(e); - setAssociation(e); - - typeOf(e) = association; //??? - - if (!expandAdj(v)) - expandAdj(v) = e->adjSource(); - adjPrev = (*itn)->firstAdj(); - } - - e = newEdge(adjPrev,v->lastAdj()); - - typeOf(e) = association; //??? - setExpansionEdge(e, 2);//can be removed if edgetypes work properly - setAssociation(e); - - }//highdegree - - // Replace all vertices with degree > 2 by cages. - else if (v->degree() >= 2 && typeOf(v) != Graph::dummy && - lowDegreeExpand) - { - edge e; - - //Set the type of the node v. It remains in the graph - // as one of the nodes of the expanded face. - typeOf(v) = Graph::lowDegreeExpander; //high?? - - // Scan the list of edges of v to find the adjacent edges of v - // according to the planar embedding. All except one edge - // will get a new adjacent node - SList adjEdges; - {forall_adj_edges(e,v) - adjEdges.pushBack(e); - } - - //The first edge remains at v. remove it from the list. - // Check if it is a generalization. - e = adjEdges.popFrontRet(); - - // Create the list of high degree expanders - // We need degree(v)-1 of them to construct a face. - // and set expanded Node to v - setExpandedNode(v, v); - SListPure expander; - for (int i = 0; i < v->degree()-1; i++) - { - node u = newNode(); - typeOf(u) = Graph::highDegreeExpander; - setExpandedNode(u, v); - expander.pushBack(u); - } - - // We move the target node of each ingoing generalization of v to a new - // node stored in expander. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - SListConstIterator itn; - - NodeArray ar(*this); - - itn = expander.begin(); - - for (it = adjEdges.begin(); it.valid(); it++) - { - // Did we allocate enough dummy nodes? - OGDF_ASSERT(itn.valid()); - - if ((*it)->source() == v) - moveSource(*it,*itn); - else - moveTarget(*it,*itn); - ar[*itn] = (*itn)->firstAdj(); - itn++; - } - ar[v] = v->firstAdj(); - - // Now introduce the circular list of new edges - // forming the border of the merge face. Keep the embedding. - adjEntry adjPrev = v->firstAdj(); - - for (itn = expander.begin(); itn.valid(); itn++) - { - e = newEdge(adjPrev,(*itn)->firstAdj()); - if (!expandAdj(v)) expandAdj(v) = e->adjSource(); - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - //new types - setAssociation(e); //should be dummy type? - setExpansion(e); - - adjPrev = (*itn)->firstAdj(); - } - e = newEdge(adjPrev,v->lastAdj()); - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - } - - }//forallnodes - -}//expand - - -void PlanRep::expandLowDegreeVertices(OrthoRep &OR) -{ - node v; - forall_nodes(v,*this) - { - if (!(isVertex(v)) || expandAdj(v) != 0) - continue; - - SList adjEdges; - SListPure > expander; - - node u = v; - bool firstTime = true; - - setExpandedNode(v, v); - - adjEntry adj; - forall_adj(adj,v) { - adjEdges.pushBack(adj->theEdge()); - - if(!firstTime) - u = newNode(); - - setExpandedNode(u, v); - typeOf(u) = Graph::lowDegreeExpander; - expander.pushBack(Tuple2(u,OR.angle(adj))); - firstTime = false; - } - - SListConstIterator it; - SListConstIterator > itn; - - itn = expander.begin().succ(); - - for (it = adjEdges.begin().succ(); it.valid(); ++it) - { - // Did we allocate enough dummy nodes? - OGDF_ASSERT(itn.valid()); - - if ((*it)->source() == v) - moveSource(*it,(*itn).x1()); - else - moveTarget(*it,(*itn).x1()); - ++itn; - } - - adjEntry adjPrev = v->firstAdj(); - itn = expander.begin(); - int nBends = (*itn).x2(); - - edge e; - for (++itn; itn.valid(); itn++) - { - e = newEdge(adjPrev,(*itn).x1()->firstAdj()); - - OR.bend(e->adjSource()).set(convexBend,nBends); - OR.bend(e->adjTarget()).set(reflexBend,nBends); - OR.angle(adjPrev) = 1; - OR.angle(e->adjSource()) = 2; - OR.angle(e->adjTarget()) = 1; - - nBends = (*itn).x2(); - - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - adjPrev = (*itn).x1()->firstAdj(); - } - - e = newEdge(adjPrev,v->lastAdj()); - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - expandAdj(v) = e->adjSource(); - - OR.bend(e->adjSource()).set(convexBend,nBends); - OR.bend(e->adjTarget()).set(reflexBend,nBends); - OR.angle(adjPrev) = 1; - OR.angle(e->adjSource()) = 2; - OR.angle(e->adjTarget()) = 1; - - } -}//expandlowdegreevertices - -void PlanRep::collapseVertices(const OrthoRep &OR, Layout &drawing) -{ - node v; - forall_nodes(v,*this) { - const OrthoRep::VertexInfoUML *vi = OR.cageInfo(v); - - if(vi == 0 || - (typeOf(v) != Graph::highDegreeExpander && - typeOf(v) != Graph::lowDegreeExpander)) - continue; - - node vOrig = original(v); - OGDF_ASSERT(vOrig != 0); - - node vCenter = newNode(); - m_vOrig[vCenter] = vOrig; - m_vCopy[vOrig] = vCenter; - m_vOrig[v] = 0; - - node lowerLeft = vi->m_corner[odNorth]->theNode(); - node lowerRight = vi->m_corner[odWest ]->theNode(); - node upperLeft = vi->m_corner[odEast ]->theNode(); - drawing.x(vCenter) = 0.5*(drawing.x(lowerLeft)+drawing.x(lowerRight)); - drawing.y(vCenter) = 0.5*(drawing.y(lowerLeft)+drawing.y(upperLeft )); - - edge eOrig; - forall_adj_edges(eOrig,vOrig) { - if(eOrig->target() == vOrig) { - node connect = m_eCopy[eOrig].back()->target(); - edge eNew = newEdge(connect,vCenter); - m_eOrig[eNew] = eOrig; - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - - } else { - node connect = m_eCopy[eOrig].front()->source(); - edge eNew = newEdge(vCenter,connect); - m_eOrig[eNew] = eOrig; - m_eIterator[eNew] = m_eCopy[eOrig].pushFront(eNew); - } - } - } -} - -//------------------------- -//object types -//set type of eCopy according to type of eOrig -void PlanRep::setCopyType(edge eCopy, edge eOrig) -{ - OGDF_ASSERT(original(eCopy) == eOrig) - m_eType[eCopy] = m_pGraphAttributes ? m_pGraphAttributes->type(eOrig) : Graph::association; - if (eOrig) - { - switch (m_pGraphAttributes ? m_pGraphAttributes->type(eOrig) : Graph::association) - { - case Graph::generalization: setGeneralization(eCopy); break; - case Graph::association: setAssociation(eCopy); break; - case Graph::dependency: setDependency(eCopy); break; - OGDF_NODEFAULT - }//switch - }//if original -}//setCopyType - - -void PlanRep::removeDeg1Nodes(Stack &S, const NodeArray &mark) -{ - for(node v = firstNode(); v != 0; v = v->succ()) - { - if(mark[v] || v->degree() == 0) - continue; - - adjEntry adjRef; - for(adjRef = v->firstAdj(); - adjRef != 0 && mark[adjRef->twinNode()]; - adjRef = adjRef->succ()) ; - - if(adjRef == 0) { - // only marked nodes adjacent with v (need no reference entry) - adjEntry adj; - forall_adj(adj,v) { - node x = adj->twinNode(); - S.push(Deg1RestoreInfo(m_eOrig[adj->theEdge()],m_vOrig[x],0)); - delCopy(x); - } - - } else { - adjEntry adj, adjNext, adjStart = adjRef; - for(adj = adjRef->cyclicSucc(); adj != adjStart; adj = adjNext) - { - adjNext = adj->cyclicSucc(); - node x = adj->twinNode(); - if(mark[x]) { - S.push(Deg1RestoreInfo(m_eOrig[adj->theEdge()],m_vOrig[x],adjRef)); - delCopy(x); - } else - adjRef = adj; - } - } - } -} - - -void PlanRep::restoreDeg1Nodes(Stack &S, List °1s) -{ - while(!S.empty()) - { - Deg1RestoreInfo info = S.pop(); - adjEntry adjRef = info.m_adjRef; - node vOrig = info.m_deg1Original; - edge eOrig = info.m_eOriginal; - - node v = newNode(vOrig); - - if(adjRef) { - if(vOrig == eOrig->source()) - newEdge(eOrig, v, adjRef); - else - newEdge(eOrig, adjRef, v); - } else { - if(vOrig == eOrig->source()) - newEdge(eOrig); - else - newEdge(eOrig); - } - deg1s.pushBack(v); - } -} - - -node PlanRep::newCopy(node v, Graph::NodeType vTyp) -{ - OGDF_ASSERT(m_vCopy[v] == 0) - - node u = newNode(); - m_vCopy[v] = u; - m_vOrig[u] = v; - //TODO:Typ? - m_vType[u] = vTyp; - - return u; -} - -//inserts copy for original edge eOrig after adAfter -edge PlanRep::newCopy(node v, adjEntry adAfter, edge eOrig) -{ - OGDF_ASSERT(eOrig->graphOf() == &(original())) - OGDF_ASSERT(m_eCopy[eOrig].size() == 0) - edge e; - if (adAfter != 0) - e = Graph::newEdge(v, adAfter); - else - { - node w = copy(eOrig->opposite(original(v))); - OGDF_ASSERT(w) - e = Graph::newEdge(v, w); - }//else - m_eOrig[e] = eOrig; - m_eIterator[e] = m_eCopy[eOrig].pushBack(e); - //set type of copy - if (m_pGraphAttributes != 0) - setCopyType(e, eOrig); - - return e; -} -//inserts copy for original edge eOrig preserving the embedding -edge PlanRep::newCopy(node v, adjEntry adAfter, edge eOrig, CombinatorialEmbedding &E) -{ - OGDF_ASSERT(eOrig->graphOf() == &(original())) - OGDF_ASSERT(m_eCopy[eOrig].size() == 0) - - edge e; - //GraphCopy checks direction for us - e = GraphCopy::newEdge(v, adAfter, eOrig, E); - //set type of copy - if (m_pGraphAttributes != 0) - setCopyType(e, eOrig); - - return e; -} - - -edge PlanRep::split(edge e) -{ - bool cageBound = (m_expandedNode[e->source()] && m_expandedNode[e->target()]) - && (m_expandedNode[e->source()] == m_expandedNode[e->target()]); - node expNode = (cageBound ? m_expandedNode[e->source()] : 0); - - edge eNew = GraphCopy::split(e); - m_eType[eNew] = m_eType[e]; - m_edgeTypes[eNew] = m_edgeTypes[e]; - m_expansionEdge[eNew] = m_expansionEdge[e]; - - m_expandedNode[eNew->source()] = expNode; - - return eNew; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanRepExpansion.cpp b/ext/OGDF/src/planarity/PlanRepExpansion.cpp deleted file mode 100644 index cc0aebbdc..000000000 --- a/ext/OGDF/src/planarity/PlanRepExpansion.cpp +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class PlanRepExpansion. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - -PlanRepExpansion::PlanRepExpansion(const Graph& G) -{ - List splittableNodes; - node v; - forall_nodes(v,G) { - if(v->degree() >= 4) - splittableNodes.pushBack(v); - } - - doInit(G,splittableNodes); -} - -PlanRepExpansion::PlanRepExpansion(const Graph& G, const List &splittableNodes) -{ - doInit(G,splittableNodes); -} - -void PlanRepExpansion::doInit(const Graph &G, const List &splittableNodes) -{ - m_pGraph = &G; - m_eAuxCopy.init(G); - - // compute connected component of G - NodeArray component(G); - m_numCC = connectedComponents(G,component); - - // intialize the array of lists of nodes contained in a CC - m_nodesInCC.init(m_numCC); - - node v; - forall_nodes(v,G) - m_nodesInCC[component[v]].pushBack(v); - - m_currentCC = -1; // not yet initialized - - m_vCopy.init(G); - m_eCopy.init(G); - m_vOrig.init(*this,0); - m_eOrig.init(*this,0); - m_vIterator.init(*this,0); - m_eIterator.init(*this,0); - - m_splittable.init(*this,false); - m_splittableOrig.init(G,false); - m_eNodeSplit.init(*this,0); - - ListConstIterator it; - for(it = splittableNodes.begin(); it.valid(); ++it) - if((*it)->degree() >= 4) - m_splittableOrig[*it] = true; -} - - -void PlanRepExpansion::initCC(int i) -{ - // delete copy / chain fields for originals of nodes in current cc - // (since we remove all these copies in initByNodes(...) - if (m_currentCC >= 0) - { - const List &origInCC = nodesInCC(i); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) - { - node vG = *itV; - - m_vCopy[vG].clear(); - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - m_eCopy[eG].clear(); - } - } - } - - m_currentCC = i; - - NodeArray vCopy(*m_pGraph); - Graph::constructInitByNodes(*m_pGraph,m_nodesInCC[i],vCopy,m_eAuxCopy); - - ListConstIterator itV; - for(itV = m_nodesInCC[i].begin(); itV.valid(); ++itV) - { - node vOrig = *itV; - node v = vCopy[vOrig]; - - m_vOrig[v] = vOrig; - m_vIterator[v] = m_vCopy[vOrig].pushBack(v); - m_splittable[v] = m_splittableOrig[vOrig]; - - adjEntry adj; - forall_adj(adj,vOrig) { - if ((adj->index() & 1) == 0) { - edge e = adj->theEdge(); - m_eIterator[m_eAuxCopy[e]] = m_eCopy[e].pushBack(m_eAuxCopy[e]); - m_eOrig[m_eAuxCopy[e]] = e; - } - } - } - - m_nodeSplits.clear(); -} - - -void PlanRepExpansion::delCopy(edge e) -{ - edge eOrig = m_eOrig[e]; - OGDF_ASSERT(m_eCopy[eOrig].size() == 1); - delEdge(e); - m_eCopy[eOrig].clear(); -} - - -bool PlanRepExpansion::embed() -{ - return planarEmbed(*this); -} - - -void PlanRepExpansion::prepareNodeSplit( - const SList &partitionLeft, - adjEntry &adjLeft, - adjEntry &adjRight) -{ - OGDF_ASSERT(!partitionLeft.empty()); - OGDF_ASSERT(partitionLeft.front()->theNode()->degree() > partitionLeft.size()); - - SListConstIterator it = partitionLeft.begin(); - adjEntry adj = *it; - adjLeft = adj; - - for(++it; it.valid(); ++it) { - moveAdjAfter(*it,adj); - adj = *it; - } - - adjRight = adj->cyclicSucc(); -} - - -void PlanRepExpansion::insertEdgePath( - edge eOrig, - nodeSplit ns, - node vStart, - node vEnd, - List &eip, - edge eSrc, - edge eTgt) -{ - OGDF_ASSERT((eOrig != 0 && ns == 0) || (eOrig == 0 && ns != 0)); - - if(eOrig) - m_eCopy[eOrig].clear(); - else - ns->m_path.clear(); - - if(eSrc != 0) { - if(eOrig) { - m_eIterator[eSrc] = m_eCopy[eOrig].pushBack(eSrc); - m_eOrig [eSrc] = eOrig; - } else { - m_eIterator [eSrc] = ns->m_path.pushBack(eSrc); - m_eNodeSplit[eSrc] = ns; - } - } - - node v = vStart; - ListConstIterator it; - for(it = eip.begin(); it.valid(); ++it) - { - adjEntry adj = (*it).m_adj; - if(adj == 0) { - adjEntry adjLeft, adjRight; - prepareNodeSplit((*it).m_partitionLeft, adjLeft, adjRight); - - node w = splitNode(adjLeft,adjRight); - edge eNew = adjLeft->cyclicPred()->theEdge(); - - m_vIterator [w] = m_vCopy[m_vOrig[adjLeft->theNode()]].pushBack(w); - m_splittable[w] = true; - m_vOrig [w] = m_vOrig[adjLeft->theNode()]; - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - (*itNS).m_nsIterator = itNS; - m_eIterator[eNew] = (*itNS).m_path.pushBack(eNew); - m_eNodeSplit[eNew] = &(*itNS); - - adj = adjRight->cyclicPred(); - } - - node u = split(adj->theEdge())->source(); - edge eNew = newEdge(v,u); - - if(eOrig) { - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig [eNew] = eOrig; - } else { - m_eIterator [eNew] = ns->m_path.pushBack(eNew); - m_eNodeSplit[eNew] = ns; - } - - v = u; - } - - edge eNew = newEdge(v,vEnd); - if(eOrig) { - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig [eNew] = eOrig; - } else { - m_eIterator [eNew] = ns->m_path.pushBack(eNew); - m_eNodeSplit[eNew] = ns; - } - - if(eTgt != 0) { - if(eOrig) { - m_eIterator[eTgt] = m_eCopy[eOrig].pushBack(eTgt); - m_eOrig [eTgt] = eOrig; - } else { - m_eIterator [eTgt] = ns->m_path.pushBack(eTgt); - m_eNodeSplit[eTgt] = ns; - } - } -} - - -void PlanRepExpansion::insertEdgePathEmbedded( - edge eOrig, - nodeSplit ns, - CombinatorialEmbedding &E, - const List > &crossedEdges) -{ - OGDF_ASSERT((eOrig != 0 && ns == 0) || (eOrig == 0 && ns != 0)); - - if(eOrig) - m_eCopy[eOrig].clear(); - else - ns->m_path.clear(); - - adjEntry adjSrc, adjTgt; - ListConstIterator > it = crossedEdges.begin(); - ListConstIterator > itLast = crossedEdges.rbegin(); - - // iterate over all adjacency entries in crossedEdges except for first - // and last - adjSrc = (*it).x1(); - for(++it; it != itLast; ++it) - { - adjEntry adj = (*it).x1(); - adjEntry adj2 = (*it).x2(); - - if(adj2 != 0) { - OGDF_ASSERT(adj->theNode() == adj2->theNode()); - OGDF_ASSERT(E.rightFace(adjSrc) == E.rightFace(adj->twin())); - node w = E.splitNode(adj,adj2); - edge eNew = adj->cyclicPred()->theEdge(); - - m_vIterator [w] = m_vCopy[m_vOrig[adj->theNode()]].pushBack(w); - m_splittable[w] = true; - m_vOrig [w] = m_vOrig[adj->theNode()]; - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - (*itNS).m_nsIterator = itNS; - m_eIterator[eNew] = (*itNS).m_path.pushBack(eNew); - m_eNodeSplit[eNew] = &(*itNS); - - adj = adj2->cyclicPred(); - } - - // split edge - node u = E.split(adj->theEdge())->source(); - - // determine target adjacency entry and source adjacency entry - // in the next iteration step - adjTgt = u->firstAdj(); - adjEntry adjSrcNext = adjTgt->succ(); - - if (adjTgt != adj->twin()) - swap(adjTgt,adjSrcNext); - - OGDF_ASSERT(adjTgt == adj->twin()); - - // insert a new edge into the face - edge eNew = E.splitFace(adjSrc,adjTgt); - - if(eOrig) { - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig [eNew] = eOrig; - } else { - m_eIterator [eNew] = ns->m_path.pushBack(eNew); - m_eNodeSplit[eNew] = ns; - } - - adjSrc = adjSrcNext; - } - - // insert last edge - edge eNew = E.splitFace(adjSrc,(*it).x1()); - - if(eOrig) { - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig [eNew] = eOrig; - } else { - m_eIterator [eNew] = ns->m_path.pushBack(eNew); - m_eNodeSplit[eNew] = ns; - } -} - - -void PlanRepExpansion::removeEdgePathEmbedded( - CombinatorialEmbedding &E, - edge eOrig, - nodeSplit ns, - FaceSetPure &newFaces, - NodeSetPure &mergedNodes, - node &oldSrc, - node &oldTgt) -{ - OGDF_ASSERT((eOrig != 0 && ns == 0) || (eOrig == 0 && ns != 0)); - - const List &path = (eOrig) ? m_eCopy[eOrig] : ns->m_path; - ListConstIterator it = path.begin(); - - oldSrc = path.front()->source(); - oldTgt = path.back()->target(); - - newFaces.insert(E.joinFaces(*it)); - - for(++it; it.valid(); ++it) - { - edge e = *it; - node u = e->source(); - - newFaces.remove(E.rightFace(e->adjSource())); - newFaces.remove(E.rightFace(e->adjTarget())); - - newFaces.insert(E.joinFaces(e)); - - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj()->theEdge(); - if (eIn->target() != u) - swap(eIn,eOut); - - E.unsplit(eIn,eOut); - - u = eIn->source(); - node v = eIn->target(); - - node vOrig = m_vOrig[v]; - if(vOrig != 0 && m_vOrig[u] == vOrig) { - m_vCopy[vOrig].del(m_vIterator[v]); - ListIterator itNS = m_eNodeSplit[eIn]->m_nsIterator; - m_nodeSplits.del(itNS); - - E.contract(eIn); - - if(mergedNodes.isMember(v)) - mergedNodes.remove(v); - mergedNodes.insert(u); - - if(oldSrc == v) oldSrc = u; - if(oldTgt == v) oldTgt = u; - } - } - - if(eOrig) - m_eCopy[eOrig].clear(); - else - ns->m_path.clear(); -} - - -void PlanRepExpansion::removeEdgePath( - edge eOrig, - nodeSplit ns, - node &oldSrc, - node &oldTgt) -{ - OGDF_ASSERT((eOrig != 0 && ns == 0) || (eOrig == 0 && ns != 0)); - - const List &path = (eOrig) ? m_eCopy[eOrig] : ns->m_path; - ListConstIterator it = path.begin(); - - oldSrc = path.front()->source(); - oldTgt = path.back()->target(); - - delEdge(*it); - - for(++it; it.valid(); ++it) - { - edge e = *it; - node u = e->source(); - - delEdge(e); - - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj()->theEdge(); - if (eIn->target() != u) - swap(eIn,eOut); - - unsplit(eIn,eOut); - - u = eIn->source(); - node v = eIn->target(); - - node vOrig = m_vOrig[v]; - if(vOrig != 0 && m_vOrig[u] == vOrig) { - m_vCopy[vOrig].del(m_vIterator[v]); - ListIterator itNS = m_eNodeSplit[eIn]->m_nsIterator; - m_nodeSplits.del(itNS); - - contract(eIn); - - if(oldSrc == v) oldSrc = u; - if(oldTgt == v) oldTgt = u; - } - } - - if(eOrig) - m_eCopy[eOrig].clear(); - else - ns->m_path.clear(); -} - - -void PlanRepExpansion::contractSplit(nodeSplit ns, CombinatorialEmbedding &E) -{ - OGDF_ASSERT(ns->m_path.size() == 1); - - edge e = ns->m_path.front(); - node v = e->target(); - node vOrig = m_vOrig[v]; - - m_vCopy[vOrig].del(m_vIterator[v]); - ListIterator itNS = ns->m_nsIterator; - m_nodeSplits.del(itNS); - - E.contract(e); -} - - -void PlanRepExpansion::contractSplit(nodeSplit ns) -{ - OGDF_ASSERT(ns->m_path.size() == 1); - - edge e = ns->m_path.front(); - node v = e->target(); - node vOrig = m_vOrig[v]; - - m_vCopy[vOrig].del(m_vIterator[v]); - ListIterator itNS = ns->m_nsIterator; - m_nodeSplits.del(itNS); - - contract(e); -} - - -int PlanRepExpansion::computeNumberOfCrossings() const -{ - int cr = 0; - - node v; - forall_nodes(v,*this) - if(m_vOrig[v] == 0) - ++cr; - - return cr; -} - - -edge PlanRepExpansion::split(edge e) -{ - edge eNew = Graph::split(e); - edge eOrig = m_eOrig[e]; - NodeSplit *ns = m_eNodeSplit[e]; - - if ((m_eOrig[eNew] = eOrig) != 0) { - m_eIterator[eNew] = m_eCopy[eOrig].insert(eNew,m_eIterator[e],after); - - } else if ((m_eNodeSplit[eNew] = ns) != 0) { - m_eIterator[eNew] = ns->m_path.insert(eNew,m_eIterator[e],after); - } - - return eNew; -} - - -void PlanRepExpansion::unsplit(edge eIn, edge eOut) -{ - edge eOrig = m_eOrig[eOut]; - NodeSplit *ns = m_eNodeSplit[eOut]; - - // update chain of eOrig if eOrig exists - if (eOrig != 0) { - m_eCopy[eOrig].del(m_eIterator[eOut]); - - } else if (ns != 0) { - ns->m_path.del(m_eIterator[eOut]); - } - - Graph::unsplit(eIn,eOut); -} - - -edge PlanRepExpansion::unsplitExpandNode( - node u, - edge eContract, - edge eExpand, - CombinatorialEmbedding &E) -{ - NodeSplit *ns = m_eNodeSplit[eContract]; - List &path = ns->m_path; - - NodeSplit *nsExp = m_eNodeSplit[eExpand]; - edge eOrigExp = m_eOrig[eExpand]; - List &pathExp = (nsExp != 0) ? nsExp->m_path : m_eCopy[eOrigExp]; - - if((eExpand->target() == u && eContract->source() != u) || - (eExpand->source() == u && eContract->target() != u)) - { - // reverse path of eContract - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - E.reverseEdge(*it); - } - path.reverse(); - } - - // remove u from list of copy nodes of its original - m_vCopy[m_vOrig[u]].del(m_vIterator[u]); - - // unsplit u and enlarge edge path of eOrigExp - edge eRet; - if(eExpand->target() == u) { - eRet = eExpand; - E.unsplit(eExpand,eContract); - - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - m_eNodeSplit[*it] = nsExp; - m_eOrig [*it] = eOrigExp; - } - - pathExp.conc(path); - - } else { - eRet = eContract; - E.unsplit(eContract,eExpand); - - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - m_eNodeSplit[*it] = nsExp; - m_eOrig [*it] = eOrigExp; - } - - pathExp.concFront(path); - } - - m_nodeSplits.del(ns->m_nsIterator); - return eRet; -} - - -edge PlanRepExpansion::unsplitExpandNode( - node u, - edge eContract, - edge eExpand) -{ - NodeSplit *ns = m_eNodeSplit[eContract]; - List &path = ns->m_path; - - NodeSplit *nsExp = m_eNodeSplit[eExpand]; - edge eOrigExp = m_eOrig[eExpand]; - List &pathExp = (nsExp != 0) ? nsExp->m_path : m_eCopy[eOrigExp]; - - if((eExpand->target() == u && eContract->source() != u) || - (eExpand->source() == u && eContract->target() != u)) - { - // reverse path of eContract - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - reverseEdge(*it); - } - path.reverse(); - } - - // remove u from list of copy nodes of its original - m_vCopy[m_vOrig[u]].del(m_vIterator[u]); - - // unsplit u and enlarge edge path of eOrigExp - edge eRet; - if(eExpand->target() == u) { - eRet = eExpand; - unsplit(eExpand,eContract); - - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - m_eNodeSplit[*it] = nsExp; - m_eOrig [*it] = eOrigExp; - } - - pathExp.conc(path); - - } else { - eRet = eContract; - unsplit(eContract,eExpand); - - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - m_eNodeSplit[*it] = nsExp; - m_eOrig [*it] = eOrigExp; - } - - pathExp.concFront(path); - } - - m_nodeSplits.del(ns->m_nsIterator); - return eRet; -} - - -edge PlanRepExpansion::enlargeSplit( - node v, - edge e) -{ - node vOrig = m_vOrig[v]; - edge eOrig = m_eOrig[e]; - - edge eNew = split(e); - node u = e->target(); - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - nodeSplit ns = &(*itNS); - ns->m_nsIterator = itNS; - - m_vOrig [u] = vOrig; - m_vIterator [u] = m_vCopy[vOrig].pushBack(u); - m_splittable[u] = true; - - List &path = m_eCopy[eOrig]; - if(v == path.front()->source()) { - ListIterator it, itNext; - for(it = path.begin(); *it != eNew; it = itNext) { - itNext = it.succ(); - - path.moveToBack(it, ns->m_path); - m_eOrig[*it] = 0; - m_eNodeSplit[*it] = ns; - } - - } else { - ListIterator it, itNext; - for(it = m_eIterator[eNew]; it.valid(); it = itNext) { - itNext = it.succ(); - - path.moveToBack(it, ns->m_path); - m_eOrig[*it] = 0; - m_eNodeSplit[*it] = ns; - } - } - - return eNew; -} - - -edge PlanRepExpansion::enlargeSplit( - node v, - edge e, - CombinatorialEmbedding &E) -{ - node vOrig = m_vOrig[v]; - edge eOrig = m_eOrig[e]; - - edge eNew = E.split(e); - node u = e->target(); - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - nodeSplit ns = &(*itNS); - ns->m_nsIterator = itNS; - - m_vOrig [u] = vOrig; - m_vIterator [u] = m_vCopy[vOrig].pushBack(u); - m_splittable[u] = true; - - List &path = m_eCopy[eOrig]; - if(v == path.front()->source()) { - ListIterator it, itNext; - for(it = path.begin(); *it != eNew; it = itNext) { - itNext = it.succ(); - - path.moveToBack(it, ns->m_path); - m_eOrig[*it] = 0; - m_eNodeSplit[*it] = ns; - } - - } else { - ListIterator it, itNext; - for(it = m_eIterator[eNew]; it.valid(); it = itNext) { - itNext = it.succ(); - - path.moveToBack(it, ns->m_path); - m_eOrig[*it] = 0; - m_eNodeSplit[*it] = ns; - } - } - - return eNew; -} - - -edge PlanRepExpansion::splitNodeSplit(edge e) -{ - nodeSplit ns = m_eNodeSplit[e]; - node vOrig = m_vOrig[ns->source()]; - - edge eNew = split(e); - node u = e->target(); - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - nodeSplit nsNew = &(*itNS); - nsNew->m_nsIterator = itNS; - - m_vOrig [u] = vOrig; - m_vIterator [u] = m_vCopy[vOrig].pushBack(u); - m_splittable[u] = true; - - List &path = ns->m_path; - path.split(m_eIterator[eNew], path, nsNew->m_path); - - ListIterator it; - for(it = nsNew->m_path.begin(); it.valid(); ++it) { - m_eNodeSplit[*it] = nsNew; - } - - return eNew; -} - - -edge PlanRepExpansion::splitNodeSplit( - edge e, - CombinatorialEmbedding &E) -{ - nodeSplit ns = m_eNodeSplit[e]; - node vOrig = m_vOrig[ns->source()]; - - edge eNew = E.split(e); - node u = e->target(); - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - nodeSplit nsNew = &(*itNS); - nsNew->m_nsIterator = itNS; - - m_vOrig [u] = vOrig; - m_vIterator [u] = m_vCopy[vOrig].pushBack(u); - m_splittable[u] = true; - - List &path = ns->m_path; - path.split(m_eIterator[eNew], path, nsNew->m_path); - - ListIterator it; - for(it = nsNew->m_path.begin(); it.valid(); ++it) { - m_eNodeSplit[*it] = nsNew; - } - - return eNew; -} - - -void PlanRepExpansion::removeSelfLoop( - edge e, - CombinatorialEmbedding &E) -{ - node u = e->source(); - nodeSplit ns = m_eNodeSplit[e]; - edge eOrig = m_eOrig[e]; - - List &path = (eOrig != 0) ? m_eCopy[eOrig] : ns->m_path; - path.del(m_eIterator[e]); - - E.joinFaces(e); - - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj ()->theEdge(); - if(eIn->target() != u) swap(eIn,eOut); - - OGDF_ASSERT(ns == m_eNodeSplit[eOut] && eOrig == m_eOrig[eOut]); - - E.unsplit(eIn,eOut); -} - - -void PlanRepExpansion::removeSelfLoop(edge e) -{ - node u = e->source(); - nodeSplit ns = m_eNodeSplit[e]; - edge eOrig = m_eOrig[e]; - - List &path = (eOrig != 0) ? m_eCopy[eOrig] : ns->m_path; - path.del(m_eIterator[e]); - - delEdge(e); - - edge eIn = u->firstAdj()->theEdge(); - edge eOut = u->lastAdj ()->theEdge(); - if(eIn->target() != u) swap(eIn,eOut); - - OGDF_ASSERT(ns == m_eNodeSplit[eOut] && eOrig == m_eOrig[eOut]); - - unsplit(eIn,eOut); -} - - -bool PlanRepExpansion::consistencyCheck() const -{ - if(Graph::consistencyCheck() == false) - return false; - - if(isLoopFree(*this) == false) - return false; - - edge eOrig; - forall_edges(eOrig,*m_pGraph) { - const List &path = m_eCopy[eOrig]; - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) { - edge e = *it; - if(it != path.begin()) { - if(e->source()->degree() != 4) - return false; - if(e->source() != (*it.pred())->target()) - return false; - } - } - } - - node vOrig; - forall_nodes(vOrig,*m_pGraph) { - const List &nodes = m_vCopy[vOrig]; - - if(nodes.size() == 1) - if(m_splittable[nodes.front()] != m_splittableOrig[vOrig]) - return false; - - if(nodes.size() <= 1) continue; - - if(m_splittableOrig[vOrig] == false) - return false; - - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) { - node v = *it; - if(v->degree() < 2) - return false; - } - } - - EdgeArray nso(*this,0); - - ListConstIterator it; - for(it = m_nodeSplits.begin(); it.valid(); ++it) { - const NodeSplit &ns = *it; - - if(ns.m_path.size() == 0) - continue; - - node v = ns.source(); - node w = ns.target(); - - node vOrig = m_vOrig[v]; - if(vOrig == 0 || vOrig != m_vOrig[w]) - return false; - - if(m_splittable[v] == false || m_splittable[w] == false) - return false; - - const List &path = ns.m_path; - ListConstIterator itE; - for(itE = path.begin(); itE.valid(); ++itE) { - edge e = *itE; - nso[e] = &ns; - if(itE != path.begin()) { - if(e->source()->degree() != 4) - return false; - if(e->source() != (*itE.pred())->target()) - return false; - } - } - } - - edge e; - forall_edges(e,*this) { - if(nso[e] != m_eNodeSplit[e]) - return false; - } - - return true; -} - - -List &PlanRepExpansion::setOrigs(edge e, edge &eOrig, nodeSplit &ns) -{ - eOrig = m_eOrig[e]; - ns = m_eNodeSplit[e]; - return (eOrig != 0) ? m_eCopy[eOrig] : ns->m_path; -} - - -PlanRepExpansion::nodeSplit PlanRepExpansion::convertDummy( - node u, - node vOrig, - PlanRepExpansion::nodeSplit ns_0) -{ - OGDF_ASSERT(u->indeg() == 2 && u->outdeg() == 2 && m_vOrig[u] == 0); - - m_vOrig [u] = vOrig; - m_vIterator [u] = m_vCopy[vOrig].pushBack(u); - m_splittable[u] = true; - - edge ec[2], eOrig[2]; - PlanRepExpansion::nodeSplit nsplit[2]; - int i = 0; - edge e; - forall_adj_edges(e,u) - if(e->source() == u) { - ec [i] = e; - eOrig [i] = m_eOrig[e]; - nsplit[i] = m_eNodeSplit[e]; - ++i; - } - - List &path_0 = (eOrig[0] != 0) ? m_eCopy[eOrig[0]] : nsplit[0]->m_path; - if(m_vOrig[path_0.front()->source()] == vOrig) - path_0.split(m_eIterator[ec[0]], ns_0->m_path, path_0); - else - path_0.split(m_eIterator[ec[0]], path_0, ns_0->m_path); - - ListConstIterator itE; - for(itE = ns_0->m_path.begin(); itE.valid(); ++itE) { - m_eNodeSplit[*itE] = ns_0; - m_eOrig [*itE] = 0; - } - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - nodeSplit ns_1 = &(*itNS); - ns_1->m_nsIterator = itNS; - - List &path_1 = (eOrig[1] != 0) ? m_eCopy[eOrig[1]] : nsplit[1]->m_path; - if(m_vOrig[path_1.front()->source()] == vOrig) - path_1.split(m_eIterator[ec[1]], ns_1->m_path, path_1); - else - path_1.split(m_eIterator[ec[1]], path_1, ns_1->m_path); - - for(itE = ns_1->m_path.begin(); itE.valid(); ++itE) { - m_eNodeSplit[*itE] = ns_1; - m_eOrig [*itE] = 0; - } - - return ns_1; -} - - -edge PlanRepExpansion::separateDummy( - adjEntry adj_1, adjEntry adj_2, node vStraight, bool isSrc) -{ - node u = adj_1->theNode(); - OGDF_ASSERT(m_vOrig[u] == 0); - - node vOrig = m_vOrig[vStraight]; - node v = newNode(); - - m_vOrig [v] = vOrig; - m_vIterator [v] = m_vCopy[vOrig].pushBack(v); - m_splittable[v] = true; - - if(adj_1->theEdge()->target() == u) - moveTarget(adj_1->theEdge(),v); - else - moveSource(adj_1->theEdge(),v); - - if(adj_2->theEdge()->target() == u) - moveTarget(adj_2->theEdge(),v); - else - moveSource(adj_2->theEdge(),v); - - edge eNew = (isSrc) ? newEdge(v,u) : newEdge(u,v); - - ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - nodeSplit nsNew = &(*itNS); - nsNew->m_nsIterator = itNS; - - edge eOrig = m_eOrig[adj_1->theEdge()]; - NodeSplit *ns = m_eNodeSplit[adj_1->theEdge()]; - List &path = (eOrig != 0) ? m_eCopy[eOrig] : ns->m_path; - - if(vStraight == path.front()->source()) { - ListIterator it, itNext; - for(it = path.begin(); (*it)->source() != v; it = itNext) { - itNext = it.succ(); - path.moveToBack(it, nsNew->m_path); - m_eOrig [*it] = 0; - m_eNodeSplit[*it] = nsNew; - } - - } else { - ListIterator it, itPrev; - for(it = path.rbegin(); (*it)->target() != v; it = itPrev) { - itPrev = it.pred(); - path.moveToFront(it, nsNew->m_path); - m_eOrig [*it] = 0; - m_eNodeSplit[*it] = nsNew; - } - } - - return eNew; - - //edge eOrig = m_eOrig[adjStraight->theEdge()]; - //NodeSplit *ns = m_eNodeSplit[adjStraight->theEdge()]; - - //Array adjA(2), adjB(2); - //int i = 0, j = 0; - - //adjEntry adj; - //forall_adj(adj,u) { - // edge e = adj->theEdge(); - // if(m_eOrig[e] == eOrig && m_eNodeSplit[e] == ns) - // adjA[i++] = adj; - // else - // adjB[j++] = adj; - //} - - //OGDF_ASSERT(i == 2 && j == 2); - - //// resolve split on adjB - //edge eB = adjB[0]->theEdge(); - //node vB = adjB[1]->twinNode(); - - //edge eOrigB; - //NodeSplit *nsB; - //List &pathB = (m_eOrig[eB] != 0) ? m_eCopy[m_eOrig[eB]] : m_eNodeSplit[eB]->m_path; - - //if(eB->target() == u) - // moveTarget(eB,vB); - //else - // moveSource(eB,vB); - - //edge eB2 = adjB[1]->theEdge(); - //pathB.del(m_eIterator[eB2]); - //delEdge(eB2); - - //// split path at u - //node vOrig = m_vOrig[vStraight]; - - //m_vOrig [u] = vOrig; - //m_vIterator [u] = m_vCopy[vOrig].pushBack(u); - //m_splittable[u] = true; - - //ListIterator itNS = m_nodeSplits.pushBack(NodeSplit()); - //nodeSplit nsNew = &(*itNS); - //nsNew->m_nsIterator = itNS; - - //List &pathA = (eOrig != 0) ? m_eCopy[eOrig] : ns->m_path; - //if(vStraight == pathA.front()->source()) { - // ListIterator it, itNext; - // for(it = pathA.begin(); (*it)->source() != u; it = itNext) { - // itNext = it.succ(); - // pathA.moveToBack(it, nsNew->m_path); - // m_eOrig [*it] = 0; - // m_eNodeSplit[*it] = nsNew; - // } - - //} else { - // ListIterator it, itPrev; - // for(it = pathA.rbegin(); (*it)->target() != u; it = itPrev) { - // itPrev = it.pred(); - // pathA.moveToFront(it, nsNew->m_path); - // m_eOrig [*it] = 0; - // m_eNodeSplit[*it] = nsNew; - // } - //} -} - - -int PlanRepExpansion::numberOfSplittedNodes() const -{ - int num = 0; - - node vOrig; - forall_nodes(vOrig,*m_pGraph) - if(m_vCopy[vOrig].size() >= 2) - ++num; - - return num; -} - - -bool PlanRepExpansion::isPseudoCrossing(node v) const -{ - if(m_vOrig[v] != 0) - return false; - - adjEntry adj_1 = v->firstAdj(); - adjEntry adj_2 = adj_1->succ(); - adjEntry adj_3 = adj_2->succ(); - - edge eOrig = m_eOrig[adj_2->theEdge()]; - nodeSplit ns = m_eNodeSplit[adj_2->theEdge()]; - - if(m_eNodeSplit[adj_1->theEdge()] == ns && m_eOrig[adj_1->theEdge()] == eOrig) - return true; - - if(m_eNodeSplit[adj_3->theEdge()] == ns && m_eOrig[adj_3->theEdge()] == eOrig) - return true; - - return false; -} - - -void PlanRepExpansion::resolvePseudoCrossing(node v) -{ - OGDF_ASSERT(isPseudoCrossing(v)); - - edge eIn[2]; - int i = 0; - edge e; - forall_adj_edges(e,v) { - if(e->target() == v) - eIn[i++] = e; - } - OGDF_ASSERT(i == 2); - - for(i = 0; i < 2; ++i) { - edge e = eIn[i]; - - ListIterator it = m_eIterator[e]; - List &path = (m_eOrig[e] != 0) ? m_eCopy[m_eOrig[e]] : m_eNodeSplit[e]->m_path; - - edge eNext = *(it.succ()); - moveSource(eNext, e->source()); - path.del(it); - delEdge(e); - } -} - - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanRepInc.cpp b/ext/OGDF/src/planarity/PlanRepInc.cpp deleted file mode 100644 index d588dc88a..000000000 --- a/ext/OGDF/src/planarity/PlanRepInc.cpp +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of PlanRepUML class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//Debug -#include - -//------------------------------------- -//zwei Moeglichkeiten: Elemente verstecken mit hide/activate -//oder Elemente, die nicht akiv sind, loeschen - -#include -#include -#include - - -namespace ogdf { - -PlanRepInc::PlanRepInc(const UMLGraph &UG) : PlanRepUML(UG) -{ - initMembers(UG); -}//constructor - -PlanRepInc::PlanRepInc(const UMLGraph &UG, const NodeArray &fixed) -: PlanRepUML(UG) -{ - initMembers(UG); - - const Graph &G = UG; - //we start the node activation status with the fixed input values - node v; - forall_nodes(v, G) - { - m_activeNodes[v] = fixed[v]; - }//forallnodes - -}//constructor - - -void PlanRepInc::initMembers(const UMLGraph &UG) -{ - m_activeNodes.init(UG, true); - //braucht man vielleicht gar nicht mehr (Kreuzungen?) - //zumindest spaeter durch type in typefields ersetzen - m_treeEdge.init(*this, false); - m_treeInit = false; -} - - -//activate a cc with at least one node, even if all nodes are -//excluded -node PlanRepInc::initMinActiveCC(int i) -{ - node v = initActiveCCGen(i, true); - return v; -} - -void PlanRepInc::initActiveCC(int i) -{ - initActiveCCGen(i, false); -} - -//activates a cc, if minnode==true, at least one node is inserted -node PlanRepInc::initActiveCCGen(int i, bool minNode) -{ - //node to be returned - node minActive = 0; - //list to be filled wih activated nodes - List activeOrigCCNodes; - // a) delete copy / chain fields for originals of nodes in current cc, - // since we change the CC number... - // (since we remove all these copies in initByNodes(...) - // b) create list of currently active original nodes - - const List &origInCC = nodesInCC(i); - - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) - { - if (m_activeNodes[(*itV)]) - activeOrigCCNodes.pushBack((*itV)); - if (m_currentCC >= 0) - { - node vG = *itV; - - m_vCopy[vG] = 0; - - adjEntry adj; - forall_adj(adj,vG) - { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - m_eCopy[eG].clear(); - } - }//if currentCC - }//for originals - //}//if non-empty - - //now we check if we have to activate a single node - if (minNode) - { - if (activeOrigCCNodes.size() == 0) - { - //Simple strategy: take the first node - minActive = origInCC.front(); - if (minActive != 0) - { - m_activeNodes[minActive] = true; - activeOrigCCNodes.pushFront(minActive); - } - } - }//minNode - - m_currentCC = i; - - //double feature: liste und nodearray, besser - GraphCopy::initByActiveNodes(activeOrigCCNodes, m_activeNodes, m_eAuxCopy); - - // set type of edges (gen. or assoc.) in the current CC - edge e; - if (m_pGraphAttributes->attributes() & GraphAttributes::edgeType) - forall_edges(e,*this) - { - m_eType[e] = m_pGraphAttributes->type(original(e)); - if (original(e)) - { - switch (m_pGraphAttributes->type(original(e))) - { - case Graph::generalization: setGeneralization(e); break; - case Graph::association: setAssociation(e); break; - OGDF_NODEFAULT - }//switch - }//if original - } - node v; - if (m_pGraphAttributes->attributes() & GraphAttributes::nodeType) - forall_nodes(v,*this) - m_vType[v] = m_pGraphAttributes->type(original(v)); - //TODO:check only in CCs or global? - m_treeInit = false; - return minActive; - -}//initActiveCC - -//node activation automatically activates all -//adjacent edges -//CCs can be joined by this method -void PlanRepInc::activateNode(node v) -{ - if (m_activeNodes[v]) return; - - m_activeNodes[v] = true; - -}//activateNode - -//Connect parts of partial active current CC. -//Note that this only makes sense when the CC parts are -//already correctly embedded. Crossings are already replaced -//by nodes -bool PlanRepInc::makeTreeConnected(adjEntry /* adjExternal */) -{ - - //we compute node numbers for the partial CCs in order to - //identify the treeConnect Edges that can be deleted later - m_component.init(*this, -1); - - //if there is only one CC, we don't need to connect - if (isConnected(*this)) return false; - //We have to insert edges connnecting nodes lying on - //the "external" face of the active parts - - //First, we activate the CC's parts one by one and compute - //the 'external' face from the layout information - //If the PlanRepInc is not embedded corresponding to - //this layout, we may introduce edges that are non-planar - //in the drawing, leading to problems when we compute paths - //in the dual graph - - List isolatedNodes; - const int numPartialCC = connectedIsolatedComponents(*this, - isolatedNodes, m_component); - - //CombinatorialEmbedding can cope with unconnected graphs - //but does not provide faces for isolated nodes - CombinatorialEmbedding E(*this); - TopologyModule tm; - List extAdjs; - //we run through all faces searching for all outer faces - face f; - forall_faces(f, E) - { - //TODO: check if we should select special adjEntry instead of first - if (tm.faceSum(*this, *m_pGraphAttributes, f) < 0) - extAdjs.pushBack(f->firstAdj()); - -#ifdef OGDF_DEBUG - cout << "FaceSum in Face " << f->index() << " Groesse " << f->size() - << " ist: " << tm.faceSum(*this, *m_pGraphAttributes, f) <<"\n" << flush; -#endif - }//forallfaces - - //now we have faces for all partial CCs that are not isolated nodes - - OGDF_ASSERT(extAdjs.size() + isolatedNodes.size() == numPartialCC) - //OGDF_ASSERT(extAdjs.size() > 1) //eigentlich: = #partial CCs - //OGDF_ASSERT(extAdjs.size() == numPartialCC) - - const int n1 = numPartialCC-1; - m_eTreeArray.init(0, n1, 0, n1, 0); - m_treeInit = true; - - //Three cases: only CCs, only isolated nodes, and both (where - //only one CC + isolated nodes is possible - - //now we connect all partial CCs by inserting edges at the adjEntries - //in extAdjs and adding all isolated nodes - adjEntry lastAdj = 0; - ListIterator it = extAdjs.begin(); - while(it.valid()) - { - //for the case: one external face, multiple isolated nodes - lastAdj = (*it); - adjEntry adj = (*it); - ListIterator it2 = it.succ(); - if (it2.valid()) - { - adjEntry adj2 = (*it2); - edge eTree = newEdge(adj, adj2); - m_treeEdge[eTree] = true; - lastAdj = eTree->adjTarget(); - //save the connection edge by CC number index - //this is used when deleting obsolete edges later - //after edge reinsertion - m_eTreeArray(componentNumber(adj->theNode()), componentNumber(adj2->theNode())) = - m_eTreeArray(m_component[adj2->theNode()], m_component[adj->theNode()]) - = eTree; - }//if CCs left to connect - - it++; - }//while - while (!isolatedNodes.empty()) - { - node uvw = isolatedNodes.popFrontRet(); - if (lastAdj) - { - //same block as above - edge eTree = newEdge(uvw, lastAdj); - m_treeEdge[eTree] = true; - //save the connection edge by CC number index - //this is used when deleting obsolete edges later - //after edge reinsertion - m_eTreeArray(componentNumber(lastAdj->theNode()), componentNumber(uvw)) = - m_eTreeArray(m_component[uvw], m_component[lastAdj->theNode()]) - = eTree; - lastAdj = eTree->adjSource(); - } - else //connect the first two isolated nodes / only iso nodes exist - { - //MUST BE #isonodes>1, else we returned already because CC connected - OGDF_ASSERT(!isolatedNodes.empty()) - node secv = isolatedNodes.popFrontRet(); - //same block as above - edge eTree = newEdge(uvw, secv); - m_treeEdge[eTree] = true; - //save the connection edge by CC number index - //this is used when deleting obsolete edges later - //after edge reinsertion - m_eTreeArray(componentNumber(secv), componentNumber(uvw)) = - m_eTreeArray(m_component[uvw], m_component[secv]) - = eTree; - lastAdj = eTree->adjSource(); - - } - }//while isolated nodes - - OGDF_ASSERT(isConnected(*this)); - - - //List extAdjs; - //getExtAdjs(extAdjs); - - - return true; -}//makeStarConnected - -//is only called when CC not connected => m_eTreeArray is initialized -void PlanRepInc::deleteTreeConnection(int i, int j) -{ - - edge e = m_eTreeArray(i, j); - if (e == 0) return; - edge nexte = 0; - OGDF_ASSERT(e); - OGDF_ASSERT(m_treeEdge[e]); - //we have to take care of treeConnection edges that - //are already crossed - while ((e->target()->degree() == 4) && - m_treeEdge[e->adjTarget()->cyclicSucc()->cyclicSucc()->theEdge()]) - { - nexte = e->adjTarget()->cyclicSucc()->cyclicSucc()->theEdge(); - OGDF_ASSERT(original(nexte) == 0) - delEdge(e); - e = nexte; - } - delEdge(e); - m_eTreeArray(i, j) = 0; - m_eTreeArray(j, i) = 0; - - OGDF_ASSERT(isConnected(*this)); - -}//deleteTreeConnection - -//is only called when CC not connected => m_eTreeArray is initialized -void PlanRepInc::deleteTreeConnection(int i, int j, CombinatorialEmbedding &E) -{ - - edge e = m_eTreeArray(i, j); - if (e == 0) return; - edge nexte = 0; - OGDF_ASSERT(e); - OGDF_ASSERT(m_treeEdge[e]); - //we have to take care of treeConnection edges that - //are already crossed - while ((e->target()->degree() == 4) && - m_treeEdge[e->adjTarget()->cyclicSucc()->cyclicSucc()->theEdge()]) - { - nexte = e->adjTarget()->cyclicSucc()->cyclicSucc()->theEdge(); - OGDF_ASSERT(original(nexte) == 0) - E.joinFaces(e); - e = nexte; - } - E.joinFaces(e); - m_eTreeArray(i, j) = 0; - m_eTreeArray(j, i) = 0; - - OGDF_ASSERT(isConnected(*this)); - -}//deleteTreeConnection - - -//use the layout information in the umlgraph to find nodes in -//unconnected active parts of a CC that can be connected without -//crossings in the given embedding -void PlanRepInc::getExtAdjs(List & /* extAdjs */) -{ - //in order not to change the current CC initialization, - //we construct a copy of the active parts (one by one) - //and use the layout information to compute a external - //face for that part. An (original) adjEntry on this face - //is then inserted into the extAdjs list. - - //derive the unconnected parts by a run through the current - //copy - //compute connected component of current CC - - NodeArray component(*this); - int numPartialCC = connectedComponents(*this, component); - EdgeArray copyEdge;//copy edges in partial CC copy - //now we compute a copy for every CC - //initialize an array of lists of nodes contained in a CC - Array > nodesInPartialCC; - nodesInPartialCC.init(numPartialCC); - - node v; - forall_nodes(v, *this) - nodesInPartialCC[component[v]].pushBack(v); - - int i = 0; - for (i = 0; i < numPartialCC; i++) - { - List &theNodes = nodesInPartialCC[i]; - GraphCopy GC; - GC.createEmpty(*this); - GC.initByNodes(theNodes, copyEdge); - //now we derive an outer face of GC by using the - //layout information on it's original - - - //TODO: Insert the bend points into the copy - - - //CombinatorialEmbedding E(GC); - - //run through the faces and compute angles to - //derive outer face - //we dont care about the original structure of - //the graph, i.e., if crossings are inserted aso - //we only take the given partial CC and its layout - //adjEntry extAdj = getExtAdj(GC, E); - - //forall_nodes(v, GC) - //{ - // - //}//forallnodes - }//for - - -}//getextadj - - -//return one adjEntry on the outer face of GC where GC -//is a partial copy of this PlanRepInc -adjEntry PlanRepInc::getExtAdj(GraphCopy & /* GC */, CombinatorialEmbedding & /* E */) -{ - return adjEntry(); -}//getextadj - -//------------------------------------- -//structure updates of underlying graph -//signaled by graph structure -void PlanRepInc::nodeDeleted(node /* v */) -{ - -} -void PlanRepInc::nodeAdded(node /* v */) {} -void PlanRepInc::edgeDeleted(edge /* e */) {} -void PlanRepInc::edgeAdded(edge /* e */) {} -void PlanRepInc::reInit() {} -void PlanRepInc::cleared() {} - - -//---------- -//DEBUGSTUFF -#ifdef OGDF_DEBUG -int PlanRepInc::genusLayout(Layout &drawing) const -{ - Graph testGraph; - GraphAttributes AG(testGraph, GraphAttributes::nodeGraphics | - GraphAttributes::edgeGraphics | - GraphAttributes::nodeColor | - GraphAttributes::nodeStyle | - GraphAttributes::edgeColor - ); - Layout xy; - NodeArray tcopy(*this, 0); - EdgeArray finished(*this, false); - EdgeArray eOrig(testGraph, 0); - EdgeArray eCol(*this, ""); - - if (numberOfNodes() == 0) return 0; - - int nIsolated = 0; - node v; - forall_nodes(v,*this) - if (v->degree() == 0) ++nIsolated; - - NodeArray component(*this); - int nCC = connectedComponents(*this,component); - - AdjEntryArray visited(*this,false); - int nFaceCycles = 0; - - int colBase = 3; - int colBase2 = 250; - forall_nodes(v,*this) - { - char prints[10]; - - ogdf::sprintf(prints,10,"#%.2X%.2X%.2X\0",colBase,colBase2,colBase); - colBase = (colBase*3) % 233; - colBase2 = (colBase*2) % 233; - String col(prints); - - if (tcopy[v] == 0) - { - node u = testGraph.newNode(); - tcopy[v] = u; - AG.x(u) = drawing.x(v); - AG.y(u) = drawing.y(v); - AG.colorNode(u) = col; - AG.nodeLine(u) = "#FF0000"; - AG.lineWidthNode(u) = 8; - }//if - - adjEntry adj1; - forall_adj(adj1,v) { - bool handled = visited[adj1]; - adjEntry adj = adj1; - - do { - node z = adj->theNode(); - if (tcopy[z] == 0) - { - node u1 = testGraph.newNode(); - tcopy[z] = u1; - AG.x(u1) = drawing.x(z); - AG.y(u1) = drawing.y(z); - AG.colorNode(u1) = col; - }//if not yet inserted in the copy - if (!finished[adj->theEdge()]) - { - node w = adj->theEdge()->opposite(z); - if (tcopy[w] != 0) - { - edge e; - if (w == adj->theEdge()->source()) - e = testGraph.newEdge(tcopy[w], tcopy[z]); - else e = testGraph.newEdge(tcopy[z], tcopy[w]); - eOrig[e] = adj->theEdge(); - if (eCol[adj->theEdge()].length() > 0) - AG.colorEdge(e) = eCol[adj->theEdge()]; - else - { - eCol[adj->theEdge()] = col; - AG.colorEdge(e) = col; - } - finished[adj->theEdge()] = true; - } - /* - else - { - eCol[adj->theEdge()] = col; - }*/ - - } - visited[adj] = true; - adj = adj->faceCycleSucc(); - } while (adj != adj1); - - if (handled) continue; - - ++nFaceCycles; - } - }//forallnodes - //insert the current embedding order by setting bends - //forall_nodes(v, testGraph) - //{ - // adjEntry ad1 = v->firstAdj(); - //} - - int genus = (numberOfEdges() - numberOfNodes() - nIsolated - nFaceCycles + 2*nCC) / 2; - //if (genus != 0) - { - AG.writeGML("GenusErrorLayout.gml"); - } - return genus; -} -//#endif - -//zu debugzwecken -void PlanRepInc::writeGML(const char *fileName, GraphAttributes &AG, bool colorEmbed) -{ - OGDF_ASSERT(m_pGraphAttributes == &(AG)); - - ofstream os(fileName); - writeGML(os, AG);//drawing, colorEmbed); - -}//writegml with AG layout - -void PlanRepInc::writeGML(ostream &os, const GraphAttributes &AG) -{ - OGDF_ASSERT(m_pGraphAttributes == &(AG)) - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::PlanRepInc::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - if (!original(v)) continue; - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " graphics [\n"; - os << " x " << AG.x(original(v)) << "\n"; - os << " y " << AG.y(original(v)) << "\n"; - os << " w " << 10.0 << "\n"; - os << " h " << 10.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (typeOf(v) == Graph::dummy) - { - if (isCrossingType(v)) - { - os << " fill \"#FF0000\"\n"; - } - else - os << " fill \"#FFFFFF\"\n"; - os << " type \"oval\"\n"; - } - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - - os << " ]\n"; // graphics - - os << "]\n"; // node - } - - edge e; - forall_edges(e,G) { - if (!(original(e->source()) && original(e->target()))) continue; - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << typeOf(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (typeOf(e) == Graph::generalization) - { - os << " arrow \"last\"\n"; - if (m_alignUpward[e->adjSource()]) - os << " fill \"#0000FF\"\n"; - else - os << " fill \"#FF0000\"\n"; - os << " width 3.0\n"; - } - else - { - if (typeOf(e->source()) == Graph::generalizationExpander || - typeOf(e->source()) == Graph::generalizationMerger || - typeOf(e->target()) == Graph::generalizationExpander || - typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else - os << " fill \"#FF0000\"\n"; - } - else - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else - os << " fill \"#00000F\"\n"; - os << " width 1.0\n"; - }//else generalization - - if (original(e) != 0) - { - const DPolyline &dpl = AG.bends(original(e)); - if (!dpl.empty()) { - os << " Line [\n"; - os << " point [ x " << AG.x(original(e->source())) << " y " << - AG.y(original(e->source())) << " ]\n"; - - ListConstIterator it; - for(it = dpl.begin(); it.valid(); ++it) - os << " point [ x " << (*it).m_x << " y " << (*it).m_y << " ]\n"; - - os << " point [ x " << AG.x(original(e->target())) << " y " << - AG.y(original(e->target())) << " ]\n"; - - os << " ]\n"; // Line - }//bends - }//original - - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} -//#endif - -double angle(DPoint p, DPoint q, DPoint r) -{ - double dx1 = q.m_x - p.m_x, dy1 = q.m_y - p.m_y; - double dx2 = r.m_x - p.m_x, dy2 = r.m_y - p.m_y; - - //two vertices on the same place! - if ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)) - return 0.0; - - double norm = (dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2); - - double cosphi = (dx1*dx2+dy1*dy2) / sqrt(norm); - - if (cosphi >= 1.0 ) return 0; if (cosphi <= -1.0 ) return Math::pi; - - double phi = acos(cosphi); - - if (dx1*dy2 < dy1*dx2) phi = -phi; - - if (phi < 0) phi += 2*Math::pi; - - return phi; -}//angle - -double fAngle(DPoint p, DPoint q, DPoint r) -{ - return angle(p, q, r)*360.0/(2*Math::pi); -} - - -void PlanRepInc::writeGML(ostream &os, const Layout &drawing, bool colorEmbed) -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " graphics [\n"; - os << " x " << drawing.x(v) << "\n"; - os << " y " << drawing.y(v) << "\n"; - os << " w " << 10.0 << "\n"; - os << " h " << 10.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (typeOf(v) == Graph::dummy) - { - if (isCrossingType(v)) - { - os << " fill \"#FF0000\"\n"; - } - else os << " fill \"#FFFFFF\"\n"; - os << " type \"oval\"\n"; - } - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - - - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - NodeArray proc(*this, false); - edge e; - forall_edges(e,G) - { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << typeOf(e) << "\n"; - os << " graphics [\n"; - - os << " type \"line\"\n"; - - int embedNum = 0; - int sNum = 0; - int tNum = 0; - if (colorEmbed) - { - //Find out embedding order number - //dirty hack, quadratic time - //color after higher degree order - node w; - //---------------- - if (proc[e->target()] && !proc[e->source()]) w = e->target(); - else if (proc[e->source()] && !proc[e->target()]) w = e->source(); - else - //---------------- - w = (e->source()->degree() > e->target()->degree() ? e->source() : e->target()); - - proc[w] = true; - adjEntry adf = w->firstAdj(); - while (adf->theEdge() != e) //ugly - { - embedNum++; - adf = adf->cyclicSucc(); - } - - node uvw = e->source(); - adf = uvw->firstAdj(); - while (adf->theEdge() != e) //ugly - { - sNum++; - adf = adf->cyclicSucc(); - } - uvw = e->target(); - adf = uvw->firstAdj(); - while (adf->theEdge() != e) //ugly - { - tNum++; - adf = adf->cyclicSucc(); - } - - - }//colorembed - - if (typeOf(e) == Graph::generalization) - { - os << " arrow \"last\"\n"; - - if (m_alignUpward[e->adjSource()]) - os << " fill \"#0000FF\"\n"; - else - { - switch (embedNum) - { - case 1: os << " fill \"#F00000\"\n";break; - case 2: os << " fill \"#D00000\"\n";break; - case 3: os << " fill \"#B00000\"\n";break; - case 4: os << " fill \"#900000\"\n";break; - case 5: os << "fill \"#800000\"\n";break; - case 6: os << " fill \"#600000\"\n";break; - case 7: os << " fill \"#400000\"\n";break; - default: os << " fill \"#FF0000\"\n"; - } - } - os << " width 3.0\n"; - } - else - { - if (typeOf(e->source()) == Graph::generalizationExpander || - typeOf(e->source()) == Graph::generalizationMerger || - typeOf(e->target()) == Graph::generalizationExpander || - typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else - os << " fill \"#FF0000\"\n"; - } - else - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else { - switch (embedNum) - { - case 1: os << " fill \"#000030\"\n";break; - case 2: os << " fill \"#000060\"\n";break; - case 3: os << " fill \"#200090\"\n";break; - case 4: os << " fill \"#3000B0\"\n";break; - case 5: os << " fill \"#4000E0\"\n";break; - case 6: os << " fill \"#5000F0\"\n";break; - case 7: os << " fill \"#8000FF\"\n";break; - default: os << " fill \"#000000\"\n";; - } - } - - os << " width 1.0\n"; - }//else generalization - - //insert a bend at each end corresponding to the - //adjacency order - if (colorEmbed) - { - double rad = 20.0; - node vs = e->source(); - node vt = e->target(); - double sx, sy, tx, ty; - - const double xs = drawing.x(vs), - ys = drawing.y(vs); //aufpunkt - const double xt = drawing.x(vt), - yt = drawing.y(vt); //aufpunkt - - //double dx = drawing.x(vt) - drawing.x(vs); - //double dy = drawing.y(vt) - drawing.y(vs); - //double length = sqrt(dx*dx + dy*dy); - //reference edge - //Aufpunkte - node rws = vs->firstAdj()->twinNode(); - node rwt = vt->firstAdj()->twinNode(); - //Richtungsvektoren - double rdxs = drawing.x(rws) - xs; - double rdys = drawing.y(rws) - ys; - double rdxt = drawing.x(rwt) - xt; - double rdyt = drawing.y(rwt) - yt; - - double rslength = sqrt(rdxs*rdxs + rdys*rdys); - double rtlength = sqrt(rdxt*rdxt + rdyt*rdyt); - - double refSx = drawing.x(vs) + (rad/rslength)*rdxs; - double refSy = drawing.y(vs) + (rad/rslength)*rdys; - double refTx = drawing.x(vt) + (rad/rtlength)*rdxt; - double refTy = drawing.y(vt) + (rad/rtlength)*rdyt; - - double refSx2 = drawing.x(vs) + rdxs/rslength; - double refSy2 = drawing.y(vs) + rdys/rslength; - double refTx2 = drawing.x(vt) + rdxt/rslength; - double refTy2 = drawing.y(vt) + rdyt/rslength; - - //do not change reference edge - if (sNum <0)//== 0) - { - sx = refSx; - sy = refSy; - } - else - { - OGDF_ASSERT(sNum < vs->degree()) - double angleS = sNum*360.0/vs->degree(); - - double refAngleS = fAngle(DPoint(xs, ys), - DPoint(refSx2, refSy2), - DPoint(xs+1.0, ys) - ); - double testAngleS = refAngleS-angleS; - - //--- - double dTS = testAngleS*2*Math::pi/360.0; - //-- - sx = xs + rad*cos(dTS);//testAngleS); - sy = ys + rad*sin(dTS);//testAngleS); - } - if (tNum <0)//== 0) - { - tx = refTx; - ty = refTy; - } - else - { - OGDF_ASSERT(tNum < vt->degree()) - double angleT = tNum*360/vt->degree(); - - double refAngleT = fAngle(DPoint(xt, yt), - DPoint(refTx2, refTy2), - DPoint(xt+1.0, yt) - ); - double testAngleT = refAngleT-angleT; - - //-- - double dTT = testAngleT*2*Math::pi/360.0; - //-- - - tx = xt + rad*cos(dTT);//testAngleT); - ty = yt + rad*sin(dTT);//testAngleT); - - } - - os << " Line [\n"; - os << " point [ x " << xs << " y " << ys << " ]\n"; - os << " point [ x " << sx << " y " << sy << " ]\n"; - os << " point [ x " << tx << " y " << ty << " ]\n"; - os << " point [ x " << xt << " y " << yt << " ]\n"; - - os << " ]\n"; // Line - - }//if colorembed - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -#endif - - -}//end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanRepUML.cpp b/ext/OGDF/src/planarity/PlanRepUML.cpp deleted file mode 100644 index 1612c3a36..000000000 --- a/ext/OGDF/src/planarity/PlanRepUML.cpp +++ /dev/null @@ -1,1355 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implementation of PlanRepUML class - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -PlanRepUML::PlanRepUML(const UMLGraph ¨Graph) : - PlanRep(umlGraph), - m_pUmlGraph(¨Graph) -{ - m_alignUpward .init(*this, false); - m_faceSplitter.init(*this,false); - m_incMergers .init(m_numCC); -} - - -PlanRepUML::PlanRepUML(const GraphAttributes &GA) : -PlanRep(GA), - m_pUmlGraph(0) -{ - m_alignUpward .init(*this, false); - m_faceSplitter.init(*this,false); - m_incMergers .init(m_numCC); -} - - -void PlanRepUML::initCC(int i) -{ - PlanRep::initCC(i); - - if(m_pUmlGraph != 0) { - //the new types that will replace the types just set - //maybe this should not be executed in initcc, only in constr. - //check this for crossings - edge e; - forall_edges(e,*this) - { - if (original(e)) - { - //edges should be embedded at outgoing generalization to allow alignment - if (m_pUmlGraph->upwards(original(e)->adjSource())) - { - m_alignUpward[e->adjSource()] = true; - }//if upwards - else m_alignUpward[e->adjSource()] = false; - - //maybe it's enough to set gen/ass without extra array - //due to planarization we have to assure that no types are lost - oriEdgeTypes(original(e)) = edgeTypes(e); - }//if ori - }//foralledges - } -}//initCC - - -//-------------------------------- -//expand nodes -//-------------------------------- -void PlanRepUML::expand(bool lowDegreeExpand) -{ - node v; - - OGDF_ASSERT(representsCombEmbedding()) - - forall_nodes(v,*this) - { - //------------------------------------------------- - // Replace merge vertices by cages. - //------------------------------------------------- - if (typeOf(v) == Graph::generalizationMerger) - { - edge e; - - // Scan the list of edges of v to find the outgoing edge of v - // Get then the cirular list of ingoing edges corresponding to - // the planar embedding. - SList inGens; - bool detect = false; - forall_adj_edges(e,v) - { - OGDF_ASSERT(typeOf(e) == Graph::generalization); - if (e->target() != v) - { - detect = true; - continue; - } - if (detect) - inGens.pushBack(e); - } - {forall_adj_edges(e,v) - { - if (e->target() != v) - break; - inGens.pushBack(e); - }} - - - setExpandedNode(v, v); - // Create the list of generalization expanders - // We need degree(v)-1 of them to construct a face. - SListPure expander; - for (int i = 0; i < v->degree()-1; i++) - { - node u = newNode(); - typeOf(u) = Graph::generalizationExpander; - setExpandedNode(u, v); - expander.pushBack(u); - } - - - // We move the target node of each ingoing generalization of v to a new - // node stored in expander. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - SListConstIterator itn; - NodeArray ar(*this); - - itn = expander.begin(); - - for (it = inGens.begin(); it.valid(); it++) - { - // all edges in the list inGens must be ingoing generalizations of v - OGDF_ASSERT((*it)->target() == v && - typeOf(*it) == Graph::generalization); - OGDF_ASSERT(itn.valid()); - - moveTarget(*it,*itn); - ar[*itn] = (*itn)->firstAdj(); - itn++; - } - ar[v] = v->firstAdj(); - - - // Now introduce the circular list of new edges - // forming the border of the merge face. Keep the embedding. - adjEntry adjPrev = v->firstAdj(); - - for (itn = expander.begin(); itn.valid(); itn++) - { - e = newEdge(adjPrev,(*itn)->firstAdj()); - - setExpansion(e); - setGeneralization(e); - - if (!expandAdj(v)) - expandAdj(v) = e->adjSource(); - - adjPrev = (*itn)->firstAdj(); - } - - e = newEdge(adjPrev,v->lastAdj()); - - setExpansion(e); - setGeneralization(e); - - OGDF_ASSERT(representsCombEmbedding()) - } - - //------------------------------------------------- - // Replace vertices with high degree by cages and - // replace degree 4 vertices with two generalizations - // adjacent in the embedding list by a cage. - //------------------------------------------------- - else if (v->degree() >= 4 && - typeOf(v) != Graph::dummy && - !lowDegreeExpand) - { - edge e; - - // Check first how many generalizations there are. - // If the node has degree 4 and at most one generalization - // nothing is to do. - int detect = 0; - forall_adj_edges(e,v) - { - if (!detect && typeOf(e) == Graph::generalization) - detect = 1; - else if (typeOf(e) == Graph::generalization) - detect = 2; - } - if (v->degree() == 4 && detect < 2) - continue; // Nothing to do. - - // Collects the nodes in the expanded face that - // are adjacent to a generalization. - // There are at most two of them. - SList genNodes; - - //Set the type of the node v. It remains in the graph - // as one of the nodes of the expanded face. - typeOf(v) = Graph::highDegreeExpander; - - - - // Scann the list of edges of v to find the adjacent edges of v - // according to the planar embedding. All except one edge - // will get a new adjacent node - // the planar embedding. - SList adjEdges; - {forall_adj_edges(e,v) - adjEdges.pushBack(e); - } - - //The first edge remains at v. remove it from the list. - // Check if it is a generalization. - e = adjEdges.popFrontRet(); - - //super sink check: don't use sink generalization, as the node may be deleted - while (typeOf(e) == Graph::generalization) - { - adjEdges.pushBack(e); - e = adjEdges.popFrontRet(); - } - //check end - - if (typeOf(e) == Graph::generalization) - genNodes.pushBack(v); - - // The node has maximum two generalization edges. - OGDF_ASSERT(genNodes.size() <= 2) - - - // Create the list of high degree expanders - // We need degree(v)-1 of them to construct a face. - // and set expanded Node to v - setExpandedNode(v, v); - SListPure expander; - for (int i = 0; i < v->degree()-1; i++) - { - node u = newNode(); - typeOf(u) = Graph::highDegreeExpander; - setExpandedNode(u, v); - expander.pushBack(u); - } - - - // We move the target node of each ingoing generalization of v to a new - // node stored in expander. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - SListConstIterator itn; - - NodeArray ar(*this); - - itn = expander.begin(); - - for (it = adjEdges.begin(); it.valid(); it++) - { - // Did we allocate enough dummy nodes? - OGDF_ASSERT(itn.valid()); - - // Check if edge is a generalization - if (typeOf((*it)) == Graph::generalization) - genNodes.pushBack(*itn); - - if ((*it)->source() == v) - moveSource(*it,*itn); - else - moveTarget(*it,*itn); - ar[*itn] = (*itn)->firstAdj(); - itn++; - } - ar[v] = v->firstAdj(); - - - // There may be at most two generalizations adjacent to v. - OGDF_ASSERT(genNodes.size() <= 2) - - //--------------------------------------------- - // Now introduce the circular list of new edges - // forming the border of the merge face. Keep the embedding. - adjEntry adjPrev = v->firstAdj(); - - for (itn = expander.begin(); itn.valid(); itn++) - { - e = newEdge(adjPrev,(*itn)->firstAdj()); - setExpansionEdge(e, 2);//can be removed if edgetypes work properly - - setExpansion(e); - setAssociation(e); - - typeOf(e) = association; //??? - - if (!expandAdj(v)) - expandAdj(v) = e->adjSource(); - adjPrev = (*itn)->firstAdj(); - } - - e = newEdge(adjPrev,v->lastAdj()); - - typeOf(e) = association; //??? - setExpansionEdge(e, 2);//can be removed if edgetypes work properly - setAssociation(e); - - - if (genNodes.size() == 2) - { - node u = genNodes.popFrontRet(); - node w = genNodes.popFrontRet(); - e = newEdge(u->firstAdj()->succ(),w->firstAdj()->succ()); - m_faceSplitter[e] = true; - } - - - OGDF_ASSERT(representsCombEmbedding()) - - } - - // Replace all vertices with degree > 2 by cages. - else if (v->degree() >= 2 && - typeOf(v) != Graph::dummy && - lowDegreeExpand) - { - edge e; - - // Check first how many generalizations there are. - // If the node has degree 4 and at most one generalization - // nothing is to do. - int detect = 0; - forall_adj_edges(e,v) - { - if (!detect && typeOf(e) == Graph::generalization) - detect = 1; - else if (typeOf(e) == Graph::generalization) - detect = 2; - } -// if (v->degree() == 4 && detect < 2) -// continue; // Nothing to do. - - // Collects the nodes in the expanded face that - // are adjacent to a generalization. - // There are at most two of them. - SList genNodes; - - //Set the type of the node v. It remains in the graph - // as one of the nodes of the expanded face. - typeOf(v) = Graph::highDegreeExpander; - - - - // Scann the list of edges of v to find the adjacent edges of v - // according to the planar embedding. All except one edge - // will get a new adjacent node - // the planar embedding. - SList adjEdges; - {forall_adj_edges(e,v) - adjEdges.pushBack(e); - } - - //The first edge remains at v. remove it from the list. - // Check if it is a generalization. - e = adjEdges.popFrontRet(); - if (typeOf(e) == Graph::generalization) - genNodes.pushBack(v); - - // The node has maximum two generalization edges. - OGDF_ASSERT(genNodes.size() <= 2) - - // Create the list of high degree expanders - // We need degree(v)-1 of them to construct a face. - // and set expanded Node to v - setExpandedNode(v, v); - SListPure expander; - for (int i = 0; i < v->degree()-1; i++) - { - node u = newNode(); - typeOf(u) = Graph::highDegreeExpander; - setExpandedNode(u, v); - expander.pushBack(u); - } - - - // We move the target node of each ingoing generalization of v to a new - // node stored in expander. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - SListConstIterator itn; - - NodeArray ar(*this); - - itn = expander.begin(); - - for (it = adjEdges.begin(); it.valid(); it++) - { - // Did we allocate enough dummy nodes? - OGDF_ASSERT(itn.valid()); - - // Check if edge is a generalization - if (typeOf((*it)) == Graph::generalization) - genNodes.pushBack(*itn); - - if ((*it)->source() == v) - moveSource(*it,*itn); - else - moveTarget(*it,*itn); - ar[*itn] = (*itn)->firstAdj(); - itn++; - } - ar[v] = v->firstAdj(); - - - // There may be at most two generalizations adjacent to v. - OGDF_ASSERT(genNodes.size() <= 2) - - // Now introduce the circular list of new edges - // forming the border of the merge face. Keep the embedding. - adjEntry adjPrev = v->firstAdj(); - - for (itn = expander.begin(); itn.valid(); itn++) - { - e = newEdge(adjPrev,(*itn)->firstAdj()); - if (!expandAdj(v)) expandAdj(v) = e->adjSource(); - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - //new types - setAssociation(e); //should be dummy type? - setExpansion(e); - - adjPrev = (*itn)->firstAdj(); - } - e = newEdge(adjPrev,v->lastAdj()); - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - - if (genNodes.size() == 2) - { - node u = genNodes.popFrontRet(); - node w = genNodes.popFrontRet(); - e = newEdge(u->firstAdj()->succ(),w->firstAdj()->succ()); - m_faceSplitter[e] = true; - } - - OGDF_ASSERT(representsCombEmbedding()) - } - } -} - - -void PlanRepUML::expandLowDegreeVertices(OrthoRep &OR, bool alignSmallDegree) -{ - node v; - forall_nodes(v,*this) - { - if (!(isVertex(v)) || expandAdj(v) != 0) - continue; - - int startDegree = v->degree(); - - SList adjEdges; - SListPure > expander; - - node u = v; - bool firstTime = true; - - setExpandedNode(v, v);//obsolete?! u=v - - adjEntry adj; - forall_adj(adj,v) { - adjEdges.pushBack(adj->theEdge()); - - if(!firstTime) - u = newNode(); - - setExpandedNode(u, v); - typeOf(u) = Graph::lowDegreeExpander; - expander.pushBack(Tuple2(u,OR.angle(adj))); - firstTime = false; - } - - - SListConstIterator it; - SListConstIterator > itn; - - itn = expander.begin().succ(); - - for (it = adjEdges.begin().succ(); it.valid(); ++it) - { - // Did we allocate enough dummy nodes? - OGDF_ASSERT(itn.valid()); - - if ((*it)->source() == v) - moveSource(*it,(*itn).x1()); - else - moveTarget(*it,(*itn).x1()); - ++itn; - } - - adjEntry adjPrev = v->firstAdj(); - itn = expander.begin(); - int nBends = (*itn).x2(); - - edge e; - for (++itn; itn.valid(); itn++) - { - e = newEdge(adjPrev,(*itn).x1()->firstAdj()); - - OR.bend(e->adjSource()).set(convexBend,nBends); - OR.bend(e->adjTarget()).set(reflexBend,nBends); - OR.angle(adjPrev) = 1; - OR.angle(e->adjSource()) = 2; - OR.angle(e->adjTarget()) = 1; - - nBends = (*itn).x2(); - - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - adjPrev = (*itn).x1()->firstAdj(); - } - - e = newEdge(adjPrev,v->lastAdj()); - typeOf(e) = association; //??? - setExpansionEdge(e, 2); - - expandAdj(v) = e->adjSource(); - - OR.bend(e->adjSource()).set(convexBend,nBends); - OR.bend(e->adjTarget()).set(reflexBend,nBends); - OR.angle(adjPrev) = 1; - OR.angle(e->adjSource()) = 2; - OR.angle(e->adjTarget()) = 1; - - if (alignSmallDegree && (startDegree == 2)) - { - node vOpp = e->source(); - if (vOpp == v) vOpp = e->target(); //only one case necessary - edge eAlign = newEdge(vOpp->lastAdj(), vOpp->lastAdj()->faceCycleSucc()); - typeOf(eAlign) = association; - OR.angle(eAlign->adjSource()) = 1; - OR.angle(eAlign->adjTarget()) = 1; - OR.angle(eAlign->adjSource()->faceCycleSucc()) = 1; - OR.angle(eAlign->adjTarget()->faceCycleSucc()) = 1; - } - - } -} - - -void PlanRepUML::collapseVertices(const OrthoRep &OR, Layout &drawing) -{ - node v; - forall_nodes(v,*this) { - const OrthoRep::VertexInfoUML *vi = OR.cageInfo(v); - - if(vi == 0 || - (typeOf(v) != Graph::highDegreeExpander && - typeOf(v) != Graph::lowDegreeExpander)) - continue; - - node vOrig = original(v); - OGDF_ASSERT(vOrig != 0); - - node vCenter = newNode(); - m_vOrig[vCenter] = vOrig; - m_vCopy[vOrig] = vCenter; - m_vOrig[v] = 0; - - node lowerLeft = vi->m_corner[odNorth]->theNode(); - node lowerRight = vi->m_corner[odWest ]->theNode(); - node upperLeft = vi->m_corner[odEast ]->theNode(); - drawing.x(vCenter) = 0.5*(drawing.x(lowerLeft)+drawing.x(lowerRight)); - drawing.y(vCenter) = 0.5*(drawing.y(lowerLeft)+drawing.y(upperLeft )); - - //Attention: The order in which the connection nodes are inserted - //ist not in the order of the copy embedding, but in the order - //of the adjacency lists of the original graph. Therefore, the edges - //may not be used to derive the correct copy order of outgoing edges. - //We compute a list of edges corresponding to the embedding and use - //this list to insert the edges. The order is e.g. used for clique positioning - List adjEdges; - //we start at an arbitrary corner - adjEntry adjCorner = vi->m_corner[odNorth]; - do { - adjEntry runAdj = adjCorner->twin(); - edge eOrig = 0; - int count = 0; //should be max. 4 (3) edges at boundary node - //the order of the edges in the copy may be incorrect, we search for the - //edge with an original - //do - //{ - runAdj = runAdj->cyclicSucc(); - eOrig = original(runAdj->theEdge()); - count++; - //} while ((count < 4) && !eOrig); - //edge found or corner reached - OGDF_ASSERT((count == 1) || (runAdj->theNode()->degree() == 2)) - if (eOrig) - { - adjEdges.pushBack(eOrig); - } - adjCorner = adjCorner->faceCycleSucc(); //TODO: pred? - } while (adjCorner != vi->m_corner[odNorth]); - - OGDF_ASSERT(adjEdges.size() == vOrig->degree()) - ListIterator itEdge = adjEdges.begin(); - - while (itEdge.valid()) - { - edge eOrig = *itEdge; - //forall_adj_edges(eOrig,vOrig) { - if(eOrig->target() == vOrig) { - node connect = m_eCopy[eOrig].back()->target(); - edge eNew = newEdge(connect,vCenter); - m_eOrig[eNew] = eOrig; - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - - } else { - node connect = m_eCopy[eOrig].front()->source(); - edge eNew = newEdge(vCenter,connect); - m_eOrig[eNew] = eOrig; - m_eIterator[eNew] = m_eCopy[eOrig].pushFront(eNew); - }//else - itEdge++; - }//while / forall adjacent edges - }//forall nodes -}//collapsevertices - -void PlanRepUML::setupIncremental(int indexCC, CombinatorialEmbedding &E) -{ - prepareIncrementalMergers(indexCC, E); -} - -void PlanRepUML::prepareIncrementalMergers(int indexCC, CombinatorialEmbedding &E) -{ - //we can't draw multiple hierarchies hanging at one class - //object, therefore we reduce the number in the given layout - //to 1 by interpreting only the edges in the largest sequence - //of generalizations as gens, all other edges are associations - //const Graph& G = uml; - - node v; - forall_nodes(v, *this) - { - if (v->degree() < 2) continue; - if (typeOf(v) == Graph::generalizationMerger) continue; - - int maxSeq = 0; //stores current best sequence size - int maxSeqRun = 0; //stores current sequence size - - adjEntry maxSeqAdj = 0; - adjEntry runSeqAdj = 0; - adjEntry ad1 = v->firstAdj(); - //We have to avoid the case where we start within a sequence - //we run back til the first non-input generalization is detected - //if there is none, the following is also correct - adjEntry stopAdj = ad1; - edge e = ad1->theEdge(); - while ((ad1->cyclicPred() != stopAdj) && - ( (e->target() == v) && - isGeneralization(e))) - { - ad1 = ad1->cyclicPred(); - e = ad1->theEdge(); - }//while search start - adjEntry ad = ad1->cyclicSucc(); - while (ad != ad1) - { - edge e = ad->theEdge(); - if ( (e->target() == v) && - isGeneralization(e)) - //(uml.type(e) == Graph::generalization) ) - { - if (maxSeqRun == 0) - { - //initialize once - runSeqAdj = ad; - maxSeqAdj = ad; - } - maxSeqRun++; - - } - else - { - //we never stop here if there is only one - //gen sequence, but then we don't need to - //(we don't use maxSeq elsewhere) - //we change edge in both cases here to avoid - //running over all edges again (#gens may be - //significantly lower then #ass) - adjEntry changeAdj = 0; - if (maxSeqRun > maxSeq) - { - //change edge type for old favorites - if (maxSeqAdj != runSeqAdj) - changeAdj = maxSeqAdj; - - maxSeq = maxSeqRun; - maxSeqAdj = runSeqAdj; - } - else - { - //change edge types for weaker sequence - if (maxSeqRun != 0) - changeAdj = runSeqAdj; - }//else, no new sequence - - //Change types for a sequence - //invariant: on every pass of the loop, if a sequence - //end is detected, one of the two sequences is deleted - //(types changed) => only one sequence when we stop - if (changeAdj != 0) - { - adjEntry runGenAdj = changeAdj; - //no infinite loop because new sequence found - edge e = runGenAdj->theEdge(); - while ((e->target() == v) && isGeneralization(e)) - //(uml.type(e) == Graph::generalization)) - { - setAssociation(e); - runGenAdj = runGenAdj->cyclicSucc(); - e = runGenAdj->theEdge(); - }//while - //changeAdj = 0; - } - maxSeqRun = 0; - }//else - - ad = ad->cyclicSucc(); - }//while - - //now we insert mergers for all edges in best sequence - //do not use maxSeq to count, may be 0 if only incoming gens - - if (maxSeqAdj != 0) - { - SList inGens; - - edge e = maxSeqAdj->theEdge(); - adjEntry runAdj = maxSeqAdj; - while ((e->target() == v) && isGeneralization(e)) - //(uml.type(e) == Graph::generalization)) - { - inGens.pushBack(e); - runAdj = runAdj->cyclicSucc(); - e = runAdj->theEdge(); - //maybe only one sequence around v - if (runAdj == maxSeqAdj) - break; - }//while generalizations - - //insert the merger for v - OGDF_ASSERT(representsCombEmbedding()) - node newMerger = insertGenMerger(v, inGens, E); - OGDF_ASSERT(representsCombEmbedding()) - if (newMerger) - m_incMergers[indexCC].pushBack(newMerger); - }//if sequence of generalizations - - }//forallnodes - - //uml.adjustHierarchyParents(); - -}//prepareIncrementalMergers - - - -//inserts a merger node for generalizations hanging at v, respecting -//embedding E -node PlanRepUML::insertGenMerger(node /* v */, const SList &inGens, - CombinatorialEmbedding &E) -{ - node u = 0; - if (empty()) return u; - if(inGens.size() >= 2) - { - // create a new node representing the merge point for the generalizations - u = newNode(); - typeOf(u) = Graph::generalizationMerger; - - //store the embedding information before inserting objects - //TODO: Front or back - face fRight = E.rightFace(inGens.front()->adjSource()); - face fLeft = E.rightFace(inGens.back()->adjTarget()); - // add the edge from v to the merge point - // this edge is a generalization, but has no original edge - //edge eMerge = insertEdge(u, (*(inGens.rbegin()))->adjTarget(), E); - edge eMerge = newEdge(u,(*(inGens.rbegin()))->adjTarget()); - //newEdge(u, (*(inGens.rbegin()))->adjTarget()); //incoming generalization - typeOf(eMerge) = Graph::generalization; - m_mergeEdges.pushBack(eMerge); - - // We move the target node of each ingoing generalization of v to u. - // Note that, for each such edge e, the target node of the original - // edge is then different from the original of the target node of e - // (the latter is 0 because u is a new (dummy) node) - SListConstIterator it; - for(it = inGens.begin(); it.valid(); ++it) - { - // all edges in the list inGens must be ingoing generalizations of v - //OGDF_ASSERT(((*it)->target() == v) && (typeOf(*it) == Graph::generalization)); - - moveTarget(*it,u); - } - //now we update the combinatorial embedding to represent the new situation - //first, update the face information at the inserted edge - E.updateMerger(eMerge, fRight, fLeft); - - }//if ingen >= 2 - - return u; -}//InsertGenMerger - - - -// Same as in GraphAttributes. Except: Writes colors to new nodes and -// to generalizations. For debugging only - -void PlanRepUML::writeGML(const char *fileName, const Layout &drawing) -{ - ofstream os(fileName); - writeGML(os,drawing); -} - - -void PlanRepUML::writeGML(const char *fileName) -{ - Layout drawing(*this); - ofstream os(fileName); - writeGML(os,drawing); -} - - -//zu debugzwecken -void PlanRepUML::writeGML(const char *fileName, GraphAttributes &AG) -{ - OGDF_ASSERT(m_pGraphAttributes == &(AG)) - Layout drawing(*this); - node v; - forall_nodes(v, *this) - { - if (original(v)) - { - drawing.x(v) = AG.x(original(v)); - drawing.y(v) = AG.y(original(v)); - } - }//forallnodes - - ofstream os(fileName); - writeGML(os, drawing); - -}//writegml with AG layout - - -void PlanRepUML::writeGML(ostream &os, const Layout &drawing) -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; -#ifdef OGDF_DEBUG - os << " label \"" << v->index() << "\"\n"; -#endif - - os << " graphics [\n"; - os << " x " << drawing.x(v) << "\n"; - os << " y " << drawing.y(v) << "\n"; - os << " w " << 10.0 << "\n"; - os << " h " << 10.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (typeOf(v) == Graph::dummy) - { - if (isCrossingType(v)) - { - os << " fill \"#FF0000\"\n"; - } - else os << " fill \"#FFFFFF\"\n"; - os << " type \"oval\"\n"; - } - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - - - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << typeOf(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (typeOf(e) == Graph::generalization) - { - os << " arrow \"last\"\n"; - if (m_alignUpward[e->adjSource()]) - os << " fill \"#0000FF\"\n"; - else - os << " fill \"#FF0000\"\n"; - os << " width 3.0\n"; - } - else - { - if (typeOf(e->source()) == Graph::generalizationExpander || - typeOf(e->source()) == Graph::generalizationMerger || - typeOf(e->target()) == Graph::generalizationExpander || - typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else - os << " fill \"#FF0000\"\n"; - } - else - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#F0F000\"\n"; //gelb - else if (isHalfBrother(e)) - os << " fill \"#FF00AF\"\n"; - else if (!(original(e))) - os << " fill \"#00F00F\"\n"; - else - os << " fill \"#00000F\"\n"; - os << " width 1.0\n"; - }//else generalization - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - - - -void PlanRepUML::writeGML(const char *fileName, const OrthoRep &OR, const Layout &drawing) -{ - ofstream os(fileName); - writeGML(os,OR,drawing); -} - -void PlanRepUML::writeGML(ostream &os, const OrthoRep &OR, const Layout &drawing) -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " label \"" << v->index() << "\"\n"; - - os << " graphics [\n"; - os << " x " << drawing.x(v) << "\n"; - os << " y " << drawing.y(v) << "\n"; - os << " w " << 3.0 << "\n"; - os << " h " << 3.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (typeOf(v) == Graph::dummy) - os << " type \"oval\"\n"; - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - - - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - forall_nodes(v,*this) - { - if (expandAdj(v) != 0 && (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander)) - { - node vOrig = original(v); - const OrthoRep::VertexInfoUML &vi = *OR.cageInfo(v); - node ll = vi.m_corner[odNorth]->theNode(); - node ur = vi.m_corner[odSouth]->theNode(); - - os << " node [\n"; - os << " id " << nextId++ << "\n"; - - if (m_pGraphAttributes->attributes() & GraphAttributes::nodeLabel) { - os << " label \"" << m_pGraphAttributes->labelNode(vOrig) << "\"\n"; - } - - os << " graphics [\n"; - os << " x " << 0.5 * (drawing.x(ur) + drawing.x(ll)) << "\n"; - os << " y " << 0.5 * (drawing.y(ur) + drawing.y(ll)) << "\n"; - os << " w " << widthOrig(vOrig) << "\n"; - os << " h " << heightOrig(vOrig) << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - os << " fill \"#FFFF00\"\n"; - - os << " ]\n"; // graphics - os << " ]\n"; // node - } - } - - edge e; - forall_edges(e,G) - { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << typeOf(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (typeOf(e) == Graph::generalization) - { - if (typeOf(e->target()) == Graph::generalizationExpander) - os << " arrow \"none\"\n"; - else - os << " arrow \"last\"\n"; - - os << " fill \"#FF0000\"\n"; - os << " width 2.0\n"; - } - else - { - if (typeOf(e->source()) == Graph::generalizationExpander || - typeOf(e->source()) == Graph::generalizationMerger || - typeOf(e->target()) == Graph::generalizationExpander || - typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - os << " fill \"#FF0000\"\n"; - } - else if (original(e) == 0) - { - os << " arrow \"none\"\n"; - os << " fill \"#AFAFAF\"\n"; - } - else - os << " arrow \"none\"\n"; - if (isBrother(e)) - os << " fill \"#00AF0F\"\n"; - if (isHalfBrother(e)) - os << " fill \"#0F00AF\"\n"; - os << " width 1.0\n"; - }//else generalization - - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -void PlanRepUML::writeGML(const char *fileName, const OrthoRep &OR, const GridLayoutMapped &drawing) -{ - ofstream os(fileName); - writeGML(os,OR,drawing); -} - -void PlanRepUML::writeGML(ostream &os, const OrthoRep &OR, const GridLayoutMapped &drawing) -{ - const Graph &G = *this; - - NodeArray id(*this); - int nextId = 0; - - os.setf(ios::showpoint); - os.precision(10); - - os << "Creator \"ogdf::GraphAttributes::writeGML\"\n"; - os << "graph [\n"; - os << " directed 1\n"; - - node v; - forall_nodes(v,G) { - os << " node [\n"; - - os << " id " << (id[v] = nextId++) << "\n"; - - os << " label \"" << v->index() << "\"\n"; - - os << " graphics [\n"; - os << " x " << drawing.toDouble(drawing.x(v)) << "\n"; - os << " y " << drawing.toDouble(drawing.y(v)) << "\n"; - os << " w " << 3.0 << "\n"; - os << " h " << 3.0 << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - if (typeOf(v) == Graph::generalizationMerger) { - os << " type \"oval\"\n"; - os << " fill \"#0000A0\"\n"; - } - else if (typeOf(v) == Graph::generalizationExpander) { - os << " type \"oval\"\n"; - os << " fill \"#00FF00\"\n"; - } - else if (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander) - os << " fill \"#FFFF00\"\n"; - else if (typeOf(v) == Graph::dummy) - os << " type \"oval\"\n"; - - else if (v->degree() > 4) - os << " fill \"#FFFF00\"\n"; - - else - os << " fill \"#000000\"\n"; - - - os << " ]\n"; // graphics - - os << " ]\n"; // node - } - - forall_nodes(v,*this) - { - if (expandAdj(v) != 0 && - (typeOf(v) == Graph::highDegreeExpander || - typeOf(v) == Graph::lowDegreeExpander)) - { - node vOrig = original(v); - const OrthoRep::VertexInfoUML &vi = *OR.cageInfo(v); - node ll = vi.m_corner[odNorth]->theNode(); - node ur = vi.m_corner[odSouth]->theNode(); - - os << " node [\n"; - os << " id " << nextId++ << "\n"; - - if (m_pGraphAttributes->attributes() & GraphAttributes::nodeLabel) { - os << " label \"" << m_pGraphAttributes->labelNode(vOrig) << "\"\n"; - } else { - os << " label \"N " << vOrig->index() << "\"\n"; - } - - os << " graphics [\n"; - os << " x " << 0.5 * drawing.toDouble(drawing.x(ur) + drawing.x(ll)) << "\n"; - os << " y " << 0.5 * drawing.toDouble(drawing.y(ur) + drawing.y(ll)) << "\n"; - os << " w " << widthOrig(vOrig) << "\n"; - os << " h " << heightOrig(vOrig) << "\n"; - os << " type \"rectangle\"\n"; - os << " width 1.0\n"; - os << " fill \"#FFFF00\"\n"; - - os << " ]\n"; // graphics - os << " ]\n"; // node - } - } - - edge e; - forall_edges(e,G) { - os << " edge [\n"; - - os << " source " << id[e->source()] << "\n"; - os << " target " << id[e->target()] << "\n"; - - os << " generalization " << typeOf(e) << "\n"; - - os << " graphics [\n"; - - os << " type \"line\"\n"; - - if (typeOf(e) == Graph::generalization) - { - if (typeOf(e->target()) == Graph::generalizationExpander) - os << " arrow \"none\"\n"; - else - os << " arrow \"last\"\n"; - - //check the vertical compaction mode - if ((typeOf(e) == Graph::generalization) && //only generalizations - !isExpansionEdge(e)) - - if ((e->adjSource() == OR.externalAdjEntry()) || - (e->adjTarget() == OR.externalAdjEntry())) - os << " fill \"#00FF00\"\n"; - else - if ((e->adjSource() == OR.alignAdjEntry()) || - (e->adjTarget() == OR.alignAdjEntry())) - os << " fill \"#FFA000\"\n"; - else - os << " fill \"#0000FF\"\n"; - else - if ((e->adjSource() == OR.externalAdjEntry()) || - (e->adjTarget() == OR.externalAdjEntry())) - os << " fill \"#00FF00\"\n"; - else - if ((e->adjSource() == OR.alignAdjEntry()) || - (e->adjTarget() == OR.alignAdjEntry())) - os << " fill \"#FFA000\"\n"; - else - os << " fill \"#FF0000\"\n"; - os << " width 2.0\n"; - } - else - { - if (typeOf(e->source()) == Graph::generalizationExpander || - typeOf(e->source()) == Graph::generalizationMerger || - typeOf(e->target()) == Graph::generalizationExpander || - typeOf(e->target()) == Graph::generalizationMerger) - { - os << " arrow \"none\"\n"; - - if (((e->adjSource() == OR.externalAdjEntry()) || - (e->adjTarget() == OR.externalAdjEntry())) || - ((e->adjSource() == OR.alignAdjEntry()) || - (e->adjTarget() == OR.alignAdjEntry()))) - os << " fill \"#00FF00\"\n"; - else - os << " fill \"#F0F00F\"\n"; - //os << " fill \"#FF0000\"\n"; - } - else if (original(e) == 0) - { - os << " arrow \"none\"\n"; - if (((e->adjSource() == OR.externalAdjEntry()) || - (e->adjTarget() == OR.externalAdjEntry())) || - ((e->adjSource() == OR.alignAdjEntry()) || - (e->adjTarget() == OR.alignAdjEntry()))) - os << " fill \"#00FF00\"\n"; - else - os << " fill \"#AFAFAF\"\n"; - } - else - os << " arrow \"none\"\n"; - - os << " width 1.0\n"; - }//else generalization - - os << " ]\n"; // graphics - - os << " ]\n"; // edge - } - - os << "]\n"; // graph -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanarPQTree.cpp b/ext/OGDF/src/planarity/PlanarPQTree.cpp deleted file mode 100644 index 6237d9a54..000000000 --- a/ext/OGDF/src/planarity/PlanarPQTree.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class PlanarPQTree. - * - * Implements a PQTree with added features for the planarity test. - * Used by BoothLueker. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - -namespace ogdf{ - -// Overriding the function doDestruction (see basic.h) -// Allows deallocation of lists of PlanarLeafKey -// and PQLeafKey in constant time using OGDF -// memory management. - -typedef PlanarLeafKey *PtrPlanarLeafKeyI; - -template<> -inline bool doDestruction(const PtrPlanarLeafKeyI*) { return false; } - - -typedef PQLeafKey *PtrPQLeafKeyEIB; - -template<> -inline bool doDestruction(const PtrPQLeafKeyEIB*) { return false; } - - - -// Replaces the pertinent subtree by a P-node with leaves as children -// corresponding to the incoming edges of the node v. These edges -// are to be specified by their keys stored in leafKeys. -void PlanarPQTree::ReplaceRoot(SListPure*> &leafKeys) -{ - if (m_pertinentRoot->status() == PQNodeRoot::FULL) - ReplaceFullRoot(leafKeys); - else - ReplacePartialRoot(leafKeys); -} - - - -// The function [[emptyAllPertinentNodes]] has to be called after a reduction -// has been processed. This overloaded function first destroys all full nodes -// by marking them as TO_BE_DELETED and then calling the base class function -// [[emptyAllPertinentNodes]]. -void PlanarPQTree::emptyAllPertinentNodes() -{ - ListIterator*> it; - for (it = m_pertinentNodes->begin(); it.valid(); it++) - { - PQNode* nodePtr = (*it); - if (nodePtr->status() == PQNodeRoot::FULL) - destroyNode(nodePtr); - } - if (m_pertinentRoot) - m_pertinentRoot->status(PQNodeRoot::FULL); - - PQTree::emptyAllPertinentNodes(); -} - - -// Initializes a PQTree by a set of leaves that will korrespond to -// the set of Keys stored in leafKeys. -int PlanarPQTree::Initialize(SListPure*> &leafKeys) -{ - SListIterator* > it; - SListPure*> castLeafKeys; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - - return PQTree::Initialize(castLeafKeys); -} - - -// Reduction reduced a set of leaves determined by their keys stored -// in leafKeys. Integer redNumber is for debugging only. -bool PlanarPQTree::Reduction(SListPure*> &leafKeys) -{ - SListIterator* > it; - SListPure*> castLeafKeys; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - - return PQTree::Reduction(castLeafKeys); -} - - -// Function ReplaceFullRoot either replaces the full root -// or one full child of a partial root of a pertinent subtree -// by a single P-node with leaves corresponding the keys stored in leafKeys. -void PlanarPQTree::ReplaceFullRoot(SListPure*> &leafKeys) -{ - if (!leafKeys.empty() && leafKeys.front() == leafKeys.back()) - { - //ReplaceFullRoot: replace pertinent root by a single leaf - PQLeaf *leafPtr = - OGDF_NEW PQLeaf(m_identificationNumber++, - PQNodeRoot::EMPTY,(PQLeafKey*)leafKeys.front()); - - exchangeNodes(m_pertinentRoot,(PQNode*) leafPtr); - if (m_pertinentRoot == m_root) - m_root = (PQNode*) leafPtr; - m_pertinentRoot = 0; // check for this emptyAllPertinentNodes - } - - else if (!leafKeys.empty()) // at least two leaves - { - PQInternalNode *nodePtr = 0; // dummy - //replace pertinent root by a $P$-node - if ((m_pertinentRoot->type() == PQNodeRoot::PNode) || - (m_pertinentRoot->type() == PQNodeRoot::QNode)) - { - nodePtr = (PQInternalNode*)m_pertinentRoot; - nodePtr->type(PQNodeRoot::PNode); - nodePtr->childCount(0); - while (!fullChildren(m_pertinentRoot)->empty()) - removeChildFromSiblings(fullChildren(m_pertinentRoot)->popFrontRet()); - } - else if (m_pertinentRoot->type() == PQNodeRoot::leaf) - { - nodePtr = OGDF_NEW PQInternalNode(m_identificationNumber++, - PQNodeRoot::PNode,PQNodeRoot::EMPTY); - exchangeNodes(m_pertinentRoot,nodePtr); - m_pertinentRoot = 0; // check for this emptyAllPertinentNodes - } - - SListPure*> castLeafKeys; - SListIterator* > it; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - addNewLeavesToTree(nodePtr,castLeafKeys); - } -} - - -// Function ReplacePartialRoot replaces all full nodes by a single P-node -// with leaves corresponding the keys stored in leafKeys. -void PlanarPQTree::ReplacePartialRoot(SListPure*> &leafKeys) -{ - m_pertinentRoot->childCount(m_pertinentRoot->childCount() + 1 - - fullChildren(m_pertinentRoot)->size()); - - while (fullChildren(m_pertinentRoot)->size() > 1) - removeChildFromSiblings(fullChildren(m_pertinentRoot)->popFrontRet()); - - PQNode *currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); - - currentNode->parent(m_pertinentRoot); - m_pertinentRoot = currentNode; - ReplaceFullRoot(leafKeys); -} - - -} diff --git a/ext/OGDF/src/planarity/PlanarSubgraphModule.cpp b/ext/OGDF/src/planarity/PlanarSubgraphModule.cpp deleted file mode 100644 index d5d865121..000000000 --- a/ext/OGDF/src/planarity/PlanarSubgraphModule.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class PlanarSubgraphModule. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -Module::ReturnType PlanarSubgraphModule::callAndDelete( - GraphCopy &PG, - const List &preferedEdges, - List &delOrigEdges, - bool preferedImplyPlanar) -{ - List delEdges; - - ReturnType retValue = call(PG, preferedEdges, delEdges, preferedImplyPlanar); - - if(isSolution(retValue)) - { - ListConstIterator it; - for(it = delEdges.begin(); it.valid(); ++it) { - edge eCopy = *it; - - delOrigEdges.pushBack(PG.original(eCopy)); - PG.delCopy(eCopy); - } - } - - return retValue; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanarSubgraphPQTree.cpp b/ext/OGDF/src/planarity/PlanarSubgraphPQTree.cpp deleted file mode 100644 index 407544244..000000000 --- a/ext/OGDF/src/planarity/PlanarSubgraphPQTree.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of the class PlanarSubgraphPQTree. - * - * Implements a PQTree with added features for the planarity test. - * Used by BoothLueker. - * - * \author Sebastian Leipert - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf{ - -// Replaces the pertinent subtree by a P-node with leaves as children -// corresponding to the incoming edges of the node v. These edges -// are to be specified by their keys stored in leafKeys. -void PlanarSubgraphPQTree:: -ReplaceRoot(SListPure*> &leafKeys) -{ - if (m_pertinentRoot->status() == PQNodeRoot::FULL) - ReplaceFullRoot(leafKeys); - else - ReplacePartialRoot(leafKeys); -} - -// Initializes a PQTree by a set of leaves that will korrespond to -// the set of Keys stored in leafKeys. -int PlanarSubgraphPQTree:: -Initialize(SListPure*> &leafKeys) -{ - SListIterator* > it; - - SListPure*> castLeafKeys; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - - return PQTree::Initialize(castLeafKeys); -} - - -// Reduction reduced a set of leaves determined by their keys stored -// in leafKeys. Integer redNumber is for debugging only. -bool PlanarSubgraphPQTree::Reduction( - SListPure*> &leafKeys, - SList*> &eliminatedKeys) -{ - SListPure*> castLeafKeys; - - SListIterator* > it; - for (it = leafKeys.begin(); it.valid(); ++it) - { - castLeafKeys.pushBack((PQLeafKey*) *it); - } - - determineMinRemoveSequence(castLeafKeys,eliminatedKeys); - removeEliminatedLeaves(eliminatedKeys); - - SListIterator* > itn = castLeafKeys.begin(); - SListIterator* > itp = itn++; - for (; itn.valid();) - { - if ((*itn)->nodePointer()->status()== PQNodeRoot::WHA_DELETE) - { - itn++; - castLeafKeys.delSucc(itp); - } - else - itp = itn++; - } - - if ((*castLeafKeys.begin())->nodePointer()->status() == PQNodeRoot::WHA_DELETE) - castLeafKeys.popFront(); - - - return Reduce(castLeafKeys); -} - - - -// Function ReplaceFullRoot either replaces the full root -// or one full child of a partial root of a pertinent subtree -// by a single P-node with leaves corresponding the keys stored in leafKeys. -void PlanarSubgraphPQTree:: -ReplaceFullRoot(SListPure*> &leafKeys) -{ - - PQLeaf *leafPtr = 0; // dummy - PQInternalNode *nodePtr = 0; // dummy - PQNode *currentNode = 0; // dummy - SListIterator* > it; - - if (!leafKeys.empty() && leafKeys.front() == leafKeys.back()) - { - //ReplaceFullRoot: replace pertinent root by a single leaf - leafPtr = OGDF_NEW PQLeaf(m_identificationNumber++, - PQNodeRoot::EMPTY,(PQLeafKey*)leafKeys.front()); - exchangeNodes(m_pertinentRoot,(PQNode*) leafPtr); - if (m_pertinentRoot == m_root) - m_root = (PQNode*) leafPtr; - } - else if (!leafKeys.empty()) // at least two leaves - { - //replace pertinent root by a $P$-node - if ((m_pertinentRoot->type() == PQNodeRoot::PNode) || - (m_pertinentRoot->type() == PQNodeRoot::QNode)) - { - nodePtr = (PQInternalNode*)m_pertinentRoot; - nodePtr->type(PQNodeRoot::PNode); - nodePtr->status(PQNodeRoot::PERTROOT); - nodePtr->childCount(0); - while (!fullChildren(m_pertinentRoot)->empty()) - { - currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); - removeChildFromSiblings(currentNode); - } - } - else if (m_pertinentRoot->type() == PQNodeRoot::leaf) - { - nodePtr = OGDF_NEW PQInternalNode(m_identificationNumber++, - PQNodeRoot::PNode,PQNodeRoot::EMPTY); - exchangeNodes(m_pertinentRoot,nodePtr); - } - SListPure*> castLeafKeys; - for (it = leafKeys.begin(); it.valid(); ++it) - castLeafKeys.pushBack((PQLeafKey*) *it); - addNewLeavesToTree(nodePtr,castLeafKeys); - } - -} - - -// Function ReplacePartialRoot replaces all full nodes by a single P-node -// with leaves corresponding the keys stored in leafKeys. -void PlanarSubgraphPQTree:: - ReplacePartialRoot(SListPure*> &leafKeys) - -{ - PQNode *currentNode = NULL; - - m_pertinentRoot->childCount(m_pertinentRoot->childCount() + 1 - - fullChildren(m_pertinentRoot)->size()); - - while (fullChildren(m_pertinentRoot)->size() > 1) - { - currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); - removeChildFromSiblings(currentNode); - } - - currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); - - currentNode->parent(m_pertinentRoot); - m_pertinentRoot = currentNode; - ReplaceFullRoot(leafKeys); - -} - - -/** -The function removeEliminatedLeaves handles the difficult task of -cleaning up after every reduction. - -After a reduction is complete, different kind of garbage has to be -handled. -\begin{itemize} -\item Pertinent leaves that are not in the maximal pertinent sequence. - from the $PQ$-tree in order to get it reducable have to be deleted. -\item The memory of some pertinent nodes, that have only pertinent leaves not beeing - in the maximal pertinent sequence in their frontier has to be freed. -\item Pertinent nodes that have only one child left after the removal - of pertinent leaves not beeing in the maximal pertinent sequence - have to be deleted. -\item The memory of all full nodes has to be freed, since the complete - pertinent subtree is replaced by a $P$-node after the reduction. -\item Nodes, that have been removed during the call of the function [[Reduce]] - of the base class template [[PQTree]] from the $PQ$-tree have to be - kept but marked as nonexisting. -\end{itemize}. -*/ - -/************************************************************************************** - removeEliminatedLeaves -***************************************************************************************/ - -void PlanarSubgraphPQTree:: -removeEliminatedLeaves(SList*> &eliminatedKeys) -{ - PQNode* nodePtr = 0; - PQNode* parent = 0; - PQNode* sibling = 0; - - SListIterator*> it; - for (it = eliminatedKeys.begin(); it.valid(); it++) - { - nodePtr = (*it)->nodePointer(); - parent = nodePtr->parent(); - sibling = nodePtr->getNextSib(NULL); - - removeNodeFromTree(parent,nodePtr); - checkIfOnlyChild(sibling,parent); - if (parent->status() == PQNodeRoot::TO_BE_DELETED) - { - parent->status(PQNodeRoot::WHA_DELETE); - } - nodePtr->status(PQNodeRoot::WHA_DELETE); - } -} - - - -} diff --git a/ext/OGDF/src/planarity/PlanarizationGridLayout.cpp b/ext/OGDF/src/planarity/PlanarizationGridLayout.cpp deleted file mode 100644 index ad3342b89..000000000 --- a/ext/OGDF/src/planarity/PlanarizationGridLayout.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements planarization with grid layout. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - - -PlanarizationGridLayout::PlanarizationGridLayout() -{ - m_subgraph .set(new FastPlanarSubgraph); - m_inserter .set(new FixedEmbeddingInserter); - m_planarLayouter.set(new MixedModelLayout); - m_packer .set(new TileToRowsCCPacker); - - m_pageRatio = 1.0; -} - - -void PlanarizationGridLayout::doCall( - const Graph &G, - GridLayout &gridLayout, - IPoint &bb) -{ - m_nCrossings = 0; - if(G.empty()) return; - - PlanRep PG(G); - - const int numCC = PG.numberOfCCs(); - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - int i; - for(i = 0; i < numCC; ++i) - { - PG.initCC(i); - const int nOrigVerticesPG = PG.numberOfNodes(); - - List deletedEdges; - m_subgraph.get().callAndDelete(PG, deletedEdges); - - m_inserter.get().call(PG,deletedEdges); - - m_nCrossings += PG.numberOfNodes() - nOrigVerticesPG; - - GridLayout gridLayoutPG(PG); - m_planarLayouter.get().callGrid(PG,gridLayoutPG); - - // copy grid layout of PG into grid layout of G - ListConstIterator itV; - for(itV = PG.nodesInCC(i).begin(); itV.valid(); ++itV) - { - node vG = *itV; - - gridLayout.x(vG) = gridLayoutPG.x(PG.copy(vG)); - gridLayout.y(vG) = gridLayoutPG.y(PG.copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - IPolyline &ipl = gridLayout.bends(eG); - ipl.clear(); - - bool firstTime = true; - ListConstIterator itE; - for(itE = PG.chain(eG).begin(); itE.valid(); ++itE) { - if(!firstTime) { - node v = (*itE)->source(); - ipl.pushBack(IPoint(gridLayoutPG.x(v),gridLayoutPG.y(v))); - } else - firstTime = false; - ipl.conc(gridLayoutPG.bends(*itE)); - } - } - } - - boundingBox[i] = m_planarLayouter.get().gridBoundingBox(); - boundingBox[i].m_x += 1; // one row/column space between components - boundingBox[i].m_y += 1; - } - - Array offset(numCC); - m_packer.get().call(boundingBox,offset,m_pageRatio); - - bb.m_x = bb.m_y = 0; - for(i = 0; i < numCC; ++i) - { - const List &nodes = PG.nodesInCC(i); - - const int dx = offset[i].m_x; - const int dy = offset[i].m_y; - - if(boundingBox[i].m_x + dx > bb.m_x) - bb.m_x = boundingBox[i].m_x + dx; - if(boundingBox[i].m_y + dy > bb.m_y) - bb.m_y = boundingBox[i].m_y + dy; - - // iterate over all nodes in i-th cc - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node vG = *it; - - gridLayout.x(vG) += dx; - gridLayout.y(vG) += dy; - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - ListIterator it; - for(it = gridLayout.bends(eG).begin(); it.valid(); ++it) { - (*it).m_x += dx; - (*it).m_y += dy; - } - } - } - } - - bb.m_x -= 1; // remove margin of topmost/rightmost box - bb.m_y -= 1; -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarity/PlanarizationLayout.cpp b/ext/OGDF/src/planarity/PlanarizationLayout.cpp deleted file mode 100644 index ca4a9bdea..000000000 --- a/ext/OGDF/src/planarity/PlanarizationLayout.cpp +++ /dev/null @@ -1,1354 +0,0 @@ -/* -* $Revision: 2616 $ -* -* last checkin: -* $Author: gutwenger $ -* $Date: 2012-07-16 15:34:43 +0200 (Mo, 16. Jul 2012) $ -***************************************************************/ - -/** \file - * \brief implementation of class PlanarizationLayout. - * - * applies planarization approach for drawing UML diagrams - * by calling a planar layouter for every planarized connected - * component - * Static and incremental calls available - * Replaces cliques (if m_processCliques is set) to speed up - * the computation, this does only work in non-UML mode - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - -//Constructor: -//set default values for parameters and set planar layouter, -//planarization modules -PlanarizationLayout::PlanarizationLayout() -{ - //modules - m_subgraph.set(new FastPlanarSubgraph); - m_inserter.set(new FixedEmbeddingInserter); - m_planarLayouter.set(new OrthoLayout); - m_packer.set(new TileToRowsCCPacker); - m_embedder.set(new SimpleEmbedder); - - //parameters - m_pageRatio = 1.0; - m_processCliques = false; //do not search for cliques, only if not uml - m_cliqueSize = 10; - m_fakeTree = true; //change edge type from generalization to association -} - - -void PlanarizationLayout::reembed(PlanRepUML &PG, int ccNumber, bool l_align, - bool l_gensExist) -{ - //TODO: update by reinitialization? - //PG.initActiveCC(i); - //first we remove all inserted crossings - node v; - List crossings; - forall_nodes(v, PG) - { - if (PG.isCrossingType(v)) - { - crossings.pushBack(v); - } - }//forallnodes - ListIterator it = crossings.begin(); - while (it.valid()) - { - PG.removeCrossing((*it)); - it++; - }//while - //*************************************** - // first phase: Compute a planar subgraph - //*************************************** - - // The planar subgraph should contain as many generalizations - // as possible, hence we put all generalizations into the list - // preferedEdges. - List preferedEdges; - edge e; - EdgeArray costOrig(PG.original(), 1); - forall_edges(e,PG) - { - if (PG.typeOf(e) == Graph::generalization) - { - if (l_align) l_gensExist = true; - preferedEdges.pushBack(e); - edge ori = PG.original(e); - //high cost to allow alignment without crossings - if ( (l_align) && - ((ori && (PG.typeOf(e->target()) == Graph::generalizationMerger)) - || (PG.alignUpward(e->adjSource())) - ) - ) - costOrig[ori] = 10; - - }//generalization - }//foralledges - - List deletedEdges; - m_subgraph.get().callAndDelete(PG, preferedEdges, deletedEdges); - - - //************************************** - // second phase: Re-insert deleted edges - //************************************** - - m_inserter.get().callForbidCrossingGens(PG, costOrig, deletedEdges); - - OGDF_ASSERT(isPlanar(PG)); - - - // - // determine embedding of PG - // - - // We currently compute any embedding and choose the maximal face - // as external face - - // if we use FixedEmbeddingInserter, we have to re-use the computed - // embedding, otherwise crossing nodes can turn into "touching points" - // of edges (alternatively, we could compute a new embedding and - // finally "remove" such unnecessary crossings). - if(!PG.representsCombEmbedding()) - planarEmbed(PG); - - - // CG: This code does not do anything... - //adjEntry adjExternal = 0; - - //if(PG.numberOfEdges() > 0) - //{ - // CombinatorialEmbedding E(PG); - // //face fExternal = E.maximalFace(); - // face fExternal = findBestExternalFace(PG,E); - // adjExternal = fExternal->firstAdj(); - // //while (PG.sinkConnect(adjExternal->theEdge())) - // // adjExternal = adjExternal->faceCycleSucc(); - //} -}//reembed - - -//--------------------------------------------------------- -//compute a layout with the given embedding, take special -//care of crossings (assumes that all crossings are non-ambiguous -//and can be derived from node/bend positions) -//--------------------------------------------------------- -void PlanarizationLayout::callFixEmbed(UMLGraph ¨Graph) -{ - m_nCrossings = 0; - - if(((const Graph &)umlGraph).empty()) - return; - - //check necessary preconditions - preProcess(umlGraph); - - int l_layoutOptions = m_planarLayouter.get().getOptions(); - bool l_align = ((l_layoutOptions & umlOpAlign)>0); - - //-------------------------------------------------------- - //first, we sort all edges around each node corresponding - //to the given layout in umlGraph - //then we insert the mergers - //try to rebuild this: insert mergers only in copy - bool umlMerge = false; //Standard: false - int i; - - //********************************************************* - // first phase: Compute planarized representation from input - //********************************************************* - - //now we derive a planar representation of the input - //graph using its layout information - PlanRepUML PG(umlGraph); - - const int numCC = PG.numberOfCCs(); - - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - - //****************************************** - //now planarize CCs and apply drawing module - for(i = 0; i < numCC; ++i) - { - // we treat connected component i - // PG is set to a copy of this CC - - PG.initCC(i); - - int nOrigVerticesPG = PG.numberOfNodes(); - - //alignment: check wether gens exist, special treatment is necessary - bool l_gensExist = false; //set this for all CC's, start with first gen, - //this setting can be mixed among CC's without problems - - //********************************************************* - // we don't need to compute a planar subgraph, because we - // use the given embedding - //********************************************************* - - adjEntry adjExternal = 0; - - //here lies the main difference to the other call - //we first planarize by using the given layout and then - //set the embedding corresponding to the input - bool embedded; - TopologyModule TM; - try { - embedded = TM.setEmbeddingFromGraph(PG, umlGraph, adjExternal, umlMerge); - }//try - catch (...) - { - //TODO: check for graph changes that are not undone - embedded = false; - } - - - //------------------------------------------------- - //if not embedded correctly - if (!embedded) - { - reembed(PG, i, l_align, l_gensExist); - }//if !embedded - - //------------------------------------------------- - - CombinatorialEmbedding E(PG); - - if (!umlMerge) - PG.setupIncremental(i, E); - - // - // determine embedding of PG - // - - // We currently compute any embedding and choose the maximal face - // as external face - - // if we use FixedEmbeddingInserter, we have to re-use the computed - // embedding, otherwise crossing nodes can turn into "touching points" - // of edges (alternatively, we could compute a new embedding and - // finally "remove" such unnecessary crossings). - - if((adjExternal == 0) && PG.numberOfEdges() > 0) - { - //face fExternal = E.maximalFace(); - face fExternal = findBestExternalFace(PG,E); - adjExternal = fExternal->firstAdj(); - //while (PG.sinkConnect(adjExternal->theEdge())) - // adjExternal = adjExternal->faceCycleSucc(); - } - - m_nCrossings += PG.numberOfNodes() - nOrigVerticesPG; - - - //********************************************************* - // third phase: Compute layout of planarized representation - //********************************************************* - - Layout drawing(PG); - - //distinguish between CC's with/without generalizations - //this changes the input layout modules options! - if (l_gensExist) - m_planarLayouter.get().setOptions(l_layoutOptions); - else m_planarLayouter.get().setOptions((l_layoutOptions & ~umlOpAlign)); - - //*************************************** - //call the Layouter for the CC's UMLGraph - m_planarLayouter.get().call(PG,adjExternal,drawing); - - // copy layout into umlGraph - // Later, we move nodes and edges in each connected component, such - // that no two overlap. - const List &origInCC = PG.nodesInCC(i); - ListConstIterator itV; - - //set position for original nodes and set bends for - //all edges - for(itV = origInCC.begin(); itV.valid(); ++itV) - { - node vG = *itV; - - umlGraph.x(vG) = drawing.x(PG.copy(vG)); - umlGraph.y(vG) = drawing.y(PG.copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) - { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - drawing.computePolylineClear(PG,eG,umlGraph.bends(eG)); - }//foralladj - }//for orig nodes - - if (!umlMerge) - { - //insert bend point for incremental mergers - const SList& mergers = PG.incrementalMergers(i); - SListConstIterator itMerger = mergers.begin(); - while (itMerger.valid()) - { - node vMerger = (*itMerger); - //due to the fact that the merger may be expanded, we are - //forced to run through the face - adjEntry adjMerger = PG.expandAdj(vMerger); - //check if there is an expansion face - if (adjMerger != 0) - { - //we run through the expansion face to the connected edges - //this edge is to dummy corner - adjEntry runAdj = adjMerger->faceCycleSucc(); - while (runAdj != adjMerger) - { - node vConnect = runAdj->theNode(); - //because of the node collapse using the original - //edges instead of the merger copy edges (should be - //fixed for incremental mode) the degree is 4 - //if (vConnect->degree() != 3) - if (vConnect->degree() != 4) - { - runAdj = runAdj->faceCycleSucc(); - continue; - } - edge eCopy = runAdj->cyclicPred()->theEdge(); - OGDF_ASSERT(eCopy->target() == runAdj->theNode()) - OGDF_ASSERT(PG.isGeneralization(eCopy)) - OGDF_ASSERT(PG.original(eCopy)) - umlGraph.bends(PG.original(eCopy)).pushBack( - DPoint(drawing.x(vMerger), drawing.y(vMerger))); - runAdj = runAdj->faceCycleSucc(); - - } - - } - else //currently all nodes are expanded, but this is not guaranteed - { - forall_adj(adjMerger, vMerger) - { - if (adjMerger->theEdge()->target() == vMerger) - { - edge eOrig = PG.original(adjMerger->theEdge()); - if (eOrig) - //incoming merger edges always have an original here! - umlGraph.bends(eOrig).pushBack(DPoint(drawing.x(vMerger), - drawing.y(vMerger))); - - } - }//forall adj - } - itMerger++; - }//while merger nodes - } - - // the width/height of the layout has been computed by the planar - // layout algorithm; required as input to packing algorithm - boundingBox[i] = m_planarLayouter.get().getBoundingBox(); - }//for cc's - - postProcess(umlGraph); - - //---------------------------------------- - // Arrange layouts of connected components - //---------------------------------------- - - arrangeCCs(PG, umlGraph, boundingBox); - - umlGraph.undoGenMergers(); - umlGraph.removeUnnecessaryBendsHV(); -}//callfixembed - - - -//----------------------------------------------------------------------------- -//call function: compute an UML layout for graph umlGraph -//----------------------------------------------------------------------------- -void PlanarizationLayout::call(UMLGraph ¨Graph) -{ - m_nCrossings = 0; - - if(((const Graph &)umlGraph).empty()) - return; - - //check necessary preconditions - preProcess(umlGraph); - - //--------------------------------------------------- - // preprocessing: insert a merger for generalizations - umlGraph.insertGenMergers(); - - PlanRepUML PG(umlGraph); - const int numCC = PG.numberOfCCs(); - - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - - //alignment section (should not be here, because planarlayout should - //not know about the meaning of layouter options and should not cope - //with them), move later - //we have to distinguish between cc's with and without generalizations - //if the alignment option is set - int l_layoutOptions = m_planarLayouter.get().getOptions(); - bool l_align = ((l_layoutOptions & umlOpAlign)>0); - //end alignment section - - //------------------------------------------ - //now planarize CCs and apply drawing module - int i; - for(i = 0; i < numCC; ++i) - { - // we treat connected component i - // PG is set to a copy of this CC - PG.initCC(i); - - int nOrigVerticesPG = PG.numberOfNodes(); - - //alignment: check wether gens exist, special treatment is necessary - bool l_gensExist = false; //set this for all CC's, start with first gen, - //this setting can be mixed among CC's without problems - - //--------------------------------------- - // first phase: Compute a planar subgraph - //--------------------------------------- - - // The planar subgraph should contain as many generalizations - // as possible, hence we put all generalizations into the list - // preferredEdges. - // In the case of clique processing we have to prevent the - // clique replacement (star) edges from being crossed. - // We do not allow that clique replacement is done in the case - // of UML diagrams, therefore we can temporarily set the type of - // all deleted and replacement edges to generalization to - // avoid crossings - EdgeArray savedType(PG); - EdgeArray savedOrigType(PG.original()); //for deleted copies - - List preferedEdges; - edge e; - EdgeArray costOrig(PG.original(), 1); - //edgearray for reinserter call: which edge may never be crossed? - EdgeArray noCrossingEdge(PG.original(), false); - forall_edges(e,PG) - { - edge ori = PG.original(e); - if (m_processCliques) - { - savedType[e] = PG.typeOf(e); - if (ori) - { - if (umlGraph.isReplacement(ori)) - { - preferedEdges.pushBack(e); - costOrig[ori] = 10; - PG.setGeneralization(e); - noCrossingEdge[ori] = true; - continue; - }//if clique replacement - - }//if - }//if cliques - - if (PG.typeOf(e) == Graph::generalization) - { - if (l_align) l_gensExist = true; - OGDF_ASSERT(!ori || !(noCrossingEdge[ori])); - preferedEdges.pushBack(e); - - //high cost to allow alignment without crossings - if (l_align && ( - (ori && (PG.typeOf(e->target()) == Graph::generalizationMerger)) - || PG.alignUpward(e->adjSource()) - )) - costOrig[ori] = 10; - - }//generalization - }//foralledges - - List deletedEdges; - m_subgraph.get().callAndDelete(PG, preferedEdges, deletedEdges); - - if (m_processCliques) - { - ListIterator itEdge = deletedEdges.begin(); - while (itEdge.valid()) - { - savedOrigType[*itEdge] = PG.typeOrig(*itEdge); - umlGraph.type(*itEdge) = Graph::generalization; - - OGDF_ASSERT(!(umlGraph.isReplacement(*itEdge))) - - itEdge++; - }//while - }//if cliques - - //-------------------------------------- - // second phase: Re-insert deleted edges - //-------------------------------------- - - if (m_processCliques) - m_inserter.get().call(PG, costOrig, noCrossingEdge, deletedEdges); - else - m_inserter.get().callForbidCrossingGens(PG, costOrig, deletedEdges); - - //reset the changed edge types - if (m_processCliques) - { - forall_edges(e, PG) - { - //if replacement - edge ori = PG.original(e); - if (ori) - if (umlGraph.isReplacement(ori)) - { - OGDF_ASSERT(PG.chain(ori).size() == 1) - PG.setType(e, savedType[e]); - umlGraph.type(ori) = Graph::association; - } - }//foralledges - //set the type of the reinserted edges in original and copy - ListIterator itEdge = deletedEdges.begin(); - while (itEdge.valid()) - { - umlGraph.type(*itEdge) = savedOrigType[*itEdge]; - const List &le = PG.chain(*itEdge); - ListConstIterator it2 = le.begin(); - while (it2.valid()) - { - PG.setType(*it2, savedOrigType[*itEdge]); - it2++; - }//while - itEdge++; - }//while - }//if cliques - - //----------------------------------------------------------------- - //additional check for clique processing - //guarantee that there is no crossing in replacement, otherwise - //we can not cluster a star - //fileName.sprintf("planar2.gml"); - - //if (m_processCliques) - //{ - // SListConstIterator itDV = umlGraph.centerNodes().begin(); - // while (itDV.valid()) - // { - // node cent = PG.copy(*itDV); - // OGDF_ASSERT(cent->degree() == (*itDV)->degree()) - // adjEntry adj; - // forall_adj(adj, cent) - // { - // OGDF_ASSERT(PG.original(adj->twinNode())) - // OGDF_ASSERT(!(PG.isGeneralization(adj->theEdge()))) - // PG.setBrother(adj->theEdge());//only output coloring - - // }//foralladj - // itDV++; - // }//while - // Layout fakeDrawing(PG); - // PG.writeGML(fileName, fakeDrawing); - //}//if clique replacement - //---------------------------------------------------------- - - - // - // determine embedding of PG - // - - // We currently compute any embedding and choose the maximal face - // as external face - - // if we use FixedEmbeddingInserter, we have to re-use the computed - // embedding, otherwise crossing nodes can turn into "touching points" - // of edges (alternatively, we could compute a new embedding and - // finally "remove" such unnecessary crossings). - if(!PG.representsCombEmbedding()) - planarEmbed(PG); - adjEntry adjExternal = 0; - - if(PG.numberOfEdges() > 0) - { - CombinatorialEmbedding E(PG); - face fExternal = findBestExternalFace(PG,E); - adjExternal = fExternal->firstAdj(); - } - - m_nCrossings += PG.numberOfNodes() - nOrigVerticesPG; - - - //--------------------------------------------------------- - // third phase: Compute layout of planarized representation - //--------------------------------------------------------- - - if (m_processCliques) - { - //insert boundaries around clique representation node - //and compute a representation layout for the cliques - //(is needed to guarantee the size of the replacement - //boundary) - //conserve external face information - SListPure centerNodes = umlGraph.centerNodes(); - SListIterator itNode = centerNodes.begin(); - while (itNode.valid()) - { - PG.insertBoundary(*itNode, adjExternal); - itNode++; - } - - }//if cliques - - Layout drawing(PG); - - //distinguish between CC's with/without generalizations - //this changes the input layout modules options! - if (l_gensExist) - m_planarLayouter.get().setOptions(l_layoutOptions); - else m_planarLayouter.get().setOptions((l_layoutOptions & ~umlOpAlign)); - - //*************************************** - //call the Layouter for the CC's UMLGraph - m_planarLayouter.get().call(PG,adjExternal,drawing); - - //-------------------------------------- - //we now have to reposition clique nodes - if (m_processCliques) - { - //-------------------------------------------------------- - //first, we derive the current size of the boundary around - //the center nodes, then we position the clique nodes - //in a circular fashion in the boundary - - //the node array is only used for the simple anchor move strategy at the - //end of this if and can later be removed - NodeArray isClique(PG, false); - - SListPure centerNodes = umlGraph.centerNodes(); - SListIterator itNode = centerNodes.begin(); - while (itNode.valid()) - { - node centerNode = (*itNode); - adjEntry adjBoundary = PG.boundaryAdj(centerNode); - //----------------------------------------------------- - //derive the boundary size - //if the boundary does not exist (connected component is clique), we - //only run over the nodes adjacent to centerNode - double minx = DBL_MAX, maxx = -DBL_MAX, miny = DBL_MAX, maxy = -DBL_MAX; - if (adjBoundary) - { - adjEntry adjRunner = adjBoundary; - //explore the dimension and position of the boundary rectangle - //TODO: guarantee (edge types?) that we run around a boundary - do { - double vx = drawing.x(adjRunner->theNode()); - double vy = drawing.y(adjRunner->theNode()); - if (vx < minx) minx = vx; - if (vx > maxx) maxx = vx; - if (vy < miny) miny = vy; - if (vy > maxy) maxy = vy; - - //are we at a bend or a crossing? - OGDF_ASSERT((adjRunner->twinNode()->degree() == 2) || - (adjRunner->twinNode()->degree() == 4)) - //bend - if (adjRunner->twinNode()->degree() < 4) - adjRunner = adjRunner->faceCycleSucc(); - else adjRunner = adjRunner->faceCycleSucc()->cyclicPred(); - } while (adjRunner != adjBoundary); - }//if boundary exists - else - { - forall_adj(adjBoundary, centerNode) - { - node w = adjBoundary->twinNode(); - double vx = drawing.x(PG.copy(w)); - double vy = drawing.y(PG.copy(w)); - if (vx < minx) minx = vx; - if (vx > maxx) maxx = vx; - if (vy < miny) miny = vy; - if (vy > maxy) maxy = vy; - } - }//else - //----------------------------------------------------------- - - //we now have to arrange the nodes on a circle with positions - //that respect the position within the given rectangle, i.e. - //the node with highest position should be on top etc. . This - //helps in avoiding unnecessary crossings of outgoing edges - //with the clique circle and unnecessary long edges to the anchors - //Note that the ordering around centerNode in umlGraph is different - //to the ordering in the drawing (defined on PG) - //recompute size of clique and the node positions - //test - //--------------------------------------------------------- - //derive the ordering of the nodes around centerNode in the - //planarized copy - List adjNodes; - fillAdjNodes(adjNodes, PG, centerNode, isClique, drawing); - - //----------------------------- - //compute clique node positions - umlGraph.computeCliquePosition(adjNodes, centerNode, - min(maxx-minx,maxy-miny)); - //testend - - double centralX = (maxx-minx)/2.0+minx; - double centralY = (maxy-miny)/2.0+miny; - double circleX = umlGraph.cliqueRect(centerNode).width()/2.0; - double circleY = umlGraph.cliqueRect(centerNode).height()/2.0; - - //now we have the position and size of the rectangle around - //the clique - - //assign shifted coordinates to drawing - forall_adj(adjBoundary, centerNode) - { - node w = adjBoundary->twinNode(); - drawing.x(PG.copy(w)) = centralX-circleX+umlGraph.cliquePos(w).m_x; - drawing.y(PG.copy(w)) = centralY-circleY+umlGraph.cliquePos(w).m_y; - } - - itNode++; - }//while - - //simple strategy to move anchor positions too (they are not needed: - // move to same position) - node w; - forall_nodes(w, PG) - { - //forall clique nodes shift the anchor points - if (isClique[w]) - { - adjEntry adRun = w->firstAdj(); - do - { - node wOpp = adRun->twinNode(); - drawing.x(wOpp) = drawing.x(w); - drawing.y(wOpp) = drawing.y(w); - adRun = adRun->cyclicSucc(); - } while (adRun != w->firstAdj()); - - } - } - - }//if cliques - - // copy layout into umlGraph - // Later, we move nodes and edges in each connected component, such - // that no two overlap. - const List &origInCC = PG.nodesInCC(i); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - - umlGraph.x(vG) = drawing.x(PG.copy(vG)); - umlGraph.y(vG) = drawing.y(PG.copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - drawing.computePolylineClear(PG,eG,umlGraph.bends(eG)); - } - } - - // the width/height of the layout has been computed by the planar - // layout algorithm; required as input to packing algorithm - boundingBox[i] = m_planarLayouter.get().getBoundingBox(); - }//for cc's - - //---------------------------------------- - // Arrange layouts of connected components - //---------------------------------------- - - arrangeCCs(PG, umlGraph, boundingBox); - - umlGraph.undoGenMergers(); - umlGraph.removeUnnecessaryBendsHV(); - - //new position after adding of cliqueprocess, check if correct - postProcess(umlGraph); -}//call - - - -//----------------------------------------------------------------------------- -//static call function: compute a layout for graph umlGraph without -//special UML or interactive features, clique processing etc. -//----------------------------------------------------------------------------- - -void PlanarizationLayout::doSimpleCall(GraphAttributes *pGA) -{ - m_nCrossings = 0; - - if(pGA->constGraph().empty()) - return; - - PlanRepUML *pPG = new PlanRepUML(*pGA); - const int numCC = pPG->numberOfCCs(); - - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - //------------------------------------------ - //now planarize CCs and apply drawing module - int i; - for(i = 0; i < numCC; ++i) - { - // we treat connected component i - // PG is set to a copy of this CC - pPG->initCC(i); - - int nOrigVerticesPG = pPG->numberOfNodes(); - - //--------------------------------------- - // first phase: Compute a planar subgraph - //--------------------------------------- - - // The planar subgraph should contain as many generalizations - // as possible, hence we put all generalizations into the list - // preferredEdges. - - List preferedEdges; - edge e; - EdgeArray costOrig(pPG->original(), 1); - //edgearray for reinserter call: which edge may never be crossed? - EdgeArray noCrossingEdge(pPG->original(), false); - forall_edges(e,*pPG) { - if (pPG->typeOf(e) == Graph::generalization) - preferedEdges.pushBack(e); - } - - List deletedEdges; - m_subgraph.get().callAndDelete(*pPG, preferedEdges, deletedEdges); - - //-------------------------------------- - // second phase: Re-insert deleted edges - //-------------------------------------- - - m_inserter.get().callForbidCrossingGens(*pPG, costOrig, deletedEdges); - - // ... and embed resulting planar graph - adjEntry adjExternal = 0; - m_embedder.get().call(*pPG, adjExternal); - - m_nCrossings += pPG->numberOfNodes() - nOrigVerticesPG; - - - //--------------------------------------------------------- - // third phase: Compute layout of planarized representation - //--------------------------------------------------------- - - Layout drawing(*pPG); - - //--------------------------------------- - //call the Layouter for the CC's UMLGraph - m_planarLayouter.get().call(*pPG,adjExternal,drawing); - - // copy layout into umlGraph - // Later, we move nodes and edges in each connected component, such - // that no two overlap. - const List &origInCC = pPG->nodesInCC(i); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - - pGA->x(vG) = drawing.x(pPG->copy(vG)); - pGA->y(vG) = drawing.y(pPG->copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) - continue; - edge eG = adj->theEdge(); - drawing.computePolylineClear(*pPG,eG,pGA->bends(eG)); - } - } - - // the width/height of the layout has been computed by the planar - // layout algorithm; required as input to packing algorithm - boundingBox[i] = m_planarLayouter.get().getBoundingBox(); - }//for cc's - - //---------------------------------------- - // Arrange layouts of connected components - //---------------------------------------- - - arrangeCCs(*pPG, *pGA, boundingBox); - delete pPG; -}//simplecall - - -//----------------------------------------------------------------------------- -//call function for simultaneous drawing: compute a layout for graph umlGraph -// without special UML or interactive features, clique processing etc. -//----------------------------------------------------------------------------- -void PlanarizationLayout::callSimDraw(UMLGraph ¨Graph) -{ - //this simple call method does not care about any special treatments - //of subgraphs, layout informations etc., therefore we save the - //option status and set them back later on - bool l_saveCliqueHandling = m_processCliques; - m_processCliques = false; - - m_nCrossings = 0; - - const Graph &G = umlGraph.constGraph(); - if(G.empty()) - return; - - PlanRepUML PG(umlGraph); - - const int numCC = PG.numberOfCCs(); - - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - int i; - - //------------------------------------------ - //now planarize CCs and apply drawing module - for(i = 0; i < numCC; ++i) - { - // we treat connected component i - // PG is set to a copy of this CC - - PG.initCC(i); - - int nOrigVerticesPG = PG.numberOfNodes(); - - edge e; - EdgeArray costOrig(PG.original(), 1); - EdgeArray esgOrig(PG.original(), 0); - forall_edges(e, G) - esgOrig[e] = umlGraph.subGraphBits(e); - - //--------------------------------------- - // first phase: Compute a planar subgraph - //--------------------------------------- - - List deletedEdges; - m_subgraph.get().callAndDelete(PG, deletedEdges); - - //************************************** - // second phase: Re-insert deleted edges - //************************************** - - m_inserter.get().call(PG, costOrig, deletedEdges, esgOrig); - - //calls embedder module: - adjEntry adjExternal = 0; - m_embedder.get().call(PG, adjExternal); - - m_nCrossings += PG.numberOfNodes() - nOrigVerticesPG; - - - //********************************************************* - // third phase: Compute layout of planarized representation - //********************************************************* - - Layout drawing(PG); - - //*************************************** - //call the Layouter for the CC's UMLGraph - m_planarLayouter.get().call(PG,adjExternal,drawing); - - // copy layout into umlGraph - // Later, we move nodes and edges in each connected component, such - // that no two overlap. - const List &origInCC = PG.nodesInCC(i); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - - umlGraph.x(vG) = drawing.x(PG.copy(vG)); - umlGraph.y(vG) = drawing.y(PG.copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - drawing.computePolylineClear(PG,eG,umlGraph.bends(eG)); - } - } - - - // the width/height of the layout has been computed by the planar - // layout algorithm; required as input to packing algorithm - boundingBox[i] = m_planarLayouter.get().getBoundingBox(); - }//for cc's - - //---------------------------------------- - // Arrange layouts of connected components - //---------------------------------------- - - arrangeCCs(PG, umlGraph, boundingBox); - - umlGraph.removeUnnecessaryBendsHV(); - m_processCliques = l_saveCliqueHandling; -}//callSimDraw - - -//################################################################# - -//additional help functions - -void PlanarizationLayout::assureDrawability(UMLGraph &UG) -{ - //preliminary - //self loops are killed by the caller (e.g., the plugin interface) - //should be done here later - - const Graph& G = UG; - - //check for selfloops and handle them - edge e; - forall_edges(e, G) { - if (e->isSelfLoop()) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcSelfLoop); - } - - // check for generalization - nontrees - // if m_fakeTree is set, change type of "back" edges to association - m_fakedGens.clear();//? - if (!dfsGenTree(UG, m_fakedGens, m_fakeTree)) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcTreeHierarchies); - - else { - ListConstIterator itE = m_fakedGens.begin(); - while (itE.valid()) { - UG.type(*itE) = Graph::association; - itE++; - } - } -}//assureDrawability - - - -void PlanarizationLayout::preProcess(UMLGraph &UG) -{ - assureDrawability(UG); - - if (m_processCliques) - { - UG.setDefaultCliqueCenterSize(m_planarLayouter.get().separation()); - const Graph& G = (const Graph &)UG; - CliqueFinder cf(G); - cf.setMinSize(m_cliqueSize); - - List< List > cliques; - cf.call(cliques); - //now replace all found cliques by stars - UG.replaceByStar(cliques); - } - //TODO: sollte kein else sein, aber man muss abfangen, - //ob eine Kante geloescht wurde (und die Info nachher wieder bereitstellen) - else - { - const SListPure &acList = UG.assClassList(); - SListConstIterator it = acList.begin(); - while (it.valid()) - { - UG.modelAssociationClass((*it)); - it++; - } - - } -}//preprocess - - -void PlanarizationLayout::postProcess(UMLGraph& UG) -{ - //reset the type of faked associations to generalization - if (m_fakeTree) - { - ListIterator itE = m_fakedGens.begin(); - while (itE.valid()) - { - UG.type(*itE) = Graph::generalization; - itE++; - } - } - - UG.undoAssociationClasses(); - if (m_processCliques) - UG.undoStars(); -}//postProcess - - -// find best suited external face according to certain criteria -face PlanarizationLayout::findBestExternalFace( - const PlanRep &PG, - const CombinatorialEmbedding &E) -{ - FaceArray weight(E); - - face f; - forall_faces(f,E) - weight[f] = f->size(); - - node v; - forall_nodes(v,PG) - { - if(PG.typeOf(v) != Graph::generalizationMerger) - continue; - - adjEntry adj; - forall_adj(adj,v) { - if(adj->theEdge()->source() == v) - break; - } - - OGDF_ASSERT(adj->theEdge()->source() == v); - - node w = adj->theEdge()->target(); - bool isBase = true; - - adjEntry adj2; - forall_adj(adj2, w) { - edge e = adj2->theEdge(); - if(e->target() != w && PG.typeOf(e) == Graph::generalization) { - isBase = false; - break; - } - } - - if(isBase == false) - continue; - - face f1 = E.leftFace(adj); - face f2 = E.rightFace(adj); - - weight[f1] += v->indeg(); - if(f2 != f1) - weight[f2] += v->indeg(); - } - - face fBest = E.firstFace(); - forall_faces(f,E) - if(weight[f] > weight[fBest]) - fBest = f; - - return fBest; -} - - -void PlanarizationLayout::arrangeCCs(PlanRep &PG, GraphAttributes &GA, Array &boundingBox) -{ - int numCC = PG.numberOfCCs(); - Array offset(numCC); - m_packer.get().call(boundingBox,offset,m_pageRatio); - - // The arrangement is given by offset to the origin of the coordinate - // system. We still have to shift each node and edge by the offset - // of its connected component. - - for(int i = 0; i < numCC; ++i) { - const List &nodes = PG.nodesInCC(i); - - const double dx = offset[i].m_x; - const double dy = offset[i].m_y; - - // iterate over all nodes in ith CC - ListConstIterator it; - for(it = nodes.begin(); it.valid(); ++it) - { - node v = *it; - - GA.x(v) += dx; - GA.y(v) += dy; - - adjEntry adj; - forall_adj(adj,v) { - if ((adj->index() & 1) == 0) continue; - edge e = adj->theEdge(); - - DPolyline &dpl = GA.bends(e); - ListIterator it; - for(it = dpl.begin(); it.valid(); ++it) { - (*it).m_x += dx; - (*it).m_y += dy; - } - } - } - } -} - - -//collects and stores nodes adjacent to centerNode in adjNodes -void PlanarizationLayout::fillAdjNodes(List& adjNodes, - PlanRepUML& PG, - node centerNode, - NodeArray& isClique, - Layout& drawing) -{ - //at this point, cages are collapsed, i.e. we have a center node - //in the planrep representing the copy of the original node - node cCopy = PG.copy(centerNode); - OGDF_ASSERT(cCopy != 0) - OGDF_ASSERT(cCopy->degree() == centerNode->degree()) - OGDF_ASSERT(cCopy->degree() > 1) - //store the node with mostright position TODO: consider cage - node rightNode = 0; - - //due to the implementation in PlanRepUML::collapseVertices, the - //ordering of the nodes in the copy does not correspond to the - //ordering in the used embedding, but to the original graph - //we therefore need to run around the cage to search for the - //attached edges - - adjEntry adjRun = cCopy->firstAdj(); - do - { - //we search for the edge outside the node cage - //anchor node - OGDF_ASSERT(adjRun->twinNode()->degree() == 4) - //should be cs->cs, but doesnt work, comb. embedding? - //adjEntry outerEdgeAdj = adjRun->twin()->cyclicSucc()->cyclicSucc(); - //TODO: braucht man glaube ich gar nicht, da bereits erste Kante Original hat - adjEntry outerEdgeAdj = adjRun->twin()->cyclicSucc(); - //this may fail in case of bends if there are no orig edges, but there - //always is one!? - while (!PG.original(outerEdgeAdj->theEdge())) - outerEdgeAdj = outerEdgeAdj->cyclicSucc(); - OGDF_ASSERT(outerEdgeAdj != adjRun) - - //hier besser: if... und alle anderen ignorieren - edge umlEdge = PG.original(outerEdgeAdj->theEdge()); - OGDF_ASSERT(umlEdge != 0) - node u = umlEdge->opposite(centerNode); - adjNodes.pushBack(u); - isClique[PG.copy(u)] = true; - - //---------------------------------------------- - //part to delete all bends that lie within the clique rectangle - //first we identify the copy node of the clique node we currently - //look at - node uCopy = PG.copy(u); - OGDF_ASSERT(uCopy) - adjEntry adjURun = uCopy->firstAdj(); - do - { - //we search for the edge outside the node cage - OGDF_ASSERT(adjURun->twinNode()->degree() == 4) - adjEntry outerEdgeUAdj = adjURun->twin()->cyclicSucc(); - while (!PG.original(outerEdgeUAdj->theEdge())) - outerEdgeUAdj = outerEdgeUAdj->cyclicSucc(); - OGDF_ASSERT(outerEdgeUAdj != adjRun) - //outerEdgeUAdj points outwards, edge does too per implementation, - //but we don't want to rely on that fact - bool outwards; - edge potKill = outerEdgeUAdj->theEdge(); - node splitter; - if (potKill->source() == outerEdgeUAdj->theNode()) //Could use opposite - { - splitter = potKill->target(); - outwards = true; - } - else - { - splitter = potKill->source(); - outwards = false; - } - //we erase bends and should check the node type here, but the only - //case that can happen is bend - while (splitter->degree() == 2) - { - if (outwards) - { - PG.unsplit(potKill, potKill->adjTarget()->cyclicSucc()->theEdge()); - splitter = potKill->target(); - } - else - { - edge ek = potKill->adjSource()->cyclicSucc()->theEdge(); - PG.unsplit(ek, potKill); - potKill = ek; - splitter = potKill->source(); - } - }//while - - adjURun = adjURun->cyclicPred(); //counterclockwise, Succ clockwise - } while (adjURun != uCopy->firstAdj()); - - //---------------------------------------------- - - //check if node is better suited to lie at the right position - if (rightNode != 0) - { - if (drawing.x(PG.copy(u)) > drawing.x(PG.copy(rightNode))) - { - rightNode = u; - } - } - else - { - rightNode = u; - } - - adjRun = adjRun->cyclicPred(); //counterclockwise, Succ clockwise - } while (adjRun != cCopy->firstAdj()); - - //--------------------------------------- - //adjust ordering to start with rightNode - //if (true) //zum debuggen ausschalten koennen - while (adjNodes.front() != rightNode) - { - node tempV = adjNodes.popFrontRet(); - adjNodes.pushBack(tempV); - } -}//filladjNodes - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/PlanarizationLayout_inc.cpp b/ext/OGDF/src/planarity/PlanarizationLayout_inc.cpp deleted file mode 100644 index f83fdc8c5..000000000 --- a/ext/OGDF/src/planarity/PlanarizationLayout_inc.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/* -* $Revision: 2559 $ -* -* last checkin: -* $Author: gutwenger $ -* $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ -***************************************************************/ - -/** \file - * \brief implementation of class UMLPlanarizationLayout. - * - * applies planarization approach for drawing UML diagrams - * by calling a planar layouter for every planarized connected - * component - * Static and incremental calls available - * Replaces cliques (if m_processCliques is set) to speed up - * the computation, this does only work in non-UML mode - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -//----------------------------------------------------------------------------- -//incremental call: takes a fixed part of the input -//graph (indicated by fixedNodes/Edges==true), embeds it using -//the input layout, then inserts the remaining part into this embedding -//currently, only the subgraph induced by the fixed nodes is fixed -void PlanarizationLayout::callIncremental( - UMLGraph ¨Graph, - NodeArray &fixedNodes, - const EdgeArray & /* fixedEdges */) -{ - try { - - if(((const Graph &)umlGraph).empty()) - return; - //------------------- - //check preconditions - //(change edge types in umlGraph at non-tree hierarchies - //or replace cliques by nodes) - preProcess(umlGraph); - - m_nCrossings = 0; //number of inserted crossings - - //use the options set at the planar layouter - int l_layoutOptions = m_planarLayouter.get().getOptions(); - bool l_align = ((l_layoutOptions & umlOpAlign)>0); - - //check: only use alignment mode if there are generalizations - bool l_gensExist = false; //set this for all CC's, start with first gen - - //------------------------------------------------------- - //first, we sort all edges around each node corresponding - //to the given layout in umlGraph, then we insert the mergers - //May be inserted in original or in copy - bool umlMerge = false; //Standard: insertion in copy - //if (umlMerge) - //{ - // umlGraph.sortEdgesFromLayout(); - // prepareIncrementalMergers(umlGraph); - //} - //----------------------------------------------------------- - //second, we embed the fixed part corresponding to the layout - //given in umlgraph - //TODO: check if we still need the global lists, do this - //for all CCs - //we create lists of the additional elements, maybe this can - //later be done implicitly within some other loop - - //---------------------------------------------------------- - // first phase: Compute planarized representation from input - //---------------------------------------------------------- - - //------------------------------------------------ - //now we derive a partial planar representation of - //the input graph using its layout information - PlanRepInc PG(umlGraph, fixedNodes); - - const int numCC = PG.numberOfCCs(); - - //TODO: adjust for CC number before/after insertion - // (width,height) of the layout of each connected component - Array boundingBox(numCC); - - //------------------------------------------ - //now planarize CCs and apply drawing module - int i; - for(i = 0; i < numCC; ++i) - { - // we treat connected component i where PG is set - // to a copy of this CC consisting only of fixed nodes - node minActive = PG.initMinActiveCC(i); - //if a single node was made active, we update its status - if (minActive != 0) - { - fixedNodes[minActive] = true; - } - -#ifdef OGDF_DEBUG - edge e; - forall_edges(e, PG) - { - edge eOrig = PG.original(e); - if (eOrig) - { - OGDF_ASSERT(PG.chain(eOrig).size() <= 1) - } - }//foralledges -#endif - - int nOrigVerticesPG = PG.numberOfNodes(); - //TODO: check if copying is really necessary - //we want to sort the additional nodes and therefore - //copy the list - List addNodes; - ListConstIterator it = PG.nodesInCC().begin(); - while (it.valid()) - { - if (!fixedNodes[(*it)]) - addNodes.pushBack((*it)); - it++; - }//while - - - //-------------------------------------------- - //now we insert the additional nodes and edges - //sort the additional nodes - //simple strategy: sort by their #connections to the fixed part - //we can therefore only count if we have fixed nodes - if ((addNodes.size() > 1) && (PG.nodesInCC().size() != addNodes.size())) - sortIncrementalNodes(addNodes, fixedNodes); - - //TODO: guarantee that the CC is non-empty and connected - //insert a first part otherwise - //DONE: unconnected parts are connected in a chain - - //attention: the following list pop relies on the property of - //the sorting algorithm, that the first node has a connection - //to a fixed node or otherwise none of the addnodes has a - //connection to fixednodes (its a CC on its own) - //in the worst case, we have to introduce a tree, which equals - //the steinertree problem, which is NP-hard. As we do not want - //to preinsert nodes that do not have layout information (they - //do have, but we do not consider it (e.g. for randomly - //inserted nodes)), we avoid the problem by inserting artificial - //edges connecting all CCs, building a tree of CCs - - //now we derive the embedding given in umlgraph for the fixed part - //we work on a copy of umlgraph, because we have to add/delete nodes - //and edges and create a PlanRep on an intermediate representation - adjEntry adjExternal = 0; - - //-------------------------------------------- - //here lies the main difference to the static call - //we first set the embedding corresponding to the - //input and then planarize the given layout - TopologyModule TM; - - bool embedded = true; - try { //TODO:should be catched within setEmbeddingFromGraph - //do not yet compute external face, embed and planarize - //with layout given in umlGraph - embedded = TM.setEmbeddingFromGraph(PG, umlGraph, - adjExternal, false, umlMerge); - }//try - catch(...) - { - embedded = false; - }//catch - - //returns true if connnectivity edges introduced - //TODO: hierhin oder eins nach unten? - PG.makeTreeConnected(adjExternal); - - //if embedding could not be set correctly, use standard embedding - if (!embedded) - { - reembed(PG, i, l_align, l_gensExist); - } - - //-------------------------------------------- - //now we compute a combinatorial embedding on - //the partial PlanRep that is used for node insertion - //and the external face - bool singleNode = (PG.numberOfNodes() == 1); - if ((PG.numberOfEdges() > 0) || singleNode) - { - CombinatorialEmbedding E(PG); - - //if we have edges, but no external face, find one - //we have also to select one later if there are no edges yet - if((adjExternal == 0) && PG.numberOfEdges() > 0) - { - //face fExternal = E.maximalFace(); - face fExternal = findBestExternalFace(PG,E); - adjExternal = fExternal->firstAdj(); - //while (PG.sinkConnect(adjExternal->theEdge())) - // adjExternal = adjExternal->faceCycleSucc(); - } - if ( (adjExternal != 0) && (PG.numberOfEdges() > 0) ) - E.setExternalFace(E.rightFace(adjExternal)); - - //------------------------------------------------- - //we insert additional nodes into the given PlanRep - SimpleIncNodeInserter inserter(PG); - ListIterator itAdd = addNodes.begin(); - while (itAdd.valid()) - { -#ifdef OGDF_DEBUG - edge eDebug = (*itAdd)->firstAdj()->theEdge(); -#endif - OGDF_ASSERT(PG.chain(eDebug).size() <= 1) - //we can check here if PG CC connected and speed - //up insertion by not updating CC part information - inserter.insertCopyNode((*itAdd), E, umlGraph.type((*itAdd))); - - //select an arbitrary external face if there was only one fixed node - if (singleNode && (PG.numberOfEdges() > 0)) - { - adjExternal = PG.firstEdge()->adjSource(); - E.setExternalFace(E.rightFace(adjExternal)); - } - else - { - adjExternal = E.externalFace()->firstAdj(); - int eNum = max(10, PG.numberOfEdges()+1); - int count = 0; - while ((adjExternal->theNode() == adjExternal->twinNode()) && - (count < eNum)) - { - adjExternal = adjExternal->faceCycleSucc(); - count++; - } - OGDF_ASSERT(count < eNum) - } - - itAdd++; - }//while - - if (!umlMerge) - PG.setupIncremental(i, E); - OGDF_ASSERT(E.consistencyCheck()) - - //we now have a complete representation of the - //original CC - - m_nCrossings += PG.numberOfNodes() - nOrigVerticesPG; - - //******************** - //copied from fixembed - - //********************************************************* - // third phase: Compute layout of planarized representation - //********************************************************* - Layout drawing(PG); - - //distinguish between CC's with/without generalizations - //this changes the input layout modules options! - if (l_gensExist) - m_planarLayouter.get().setOptions(l_layoutOptions); - else m_planarLayouter.get().setOptions((l_layoutOptions & ~umlOpAlign)); - - - //*************************************** - //call the Layouter for the CC's UMLGraph - m_planarLayouter.get().call(PG,adjExternal,drawing); - - // copy layout into umlGraph - // Later, we move nodes and edges in each connected component, such - // that no two overlap. - const List &origInCC = PG.nodesInCC(i); - ListConstIterator itV; - - //set position for original nodes and set bends for - //all edges - for(itV = origInCC.begin(); itV.valid(); ++itV) - { - node vG = *itV; - - umlGraph.x(vG) = drawing.x(PG.copy(vG)); - umlGraph.y(vG) = drawing.y(PG.copy(vG)); - - adjEntry adj; - forall_adj(adj,vG) - { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - - drawing.computePolylineClear(PG,eG,umlGraph.bends(eG)); - }//foralladj - }//for orig nodes - - - if (!umlMerge) - { - //insert bend point for incremental mergers - const SList& mergers = PG.incrementalMergers(i); - SListConstIterator itMerger = mergers.begin(); - while (itMerger.valid()) - { - node vMerger = (*itMerger); - //due to the fact that the merger may be expanded, we are - //forced to run through the face - adjEntry adjMerger = PG.expandAdj(vMerger); - //first save a pointer to the bends of the generalization - //leading to the target - DPolyline dpUp; - - //check if there is an expansion face - if (adjMerger != 0) - { - //if there are bends on the edge, copy them - //TODO: check where to derive the bends from - //if eUp is nil - adjEntry adjUp = adjMerger->cyclicPred(); - OGDF_ASSERT(PG.isGeneralization(adjUp->theEdge())) - edge eUp = PG.original(adjUp->theEdge()); - //There is never an original here in current incremental algo - //OGDF_ASSERT(eUp) - if (eUp) dpUp = umlGraph.bends(eUp); - //we run through the expansion face to the connected edges - //this edge is to dummy corner - adjEntry runAdj = adjMerger->faceCycleSucc(); - while (runAdj != adjMerger) - { - node vConnect = runAdj->theNode(); - //because of the node collapse using the original - //edges instead of the merger copy edges (should be - //fixed for incremental mode) the degree is 4 - //FIXED!? - //if (vConnect->degree() != 4) - //while? - if (vConnect->degree() != 3) - { - runAdj = runAdj->faceCycleSucc(); - continue; - } - edge eCopy = runAdj->cyclicPred()->theEdge(); - OGDF_ASSERT(eCopy->target() == runAdj->theNode()) - OGDF_ASSERT(PG.isGeneralization(eCopy)) - OGDF_ASSERT(PG.original(eCopy)) - - DPolyline &eBends = umlGraph.bends(PG.original(eCopy)); - - eBends.pushBack( - DPoint(drawing.x(vMerger), drawing.y(vMerger))); - - if (eUp) - { - ListConstIterator itDp; - for(itDp = dpUp.begin(); itDp.valid(); ++itDp) - eBends.pushBack(*itDp); - } - else - eBends.pushBack(DPoint(drawing.x(adjUp->twinNode()), - drawing.y(adjUp->twinNode()))); - - runAdj = runAdj->faceCycleSucc(); - - } - - } - else //currently all nodes are expanded, but this is not guaranteed - { - //first save the bends - adjEntry adjUp = 0; - forall_adj(adjMerger, vMerger) - { - //upgoing edge - if (adjMerger->theEdge()->source() == vMerger) - { - adjUp = adjMerger; - OGDF_ASSERT(PG.isGeneralization(adjMerger->theEdge())) - edge eUp = PG.original(adjMerger->theEdge()); - //check if this is - //a) the merger up edge and not a connectivity edge - //b) what to do if there is no original of outgoing edge - if (eUp) - dpUp = umlGraph.bends(eUp); - break; - }//if - - }//foralladj - forall_adj(adjMerger, vMerger) - { - if (adjMerger->theEdge()->target() == vMerger) - { - edge eOrig = PG.original(adjMerger->theEdge()); - if (eOrig) - { - //incoming merger edges always have an original here! - umlGraph.bends(eOrig).pushBack(DPoint(drawing.x(vMerger), - drawing.y(vMerger))); - - //was there an original edge? - if (dpUp.size()>0) - { - ListConstIterator itDp; - for(itDp = dpUp.begin(); itDp.valid(); ++itDp) - umlGraph.bends(eOrig).pushBack(*itDp); - }//if - else - { - if (adjUp) - umlGraph.bends(eOrig).pushBack(DPoint(drawing.x(adjUp->twinNode()), - drawing.y(adjUp->twinNode()))); - }//else - }//if - - } - }//forall adj - }//else - itMerger++; - }//while merger nodes - }//if !umlMerge - - //umlGraph.writeGML("C:\\FullLayout2Inc.gml"); - - // the width/height of the layout has been computed by the planar - // layout algorithm; required as input to packing algorithm - boundingBox[i] = m_planarLayouter.get().getBoundingBox(); - - //******************* - - }//if #edges > 0 - - else - { - //TODO: what if there are no edges but the insertion edges - //DONE: we make the CC treeConnected - //Nonetheless we have to compute a layout here - OGDF_ASSERT(PG.numberOfNodes() < 2) - } - - - - //TODO: set m_crossings here - //m_nCrossings += PG.numberOfNodes() - numOrigNodes; - - }//for connected components - - //******************* - //TODO: check shifting to new place - - //---------------------------------------- - // Arrange layouts of connected components - //---------------------------------------- - - arrangeCCs(PG, umlGraph, boundingBox); - - if (umlMerge) umlGraph.undoGenMergers(); - - umlGraph.removeUnnecessaryBendsHV(); - - //******************** - //new position after adding clique process, check if correct - postProcess(umlGraph); - }//try - catch (...) - { - call(umlGraph); - return; - } -}//callIncremental - - -//Insertion order of added nodes: -//sorting strategy: we count all adjacent nodes that are in -//fixedNodes and sort the nodes correspondingly -//In addition, we guarantee that no node is inserted before at least one -//of its neighbours is inserted - -//compute how far away from the fixed part the added nodes lay -//uses BFS -void PlanarizationLayout::getFixationDistance(node startNode, - HashArray &distance, - const NodeArray &fixedNodes) -{ - //we only change the distance for nodes with distance <=0 because they are not - //connected to the fixed part - //we only care about nodes which are members of array distance - HashArray indexMark(false); - //the BFS queue - QueuePure nodeQ; - - nodeQ.append(startNode); - indexMark[startNode->index()] = true; - while (!nodeQ.empty()) - { - adjEntry adjE; - node topNode = nodeQ.pop(); - //hier aufpassen: geht nur, wenn kein fixedNode eine Distance hat - //alternativ: alle auf null - //zur sicherheit: fixed uebergeben und vergleichen - bool fixedBase = fixedNodes[topNode]; - - forall_adj(adjE, topNode) - { - node testNode = adjE->twinNode(); - int ind = testNode->index(); - - if (!indexMark[ind]) - { - indexMark[ind] = true; - nodeQ.append(testNode); - } - - //we have a distance value, i.e. ind is an additional node - if (!fixedNodes[testNode]) - { - if (distance[ind] <= 0) - { - //should never occur (check: nodes not in CC?) - if (fixedBase) - { - distance[ind] = max(-1, distance[ind]); - OGDF_ASSERT(false) - } - else - { - if (distance[ind] == 0) distance[ind] = min(-1, distance[topNode->index()] - 1); - else distance[ind] = min(-1, max(distance[ind], distance[topNode->index()] - 1)); - }//else - }//if node without contact to fixed nodes - }//if distance (is an addnode) - }//foralladj - }//while - -}//getFixationDistance - -//Attention: changing this behavior makes it necessary to check -//the call procedure for the case where one of the addnodes is -//made fix to allow insertion of an edge -void PlanarizationLayout::sortIncrementalNodes(List &addNodes, - const NodeArray &fixedNodes) -{ - //if there are no fixed nodes, we can not sort - //todo: do some other sorting - - //we count all adjacent fixed nodes - //store degree by node index - HashArray indexToDegree(0); - ListIterator it = addNodes.begin(); - adjEntry adjE; - node someFixedNode = 0; - - while (it.valid()) - { - if ((*it)->degree() < 1) - { - indexToDegree[(*it)->index()] = 0; - it++; - continue; - } - int vDegree = 0; - adjE = (*it)->firstAdj(); - do { - if (fixedNodes[adjE->twinNode()]) - { - vDegree++; - someFixedNode = adjE->twinNode(); - } - adjE = adjE->cyclicSucc(); - } while (adjE != (*it)->firstAdj()); - - indexToDegree[(*it)->index()] = vDegree; - - it++; - }//while - //for all nodes that are not connected to the fixed part we have to guarantee - //that they are not inserted before one of their neighbours is inserted - //therefore we set negative values for all nodes corresponding to their distance - //to the fixed part - OGDF_ASSERT(someFixedNode != 0) - if (someFixedNode == 0) throw AlgorithmFailureException(); - //we start the BFS at some fixed node - getFixationDistance(someFixedNode,indexToDegree, fixedNodes); - - - //we sort the nodes in decreasing vDegree value order - AddNodeComparer comp(indexToDegree); - addNodes.quicksort(comp); - -}//sortincrementalnodes - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/SimpleEmbedder.cpp b/ext/OGDF/src/planarity/SimpleEmbedder.cpp deleted file mode 100644 index 33ce141e8..000000000 --- a/ext/OGDF/src/planarity/SimpleEmbedder.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief A simple embedder algorithm. - * - * \author Thorsten Kerkhof - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - - void SimpleEmbedder::call(Graph& G, adjEntry& adjExternal) - { - OGDF_ASSERT(isPlanar(G)); - - //---------------------------------------------------------- - // - // determine embedding of G - // - - // We currently compute any embedding and choose the maximal face - // as external face - - // if we use FixedEmbeddingInserter, we have to re-use the computed - // embedding, otherwise crossing nodes can turn into "touching points" - // of edges (alternatively, we could compute a new embedding and - // finally "remove" such unnecessary crossings). - adjExternal = 0; - if(!G.representsCombEmbedding()) - planarEmbed(G); - - if (G.numberOfEdges() > 0) - { - CombinatorialEmbedding E(G); - //face fExternal = E.maximalFace(); - face fExternal = findBestExternalFace(G, E); - adjExternal = fExternal->firstAdj(); - } - } - - - face SimpleEmbedder::findBestExternalFace( - const PlanRep& PG, - const CombinatorialEmbedding& E) - { - FaceArray weight(E); - - face f; - forall_faces(f,E) - weight[f] = f->size(); - - node v; - forall_nodes(v,PG) - { - if(PG.typeOf(v) != Graph::generalizationMerger) - continue; - - adjEntry adj; - forall_adj(adj,v) { - if(adj->theEdge()->source() == v) - break; - } - - OGDF_ASSERT(adj->theEdge()->source() == v); - - node w = adj->theEdge()->target(); - bool isBase = true; - - adjEntry adj2; - forall_adj(adj2, w) { - edge e = adj2->theEdge(); - if(e->target() != w && PG.typeOf(e) == Graph::generalization) { - isBase = false; - break; - } - } - - if(isBase == false) - continue; - - face f1 = E.leftFace(adj); - face f2 = E.rightFace(adj); - - weight[f1] += v->indeg(); - if(f2 != f1) - weight[f2] += v->indeg(); - } - - face fBest = E.firstFace(); - forall_faces(f,E) - if(weight[f] > weight[fBest]) - fBest = f; - - return fBest; - } - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/SubgraphPlanarizer.cpp b/ext/OGDF/src/planarity/SubgraphPlanarizer.cpp deleted file mode 100644 index f5e73b582..000000000 --- a/ext/OGDF/src/planarity/SubgraphPlanarizer.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class SubgraphPlanarizer. - * - * \author Markus Chimani - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf -{ - -SubgraphPlanarizer::SubgraphPlanarizer() -{ - FastPlanarSubgraph* s= new FastPlanarSubgraph(); - s->runs(100); - m_subgraph.set(s); - - VariableEmbeddingInserter* i = new VariableEmbeddingInserter(); - i->removeReinsert(VariableEmbeddingInserter::rrAll); - m_inserter.set(i); - - m_permutations = 1; - m_setTimeout = true; -} - -Module::ReturnType SubgraphPlanarizer::doCall(PlanRep &PG, - int cc, - const EdgeArray &cost, - const EdgeArray &forbid, - const EdgeArray &subgraphs, - int& crossingNumber) -{ - OGDF_ASSERT(m_permutations >= 1); - - OGDF_ASSERT(!(useSubgraphs()) || useCost()); // ersetze durch exception handling - - double startTime; - usedTime(startTime); - - if(m_setTimeout) - m_subgraph.get().timeLimit(m_timeLimit); - - List deletedEdges; - PG.initCC(cc); - EdgeArray costPG(PG); - edge e; - forall_edges(e,PG) - costPG[e] = cost[PG.original(e)]; - ReturnType retValue = m_subgraph.get().call(PG, costPG, deletedEdges); - if(isSolution(retValue) == false) - return retValue; - - for(ListIterator it = deletedEdges.begin(); it.valid(); ++it) - *it = PG.original(*it); - - bool foundSolution = false; - CrossingStructure cs; - for(int i = 1; i <= m_permutations; ++i) - { - const int nG = PG.numberOfNodes(); - - for(ListConstIterator it = deletedEdges.begin(); it.valid(); ++it) - PG.delCopy(PG.copy(*it)); - - deletedEdges.permute(); - - if(m_setTimeout) - m_inserter.get().timeLimit( - (m_timeLimit >= 0) ? max(0.0,m_timeLimit - usedTime(startTime)) : -1); - - ReturnType ret; - if(useForbid()) { - if(useCost()) { - if(useSubgraphs()) - ret = m_inserter.get().call(PG, cost, forbid, deletedEdges, subgraphs); - else - ret = m_inserter.get().call(PG, cost, forbid, deletedEdges); - } else - ret = m_inserter.get().call(PG, forbid, deletedEdges); - } else { - if(useCost()) { - if(useSubgraphs()) - ret = m_inserter.get().call(PG, cost, deletedEdges, subgraphs); - else - ret = m_inserter.get().call(PG, cost, deletedEdges); - } else - ret = m_inserter.get().call(PG, deletedEdges); - } - - if(isSolution(ret) == false) - continue; // no solution found, that's bad... - - if(!useCost()) - crossingNumber = PG.numberOfNodes() - nG; - else { - crossingNumber = 0; - node n; - forall_nodes(n, PG) { - if(PG.original(n) == 0) { // dummy found -> calc cost - edge e1 = PG.original(n->firstAdj()->theEdge()); - edge e2 = PG.original(n->lastAdj()->theEdge()); - if(useSubgraphs()) { - int subgraphCounter = 0; - for(int i=0; i<32; i++) { - if(((subgraphs[e1] & (1< 30 && i <= 100 && (i % 5) == 0) || ((i % 10) == 0)) - sout() << "\t" << cs.weightedCrossingNumber(); - } - - PG.initCC(cc); - - if(m_timeLimit >= 0 && usedTime(startTime) >= m_timeLimit) { - if(foundSolution == false) - return retTimeoutInfeasible; // not able to find a solution... - break; - } - } - - cs.restore(PG,cc); // restore best solution in PG - crossingNumber = cs.weightedCrossingNumber(); - - OGDF_ASSERT(isPlanar(PG) == true); - - return retFeasible; -} - - -void SubgraphPlanarizer::CrossingStructure::init(PlanRep &PG, int weightedCrossingNumber) -{ - m_weightedCrossingNumber = weightedCrossingNumber; - m_crossings.init(PG.original()); - - m_numCrossings = 0; - NodeArray index(PG,-1); - node v; - forall_nodes(v,PG) - if(PG.isDummy(v)) - index[v] = m_numCrossings++; - - edge ePG; - forall_edges(ePG,PG) - { - if(PG.original(ePG->source()) != 0) { - edge e = PG.original(ePG); - ListConstIterator it = PG.chain(e).begin(); - for(++it; it.valid(); ++it) { - //cout << index[(*it)->source()] << " "; - m_crossings[e].pushBack(index[(*it)->source()]); - } - } - } -} - -void SubgraphPlanarizer::CrossingStructure::restore(PlanRep &PG, int cc) -{ - //PG.initCC(cc); - - Array id2Node(0,m_numCrossings-1,0); - - SListPure edges; - PG.allEdges(edges); - - for(SListConstIterator itE = edges.begin(); itE.valid(); ++itE) - { - edge ePG = *itE; - edge e = PG.original(ePG); - - SListConstIterator it; - for(it = m_crossings[e].begin(); it.valid(); ++it) - { - node x = id2Node[*it]; - edge ePGOld = ePG; - ePG = PG.split(ePG); - node y = ePG->source(); - - if(x == 0) { - id2Node[*it] = y; - } else { - PG.moveTarget(ePGOld, x); - PG.moveSource(ePG, x); - PG.delNode(y); - } - } - } -} - -} // namspace ogdf diff --git a/ext/OGDF/src/planarity/TopologyModule.cpp b/ext/OGDF/src/planarity/TopologyModule.cpp deleted file mode 100644 index dd7a26275..000000000 --- a/ext/OGDF/src/planarity/TopologyModule.cpp +++ /dev/null @@ -1,1234 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of TopologyModule (sets embedding - * from layout) - * - * \author Karsten Klein - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -//debug -#include - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -//---------------------------------------------------------- -//sets the embedding in PG corresponding to the layout in AG -//returns false if planarization fails (there may be diagram- -//inherent reasons for that) -bool TopologyModule::setEmbeddingFromGraph( - PlanRep &PG, - GraphAttributes &AG, - adjEntry &adjExternal, - bool setExternal, - bool reuseAGEmbedding) -{ - const Graph & GG = AG.constGraph(); - m_eLegs.init(GG); - //TODO: we have to check consistency: - //input: (same graph in AG and PG) - //after planarize: is planar - - - //intialize the crossing positions nodearray - m_crossPosition.init(PG); - - //do we have to compute the new embedding or is it given? - if (!reuseAGEmbedding) - { - //we order the edges around each node corresponding to - //the input embedding in the GraphAttributes layout. - //we could use the sorting in UMLGraph/GraphAttributes - //here, but AG can't access its graph non-const. - NodeArray > adjList(PG); - - adjExternal = 0; - - //sorts edges by layout information - EdgeComparer* ec = new EdgeComparer(AG, PG); - - //we only allow PlanReps that have no bend nodes for the bends - node v; - adjEntry ae; - forall_nodes(v, PG) - { - forall_adj(ae, v) - { - adjList[v].pushBack(ae); - }//forall adjacency edges - //sort the entries - adjList[v].quicksort(*ec); - PG.sort(v, adjList[v]); - }//forall nodes - - delete ec; - }//if not reuse - - //now insert necessary crossings - //efficient check, if any crossings are necessary - //before computing them (#e^2) - - //TODO: hier mal checken, ob PG zusammenhaengend ist, - //und schauen ob es sein muss. - //Resultat: Fuer representsCombEmbedding (Genus) und - //den planaritytest muss es nicht sein. - - if(!PG.representsCombEmbedding()) - { -#ifdef OGDF_DEBUG - ((PlanRepInc&)PG).writeGML("Vorplanaris.gml", AG); -#endif - planarizeFromLayout(PG, AG); - if (!PG.representsCombEmbedding()) - handleImprecision(PG); -#ifdef OGDF_DEBUG - ((PlanRepInc&)PG).writeGML("Nachplanaris.gml", AG); -#endif - } - - //TODO: there may be non-planarizable drawings, - //so we should not assert, but planarise without - //respect to the given drawing - //Result: Done, but this must be consistent with the - //surrounding algorithm (should be aware of the fact - //that the embedding does not represent the layout - //information - if (!isPlanar(PG)) - return false; - - if(!PG.representsCombEmbedding()) - { - //we don't have a correct embedding, but there - //may be several reasons, some of them are repairable - //if we still have no correct embedding, it is typically - //because the positioning input didn't make any sense in - //an interpretation, e.g. all positions zero - planarEmbed(PG); - } - - PG.removePseudoCrossings(); - postProcess(PG); - if (!isPlanar(PG)) - return false; - - //if it is still not correct, we have to reembed without - //respecting the user input - if(!PG.representsCombEmbedding()) - { -#ifdef OGDF_DEBUG - PG.writeGML("outputEmbed.gml"); -#endif - planarEmbed(PG); - PG.removePseudoCrossings(); - } - - //now compute the external face - if(setExternal &&(PG.numberOfEdges() > 0)) - { - face f = getExternalFace(PG, AG); - adjExternal = f->firstAdj(); - } - -//face fExternal = E.maximalFace(); -//face fExternal = findBestExternalFace(PG,E); -//adjExternal = fExternal->firstAdj(); -//debug -#ifdef OGDF_DEBUG - ofstream f("AdjSortCopy.txt"); - node v; - adjEntry ae; - forall_nodes(v, PG) - { - if (PG.original(v)) - { - f << "\nNode: " << PG.original(v)->index() <<"\n"; - forall_adj(ae, v) - { - node w = PG.original(ae->twinNode()); - if (w) - f << " Eintrag: " << w->index() << "\n"; - else f <<"No original\n"; - - }//adjs - } - } -#endif - return true; -}//setEmbeddingFromGraph - - -//we handle and correct cases were imprecision occurs, e.g. -//double computations for mergers and crossings -void TopologyModule::handleImprecision(PlanRep &PG) -{ - List problems; - node v; - //we don't need to check processing from both sides as long - //as we only process crossings at original nodes - //EdgeArray processed(PG, false); - forall_nodes(v, PG) - { - if (PG.isCrossingType(v)) - { - //if cases can occur where the assertion fails, - //the following loop condition may fail, too - OGDF_ASSERT(v->degree() == 4) - adjEntry adFirst = v->firstAdj(); - adjEntry adRun = adFirst; - do - { - adjEntry adNext = adRun->cyclicSucc(); - node w = adRun->theEdge()->opposite(v); - if (w == adNext->theEdge()->opposite(v)) - { - //We only take the cases into account - //were the crossing is near an input node - //thereby respecting the input embedding - //vs. crossing imprecision dilemma - if (PG.original(w) && - (adNext->twin() == adRun->twin()->cyclicSucc()) - ) - {//wrong order at w - PG.swapAdjEdges(adNext->twin(), adRun->twin()->cyclicSucc()); - problems.pushBack(v); - } - - }//if - adRun = adNext; - } while (adRun != adFirst); - }//iscrossing - }//forallnodes - ListIterator it = problems.begin(); - while (it.valid()) - { - //hier entweder switchen oder Kreuzung entfernen - //PG.removeCrossing((*it)); - it++; - }//while - - //TODO: take care not to handle crossing cascades - //leading to multiple -}//handleimprecision - - -void TopologyModule::postProcess(PlanRep &PG) -{ - //remove crossings between edges at the same node - //TODO: should be automatically detected while inserting - //crossings - - OGDF_ASSERT(PG.representsCombEmbedding()) - //remove consecutive crossings between two edges - if (m_options & opLoop) - { - node v; - List obsoleteCrossings; - NodeArray processed(PG, false); - forall_nodes(v, PG) - { - if (processed[v]) continue; - if (v->degree() != 4) continue; - if (!PG.isCrossingType(v)) continue; - - adjEntry ad1 = v->firstAdj(); - adjEntry adRun1 = ad1; - adjEntry adRun2 = adRun1->cyclicSucc(); - do - { - node w = adRun2->twinNode(); - node u = adRun1->twinNode(); - if ( (w->degree() == 4) && (w == u) && - (w != v) ) - { - //entweder abfragen, ob v processed - //oder unten continue (nur paarweise loeschen) - if (PG.isCrossingType(w) && !processed[w]) - { - obsoleteCrossings.pushBack(w); - processed[w] = true; - - if (!processed[v]) //obsolete - { - processed[v] = true; - obsoleteCrossings.pushBack(v); - continue; - } - }//if crossing - } - adRun1 = adRun2; - adRun2 = adRun2->cyclicSucc(); - } while (adRun1 != ad1); - - }//forallnodes - - OGDF_ASSERT((obsoleteCrossings.size() % 2) == 0) - ListIterator it = obsoleteCrossings.begin(); - while (it.valid()) - { - PG.removeCrossing((*it)); - it++; - }//while obsolete crossings - }//if oploop - - OGDF_ASSERT(PG.representsCombEmbedding()) - - if (m_options & opCrossFlip) - { - //this is useful only if the crossing is the first crossing - //near the common node - //check which edges are to be deleted by - //removeunnecessaryCrossings, then flip - //slow, should be detected when inserting crossings - List flipper; - node v; - forall_nodes(v, PG) - { - bool flip = false; - - //we remove the crossing and flip the edge order - if (PG.isCrossingType(v))//(v->degree() == 4) - { - flip = checkFlipCrossing(PG, v, false); - if (flip) - flipper.pushBack(v); - - } - }//forallnodes - //TODO: we should reuse the computation above - ListIterator itFlip = flipper.begin(); - while (itFlip.valid()) - { - checkFlipCrossing(PG, (*itFlip), true); - itFlip++; - } - }//if opcrossflip - - OGDF_ASSERT(PG.representsCombEmbedding()) - -}//postprocess after planarization - - -void TopologyModule::planarizeFromLayout(PlanRep &PG, - GraphAttributes &AG) -{ - //------------------------ - //Debug - Layout xy(PG); - node u; - forall_nodes(u, PG) - { - if (PG.original(u)) - { - xy.x(u) = AG.x(PG.original(u)); - xy.y(u) = AG.y(PG.original(u)); - } - - } - //------------------------- - - //First, we create a set of EdgeLegs representing the - //segments in the given layout, we assign the (ASSERT!) - //only copy of an edge as the EdgeLeg copy edge - - //Preliminary we use a list to save and process all edgelegs - //TODO: Insert a storage here to sort the legs and process - //them by sweepline - //TODO: Check if pointer from edge to its legs is necessary - //(via edgearray?) - - List legList; - //-- - //test to get only the edges in cc - //-- - const List &origInCC = PG.nodesInCC(PG.currentCC()); - - //currentCC or i?? - //const List &origInCC = nodesInCC(i); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) - { - node vG = *itV; - edge e; - forall_adj_edges(e,vG) - { - if (vG == e->target()) continue; - //-- - - //----------------------------------------------------- - //create edgeLeg objects for edge segments - //----------------------------------------------------- - //while (e) - //{ - //there may be edges in other CCs without representation - if ((PG.chain(e)).size() == 0) - { - //TODO: this doesnt seem to be correct anymore, was it? - //e = e->succ(); - continue; - }//if not in CC - //guarantee that there are no bends or crossings yet - OGDF_ASSERT((PG.chain(e)).size() == 1) - - m_eLegs[e].clear(); - - const DPolyline &bends1 = AG.bends(e); - int legNumber = 0; //start legcount at 0 - //run over all segments - double startX = AG.x(e->source()); - double startY = AG.y(e->source()); - double endX; - double endY; - - //create all legs for bends - ListConstIterator it = bends1.begin(); - while (it.valid()) - { - endX = (*it).m_x; - endY = (*it).m_y; - - //now we create an EdgeLeg and initialize it with - //the only copy of e in PG - EdgeLeg* eLeg = new EdgeLeg(PG.copy(e),legNumber, - DPoint(startX, startY), DPoint(endX, endY)); - //insert the leg into the list of legs for e - eLeg->m_eIterator = m_eLegs[e].pushBack(eLeg); - //insert the leg into the crossing search list - legList.pushBack(eLeg); - - - //proceed with the next leg - legNumber++; - startX = endX; - startY = endY; - - it++; - } - - //create the final leg - endX = AG.x(e->target()); - endY = AG.y(e->target()); - EdgeLeg* eLeg = new EdgeLeg(PG.copy(e),legNumber, - DPoint(startX, startY), DPoint(endX, endY)); - //insert the leg into the list of legs for e - eLeg->m_eIterator = m_eLegs[e].pushBack(eLeg); - legList.pushBack(eLeg); - - - e = e->succ(); - //}//while e - }//if - }//for orig in cc - - //Now we compute the crossings between segments, thereby - //introducing new segments if crossings are detected - //We add the newly created edges as edgelegs into the set of crossings, - //which gives an computational overhead depending on the number - //of crossings compared to the precomputation of crossings, - //but helps in detecting the correct position of the crossing - //on the edge (in the sorting order of the edge crossings) - //We run over the list of edgelegs, delete the current edgeleg - //from the list and compute its crossings with the edgelegs - //remaining in the list. The crossings are inserted into the - //PlanRep und the crossed (second) edgeleg is replaced by - //the edgelegs introduced by the crossings. - - while (legList.size() > 0) - { - EdgeLeg* crossLeg = legList.popFrontRet(); - //compute crossings of crossLeg with all other edgeLegs - ListIterator runIt = legList.begin(); - DPoint xp(0, 0); //crossing point - //Lists of crossed EdgeLegs (their iterators in legList) - //and the corresponding crossing points - List > iterList; - - //from now on, we store the crossing in the edgeleg - //(they are only there for this purpose) - //List xpList; - while (runIt.valid()) - { - //special case of parallel generalization segments - //at mergers in drawings - if ((PG.isGeneralization(crossLeg->copyEdge()) && - PG.isGeneralization((*runIt)->copyEdge()))) - { - /*if ( (crossLeg->start().m_x == (*runIt)->start().m_x) && - (crossLeg->start().m_y == (*runIt)->start().m_y) && - (crossLeg->end().m_x == (*runIt)->end().m_x) && - (crossLeg->end().m_y == (*runIt)->end().m_y)) - */ - { - //EdgeLeg* teste = (*runIt); - } - } - if (hasCrossing(crossLeg, (*runIt), xp)) - { - //check crossings for the special case - //of two generalizations: - if (PG.isGeneralization(crossLeg->copyEdge()) && - PG.isGeneralization((*runIt)->copyEdge())) - { - //EdgeLeg* teste = (*runIt); - if (m_options & opDegOneCrossings) - { - //has priority over gentoass - //TODO - } - if (m_options & opGenToAss) - { - //TODO: check if we have to set all copies - //TODO: check if we prefer an edge, e.g. most crossed - //TODO: should we set original as well. - edge converter = crossLeg->copyEdge(); - //check if incident to merger - if ( (PG.typeOf(converter->source()) == Graph::generalizationMerger) || - (PG.typeOf(converter->target()) == Graph::generalizationMerger) ) - converter = (*runIt)->copyEdge(); - //TODO: converter may still be incident to merger - AG.type( PG.original(converter) ) = Graph::association; - PG.oriEdgeTypes(PG.original(converter) ) = Graph::association; - ListConstIterator it = - PG.chain(PG.original(converter)).begin(); - while (it.valid()) - { - PG.setAssociation((*it)); - it++; - } - }//if option set - - }//if crossing between generalizations - //first we store all crossings together - //with their crossing point, these are only - //used to compute an ordering - //xpList.pushBack(xp); - (*runIt)->m_xp = xp; - iterList.pushBack(runIt); - //then we check if we have topDown or - //bottom up crossing direction - //we have top Down crossing from runitleg - //over crossleg, if the segment - //crosslegs startpoint -> runitleg startpoint lies - //clockwise before the segment defined by - //crossleg - EdgeComparer ec(AG, PG); - DPoint u = crossLeg->start(); - DPoint v = (*runIt)->start(); - DPoint w = crossLeg->end(); - if (ec.before(u, v, w)) - //if increasing y values go up, before - //gives the correct value, but we flip - (*runIt)->m_topDown = false; //depends on y-axis direction - else (*runIt)->m_topDown = true; - - }//if crossing detected - runIt++; - }//while running over all edgeLegs - if (iterList.size() > 0) - { - // first sort the crossings corresponding to the - // edgeleg direction - if (iterList.size() > 1) - { - //just compute the distance to the start vertex - //sqrt(sqr(x2-x1) + sqr(y2-y1)); - PointComparer pc(crossLeg->start()); - iterList.quicksort(pc); - } - // then we insert the detected crossings: - // we insert the crossing into PG and update the - // crossed edgeLeg, insert the new edge leg - // we do not have to worry about crossLeg, because - // after this loop, we will never return there (no - // more crossings possible) - ListIterator< ListIterator< EdgeLeg* > > it = iterList.begin(); - //ListIterator itXp = xpList.begin(); - - while (it.valid()) - { - //we insert the crossing for the current leg - ListIterator< EdgeLeg* > itLeg = (*it); - - //before we create the crossing and thereby destroy the - //crossLeg copy edge, we save all subsequent edgelegs on - //the same copy edge to update the afterwards - List affectedSegments; - ListIterator< EdgeLeg* > itSearch2 = crossLeg->m_eIterator; - itSearch2++; //crossLeg itself is automatically updated in insertcrossing - while (itSearch2.valid() && - ( (*itSearch2)->copyEdge() == crossLeg->copyEdge()) ) - { - affectedSegments.pushBack((*itSearch2)); - itSearch2++; - } - //TODO: check if automatic update of new crossleg - //copyedge works after first crossing - //we implicitly change the crossleg edge and do not - //introduce new edgelegs for the crossing edge, - //because they won't be used anymore - OGDF_ASSERT(PG.original((*itLeg)->copyEdge())) - edge newEdge = PG.insertCrossing(crossLeg->copyEdge(), - (*itLeg)->copyEdge(), ((*itLeg)->m_topDown)); - m_crossPosition[newEdge->source()] = (*itLeg)->m_xp;//(*itXp); - OGDF_ASSERT(PG.original((*itLeg)->copyEdge())) - //automatischer Seiteneffekt - //crossLeg->copyEdge() = newEdge; - //---------------------------------------- - //debug - xy.x(newEdge->source()) = (*itLeg)->m_xp.m_x; - xy.y(newEdge->source()) = (*itLeg)->m_xp.m_y; - //---------------------------------------- - - //debugstring - //String fileName; - //fileName.sprintf("inserted%d.gml", i++); - //PG.writeGML(fileName); - - //insert the edgeleg for newEdge and update (*itleg) - //accordingly (endpoint is now crossing point, TODO: depending - //on the direction!) - - //TODO: check: legnumber should be ok, otherwise - //we would have to update it for all subsequent legs - //it only tells us where we are in the bend ordering of the - //original edge (after legnumber #bends) , no change after crossing - EdgeLeg* eLeg = new EdgeLeg(newEdge,(*itLeg)->number(), - //DPoint((*itXp)), - (*itLeg)->m_xp, - (*itLeg)->end()); //TODO: decide end/start - //depending on direction - (*itLeg)->end() = (*itLeg)->m_xp;//DPoint((*itXp)); - - //we insert the new leg into the list of legs for e - //TODO: we have to check the right direction?? - //muesste automatisch immer hinter der alten Kante liegen - edge searchEdge = (*itLeg)->copyEdge(); - OGDF_ASSERT(PG.original(searchEdge) == PG.original(newEdge)) - eLeg->m_eIterator = - m_eLegs[PG.original(newEdge)].insert(eLeg, (*itLeg)->m_eIterator); - //We update (depending on the direction) all - //following edgelegs with the same copy edge to newedge - ListIterator< EdgeLeg* > itSearch = eLeg->m_eIterator; - itSearch++; //eLeg itself is ok - while (itSearch.valid() && ( (*itSearch)->copyEdge() == searchEdge ) ) - { - (*itSearch)->copyEdge() = newEdge; - itSearch++; - } - //We update (depending on the direction) all - //following edgelegs with the same copy edge to newedge - itSearch2 = affectedSegments.begin(); - while (itSearch2.valid()) - { - (*itSearch2)->copyEdge() = crossLeg->copyEdge(); - itSearch2++; - } - - //TODO: we simply push the new leg into the list, - // check if this can cause problems - legList.pushBack(eLeg); - - //itXp++; - it++; - }//while valid crossings - - }//if crossings - - }//while all edgeLegs - - //delete the created edgeLegs - ListIterator legIt = legList.begin(); - while (legIt.valid()) - { - EdgeLeg* el = (*legIt); - delete el; - legIt++; - }//while all edgeLegs - - //----------------------------------------------- - //debug -#ifdef OGDF_DEBUG - ((PlanRepInc&)PG).genusLayout(xy); - ((PlanRepInc&)PG).writeGML("planarisiert.gml", xy); -#endif -}//planarizefromlayout - - -//compute sum of angles in face -double TopologyModule::faceSum(PlanRep &PG, - const GraphAttributes &AG, face f) -{ - DPolyline l; double rho = 0; DPolyline B; - - //Run through the faces and count the angles. - //we can't run over original edges because segments - //may lie in different faces after crossing insertion. - //(bends are not yet replaced by nodes, crossings can - //therefore split them) - //on every copy edge the original edge is unambigious - //we can check at which point in the range of crossings - //we lie //unefficient if many crossings/bends, but we - //can not efficiently store this at the CROSSED edge - //when inserting crossings - - adjEntry iti = f->firstAdj(); - while (iti != 0) - { - //list of points along copy iti - B.clear(); - edge eOrig = PG.original(iti->theEdge()); - //only the source node is considered in CASE A - //we do not use endpoints(would be doublettes) - node srcNode = PG.original((iti)->theNode()); - DPolyline dp = AG.bends(eOrig); - //check direction - bool reversed = (iti)->theNode() != (iti)->theEdge()->source(); - if (reversed) - dp.reverse(); - - //CASE A: no crossings - if (PG.chain(PG.original(iti->theEdge())).size() == 1 ) - { - OGDF_ASSERT(PG.original((iti)->theNode())) - OGDF_ASSERT(PG.original((iti->twin())->theNode())) - - B.pushFront(DPoint(AG.x(srcNode), AG.y(srcNode))); - - B.conc(dp); - l.conc(B); - - iti = f->nextFaceEdge(iti); - continue; - } - - //CASE B: we have crossings, but no bends on the edge - if (dp.empty()) - { - DPoint dp1; - if (srcNode) - dp1 = DPoint(AG.x(srcNode), AG.y(srcNode)); - else - dp1 = DPoint(m_crossPosition[(iti)->theNode()]); - - l.pushBack(dp1); - - iti = f->nextFaceEdge(iti); - continue; - } - - //CASE C: we have crossings on the original edge, - //we need to exactly define the list of bends/crossings - //on the COPY edge (bends are not nodes here!) - - node tgtNode = PG.original((iti->twin())->theNode()); - //three cases: - //1) From original to crossing - bool case1 = (srcNode != 0); - //2) From crossing to original - bool case2 = (tgtNode != 0); - //3) From crossing to crossing - //fuers debuggen eigentlich testen: beide Kreuzungen - bool case3 = !(case1 || case2); - - //We basically run through all the bends on the original edge - //to check where the crossing lies - //maybe we can save some time if we save this for consecutive - //segments of the same edge (but may be non-contiguous) - - //die drei cases in Funktion DPolyline getSegmentBends() packen - if (case1) - { - OGDF_ASSERT(!case2) - OGDF_ASSERT((iti->twin())->theNode()->degree() == 4) - DPoint sNode = DPoint(AG.x(srcNode), AG.y(srcNode)); - //sourceNode is on face border - B.pushFront(sNode); - //search segment with crossing point - //if (!(dp.empty())) always a bend in Case C - { - DPoint p1 = m_crossPosition[(iti->twin())->theNode()]; - - //Searchloop - ListIterator it = dp.begin(); - DPoint tNode = (*it); - DLine dl(sNode, tNode); - while(!(dl.contains(p1))) - { - B.pushBack(tNode); - it = it.succ(); - sNode = tNode; - if (it.valid()) - { - tNode = (*it); - dl = DLine(sNode, tNode); - } - else break; - }//while - - }//if bends - }//case1 - - //case 2: segment from crossing to original node - if (case2) - { - OGDF_ASSERT(!case1) - OGDF_ASSERT(iti->theNode()->degree() == 4) - - DPoint dp1 = m_crossPosition[(iti)->theNode()]; - B.pushFront(dp1); - //we start searching from the edge's original start node - node srcONode = (reversed ? eOrig->target() : eOrig->source()); - DPoint sNode = DPoint(AG.x(srcONode), AG.y(srcONode)); - //AG.x(srcNode), AG.y(srcNode)); - - //Searchloop - ListIterator it = dp.begin(); - DPoint tNode = (*it); - DLine dl(sNode, tNode); - while(!(dl.contains(dp1))) - { - it = it.succ(); - sNode = tNode; - if (it.valid()) - { - tNode = (*it); - dl = DLine(sNode, tNode); - } - else break; - }//while - while (it.valid()) - { - B.pushBack((*it)); - it++; - }//while valid - - }//case2 - if (case3) - { - //first, we search for the position of the first crossing, - //then look for the second - DPoint dp1 = m_crossPosition[(iti)->theNode()]; - DPoint dp2 = m_crossPosition[(iti->twin())->theNode()]; - - B.pushFront(dp1); - //we start searching from the edge's original start node - node srcONode = (reversed ? eOrig->target() : eOrig->source()); - DPoint sNode = DPoint(AG.x(srcONode), AG.y(srcONode)); - //DPoint sNode = DPoint(AG.x(srcNode), AG.y(srcNode)); - //Searchloop1 - ListIterator it = dp.begin(); - DPoint tNode = (*it); - DLine dl(sNode, tNode); - while (!(dl.contains(dp1))) - { - it = it.succ(); - sNode = tNode; - if (it.valid()) - { - tNode = (*it); - dl = DLine(sNode, tNode); - } - else break; - }//while - //are there any bends after crossing 1? - if (it.valid()) - { - //search for dp2 - while (!(dl.contains(dp2))) - { - B.pushBack(tNode); - it = it.succ(); - sNode = tNode; - if (it.valid()) - { - tNode = (*it); - dl = DLine(sNode, tNode); - } - else break; - } - }//if still bends after crossing1 - - } - - l.conc(B); - //it++; - iti = f->nextFaceEdge(iti); - } - ListIterator it = l.begin(); - - while (it.valid()) - { - //DPoint p = (*it), r = (*( l.cyclicPred(it) )), q = (*( l.cyclicSucc(it) )); - DPoint p = (*it), r = (*( l.cyclicSucc(it) )), q = (*( l.cyclicPred(it) )); - rho += angle(p, r, q) - Math::pi; - it++; - } - - return rho; -}//faceSum - - -face TopologyModule::getExternalFace( - PlanRep &PG, - const GraphAttributes &AG) -{ - CombinatorialEmbedding E(PG); //computes faces - - face f; - forall_faces(f, E) - { - if (faceSum(PG, AG, f) < 0) return f; - - }//forall faces - - //debug or release? sollte das abgefangen werden?? - throw AlgorithmFailureException(afcExternalFace); - - //return 0; - -} - - -bool TopologyModule::skipable(EdgeLeg* legA, EdgeLeg* legB) -{ - //we spare out edgelegs of the same edge - //TODO: if we widen the definition for allowed input shapes, - //this should be reviewed, e.g. selfcrossings - if (legA->copyEdge() == legB->copyEdge()) return true; - //we check if endpoints of one edge lie on the other edge - //which can be the case for merger (this can also be the case - //if an edge cuts a vertex, we have to reembed then) - //TODO: SPEED do not allocate these variables twice - double x1 = legA->start().m_x; - double x2 = legA->end().m_x; - double y1 = legA->start().m_y; - double y2 = legA->end().m_y; - - double xB1 = legB->start().m_x; - double xB2 = legB->end().m_x; - double yB1 = legB->start().m_y; - double yB2 = legB->end().m_y; - DPoint s1(x1, y1), t1(x2, y2), - s2(xB1, yB1), t2(xB2, yB2); - DLine l1(s1,t1), l2(s2,t2); - if (l1.contains(s2) || l1.contains(t2) || - l2.contains(s1) || l2.contains(t1)) - return true; - return false; -} - - -//TODO: implement this efficiently, do not create all the -//variables every time -//returns true if edgeLegs leg1 and leg2 cross each other -bool TopologyModule::hasCrossing(EdgeLeg* legA, EdgeLeg* legB, DPoint& xp) -{ - //we can skip this for same special cases - if (skipable(legA, legB)) return false; - - //Could be more efficient with integers... - double x1 = legA->start().m_x; - double x2 = legA->end().m_x; - double y1 = legA->start().m_y; - double y2 = legA->end().m_y; - - double xB1 = legB->start().m_x; - double xB2 = legB->end().m_x; - double yB1 = legB->start().m_y; - double yB2 = legB->end().m_y; - - double aVal1 = x2 - x1; - double aVal2 = y2 - y1; - double bVal1 = xB2 - xB1; - double bVal2 = yB2 - yB1; - - if ( ((DIsLess(aVal1*yB1 - aVal2*xB1, - aVal1*y1 - aVal2*x1)) - ^ - (DIsLess(aVal1*yB2 - aVal2*xB2, - aVal1*y1 - aVal2*x1))) - && - ((DIsLess(bVal1*y1 - bVal2*x1, - bVal1*yB1 - bVal2*xB1)) - ^ - (DIsLess(bVal1*y2 - bVal2*x2, - bVal1*yB1 - bVal2*xB1))) - ) - { - // we only do the geometric computation with division - // if really necessary - DPoint s1(x1, y1), t1(x2, y2), - s2(xB1, yB1), t2(xB2, yB2); - DLine l1(s1,t1), l2(s2,t2); - - bool result = l1.intersection(l2, xp, false); - //due to the false parameter, this might not be the case: - //OGDF_ASSERT(result); - return result; - } - return false; -} - - -bool TopologyModule::checkFlipCrossing(PlanRep& PG, node v, bool flip) -{ - if (v->indeg() != 2) return false; - - if (PG.isCrossingType(v)) - { - bool crossing = false; - OGDF_ASSERT(v->degree() == 4) - adjEntry a1 = v->firstAdj(); - adjEntry b1 = a1->cyclicSucc(); - adjEntry a2 = b1->cyclicSucc(); - adjEntry b2 = a2->cyclicSucc(); - //----------------------------------------- - //check if the edges have a common endpoint - node va1 = a1->twinNode(); - node va2 = a2->twinNode(); - node vb1 = b1->twinNode(); - node vb2 = b2->twinNode(); - - //to match the crossflip case, two successive edges - //need to have the same endpoint, with original node - if (PG.original(va1)) - { - if (va1 == vb1) //case1 - { - if (m_options & opFlipUML) - { - if ( (PG.isGeneralization(a1->theEdge()) && !(PG.isGeneralization(b1->theEdge())) ) - || - (PG.isGeneralization(b1->theEdge()) && !(PG.isGeneralization(a1->theEdge()))) - ) - { - return false; - } - - }//if only equal type flip - crossing = true; - //remove the crossing and flip the order - //in removeCrossing, the first two adjacency entries survive - if (flip) - { - PG.removeCrossing(v); - //TODO: check did the adjentries survive? - //TODO: check is it behind or before adj? - - if (a1->twin() == b1->twin()->cyclicSucc()) - { - PG.moveAdj(a1->twin(), before,b1->twin()); - } - else - { - OGDF_ASSERT(a1->twin() == b1->twin()->cyclicPred()) - } - } - - } - else //TODO: check can both b1, b2 be the same? - if (va1 == vb2) - { - //check if flipping allowed - if (m_options & opFlipUML) - { - if ( (PG.isGeneralization(a1->theEdge()) && - !(PG.isGeneralization(b2->theEdge())) ) - || - (PG.isGeneralization(b2->theEdge()) && - !(PG.isGeneralization(a1->theEdge()))) - ) - { - return false; - } - - }//if only equal type flip - //see comments in case1 - crossing = true; - if (flip) - { - PG.removeCrossing(v); - OGDF_ASSERT(a1->twin() == b1->cyclicPred()) - PG.moveAdj(a1->twin(), after, b1); - } - } - }//if va1 - if (PG.original(va2)) - { - if (va2 == vb1) - { - //check if flipping allowed - if (m_options & opFlipUML) - { - if ( (PG.isGeneralization(a2->theEdge()) && !(PG.isGeneralization(b1->theEdge())) ) - || - (PG.isGeneralization(b1->theEdge()) && !(PG.isGeneralization(a2->theEdge()))) - ) - { - return false; - } - - }//if only equal type flip - crossing = true; - //see comments in case1 - if (flip) - { - PG.removeCrossing(v); - OGDF_ASSERT(a1 == b1->twin()->cyclicPred()) - PG.moveAdj(a1, after,b1->twin()); - } - } - else - if (va2 == vb2) - { - //check if flipping allowed - if (m_options & opFlipUML) - { - if ( (PG.isGeneralization(a2->theEdge()) && - !(PG.isGeneralization(b2->theEdge())) ) - || - (PG.isGeneralization(b2->theEdge()) && - !(PG.isGeneralization(a2->theEdge()))) - ) - { - return false; - } - - }//if only equal type flip - crossing = true; - if (flip) - { - PG.removeCrossing(v); - OGDF_ASSERT(a1 == b1->cyclicSucc()) - PG.moveAdj(a1, before,b1); - } - - } - - }//if va2 - return crossing; - }//if iscrossingtype - - return false; -}//checkflipcrossing - - -/*copied back from umlgraph -//sorts the edges around all nodes of AG corresponding to the -//layout given in AG -//there is no check of the embedding afterwards because this -//method could be used as a first step of a planarization -void TopologyModule::sortEdgesFromLayout(GraphAttributes& AG) -{ - //we order the edges around each node corresponding to - //the input embedding in the GraphAttributes layout - NodeArray > adjList(*m_pG); - - EdgeComparer* ec = new EdgeComparer(*this); - - node v; - adjEntry ae; - forall_nodes(v, *m_pG) - { - forall_adj(ae, v) - { - adjList[v].pushBack(ae); - }//forall adjacency edges - //sort the entries - adjList[v].quicksort(*ec); - m_pG->sort(v, adjList[v]); - - }//forall nodes - - delete ec; -}//sortedgesfromlayout -*/ - -//computes angle between vectors, used to compute external face -double TopologyModule::angle(DPoint p, DPoint q, DPoint r) -{ - double dx1 = q.m_x - p.m_x, dy1 = q.m_y - p.m_y; - double dx2 = r.m_x - p.m_x, dy2 = r.m_y - p.m_y; - - //two vertices on the same place! - if ((dx1 == 0 && dy1 == 0) || (dx2 == 0 && dy2 == 0)) - return 0.0; - - double norm = (dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2); - - double cosphi = (dx1*dx2+dy1*dy2) / sqrt(norm); - - if (cosphi >= 1.0 ) return 0; if (cosphi <= -1.0 ) return Math::pi; - - double phi = acos(cosphi); - - if (dx1*dy2 < dy1*dx2) phi = -phi; - - if (phi < 0) phi += 2*Math::pi; - - return phi; -} - - -//is independent of y-axis flipping -int PointComparer::compare(const ListIterator &ep1, const ListIterator &ep2) const -{ - DPoint p1 = (*ep1)->m_xp; - DPoint p2 = (*ep2)->m_xp; - //we compute the distance of the two points to - //our reference and return the corresponding ordering - //-1 if p1 closer than p2 - double xdiff1 = p1.m_x - m_refPoint.m_x; - double xdiff2 = p2.m_x - m_refPoint.m_x; - double ydiff1 = p1.m_y - m_refPoint.m_y; - double ydiff2 = p2.m_y - m_refPoint.m_y; - double dist1 = sqrt(xdiff1*xdiff1 + ydiff1*ydiff1); - double dist2 = sqrt(xdiff2*xdiff2 + ydiff2*ydiff2); - - if (dist1 == dist2) return 0; - return (dist1 < dist2 ? -1 : 1); //original: -1 1 -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarity/VariableEmbeddingInserter.cpp b/ext/OGDF/src/planarity/VariableEmbeddingInserter.cpp deleted file mode 100644 index 1f7d5d5d9..000000000 --- a/ext/OGDF/src/planarity/VariableEmbeddingInserter.cpp +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief implements class VariableEmbeddingInserter - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include - - -namespace ogdf { - -int VariableEmbeddingInserter::m_bigM = 10000; - -//--------------------------------------------------------- -// constructor -// sets default values for options -// -VariableEmbeddingInserter::VariableEmbeddingInserter() -{ - m_rrOption = rrNone; - m_percentMostCrossed = 25; -} - - -//--------------------------------------------------------- -// VEICrossingsBucket -// bucket function for sorting edges by decreasing number -// of crossings -class VEICrossingsBucket : public BucketFunc -{ - const PlanRep *m_pPG; - -public: - VEICrossingsBucket(const PlanRep *pPG) : - m_pPG(pPG) { } - - int getBucket(const edge &e) { - return -m_pPG->chain(e).size(); - } -}; - - - -//--------------------------------------------------------- -// actual call (called by all variations of call) -// crossing of generalizations is forbidden if forbidCrossingGens = true -// edge costs are obeyed if costOrig != 0 -// -Module::ReturnType VariableEmbeddingInserter::doCall( - PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig, - const EdgeArray *edgeSubgraph) -{ - double T; - usedTime(T); - - ReturnType retValue = retFeasible; - m_runsPostprocessing = 0; - - if (origEdges.size() == 0) - return retOptimal; // nothing to do - - OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0); - - m_pPG = &PG; - m_forbidCrossingGens = forbidCrossingGens; - m_costOrig = costOrig; - m_forbiddenEdgeOrig = forbiddenEdgeOrig; - m_edgeSubgraph = edgeSubgraph; - - SListPure currentOrigEdges; - if(removeReinsert() == rrIncremental) { - edge e; - forall_edges(e,PG) - currentOrigEdges.pushBack(PG.original(e)); - } - - // insertion of edges - ListConstIterator it; - for(it = origEdges.begin(); it.valid(); ++it) - { - edge eOrig = *it; - m_typeOfCurrentEdge = m_forbidCrossingGens ? ((PlanRepUML&)PG).typeOrig(eOrig) : Graph::association; - - SList eip; - m_st = eOrig; //save original edge for simdraw cost calculation in dfsvertex - insert(PG.copy(eOrig->source()),PG.copy(eOrig->target()),eip); - - PG.insertEdgePath(eOrig,eip); - - if(removeReinsert() == rrIncremental || removeReinsert() == rrIncInserted) { - currentOrigEdges.pushBack(eOrig); - - bool improved; - do { - ++m_runsPostprocessing; - improved = false; - - SListConstIterator itRR; - for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR) - { - edge eOrigRR = *itRR; - - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrigRR); - else - pathLength = PG.chain(eOrigRR).size() - 1; - if (pathLength == 0) continue; // cannot improve - - PG.removeEdgePath(eOrigRR); - - m_typeOfCurrentEdge = m_forbidCrossingGens ? ((PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association; - - SList eip; - m_st = eOrigRR; - insert(PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()),eip); - PG.insertEdgePath(eOrigRR,eip); - - int newPathLength = (costOrig != 0) ? costCrossed(eOrigRR) : (PG.chain(eOrigRR).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - } - } - - - if(removeReinsert() != rrIncremental && removeReinsert() != rrIncInserted) { - // postprocessing (remove-reinsert heuristc) - const Graph &G = PG.original(); - SListPure rrEdges; - - switch(removeReinsert()) - { - case rrAll: - case rrMostCrossed: { - const List &origInCC = PG.nodesInCC(); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - rrEdges.pushBack(eG); - } - } - } - break; - - case rrInserted: - for(ListConstIterator it = origEdges.begin(); it.valid(); ++it) - rrEdges.pushBack(*it); - break; - - case rrNone: - case rrIncremental: - case rrIncInserted: - break; - } - - - - // marks the end of the interval of rrEdges over which we iterate - // initially set to invalid iterator which means all edges - SListConstIterator itStop; - - bool improved; - do { - // abort postprocessing if time limit reached - if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) { - retValue = retTimeoutFeasible; - break; - } - - ++m_runsPostprocessing; - improved = false; - - if(removeReinsert() == rrMostCrossed) - { - VEICrossingsBucket bucket(&PG); - rrEdges.bucketSort(bucket); - - const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); - itStop = rrEdges.get(num); - } - - SListConstIterator it; - for(it = rrEdges.begin(); it != itStop; ++it) - { - edge eOrig = *it; - - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrig); - else - pathLength = PG.chain(eOrig).size() - 1; - if (pathLength == 0) continue; // cannot improve - - PG.removeEdgePath(eOrig); - - m_typeOfCurrentEdge = m_forbidCrossingGens ? ((PlanRepUML&)PG).typeOrig(eOrig) : Graph::association; - - SList eip; - m_st = eOrig; - insert(PG.copy(eOrig->source()),PG.copy(eOrig->target()),eip); - PG.insertEdgePath(eOrig,eip); - - // we cannot find a shortest path that is longer than before! - int newPathLength = (costOrig != 0) ? costCrossed(eOrig) : (PG.chain(eOrig).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - } - -#ifdef OGDF_DEBUG - bool isPlanar = -#endif - planarEmbed(PG); - - OGDF_ASSERT(isPlanar); - - PG.removePseudoCrossings(); - OGDF_ASSERT(PG.representsCombEmbedding()); - OGDF_ASSERT(forbidCrossingGens == false || checkCrossingGens((const PlanRepUML&)PG) == true); - - return retValue; -} - - -Module::ReturnType VariableEmbeddingInserter::doCallPostprocessing( - PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig, - const EdgeArray *edgeSubgraph) -{ - double T; - usedTime(T); - ReturnType retValue = retFeasible; - m_runsPostprocessing = 0; - - if (origEdges.size() == 0) - return retOptimal; // nothing to do - - if(removeReinsert() == rrIncremental || removeReinsert() == rrIncInserted) - return retFeasible; - - OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0); - - m_pPG = &PG; - m_forbidCrossingGens = forbidCrossingGens; - m_costOrig = costOrig; - m_forbiddenEdgeOrig = forbiddenEdgeOrig; - m_edgeSubgraph = edgeSubgraph; - - SListPure currentOrigEdges; - - // postprocessing (remove-reinsert heuristc) - const Graph &G = PG.original(); - SListPure rrEdges; - - switch(removeReinsert()) - { - case rrAll: - case rrMostCrossed: { - const List &origInCC = PG.nodesInCC(); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - rrEdges.pushBack(eG); - } - } - } - break; - - case rrInserted: - for(ListConstIterator it = origEdges.begin(); it.valid(); ++it) - rrEdges.pushBack(*it); - break; - - case rrNone: - case rrIncremental: - case rrIncInserted: - break; - } - - - - // marks the end of the interval of rrEdges over which we iterate - // initially set to invalid iterator which means all edges - SListConstIterator itStop; - - bool improved; - do { - // abort postprocessing if time limit reached - if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) { - retValue = retTimeoutFeasible; - break; - } - - ++m_runsPostprocessing; - improved = false; - - if(removeReinsert() == rrMostCrossed) - { - VEICrossingsBucket bucket(&PG); - rrEdges.bucketSort(bucket); - - const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); - itStop = rrEdges.get(num); - } - - SListConstIterator it; - for(it = rrEdges.begin(); it != itStop; ++it) - { - edge eOrig = *it; - - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrig); - else - pathLength = PG.chain(eOrig).size() - 1; - if (pathLength == 0) continue; // cannot improve - - PG.removeEdgePath(eOrig); - - m_typeOfCurrentEdge = m_forbidCrossingGens ? ((PlanRepUML&)PG).typeOrig(eOrig) : Graph::association; - - SList eip; - m_st = eOrig; - insert(PG.copy(eOrig->source()),PG.copy(eOrig->target()),eip); - PG.insertEdgePath(eOrig,eip); - - // we cannot find a shortest path that is longer than before! - int newPathLength = (costOrig != 0) ? costCrossed(eOrig) : (PG.chain(eOrig).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - -#ifdef OGDF_DEBUG - bool isPlanar = -#endif - planarEmbed(PG); - - OGDF_ASSERT(isPlanar); - - PG.removePseudoCrossings(); - OGDF_ASSERT(PG.representsCombEmbedding()); - OGDF_ASSERT(forbidCrossingGens == false || checkCrossingGens((const PlanRepUML&)PG) == true); - - return retValue; -} - - -edge VariableEmbeddingInserter::crossedEdge(adjEntry adj) const -{ - edge e = adj->theEdge(); - - adj = adj->cyclicSucc(); - while(adj->theEdge() == e) - adj = adj->cyclicSucc(); - - return adj->theEdge(); -} - - -int VariableEmbeddingInserter::costCrossed(edge eOrig) const -{ - int c = 0; - - const List &L = m_pPG->chain(eOrig); - - ListConstIterator it = L.begin(); - if(m_edgeSubgraph != 0) { - for(++it; it.valid(); ++it) { - int counter = 0; - edge e = m_pPG->original(crossedEdge((*it)->adjSource())); - for(int i=0; i<32; i++) - if((*m_edgeSubgraph)[eOrig] & (*m_edgeSubgraph)[e] & (1<original(crossedEdge((*it)->adjSource()))]; - } - } - - return c; -} - - -//------------------------------------------------------------------- -// find optimal edge insertion path from s to t in connected -// graph G -//------------------------------------------------------------------- - -void VariableEmbeddingInserter::insert(node s, - node t, - SList &eip) -{ - PlanRep &PG = *m_pPG; - eip.clear(); - - m_s = s; m_t = t; - m_pEip = &eip; - - // compute biconnected components of PG - EdgeArray compnum(PG); - int c = biconnectedComponents(PG,compnum); - - m_compV.init(PG); - m_nodeB.init(c); - - // edgeB[i] = list of edges in component i - m_edgeB.init(c); - edge e; - forall_edges(e,PG) - m_edgeB[compnum[e]].pushBack(e); - - // construct arrays compV and nodeB such that - // m_compV[v] = list of components containing v - // m_nodeB[i] = list of vertices in component i - NodeArray mark(PG,false); - - int i; - for(i = 0; i < c; ++i) { - SListConstIterator itEdge; - for(itEdge = m_edgeB[i].begin(); itEdge.valid(); ++itEdge) - { - edge e = *itEdge; - - if (!mark[e->source()]) { - mark[e->source()] = true; - m_nodeB[i].pushBack(e->source()); - } - if (!mark[e->target()]) { - mark[e->target()] = true; - m_nodeB[i].pushBack(e->target()); - } - } - - SListConstIterator itNode; - for(itNode = m_nodeB[i].begin(); itNode.valid(); ++itNode) - { - node v = *itNode; - m_compV[v].pushBack(i); - mark[v] = false; - } - } - mark.init(); - - // find path from s to t in BC-tree - // call of blockInsert() is done in dfs_vertex() when we have found the - // path and we return from the recursion. - // if no path is found, s and t are in different connected components - // and thus an empty edge insertion path is correct! - m_GtoBC.init(PG,0); - dfsVertex(s,-1); - - // deallocate resources used by insert() - m_GtoBC.init(); - m_edgeB.init(); - m_nodeB.init(); - m_compV.init(); -} - - -class BiconnectedComponent : public Graph -{ -public: - // constructor - BiconnectedComponent() - { - m_BCtoG .init(*this); - m_cost .init(*this,1); - m_typeOf.init(*this, Graph::association); - } - - void cost(edge e, int c) { - m_cost[e] = c; - } - - int cost(edge e) const { - return m_cost[e]; - } - - void typeOf(edge e, EdgeType et) { - m_typeOf[e] = et; - } - - EdgeType typeOf(edge e) const { - return m_typeOf[e]; - } - - AdjEntryArray m_BCtoG; - -private: - EdgeArray m_cost; - EdgeArray m_typeOf; -}; - - - -//------------------------------------------------------------------- -// recursive path search from s to t in BC-tree (vertex case) -//------------------------------------------------------------------- - -bool VariableEmbeddingInserter::dfsVertex(node v, int parent) -{ - // forall biconnected components containing v (except predecessor parent) - SListConstIterator itI; - for(itI = m_compV[v].begin(); itI.valid(); ++itI) - { - int i = *itI; - - if (i == parent) continue; - - node repT; // representative of t in B(i) - if (dfsComp(i,v,repT) == true) { // path found? - // build graph BC of biconnected component B(i) - SList nodesG; - BiconnectedComponent BC; - - SListConstIterator itE; - for(itE = m_edgeB[i].begin(); itE.valid(); ++itE) - { - edge e = *itE; - - if (m_GtoBC[e->source()] == 0) { - m_GtoBC[e->source()] = BC.newNode(); - nodesG.pushBack(e->source()); - } - if (m_GtoBC[e->target()] == 0) { - m_GtoBC[e->target()] = BC.newNode(); - nodesG.pushBack(e->target()); - } - - edge eBC = BC.newEdge(m_GtoBC[e->source()],m_GtoBC[e->target()]); - BC.m_BCtoG[eBC->adjSource()] = e->adjSource(); - BC.m_BCtoG[eBC->adjTarget()] = e->adjTarget(); - - BC.typeOf(eBC, m_forbidCrossingGens ? ((PlanRepUML*)m_pPG)->typeOf(e) : Graph::association); - edge eOrig = m_pPG->original(e); - if(m_costOrig != 0) { - if(m_edgeSubgraph != 0) { - int counter = 0; - for(int i = 0; i<32; i++) - if((*m_edgeSubgraph)[m_st] & (*m_edgeSubgraph)[eOrig] & (1<= 3) { - List L; - blockInsert(BC,m_GtoBC[v],m_GtoBC[repT],L); // call biconnected case - - // transform crossed edges to edges in G - ListConstIterator it; - for(it = L.rbegin(); it.valid(); --it) { - m_pEip->pushFront(BC.m_BCtoG[*it]); - } - } - - // set entries of GtoBC back to nil (GtoBC allocated only once - // in insert()!) - SListConstIterator itV; - for(itV = nodesG.begin(); itV.valid(); ++itV) - m_GtoBC[*itV] = 0; - - return true; // path found - } - } - - return false; // path not found -} - - - -//------------------------------------------------------------------- -// recursive path search from s to t in BC-tree (component case) -//------------------------------------------------------------------- - -bool VariableEmbeddingInserter::dfsComp(int i, node parent, node &repT) -{ - // forall nodes in biconected component B(i) (except predecessor parent) - SListConstIterator it; - for(it = m_nodeB[i].begin(); it.valid(); ++it) - { - repT = *it; - - if (repT == parent) continue; - if (repT == m_t) { // t found? - return true; - } - if (dfsVertex(repT,i) == true) { - return true; // path found - } - } - - return false; // path not found -} - - - -//------------------------------------------------------------------- -// ExpandedGraph represents the (partially) expanded graph with -// its augmented dual -//------------------------------------------------------------------- - -class ExpandedGraph -{ - const StaticSPQRTree &m_T; - const BiconnectedComponent &m_BC; - - NodeArray m_GtoExp; - List m_nodesG; - Graph m_exp; // expanded graph - ConstCombinatorialEmbedding m_E; - AdjEntryArray m_expToG; - edge m_eS, m_eT; // (virtual) edges in exp representing s and t (if any) - - Graph m_dual; // augmented dual graph of exp - EdgeArray m_primalEdge; - EdgeArray m_primalIsGen; // true iff corresponding primal edge is a generalization - - node m_vS, m_vT; // augmented nodes in dual representing s and t - -public: - ExpandedGraph(const BiconnectedComponent &BC, const StaticSPQRTree &T); - - void expand(node v, edge eIn, edge eOut); - - void constructDual(node s, node t, GraphCopy &GC, const EdgeArray *forbiddenEdgeOrig); - void constructDualForbidCrossingGens(node s, node t); - - void findShortestPath(Graph::EdgeType eType, List &L); - void findWeightedShortestPath(Graph::EdgeType eType, - List &L); - - int costDual(edge eDual) const { - adjEntry adjExp = m_primalEdge[eDual]; - return (adjExp == 0) ? 0 : m_BC.cost(m_expToG[adjExp]->theEdge()); - } - - // avoid automatic creation of assignment operator - ExpandedGraph &operator=(const ExpandedGraph &); - -private: - edge insertEdge(node vG, node wG, edge eG); - void expandSkeleton(node v, edge e1, edge e2); -}; - - -ExpandedGraph::ExpandedGraph(const BiconnectedComponent &BC,const StaticSPQRTree &T) - : m_T(T), m_BC(BC), - m_GtoExp(T.originalGraph(),0), m_expToG(m_exp,0), - m_primalEdge(m_dual,0), m_primalIsGen(m_dual,false) -{ -} - - -//------------------------------------------------------------------- -// build expanded graph (by expanding skeleton(v), edges eIn and eOut -// are the adjacent tree edges on the path from v1 to v2 -//------------------------------------------------------------------- - -void ExpandedGraph::expand(node v, edge eIn, edge eOut) -{ - m_exp.clear(); - while (!m_nodesG.empty()) - m_GtoExp[m_nodesG.popBackRet()] = 0; - - const Skeleton &S = m_T.skeleton(v); - - if (eIn != 0) { - edge eInS = (v != eIn->source()) ? m_T.skeletonEdgeTgt(eIn) : - m_T.skeletonEdgeSrc(eIn); - node x = S.original(eInS->source()), y = S.original(eInS->target()); - m_eS = insertEdge(x,y,0); - } - if (eOut != 0) { - edge eOutS = (v != eOut->source()) ? m_T.skeletonEdgeTgt(eOut) : - m_T.skeletonEdgeSrc(eOut); - node x = S.original(eOutS->source()), y = S.original(eOutS->target()); - m_eT = insertEdge(x,y,0); - } - - expandSkeleton(v, eIn, eOut); - - planarEmbed(m_exp); - m_E.init(m_exp); -} - - -//------------------------------------------------------------------- -// expand one skeleton (recursive construction) -//------------------------------------------------------------------- - -void ExpandedGraph::expandSkeleton(node v, edge e1, edge e2) -{ - const StaticSkeleton &S = *dynamic_cast(&m_T.skeleton(v)); - const Graph &M = S.getGraph(); - - edge e; - forall_edges(e,M) - { - edge eG = S.realEdge(e); - if (eG != 0) { - insertEdge(eG->source(),eG->target(),eG); - - } else { - edge eT = S.treeEdge(e); - - // do not expand virtual edges corresponding to tree edges e1 or e2 - if (eT != e1 && eT != e2) { - expandSkeleton((v == eT->source()) ? eT->target() : eT->source(), - eT,0); - } - } - } -} - - -//------------------------------------------------------------------- -// insert edge in exp (from a node corresponding to vG in G to a node -// corresponding to wG) -//------------------------------------------------------------------- - -edge ExpandedGraph::insertEdge(node vG, node wG, edge eG) -{ - node &rVG = m_GtoExp[vG]; - node &rWG = m_GtoExp[wG]; - - if (rVG == 0) { - rVG = m_exp.newNode(); - m_nodesG.pushBack(vG); - } - if (rWG == 0) { - rWG = m_exp.newNode(); - m_nodesG.pushBack(wG); - } - - edge e1 = m_exp.newEdge(rVG,rWG); - - if(eG != 0) { - m_expToG[e1->adjSource()] = eG->adjSource(); - m_expToG[e1->adjTarget()] = eG->adjTarget(); - } else { - m_expToG[e1->adjSource()] = 0; - m_expToG[e1->adjTarget()] = 0; - } - - return e1; -} - - -//------------------------------------------------------------------- -// construct augmented dual of exp -//------------------------------------------------------------------- - -void ExpandedGraph::constructDual(node s, node t, - GraphCopy &GC, const EdgeArray *forbiddenEdgeOrig) -{ - m_dual.clear(); - - FaceArray faceNode(m_E); - - // constructs nodes (for faces in exp) - face f; - forall_faces(f,m_E) { - faceNode[f] = m_dual.newNode(); - } - - // construct dual edges (for primal edges in exp) - node v; - forall_nodes(v,m_exp) - { - adjEntry adj; - forall_adj(adj,v) - { - // cannot cross edges that does not correspond to real edges - adjEntry adjG = m_expToG[adj]; - if(adjG == 0) - continue; - - // Do not insert edges into dual if crossing the original edge - // is forbidden - if(forbiddenEdgeOrig && - (*forbiddenEdgeOrig)[GC.original(m_BC.m_BCtoG[m_expToG[adj]]->theEdge())] == true) - continue; - - node vLeft = faceNode[m_E.leftFace (adj)]; - node vRight = faceNode[m_E.rightFace(adj)]; - - m_primalEdge[m_dual.newEdge(vLeft,vRight)] = adj; - } - } - - // augment dual by m_vS and m_vT - m_vS = m_dual.newNode(); - if (m_GtoExp[s] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[s]) - m_dual.newEdge(m_vS,faceNode[m_E.rightFace(adj)]); - } - else - { - m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjSource())]); - m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjTarget())]); - } - - m_vT = m_dual.newNode(); - if (m_GtoExp[t] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[t]) - m_dual.newEdge(faceNode[m_E.rightFace(adj)], m_vT); - } - else - { - m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjSource())], m_vT); - m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjTarget())], m_vT); - } -} - - -void ExpandedGraph::constructDualForbidCrossingGens(node s, node t) -{ - m_dual.clear(); - - FaceArray faceNode(m_E); - - // constructs nodes (for faces in exp) - face f; - forall_faces(f,m_E) { - faceNode[f] = m_dual.newNode(); - } - - edge eDual; - // construct dual edges (for primal edges in exp) - node v; - forall_nodes(v,m_exp) - { - adjEntry adj; - forall_adj(adj,v) - { - // cannot cross edges that does not correspond to real edges - adjEntry adjG = m_expToG[adj]; - if(adjG == 0) - continue; - - node vLeft = faceNode[m_E.leftFace (adj)]; - node vRight = faceNode[m_E.rightFace(adj)]; - - edge e = m_dual.newEdge(vLeft,vRight); - m_primalEdge[e] = adj; - - // mark dual edges corresponding to generalizations - if (adjG && m_BC.typeOf(adjG->theEdge()) == Graph::generalization) - m_primalIsGen[e] = true; - - OGDF_ASSERT(m_primalEdge[e] == 0 || m_expToG[m_primalEdge[e]] != 0); - } - } - - // augment dual by m_vS and m_vT - m_vS = m_dual.newNode(); - if (m_GtoExp[s] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[s]) { - eDual = m_dual.newEdge(m_vS,faceNode[m_E.rightFace(adj)]); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } - } - else - { - eDual = m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjSource())]); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - - eDual = m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjTarget())]); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } - - m_vT = m_dual.newNode(); - if (m_GtoExp[t] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[t]) { - eDual = m_dual.newEdge(faceNode[m_E.rightFace(adj)], m_vT); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } - } - else - { - eDual = m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjSource())], m_vT); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - - eDual = m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjTarget())], m_vT); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } -} - - -//------------------------------------------------------------------- -// find shortest path in dual from m_vS to m_vT; output this path -// in L by omitting first and last edge, and translating edges to G -//------------------------------------------------------------------- - -void ExpandedGraph::findShortestPath(Graph::EdgeType eType, List &L) -{ - NodeArray spPred(m_dual,0); // predecessor in shortest path tree - List queue; // candidate edges - - // start with all edges leaving from m_vS - edge e; - forall_adj_edges(e,m_vS) - queue.pushBack(e); - - for( ; ; ) { - edge eCand = queue.popFrontRet(); // next candidate from front of queue - node v = eCand->target(); - - // hit an unvisited node ? - if (spPred[v] == 0) { - spPred[v] = eCand; - - // if it is m_vT, we have found the shortest path - if (v == m_vT) { - // build path from shortest path tree - while(v != m_vS) { - adjEntry adjExp = m_primalEdge[spPred[v]]; - if (adjExp != 0) // == nil for first and last edge - L.pushFront(m_expToG[adjExp]); - v = spPred[v]->source(); - } - return; - } - - // append next candidates to end of queue - forall_adj_edges(e,v) { - if(v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - queue.pushBack(e); - } - } - } - } -} - - -//------------------------------------------------------------------- -// find weighted shortest path in dual from m_vS to m_vT; output this path -// in L by omitting first and last edge, and translating edges to G -//------------------------------------------------------------------- - -void ExpandedGraph::findWeightedShortestPath(Graph::EdgeType eType, - List &L) -{ - int maxCost = 0; - edge eDual; - forall_edges(eDual,m_dual) { - int c = costDual(eDual); - if (c > maxCost) maxCost = c; - } - - ++maxCost; - Array > nodesAtDist(maxCost); - - NodeArray spPred(m_dual,0); // predecessor in shortest path tree - //List queue; // candidate edges - - // start with all edges leaving from m_vS - edge e; - forall_adj_edges(e,m_vS) - nodesAtDist[0].pushBack(e); - - // actual search (using extended bfs on directed dual) - int currentDist = 0; - for( ; ; ) { - // next candidate edge - while(nodesAtDist[currentDist % maxCost].empty()) - ++currentDist; - - edge eCand = nodesAtDist[currentDist % maxCost].popFrontRet(); - node v = eCand->target(); - - // leads to an unvisited node ? - if (spPred[v] == 0) { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == m_vT) { - // ... then search is done. - // construct list of used edges (translated to crossed - // adjacency entries in G) - while(v != m_vS) { - adjEntry adjExp = m_primalEdge[spPred[v]]; - if (adjExp != 0) // == nil for first and last edge - L.pushFront(m_expToG[adjExp]); - v = spPred[v]->source(); - } - return; - } - - // append next candidates to end of queue - // (all edges leaving v) - forall_adj_edges(e,v) { - if(v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - int listPos = (currentDist + costDual(e)) % maxCost; - nodesAtDist[listPos].pushBack(e); - } - } - } - } -} - - -//------------------------------------------------------------------- -// find optimal edge insertion path from s to t for biconnected -// graph G (OptimalBlockInserter) -//------------------------------------------------------------------- - -void VariableEmbeddingInserter::blockInsert(const BiconnectedComponent &BC, - node s, - node t, - List &L) -{ - L.clear(); - - // construct SPQR-tree - StaticPlanarSPQRTree T(BC); - const Graph &tree = T.tree(); - - - // find allocation nodes of s and t and representatives in skeletons - NodeArray containsS(tree,0); - NodeArray containsT(tree,0); - - node v, w; - forall_nodes(v,tree) { - const Skeleton &S = T.skeleton(v); - const Graph &M = S.getGraph(); - - forall_nodes(w,M) { - if (S.original(w) == s) - containsS[m_v1 = v] = w; - if (S.original(w) == t) - containsT[m_v2 = v] = w; - } - } - - // find path in tree from an allocation node m_v1 of s to an - // allocation m_v2 of t - List path; - pathSearch(m_v1,0,path); - - // remove unnecessary allocation nodes of s from start of path - while(!path.empty() && containsS[w = path.front()->opposite(m_v1)] != 0) - { - m_v1 = w; - path.popFront(); - } - - // remove unnecessary allocation nodes of t from end of path - while(!path.empty() && containsT[w = path.back()->opposite(m_v2)] != 0) - { - m_v2 = w; - path.popBack(); - } - - // call build_subpath for every R-node building the list L of crossed edges - ExpandedGraph Exp(BC,T); - - if (T.typeOf(m_v1) == SPQRTree::RNode) - buildSubpath(m_v1, 0, (path.empty()) ? 0 : path.front(), L, Exp, s, t); - - v = m_v1; - ListConstIterator it; - for(it = path.begin(); it.valid(); ++it) - { - edge e = *it; - v = e->opposite(v); - - if (T.typeOf(v) == SPQRTree::RNode) - buildSubpath(v, e, - (it.succ().valid() == false) ? 0 : *(it.succ()), L, Exp, s, t); - } -} - - -//------------------------------------------------------------------- -// recursive search for path from v1 to v2 in tree -//------------------------------------------------------------------- - -bool VariableEmbeddingInserter::pathSearch(node v, edge parent, List &path) -{ - if (v == m_v2) - return true; - - edge e; - forall_adj_edges(e,v) { - if (e == parent) continue; - if (pathSearch(e->opposite(v),e,path) == true) { - path.pushFront(e); - return true; - } - } - - return false; -} - - -//------------------------------------------------------------------- -// find the shortest path from represent. of s to represent. of t in -// the dual of the (partially) expanded skeleton of v -//------------------------------------------------------------------- - -void VariableEmbeddingInserter::buildSubpath( - node v, - edge eIn, - edge eOut, - List &L, - ExpandedGraph &Exp, - node s, - node t) -{ - // build expanded graph Exp - Exp.expand(v,eIn,eOut); - - // construct augmented dual of expanded graph - if(m_forbidCrossingGens) - Exp.constructDualForbidCrossingGens(s,t); - else - Exp.constructDual(s,t,*m_pPG,m_forbiddenEdgeOrig); - - // find shortest path in augmented dual - List subpath; - if(m_costOrig != 0) - Exp.findWeightedShortestPath(m_typeOfCurrentEdge,subpath); - else - Exp.findShortestPath(m_typeOfCurrentEdge,subpath); - - L.conc(subpath); -} - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarity/VariableEmbeddingInserter2.cpp b/ext/OGDF/src/planarity/VariableEmbeddingInserter2.cpp deleted file mode 100644 index 2b0af6c5c..000000000 --- a/ext/OGDF/src/planarity/VariableEmbeddingInserter2.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class VariableEmbeddingInserter2 - * - * \author Carsten Gutwenger
    Jan Papenfuß - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -namespace ogdf { - -//--------------------------------------------------------- -// BCandSPQRtrees -//--------------------------------------------------------- - -class BCandSPQRtrees { - -private: - - PlanRep* m_pPG; - DynamicSPQRForest m_dynamicSPQRForest; - - bool m_forbidCrossingGens; - const EdgeArray* m_costOrig; - EdgeArray m_cost; - EdgeArray m_typeOf; - -public: - - BCandSPQRtrees (PlanRep* pPG, bool forbidCrossingGens, const EdgeArray* costOrig); - DynamicSPQRForest& dynamicSPQRForest () { return m_dynamicSPQRForest; } - void insertEdgePath (edge eOrig, const SList& crossedEdges); - - void cost (edge e, int c) { m_cost[e] = c; } - int cost (edge e) const { return m_cost[e]; } - void typeOf (edge e, Graph::EdgeType et) { m_typeOf[e] = et; } - Graph::EdgeType typeOf (edge e) const { return m_typeOf[e]; } - -}; - -BCandSPQRtrees::BCandSPQRtrees (PlanRep* pPG, bool forbidCrossingGens, const EdgeArray* costOrig) : m_pPG(pPG), m_dynamicSPQRForest(*pPG), m_forbidCrossingGens(forbidCrossingGens), m_costOrig(costOrig) -{ - const Graph& H = m_dynamicSPQRForest.auxiliaryGraph(); - m_cost.init(H); - m_typeOf.init(H); - edge f; - forall_edges (f,H) { - edge e = m_dynamicSPQRForest.original(f); - m_typeOf[f] = m_forbidCrossingGens ? m_pPG->typeOf(e) : Graph::association; - if (m_costOrig) { - edge eOrig = m_pPG->original(e); - m_cost[f] = eOrig ? (*m_costOrig)[eOrig] : 0; - } - else m_cost[f] = 1; - } -} - -void BCandSPQRtrees::insertEdgePath (edge eOrig, const SList& crossedEdges) -{ - SList ti; - SList tj; - SListConstIterator kt; - for (kt=crossedEdges.begin(); kt.valid(); ++kt) { - ti.pushBack((*kt)->theEdge()); - tj.pushBack((*kt)->theEdge()->target()); - } - - m_pPG->insertEdgePath(eOrig,crossedEdges); - - Graph::EdgeType typeOfEOrig = m_forbidCrossingGens ? m_pPG->typeOrig(eOrig) : Graph::association; - int costOfEOrig = m_costOrig ? eOrig ? (*m_costOrig)[eOrig] : 0 : 1; - - node v = m_pPG->copy(eOrig->source()); - SListConstIterator it = ti.begin(); - SListConstIterator jt = tj.begin(); - for (kt=crossedEdges.begin(); it.valid(); ++it, ++jt, ++kt) { - edge e = *it; - node u = e->target(); - adjEntry a; - for (a=u->firstAdj(); a->theEdge()->target()!=*jt; a=a->succ()); - edge f = a->theEdge(); - m_dynamicSPQRForest.updateInsertedNode(e,f); - e = m_dynamicSPQRForest.rep(e); - f = m_dynamicSPQRForest.rep(f); - m_typeOf[f] = m_typeOf[e]; - m_cost[f] = m_cost[e]; - for (a=u->firstAdj(); a->theEdge()->source()!=v; a=a->succ()); - f = a->theEdge(); - m_dynamicSPQRForest.updateInsertedEdge(f); - f = m_dynamicSPQRForest.rep(f); - m_typeOf[f] = typeOfEOrig; - m_cost[f] = costOfEOrig; - v = u; - } - node u = m_pPG->copy(eOrig->target()); - adjEntry a; - for (a=v->firstAdj(); a->theEdge()->target()!=u; a=a->succ()); - edge f = a->theEdge(); - m_dynamicSPQRForest.updateInsertedEdge(f); - f = m_dynamicSPQRForest.rep(f); - m_typeOf[f] = typeOfEOrig; - m_cost[f] = costOfEOrig; -} - - - -//------------------------------------------------------------------- -// ExpandedGraph2 represents the (partially) expanded graph with -// its augmented dual -//------------------------------------------------------------------- - -class ExpandedGraph2 -{ - BCandSPQRtrees &m_BC; - - NodeArray m_GtoExp; - List m_nodesG; - Graph m_exp; // expanded graph - ConstCombinatorialEmbedding m_E; - AdjEntryArray m_expToG; - edge m_eS, m_eT; // (virtual) edges in exp representing s and t (if any) - - Graph m_dual; // augmented dual graph of exp - EdgeArray m_primalEdge; - EdgeArray m_primalIsGen; // true iff corresponding primal edge is a generalization - - node m_vS, m_vT; // augmented nodes in dual representing s and t - -public: - ExpandedGraph2(BCandSPQRtrees &BC); - - void expand(node v, node vPred, node vSucc); - - void constructDual(node s, node t, GraphCopy &GC, const EdgeArray *forbiddenEdgeOrig); - void constructDualForbidCrossingGens(node s, node t); - - void findShortestPath(Graph::EdgeType eType, List &L); - void findWeightedShortestPath(Graph::EdgeType eType, - List &L); - - int costDual(edge eDual) const { - adjEntry adjExp = m_primalEdge[eDual]; - return (adjExp == 0) ? 0 : m_BC.cost(m_expToG[adjExp]->theEdge()); - } - - // avoid automatic creation of assignment operator - ExpandedGraph2 &operator=(const ExpandedGraph2 &); - -private: - edge insertEdge(node vG, node wG, edge eG); - void expandSkeleton(node v, edge e1, edge e2); -}; - - -ExpandedGraph2::ExpandedGraph2(BCandSPQRtrees &BC) : m_BC(BC), - m_GtoExp(BC.dynamicSPQRForest().auxiliaryGraph(),0), m_expToG(m_exp,0), - m_primalEdge(m_dual,0), m_primalIsGen(m_dual,false) -{ -} - - -//------------------------------------------------------------------- -// build expanded graph (by expanding skeleton(v), nodes vPred and -// vSucc are the predecessor and successor tree nodes of v on the -// path from v1 to v2 -//------------------------------------------------------------------- - -void ExpandedGraph2::expand(node v, node vPred, node vSucc) -{ - m_exp.clear(); - while (!m_nodesG.empty()) - m_GtoExp[m_nodesG.popBackRet()] = 0; - - edge eInS = 0; - if (vPred != 0) { - eInS = m_BC.dynamicSPQRForest().virtualEdge(vPred,v); - m_eS = insertEdge(eInS->source(),eInS->target(),0); - } - edge eOutS = 0; - if (vSucc != 0) { - eOutS = m_BC.dynamicSPQRForest().virtualEdge(vSucc,v); - m_eT = insertEdge(eOutS->source(),eOutS->target(),0); - } - - expandSkeleton(v, eInS, eOutS); - - planarEmbed(m_exp); - m_E.init(m_exp); -} - - -//------------------------------------------------------------------- -// expand one skeleton (recursive construction) -//------------------------------------------------------------------- - -void ExpandedGraph2::expandSkeleton(node v, edge e1, edge e2) -{ - ListConstIterator i; - for(i = m_BC.dynamicSPQRForest().hEdgesSPQR(v).begin(); i.valid(); ++i) - { - edge et = m_BC.dynamicSPQRForest().twinEdge(*i); - - if (et == 0) insertEdge((*i)->source(),(*i)->target(),*i); - - // do not expand virtual edges corresponding to tree edges e1 or e2 - else if (*i != e1 && *i != e2) - expandSkeleton(m_BC.dynamicSPQRForest().spqrproper(et),et,0); - } -} - - -//------------------------------------------------------------------- -// insert edge in exp (from a node corresponding to vG in G to a node -// corresponding to wG) -//------------------------------------------------------------------- - -edge ExpandedGraph2::insertEdge(node vG, node wG, edge eG) -{ - node &rVG = m_GtoExp[vG]; - node &rWG = m_GtoExp[wG]; - - if (rVG == 0) { - rVG = m_exp.newNode(); - m_nodesG.pushBack(vG); - } - if (rWG == 0) { - rWG = m_exp.newNode(); - m_nodesG.pushBack(wG); - } - - edge e1 = m_exp.newEdge(rVG,rWG); - - if(eG != 0) { - m_expToG[e1->adjSource()] = eG->adjSource(); - m_expToG[e1->adjTarget()] = eG->adjTarget(); - } else { - m_expToG[e1->adjSource()] = 0; - m_expToG[e1->adjTarget()] = 0; - } - - return e1; -} - - -//------------------------------------------------------------------- -// construct augmented dual of exp -//------------------------------------------------------------------- - -void ExpandedGraph2::constructDual(node s, node t, - GraphCopy &GC, const EdgeArray *forbiddenEdgeOrig) -{ - m_dual.clear(); - - FaceArray faceNode(m_E); - - // constructs nodes (for faces in exp) - face f; - forall_faces(f,m_E) { - faceNode[f] = m_dual.newNode(); - } - - // construct dual edges (for primal edges in exp) - node v; - forall_nodes(v,m_exp) - { - adjEntry adj; - forall_adj(adj,v) - { - // cannot cross edges that does not correspond to real edges - adjEntry adjG = m_expToG[adj]; - if(adjG == 0) - continue; - - // Do not insert edges into dual if crossing the original edge - // is forbidden - if(forbiddenEdgeOrig && - (*forbiddenEdgeOrig)[GC.original(m_BC.dynamicSPQRForest().original(m_expToG[adj]->theEdge()))] == true) - continue; - - node vLeft = faceNode[m_E.leftFace (adj)]; - node vRight = faceNode[m_E.rightFace(adj)]; - - m_primalEdge[m_dual.newEdge(vLeft,vRight)] = adj; - } - } - - // augment dual by m_vS and m_vT - m_vS = m_dual.newNode(); - if (m_GtoExp[s] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[s]) - m_dual.newEdge(m_vS,faceNode[m_E.rightFace(adj)]); - } - else - { - m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjSource())]); - m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjTarget())]); - } - - m_vT = m_dual.newNode(); - if (m_GtoExp[t] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[t]) - m_dual.newEdge(faceNode[m_E.rightFace(adj)], m_vT); - } - else - { - m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjSource())], m_vT); - m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjTarget())], m_vT); - } -} - - -void ExpandedGraph2::constructDualForbidCrossingGens(node s, node t) -{ - m_dual.clear(); - - FaceArray faceNode(m_E); - - // constructs nodes (for faces in exp) - face f; - forall_faces(f,m_E) { - faceNode[f] = m_dual.newNode(); - } - - edge eDual; - // construct dual edges (for primal edges in exp) - node v; - forall_nodes(v,m_exp) - { - adjEntry adj; - forall_adj(adj,v) - { - // cannot cross edges that does not correspond to real edges - adjEntry adjG = m_expToG[adj]; - if(adjG == 0) - continue; - - node vLeft = faceNode[m_E.leftFace (adj)]; - node vRight = faceNode[m_E.rightFace(adj)]; - - edge e = m_dual.newEdge(vLeft,vRight); - m_primalEdge[e] = adj; - - // mark dual edges corresponding to generalizations - if (adjG && m_BC.typeOf(adjG->theEdge()) == Graph::generalization) - m_primalIsGen[e] = true; - - OGDF_ASSERT(m_primalEdge[e] == 0 || m_expToG[m_primalEdge[e]] != 0); - } - } - - // augment dual by m_vS and m_vT - m_vS = m_dual.newNode(); - if (m_GtoExp[s] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[s]) { - eDual = m_dual.newEdge(m_vS,faceNode[m_E.rightFace(adj)]); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } - } - else - { - eDual = m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjSource())]); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - - eDual = m_dual.newEdge(m_vS,faceNode[m_E.rightFace(m_eS->adjTarget())]); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } - - m_vT = m_dual.newNode(); - if (m_GtoExp[t] != 0) - { - adjEntry adj; - forall_adj(adj,m_GtoExp[t]) { - eDual = m_dual.newEdge(faceNode[m_E.rightFace(adj)], m_vT); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } - } - else - { - eDual = m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjSource())], m_vT); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - - eDual = m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjTarget())], m_vT); - OGDF_ASSERT(m_primalEdge[eDual] == 0 || m_expToG[m_primalEdge[eDual]] != 0); - } -} - - -//------------------------------------------------------------------- -// find shortest path in dual from m_vS to m_vT; output this path -// in L by omitting first and last edge, and translating edges to G -//------------------------------------------------------------------- - -void ExpandedGraph2::findShortestPath(Graph::EdgeType eType, List &L) -{ - NodeArray spPred(m_dual,0); // predecessor in shortest path tree - List queue; // candidate edges - - // start with all edges leaving from m_vS - edge e; - forall_adj_edges(e,m_vS) - queue.pushBack(e); - - for( ; ; ) { - edge eCand = queue.popFrontRet(); // next candidate from front of queue - node v = eCand->target(); - - // hit an unvisited node ? - if (spPred[v] == 0) { - spPred[v] = eCand; - - // if it is m_vT, we have found the shortest path - if (v == m_vT) { - // build path from shortest path tree - while(v != m_vS) { - adjEntry adjExp = m_primalEdge[spPred[v]]; - if (adjExp != 0) // == nil for first and last edge - L.pushFront(m_expToG[adjExp]); - v = spPred[v]->source(); - } - return; - } - - // append next candidates to end of queue - forall_adj_edges(e,v) { - if(v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - queue.pushBack(e); - } - } - } - } -} - - -//------------------------------------------------------------------- -// find weighted shortest path in dual from m_vS to m_vT; output this path -// in L by omitting first and last edge, and translating edges to G -//------------------------------------------------------------------- - -void ExpandedGraph2::findWeightedShortestPath(Graph::EdgeType eType, - List &L) -{ - int maxCost = 0; - edge eDual; - forall_edges(eDual,m_dual) { - int c = costDual(eDual); - if (c > maxCost) maxCost = c; - } - - ++maxCost; - Array > nodesAtDist(maxCost); - - NodeArray spPred(m_dual,0); // predecessor in shortest path tree - //List queue; // candidate edges - - // start with all edges leaving from m_vS - edge e; - forall_adj_edges(e,m_vS) - nodesAtDist[0].pushBack(e); - - // actual search (using extended bfs on directed dual) - int currentDist = 0; - for( ; ; ) { - // next candidate edge - while(nodesAtDist[currentDist % maxCost].empty()) - ++currentDist; - - edge eCand = nodesAtDist[currentDist % maxCost].popFrontRet(); - node v = eCand->target(); - - // leads to an unvisited node ? - if (spPred[v] == 0) { - // yes, then we set v's predecessor in search tree - spPred[v] = eCand; - - // have we reached t ... - if (v == m_vT) { - // ... then search is done. - // construct list of used edges (translated to crossed - // adjacency entries in G) - while(v != m_vS) { - adjEntry adjExp = m_primalEdge[spPred[v]]; - if (adjExp != 0) // == nil for first and last edge - L.pushFront(m_expToG[adjExp]); - v = spPred[v]->source(); - } - return; - } - - // append next candidates to end of queue - // (all edges leaving v) - forall_adj_edges(e,v) { - if(v == e->source() && - (eType != Graph::generalization || m_primalIsGen[e] == false)) - { - int listPos = (currentDist + costDual(e)) % maxCost; - nodesAtDist[listPos].pushBack(e); - } - } - } - } -} - - - -//--------------------------------------------------------- -// VEICrossingsBucket -// bucket function for sorting edges by decreasing number -// of crossings -//--------------------------------------------------------- - -class VEICrossingsBucket : public BucketFunc -{ - const PlanRep *m_pPG; - -public: - VEICrossingsBucket(const PlanRep *pPG) : - m_pPG(pPG) { } - - int getBucket(const edge &e) { - return -m_pPG->chain(e).size(); - } -}; - - - -//--------------------------------------------------------- -// VariableEmbeddingInserter2 -//--------------------------------------------------------- - -//--------------------------------------------------------- -// constructor -// sets default values for options -// -VariableEmbeddingInserter2::VariableEmbeddingInserter2() -{ - m_rrOption = rrNone; - m_percentMostCrossed = 25; -} - - -//--------------------------------------------------------- -// actual call (called by all variations of call) -// crossing of generalizations is forbidden if forbidCrossingGens = true -// edge costs are obeyed if costOrig != 0 -// -Module::ReturnType VariableEmbeddingInserter2::doCall( - PlanRep &PG, - const List &origEdges, - bool forbidCrossingGens, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig) -{ - double T; - usedTime(T); - - ReturnType retValue = retFeasible; - m_runsPostprocessing = 0; - - if (origEdges.size() == 0) - return retOptimal; // nothing to do - - OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0); - - m_pPG = &PG; - m_forbidCrossingGens = forbidCrossingGens; - m_costOrig = costOrig; - m_forbiddenEdgeOrig = forbiddenEdgeOrig; - - SListPure currentOrigEdges; - ListConstIterator it; - - if(removeReinsert() == rrIncremental) { - edge e; - forall_edges(e,PG) - currentOrigEdges.pushBack(PG.original(e)); - - // insertion of edges - for(it = origEdges.begin(); it.valid(); ++it) - { - edge eOrig = *it; - m_typeOfCurrentEdge = m_forbidCrossingGens ? PG.typeOrig(eOrig) : Graph::association; - - m_pBC = new BCandSPQRtrees(m_pPG,m_forbidCrossingGens,m_costOrig); - SList eip; - insert(eOrig,eip); - PG.insertEdgePath(eOrig,eip); - delete m_pBC; - - currentOrigEdges.pushBack(eOrig); - - bool improved; - do { - ++m_runsPostprocessing; - improved = false; - - SListConstIterator itRR; - for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR) - { - edge eOrigRR = *itRR; - - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrigRR); - else - pathLength = PG.chain(eOrigRR).size() - 1; - if (pathLength == 0) continue; // cannot improve - - PG.removeEdgePath(eOrigRR); - - m_typeOfCurrentEdge = m_forbidCrossingGens ? PG.typeOrig(eOrigRR) : Graph::association; - - m_pBC = new BCandSPQRtrees(m_pPG,m_forbidCrossingGens,m_costOrig); - SList eip; - insert(eOrigRR,eip); - PG.insertEdgePath(eOrigRR,eip); - delete m_pBC; - - int newPathLength = (costOrig != 0) ? costCrossed(eOrigRR) : (PG.chain(eOrigRR).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - } - } - else { - // insertion of edges - m_pBC = new BCandSPQRtrees(m_pPG,m_forbidCrossingGens,m_costOrig); - for(it = origEdges.begin(); it.valid(); ++it) - { - edge eOrig = *it; - m_typeOfCurrentEdge = m_forbidCrossingGens ? PG.typeOrig(eOrig) : Graph::association; - - SList eip; - insert(eOrig,eip); - m_pBC->insertEdgePath(eOrig,eip); - - } - - // postprocessing (remove-reinsert heuristc) - const Graph &G = PG.original(); - SListPure rrEdges; - - switch(removeReinsert()) - { - case rrAll: - case rrMostCrossed: { - const List &origInCC = PG.nodesInCC(); - ListConstIterator itV; - - for(itV = origInCC.begin(); itV.valid(); ++itV) { - node vG = *itV; - adjEntry adj; - forall_adj(adj,vG) { - if ((adj->index() & 1) == 0) continue; - edge eG = adj->theEdge(); - rrEdges.pushBack(eG); - } - } - } - break; - - case rrInserted: - for(ListConstIterator it = origEdges.begin(); it.valid(); ++it) - rrEdges.pushBack(*it); - break; - - default: - break; - } - - delete m_pBC; - - // marks the end of the interval of rrEdges over which we iterate - // initially set to invalid iterator which means all edges - SListConstIterator itStop; - - bool improved; - do { - // abort postprocessing if time limit reached - if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) { - retValue = retTimeoutFeasible; - break; - } - - ++m_runsPostprocessing; - improved = false; - - if(removeReinsert() == rrMostCrossed) - { - VEICrossingsBucket bucket(&PG); - rrEdges.bucketSort(bucket); - - const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); - itStop = rrEdges.get(num); - } - - SListConstIterator it; - for(it = rrEdges.begin(); it != itStop; ++it) - { - edge eOrig = *it; - - int pathLength; - if(costOrig != 0) - pathLength = costCrossed(eOrig); - else - pathLength = PG.chain(eOrig).size() - 1; - if (pathLength == 0) continue; // cannot improve - - PG.removeEdgePath(eOrig); - - m_typeOfCurrentEdge = m_forbidCrossingGens ? PG.typeOrig(eOrig) : Graph::association; - - m_pBC = new BCandSPQRtrees(m_pPG,m_forbidCrossingGens,m_costOrig); - SList eip; - insert(eOrig,eip); - PG.insertEdgePath(eOrig,eip); - delete m_pBC; - - // we cannot find a shortest path that is longer than before! - int newPathLength = (costOrig != 0) ? costCrossed(eOrig) : (PG.chain(eOrig).size() - 1); - OGDF_ASSERT(newPathLength <= pathLength); - - if(newPathLength < pathLength) - improved = true; - } - } while (improved); - } - -#ifdef OGDF_DEBUG - bool isPlanar = -#endif - planarEmbed(PG); - - OGDF_ASSERT(isPlanar); - - PG.removePseudoCrossings(); - OGDF_ASSERT(PG.representsCombEmbedding()); - OGDF_ASSERT(forbidCrossingGens == false || checkCrossingGens(static_cast(PG)) == true); - - return retValue; -} - - -edge VariableEmbeddingInserter2::crossedEdge(adjEntry adj) const -{ - edge e = adj->theEdge(); - - adj = adj->cyclicSucc(); - while(adj->theEdge() == e) - adj = adj->cyclicSucc(); - - return adj->theEdge(); -} - - -int VariableEmbeddingInserter2::costCrossed(edge eOrig) const -{ - int c = 0; - - const List &L = m_pPG->chain(eOrig); - - ListConstIterator it = L.begin(); - for(++it; it.valid(); ++it) { - c += (*m_costOrig)[m_pPG->original(crossedEdge((*it)->adjSource()))]; - } - - return c; -} - - -//------------------------------------------------------------------- -// find optimal edge insertion path from s to t in connected -// graph G -//------------------------------------------------------------------- - -void VariableEmbeddingInserter2::insert (edge eOrig, SList& eip) -{ - eip.clear(); - node s = m_pPG->copy(eOrig->source()); - node t = m_pPG->copy(eOrig->target()); - - // find path from s to t in BC-tree - // call of blockInsert() is done when we have found the path - // if no path is found, s and t are in different connected components - // and thus an empty edge insertion path is correct! - DynamicSPQRForest& dSPQRF = m_pBC->dynamicSPQRForest(); - SList& path = dSPQRF.findPath(s,t); - if (!path.empty()) { - SListIterator it=path.begin(); - node repS = dSPQRF.repVertex(s,*it); - for (SListIterator jt=it; it.valid(); ++it) { - node repT = (++jt).valid() ? dSPQRF.cutVertex(*jt,*it) : dSPQRF.repVertex(t,*it); - - // less than 3 nodes requires no crossings (cannot build SPQR-tree - // for a graph with less than 3 nodes!) - if (dSPQRF.numberOfNodes(*it)>3) { - List L; - blockInsert(repS,repT,L); // call biconnected case - - // transform crossed edges to edges in G - for (ListConstIterator kt=L.begin(); kt.valid(); ++kt) { - edge e = (*kt)->theEdge(); - eip.pushBack(e->adjSource()==*kt ? dSPQRF.original(e)->adjSource() - : dSPQRF.original(e)->adjTarget()); - } - } - if (jt.valid()) repS = dSPQRF.cutVertex(*it,*jt); - } - } - delete &path; -} - - -//------------------------------------------------------------------- -// find optimal edge insertion path from s to t for biconnected -// graph G (OptimalBlockInserter) -//------------------------------------------------------------------- - -void VariableEmbeddingInserter2::blockInsert(node s, node t, List &L) -{ - L.clear(); - - // find path in SPQR-tree from an allocation node of s - // to an allocation node of t - SList& path = m_pBC->dynamicSPQRForest().findPathSPQR(s,t); - - // call build_subpath for every R-node building the list L of crossed edges - ExpandedGraph2 Exp(*m_pBC); - - node vPred = 0; - path.pushBack(0); - SListConstIterator it; - for(it = path.begin(); *it; ++it) - { - node v = *it; - node vSucc = *it.succ(); - - if (m_pBC->dynamicSPQRForest().typeOfTNode(v) == DynamicSPQRForest::RComp) - buildSubpath(v, vPred, vSucc, L, Exp, s, t); - - vPred = v; - } - - delete &path; -} - - -//------------------------------------------------------------------- -// find the shortest path from represent. of s to represent. of t in -// the dual of the (partially) expanded skeleton of v -//------------------------------------------------------------------- - -void VariableEmbeddingInserter2::buildSubpath( - node v, - node vPred, - node vSucc, - List &L, - ExpandedGraph2 &Exp, - node s, - node t) -{ - // build expanded graph Exp - Exp.expand(v,vPred,vSucc); - - // construct augmented dual of expanded graph - if(m_forbidCrossingGens) - Exp.constructDualForbidCrossingGens(s,t); - else - Exp.constructDual(s,t,*m_pPG,m_forbiddenEdgeOrig); - - // find shortest path in augmented dual - List subpath; - if(m_costOrig != 0) - Exp.findWeightedShortestPath(m_typeOfCurrentEdge,subpath); - else - Exp.findShortestPath(m_typeOfCurrentEdge,subpath); - - L.conc(subpath); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/BiconnectedShellingOrder.cpp b/ext/OGDF/src/planarlayout/BiconnectedShellingOrder.cpp deleted file mode 100644 index e7eb1db0d..000000000 --- a/ext/OGDF/src/planarlayout/BiconnectedShellingOrder.cpp +++ /dev/null @@ -1,1370 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class BiconnectedShellingOrder which computes - * a shelling order for a biconnected planar graph. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - -#include -#include - - -//#define OUTPUT_BSO - -namespace ogdf { - - -//--------------------------------------------------------- -// pair of node v and list itrator it -//--------------------------------------------------------- -struct PairFaceItem; - -struct PairNodeItem -{ - // constructor - PairNodeItem() { } - - PairNodeItem(node v, ListIterator it = ListIterator()) - { - m_v = v; - m_it = it; - } - - node m_v; - ListIterator m_it; -}; - - -//--------------------------------------------------------- -// pair of face f and list iterator it -//--------------------------------------------------------- - -struct PairFaceItem -{ - // constructor - PairFaceItem() - { - m_f = 0; - m_it = 0; - } - - PairFaceItem(face f) - { - m_f = f; - m_it = 0; - } - - PairFaceItem(face f, ListIterator it) - { - m_f = f; - m_it = it; - } - - face m_f; - ListIterator m_it; -}; - - -// defines (as shortcuts) -// initialization of a variable -#define INIT_VAR(x,var,val) \ - var[x] = (val); \ - setUpdate(x); - -// decrement of a variable -#define DEC_VAR(x,var) \ - --var[x]; \ - setUpdate(x); - -// increment of a variable -#define INC_VAR(x,var) \ - ++var[x]; \ - setUpdate(x); - - -//--------------------------------------------------------- -// class ComputeBicOrder -//--------------------------------------------------------- -class ComputeBicOrder -{ -public: - // types of structures to be removed - enum CandidateType { typeFace, typeNode, typeEdge }; - - - // constructor - ComputeBicOrder ( - const Graph &G, // biconnected planar graph - ConstCombinatorialEmbedding &E, // combinatorial embedding of G - face extFace, // external face - double baseRatio); // size of base (baseRatio * size(extFace) - - // returns external face - face externalFace() { return m_extFace; } - - // returns face left of adj - face left(adjEntry adj) { return m_pEmbedding->leftFace(adj); } - - // returns face right of adj - face right(adjEntry adj) { return m_pEmbedding->rightFace(adj); } - - // if v = c_i, returns face right of c_i -> c_i+1 - face right(node v) { return left(m_nextSucc[v]); } - - // if v = c_i, returns face left of c_i -> c_i-1 - face left(node v) { return right(m_prevPred[v]); } - - // returns number of virtual edges adjacent to v - int virte (node v); - - // returns successor of v on contour (if v=c_i returns c_i+1) - node next(node v) { return m_next[v]; } - - // returns predecessor of v on contour (if v=c_i returns c_ii1) - node prev(node v) { return m_prev[v]; } - - // returns true <=> f contains a virtual edge - bool cutv(face f) { return (m_virtSrc[f] != 0); } - - // returns true <=> f is a possible next face, i.e - // outv(f) >= 3 and outv(f) = oute(f)+1 - bool isPossFace(face f) { - return (f != externalFace() && m_outv[f] >= 3 && m_outv[f] == m_oute[f]+1); - } - - // returns true <=> v is a possible next node, i.e. - // cutf(v) <= 1, cutf(v) = virte(v), numsf(v) = 0 and deg(v) >= 3 - bool isPossNode(node v) { // precond.: v on C_k' - return (m_onBase[v] == false && m_cutf[v] <= 1 && - m_cutf[v] == virte(v) && m_numsf[v] == 0 && m_deg[v] >= 3); - } - - // returns true <=> v=c_i and c_i -> c_i+1 is a possible next virtual edge, i.e. - // c_i -> c_i+1 is a virtual edge and (deg(c_i) = 2 and c_i != vLeft) or - // deg(c_i+1) = 2 and c_i+1 != vRight) - bool isPossVirt(node v) { // precond.: v on C_k' - return m_virtEdge[v] && ((m_deg[v] == 2 && v != m_vLeft) || - (m_deg[next(v)] == 2 && next(v) != m_vRight)); - } - - // stores the next candidate in m_nextType and m_nextF, m_nextV or - // m_nextE (depending on type) - // returns true <=> there is a next candidate - bool getPossible(); - - // returns the type of the next candidate - CandidateType nextPoss() { return m_nextType; } - - // puts nodes on base into shelling order set V - void setV1(ShellingOrderSet &V); - - // initializes possible nodes and faces - void initPossibles(); - - // removes next possible face - void removeNextFace(ShellingOrderSet &V); - // removes next possible node - void removeNextNode(ShellingOrderSet &V); - // removes next possible virtual edge - void removeNextVirt(ShellingOrderSet &V); - - // updates variables of face and nodes contained in m_updateFaces and - // m_updateNodes; also updates list of possible nodes, faces and virtual edges - void doUpdate(); - - // outputs contour and some node and face variables - // for debugging only - void print(); - -private: - // if adj = w->v, puts edge (v,w) onto contour - void edgeToContour(adjEntry adj); - // puts virtual edge (v,w) onto contour and sets m_nextSucc[v] and m_prevPred[w] - void virtToContour(node v, node w, adjEntry adjNextSucc, adjEntry adjPrevPred); - // puts virtual edge (v,w) onto contour - void virtToContour(node v, node w); - - // returns vertex cl of a face to be removed - node getFaceCl(face f); - - void setOutv(node v); - void setSeqp(node cl, node cr); - void delOuterNode(node v); - void decSeqp(node v); - void putOnOuter(node v, face f); - void delOuterRef(face f); - - // returns faces adjacent with v in list L - void getAdjFaces(node v, SListPure &L); - // returns nodes adjacent with v in list L; nodes are sorted from left - // to right - void getAdjNodes(node v, SListPure &L); - - // marks face f to be updated - void setUpdate(face f); - // marks node v to be updated - void setUpdate(node v); - - void initVInFStruct(const ConstCombinatorialEmbedding &E); - bool vInF(node v, face f); - void delVInF(node v, face f); - - int getBaseChain(ConstCombinatorialEmbedding &E, - face f, - double baseRatio, - adjEntry &adjLeft, - adjEntry &adjRight); - - adjEntry findMaxBaseChain(ConstCombinatorialEmbedding &E, - face f, - int &length); - - const Graph *m_pGraph; // the graph - ConstCombinatorialEmbedding *m_pEmbedding; // the embedding of the graph - - face m_extFace; // the external face - - adjEntry m_adjLeft; // adjacency entry z_1 -> z_2 (if z_1,...,z_p is base) - adjEntry m_adjRight; // adjacency entry z_p-1 -> z_p - - node m_vLeft, m_vRight; // left and right node on base - int m_baseLength; // length of base - - // next candidate to be removed - CandidateType m_nextType; // type of next candidate - face m_nextF; // next face (if m_nextType = typeFace) - node m_nextV; // next node (if m_nextType = typeNode) - node m_nextE; // next virtual edge (if m_nextType = typeEdge) - - // variables of nodes - NodeArray m_deg; // current degree - NodeArray m_cutf; // number of adjacent faces f with cutv(f) = true - NodeArray m_numsf; // number of adjacent faces f with outv(f) > seqp(f)+1 - NodeArray m_onOuter; // true <=> v on contour - NodeArray m_onBase; // true <=> v on base - - // list iterator in m_possNodes containing node (or nil if not contained) - NodeArray > m_vLink; - // list iterator in m_possVirt containing virtual edge at node (or nil if not contained) - NodeArray > m_virtLink; - NodeArray m_vUpdate; // true <=> node marked to be updated - NodeArray > m_inOutNodes; - - // variables of faces - FaceArray m_outv, // number of nodes contained in face on contour - m_oute, // number of edges contained in face on contour - m_seqp; // number of sequential pairs c_i,c_i+1 of face - FaceArray m_virtSrc; // if face contains virtual edge e then source(e), otherwise nil - // list iterator in m_possFaces containing face (or nil if not contained) - FaceArray > m_fLink; - FaceArray m_fUpdate; // true <=> face marked to be updated - FaceArray m_isSf; // true <=> outv(f) > seqp(f)+1 - FaceArray > m_outerNodes; // list of all nodes of face on contour - - // represantation of the contour - NodeArray m_next, m_prev; - NodeArray m_nextSucc, m_prevPred; - NodeArray m_virtEdge; // virt_edge[c_i] = true <=> (c_i,c_i+1) virtuelle Kante - - // lists of possible faces, nodes and edges - ListPure m_possFaces; // faces with outv(f) >= 3 und outv(f) = oute(f)+1 - ListPure m_possNodes; // nodes with cutf(v) <= 1, cutf(v) = virte(v), numsf(v) = 0 and deg(v) >= 3 - ListPure m_possVirt; // node v denotes virtual edge e = (v,next[v]), that satisfies - // (deg(v) = 2 and v != vLeft) or (deg(next(v)) = 2 and next(v) != vRight) - - ListPure m_updateNodes; // list of nodes to be updated - SListPure m_updateFaces; // list of faces to be updated - - // deciding "v in F ?" in constant time - NodeArray > m_facesOf; - FaceArray > m_nodesOf; -}; - - -void ComputeBicOrder::print() -{ - cout << "contour:\n"; - node v; - for(v = m_vLeft; v != 0; v = m_next[v]) - cout << " " << v << "[" << m_prev[v] << "," << m_prevPred[v] << - " : " << m_next[v] << "," << m_nextSucc[v] << - "; " << m_virtEdge[v] << "]\n"; - - cout << "node infos:\n"; - forall_nodes(v,*m_pGraph) - cout << v << ": deg = " << m_deg[v] << ", cutf = " << m_cutf[v] << - ", numsf = " << m_numsf[v] << endl; - - cout << "face infos:\n"; - face f; - forall_faces(f,*m_pEmbedding) { - cout << f->index() << ": outv = " << m_outv[f] << ", oute = " << - m_oute[f] << ", seqp = " << m_seqp[f] << ", isSF = " << - m_isSf[f] << ", virtSrc = " << m_virtSrc[f] << endl; - } - cout << endl; -} - - -ComputeBicOrder::ComputeBicOrder(const Graph &G, // the graph - ConstCombinatorialEmbedding &E, // embedding of the graph - face extFace, // the external face - double baseRatio) // length of the base = baseRatio*size(extface) -{ - m_pGraph = &G; - m_pEmbedding = &E; - -#ifdef OUTPUT_BSO - cout << "faces:" << endl; - face fh; - forall_faces(fh,E) { - cout << fh->index() << ":"; - adjEntry adj; - forall_face_adj(adj,fh) - cout << " " << adj; - cout << endl; - } - - cout << "adjacency lists:" << endl; - node vh; - forall_nodes(vh,G) { - cout << vh << ":"; - adjEntry adj; - forall_adj(adj,vh) - cout << " " << adj; - cout << endl; - } -#endif - - m_vLink .init(G, ListIterator()); - m_virtLink.init(G, ListIterator()); - - m_extFace = extFace; - -#ifdef OUTPUT_BSO - cout << "external face = " << extFace->index() << endl; -#endif - - m_baseLength = getBaseChain(E, m_extFace, baseRatio, m_adjLeft, m_adjRight); - m_vLeft = m_adjLeft->theNode(); - m_vRight = m_adjRight->twinNode(); - -#ifdef OUTPUT_BSO - cout << "vLeft = " << m_vLeft << ", " << "vRight = " << m_vRight << endl; -#endif - - // initialization of node and face variables - m_deg .init (G); - m_cutf .init (G, 0); - m_numsf .init (G, 0); - m_onOuter .init (G, false); - m_next .init (G); - m_prev .init (G); - m_nextSucc .init (G); - m_prevPred .init (G); - m_virtEdge .init (G, false); - m_vUpdate .init (G, false); - m_inOutNodes .init (G); - m_outv .init (E, 0); - m_oute .init (E, 0); - m_seqp .init (E, 0); - m_virtSrc .init (E, 0); - m_fLink .init (E, ListIterator()); - m_fUpdate .init (E, false); - m_isSf .init (E, false); - m_outerNodes .init (E); - m_onBase .init (G, false); - - initVInFStruct(E); - - // initialization of degree - node v, w; - forall_nodes(v,G) - m_deg[v] = v->degree(); - - // initialization of m_onBase[v] - adjEntry adj; - for(adj = m_adjRight; adj != m_adjLeft; adj = adj->faceCyclePred()) - m_onBase[adj->theNode()] = true; - m_onBase [m_vLeft] = m_onBase [m_vRight] = true; - - adj = m_adjLeft; - do { - v = adj->theNode(); - adjEntry adj2; - forall_adj(adj2,v) - { - face f = E.rightFace(adj2); - if (f != m_extFace) { - m_outv[f] ++; - putOnOuter(v,f); - } - } - adj = adj->faceCyclePred(); - } while(adj != m_adjRight); - - for(adj = m_adjRight->faceCycleSucc(); adj != m_adjLeft; adj = adj->faceCycleSucc()) - m_oute[E.leftFace(adj)]++; - - m_onOuter [m_vLeft] = true; - m_prevPred[m_vLeft] = m_nextSucc[m_vRight] = 0; - m_prev[m_vLeft] = m_next[m_vRight] = 0; - for (adj = m_adjLeft->faceCyclePred(); adj != m_adjRight; adj = adj->faceCyclePred()) - { - v = adj->twinNode(); w = adj->theNode(); - m_onOuter[w] = true; - edgeToContour(adj); - - adjEntry adj2; - forall_adj(adj2,w) - { - face f = left(adj2); - if (vInF(v,f)) - ++m_seqp[f]; - } - } - - for (v = m_vLeft; v != 0; v = next(v)) - { - forall_adj(adj,v) { - face f = left(adj); - if ((m_isSf[f] = (m_outv[f] > m_seqp[f]+1)) == true) - ++m_numsf[v]; - } - } -} - - -void ComputeBicOrder::setV1(ShellingOrderSet &V) -{ - V = ShellingOrderSet(m_baseLength, 0, 0); - - int i; - adjEntry adj; - for (i = 1, adj = m_adjLeft; i <= m_baseLength; - i++, adj = adj->faceCycleSucc()) - { - V[i] = adj->theNode(); - } -} - - -void ComputeBicOrder::edgeToContour(adjEntry adj) -{ - node v = adj->twinNode(), w = adj->theNode(); - - m_next [v] = w; - m_prev [w] = v; - m_nextSucc [v] = adj->twin()->cyclicSucc(); - m_prevPred [w] = adj->cyclicPred(); - m_virtEdge [v] = false; -} - - -void ComputeBicOrder::virtToContour( - node v, - node w, - adjEntry adjNextSucc, - adjEntry adjPrevPred) -{ - m_next [v] = w; - m_prev [w] = v; - m_nextSucc [v] = adjNextSucc; - m_prevPred [w] = adjPrevPred; - m_virtEdge [v] = true; -} - - -void ComputeBicOrder::virtToContour(node v, node w) -{ - m_next [v] = w; - m_prev [w] = v; - m_virtEdge [v] = true; -} - - -void ComputeBicOrder::putOnOuter(node v, face f) -{ - ListIterator it; - - it = m_outerNodes[f].pushBack(PairNodeItem(v)); - (*it).m_it = m_inOutNodes[v].pushBack(PairFaceItem(f,it)); -} - - -void ComputeBicOrder::delOuterRef(face f) -{ - ListPure &L = m_outerNodes[f]; - PairNodeItem x; - - while (!L.empty()) { - x = L.popFrontRet(); - m_inOutNodes[x.m_v].del(x.m_it); - } -} - - -int ComputeBicOrder::virte(node v) -{ - int num = 0; - - if (m_onOuter[v] == true) - { - if (m_virtEdge[v] == true) - num++; - if (v != m_vLeft && m_virtEdge[prev(v)] == true) - num++; - } - return num; -} - - -void ComputeBicOrder::initVInFStruct(const ConstCombinatorialEmbedding &E) -{ - const Graph &G = E; - - m_facesOf.init(G); - m_nodesOf.init(E); - - face f; - forall_faces(f,E) - { - adjEntry adj; - forall_face_adj(adj,f) { - node v = adj->theNode(); - - ListIterator it = m_facesOf[v].pushBack(PairFaceItem(f)); - (*it).m_it = m_nodesOf[f].pushBack(PairNodeItem(v,it)); - } - } - - SListPure smallV; - node v; - forall_nodes(v,G) { - if (m_facesOf[v].size() <= 5) - smallV.pushBack(v); - } - - SListPure smallF; - forall_faces(f,E) { - if (m_nodesOf[f].size() <= 5) - smallF.pushBack(f); - } - - for( ; ; ) - { - if (!smallV.empty()) { - v = smallV.popFrontRet(); - - ListIterator it; - for(it = m_facesOf[v].begin(); it.valid(); ++it) { - PairFaceItem f_it = *it; - m_nodesOf[f_it.m_f].del(f_it.m_it); - if (m_nodesOf[f_it.m_f].size() == 5) - smallF.pushBack(f_it.m_f); - } - } else if (!smallF.empty()) { - f = smallF.popFrontRet(); - ListIterator it; - for(it = m_nodesOf[f].begin(); it.valid(); ++it) { - PairNodeItem v_it = *it; - m_facesOf[v_it.m_v].del(v_it.m_it); - if (m_facesOf[v_it.m_v].size() == 5) - smallV.pushBack(v_it.m_v); - } - } else - break; - } -} - - -bool ComputeBicOrder::vInF(node v, face f) -{ - ListIterator itNI; - for(itNI = m_nodesOf[f].begin(); itNI.valid(); ++itNI) - if ((*itNI).m_v == v) return true; - - ListIterator itFI; - for(itFI = m_facesOf[v].begin(); itFI.valid(); ++itFI) - if ((*itFI).m_f == f) return true; - - return false; -} - - -void ComputeBicOrder::delVInF(node v, face f) -{ - List &L_f = m_nodesOf[f]; - List &L_v = m_facesOf[v]; - - ListIterator itNI; - for(itNI = L_f.begin(); itNI.valid(); ++itNI) { - if ((*itNI).m_v == v) { - L_f.del(itNI); - return; - } - } - - ListIterator itFI; - for(itFI = L_v.begin(); itFI.valid(); ++itFI) { - if ((*itFI).m_f == f) { - L_v.del(itFI); - return; - } - } -} - - -void ComputeBicOrder::initPossibles() -{ - face f; - forall_faces (f, (*m_pEmbedding)) { - if (isPossFace(f)) - m_fLink[f] = m_possFaces.pushBack(f); - } - - node v; - for (v = next(m_vLeft); v != m_vRight; v = next(v)) - if (isPossNode(v)) - m_vLink[v] = m_possNodes.pushBack(v); -} - - -bool ComputeBicOrder::getPossible() -{ - if (!m_possFaces.empty()) { - m_nextType = typeFace; - m_nextF = m_possFaces.popFrontRet(); - return true; - - } else if (!m_possNodes.empty()) { - m_nextType = typeNode; - m_nextV = m_possNodes.popFrontRet(); - return true; - - } else if (!m_possVirt.empty()) { - m_nextType = typeEdge; - m_nextE = m_possVirt.popFrontRet(); - m_virtLink[m_nextE] = ListIterator(); - return true; - - } else - return false; -} - - -node ComputeBicOrder::getFaceCl(face f) -{ - node v; - - if (cutv (f)) { - v = m_virtSrc [f]; - - } else { - adjEntry adj; - forall_face_adj(adj, f) { - if (m_onOuter[v = adj->theNode()] == true && m_deg[v] == 2) - break; - } - } - - while (v != m_vLeft && m_deg[v] == 2) - v = prev(v); - - return v; -} - - -void ComputeBicOrder::getAdjFaces(node v, SListPure &L) -{ - L.clear(); - if (m_deg[v] <= 1) return; - - adjEntry adjEnd = (v != m_vLeft) ? m_prevPred[v] : m_adjLeft->cyclicPred(); - adjEntry adjStart = (v != m_vRight) ? m_nextSucc[v] : m_adjRight->twin()->cyclicSucc(); - - if (left(adjStart) != m_extFace) - L.pushBack(left(adjStart)); - - if (m_deg[v] >= 3) { - adjEntry adj; - for (adj = adjStart; adj != adjEnd; adj = adj->cyclicSucc()) - L.pushBack(right(adj)); - - L.pushBack(right(adjEnd)); - } -} - - -void ComputeBicOrder::getAdjNodes(node v, SListPure &L) -{ - adjEntry adjEnd = (v != m_vLeft) ? m_prevPred[v] : m_adjLeft->cyclicPred(); - adjEntry adjStart = (v != m_vRight) ? m_nextSucc[v] : m_adjRight->twin()->cyclicSucc(); - - L.clear(); - L.pushBack((v != m_vLeft) ? prev(v) : m_adjLeft->twinNode()); - - if (m_deg[v] >= 3) { - adjEntry adj; - for (adj = adjEnd; adj != adjStart; adj = adj->cyclicPred()) - L.pushBack(adj->twinNode()); - L.pushBack(adjStart->twinNode()); - } - L.pushBack((v != m_vRight) ? next(v) : m_adjRight->theNode()); -} - - -void ComputeBicOrder::decSeqp(node v) -{ - node vNext = next(v); - node vPrev = prev(v); - - SListPure L; - getAdjFaces(v,L); - - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) { - face f = *it; - if (vInF(vNext,f)) - m_seqp[f]--; - if (vInF(vPrev,f)) - m_seqp[f]--; - } -} - - -void ComputeBicOrder::delOuterNode(node v) -{ - ListIterator it; - for(it = m_inOutNodes[v].begin(); it.valid(); ++it) - m_outerNodes[(*it).m_f].del((*it).m_it); -} - - -void ComputeBicOrder::setOutv(node v) -{ - SListPure L; - getAdjFaces(v,L); - - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) { - face f = *it; - - INC_VAR(f,m_outv) - putOnOuter(v,f); - if (cutv(f) == true) { - INC_VAR(v, m_cutf) - } - if (m_isSf [f]) { - INC_VAR(v, m_numsf) - } - } -} - - -void ComputeBicOrder::setSeqp(node cl, node cr) -{ - SListPure L; - - node v, w; - for (v = cl; v != cr; v = w) - { - w = next(v); - - node wSmall, wBig; - if (m_deg[v] < m_deg[w]) { - wSmall = v; - wBig = w; - } else { - wSmall = w; - wBig = v; - } - - getAdjFaces(wSmall, L); - - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) { - if (vInF(wBig,*it)) { - INC_VAR (*it,m_seqp) - } - } - } -} - - -void ComputeBicOrder::removeNextFace(ShellingOrderSet &V) -{ -#ifdef OUTPUT_BSO - cout << "remove next face: " << m_nextF->index() << endl; -#endif - - node cl = getFaceCl(m_nextF), cr, v; - - V = ShellingOrderSet(m_outv[m_nextF]-2); - V.left(cl); - - int i; - for (i = 1, cr = next(cl); cr != m_vRight && m_deg[cr] == 2; i++, cr = next(cr)) - V [i] = cr ; - V.right (cr); - V.leftAdj (m_virtEdge[cl] ? 0 : m_nextSucc[cl]->cyclicSucc()->twin()); - V.rightAdj(m_virtEdge[prev(cr)] ? 0 : m_prevPred[cr]->cyclicPred()->twin()); - - if (cutv(m_nextF) && next(m_virtSrc[m_nextF]) == cr) - setUpdate(cr); - - if (cutv(m_nextF)) { - DEC_VAR(cl,m_cutf) - DEC_VAR(cr,m_cutf) - v = m_virtSrc[m_nextF]; - if (v != cr) { - m_possVirt.del(m_virtLink[v]); - m_virtLink[v] = ListIterator(); - } - } - - adjEntry adj = m_nextSucc[cl]->twin(); - for( ; ; ) { - edgeToContour(adj); - - if (adj->theNode() == cr) - break; - else { - INIT_VAR(adj->theNode(),m_onOuter,true) - } - - adj = adj->faceCyclePred(); - } - DEC_VAR (cl,m_deg) - DEC_VAR (cr,m_deg) - - for (v = cl; v != cr; v = next(v)) { - INC_VAR(right(v),m_oute) - if (v != cl) - setOutv(v); - } - - setSeqp(cl, cr); - - // possibly remove virtual edge - if (cutv(m_nextF)) { - if (m_virtSrc[m_nextF] == cl) { - setUpdate(cl); - m_virtEdge[cl] = false; - } - m_virtSrc[m_nextF] = 0; - } - delOuterRef(m_nextF); -} - - -void ComputeBicOrder::removeNextNode(ShellingOrderSet &V) -{ -#ifdef OUTPUT_BSO - cout << "remove next node: " << m_nextV << endl; -#endif - - node cl = prev(m_nextV); - node cr = next(m_nextV); - - V = ShellingOrderSet(1); - V[1] = m_nextV; - - if (m_virtEdge[prev(m_nextV)] == true) { - V.left(m_prevPred[m_nextV]->twinNode()); - V.leftAdj(m_prevPred[m_nextV]); - } else { - V.left(prev(m_nextV)); - V.leftAdj(m_prevPred[m_nextV]->cyclicPred()); - } - - if (m_virtEdge[m_nextV] == true) { - V.right(m_nextSucc[m_nextV]->twinNode()); - V.rightAdj(m_nextSucc[m_nextV]); - } else { - V.right(next(m_nextV)); - V.rightAdj(m_nextSucc[m_nextV]->cyclicSucc()); - } - - node vVirt = 0; - face fVirt = 0; - if (m_virtEdge[prev(m_nextV)]) { - INIT_VAR(prev(m_nextV), m_virtEdge, false) - vVirt = cl; - fVirt = left(m_nextV); - m_virtSrc [fVirt] = 0; - } - - if (m_virtEdge[m_nextV]) { - if (m_virtLink[m_nextV].valid()) { - m_possVirt.del(m_virtLink[m_nextV]); - m_virtLink[m_nextV] = ListIterator(); - } - vVirt = cr; - fVirt = right(m_nextV); - m_virtSrc[fVirt] = 0; - } - - SListPure L; - getAdjFaces(m_nextV, L); - SListConstIterator itF; - for(itF = L.begin(); itF.valid(); ++itF) - --m_outv[*itF]; - - SListPure L_v; - getAdjNodes(m_nextV, L_v); - - delOuterNode(m_nextV); - --m_oute[left (m_nextV)]; - --m_oute[right(m_nextV)]; - decSeqp(m_nextV); - - SListIterator itV; - for(itV = L_v.begin(); itV.valid(); ++itV) { - m_onOuter[*itV] = true; - DEC_VAR (*itV, m_deg) - } - - face potF = 0; - node w1 = L_v.popFrontRet(); - bool firstTime = true; - adjEntry adj,adj2; - for(itV = L_v.begin(); itV.valid(); ++itV) - { - node w = *itV; - - if (firstTime == true) { - adj2 = m_nextSucc[prev(m_nextV)]; - adj = m_prevPred[m_nextV]; - firstTime = false; - - if (prev(m_nextV) != m_vLeft) { - face f = left(adj2); - if (vInF(prev(prev(m_nextV)),f)) - potF = f; - } - - } else { - adj2 = adj->twin()->faceCyclePred()->twin(); - adj = adj->cyclicPred(); - } - - for( ; ; ) - { - node v = adj2->twinNode(); - - if (v != w && m_onOuter[v] == true) - { - face f = left(adj2); - - // possibly remove "v in F" relation - if (adj2->theNode() != w1) - { - adjEntry adj1 = adj2->twin()->faceCycleSucc(); - do { - delVInF(adj1->twinNode(),f); - adj1 = adj1->faceCycleSucc(); - } while (adj1->theNode() != w1); - } - if (f == potF && adj2->theNode() != prev(m_nextV)) { - DEC_VAR(f,m_seqp) - } - - // insert new virtual edge - virtToContour(adj2->theNode(), w, adj2, (w == next(m_nextV)) ? - m_prevPred[w] : adj->twin()->cyclicPred()); - - setUpdate(f); - - INC_VAR(adj2->theNode(),m_deg) - INC_VAR(w,m_deg) - - if (f != fVirt) { - ListIterator itU; - for(itU = m_outerNodes[f].begin(); itU.valid(); ++itU) { - INC_VAR((*itU).m_v, m_cutf); - } - } - m_virtSrc[f] = adj2->theNode(); - - break; - } - - edgeToContour(adj2->twin()); - - if (v == w) { - delOuterRef(left(adj2)); - break; - } - INIT_VAR(v,m_onOuter,true) - if (adj2->theNode() == cl) - { - ListIterator it, itSucc; - ListPure &L = m_outerNodes[left(adj2)]; - for(it = L.begin(); it.valid(); it = itSucc) { - itSucc = it.succ(); - if ((*it).m_v == cl) { - m_inOutNodes[cl].del((*it).m_it); - L.del(it); - break; - } - } - m_outv[left(adj2)]--; - } - adj2 = adj2->twin()->faceCyclePred()->twin(); - } - w1 = w; - } - - for (node v = cl; v != cr; v = next(v)) { - INC_VAR(right(v),m_oute) - if (v != cl) - setOutv(v); - } - - setSeqp(cl,cr); - - if ((vVirt != 0 && m_virtSrc[fVirt] == 0) || - (vVirt == cl && m_virtSrc[fVirt] != cl)) { - DEC_VAR(vVirt,m_cutf) - } -} - - -void ComputeBicOrder::removeNextVirt(ShellingOrderSet &V) -{ -#ifdef OUTPUT_BSO - cout << "remove next virt: " << m_nextE << endl; -#endif - - node v, cl = m_nextE, cr = next(m_nextE); - int i = 0; - - while (m_deg[cl] == 2 && cl != m_vLeft) - { cl = prev(cl); i++; } - while (m_deg[cr] == 2 && cr != m_vRight) - { cr = next(cr); i++; } - - V = ShellingOrderSet(i,m_virtEdge[cl] ? 0 : m_prevPred[next(cl)], - m_virtEdge[prev(cr)] ? 0 : m_nextSucc[prev(cr)]); - for (i = 1, v = next(cl); v != cr; v = next(v)) { - V[i++] = v; - delOuterNode(v); - } - V.left (cl); - V.right(cr); - - face f = right(cl); - m_virtSrc[f] = cl; - - virtToContour(cl, cr); - - INIT_VAR(f,m_outv,(m_outv[f] - V.len())) - INIT_VAR(f,m_oute,(m_oute[f] - V.len())) - INIT_VAR(f,m_seqp,(m_seqp[f] - V.len()-1)) - setSeqp(cl,cr); - setUpdate(cl); - setUpdate(cr); -} - - -void ComputeBicOrder::setUpdate(node v) -{ - if (m_vUpdate[v] == false) { - m_updateNodes.pushBack(v); - m_vUpdate[v] = true; - } -} - - -void ComputeBicOrder::setUpdate(face f) -{ - if (m_fUpdate[f] == false) { - m_updateFaces.pushBack(f); - m_fUpdate[f] = true; - } -} - - -void ComputeBicOrder::doUpdate() -{ - while (!m_updateFaces.empty()) - { - face f = m_updateFaces.popFrontRet(); - m_fUpdate[f] = false; - bool isSeperatingFace = (m_outv[f] > m_seqp[f]+1); - if (isSeperatingFace != m_isSf[f]) - { - ListIterator it; - for(it = m_outerNodes[f].begin(); it.valid(); ++it) - { - if (isSeperatingFace) { - INC_VAR((*it).m_v,m_numsf) - } else { - DEC_VAR((*it).m_v,m_numsf) - } - } - m_isSf[f] = isSeperatingFace; - } - bool possible = isPossFace(f); - if (possible && !m_fLink[f].valid()) - m_fLink[f] = m_possFaces.pushBack(f); - else if (!possible && m_fLink[f].valid()) { - m_possFaces.del(m_fLink[f]); - m_fLink[f] = ListIterator(); - } - } - - ListIterator it, itPrev; - for (it = m_updateNodes.rbegin(); it.valid(); it = itPrev) - { - itPrev = it.pred(); - node v = *it; - if (v != m_vLeft && m_virtEdge[prev(v)] == true) - setUpdate(prev(v)); - } - - while (!m_updateNodes.empty()) - { - node v = m_updateNodes.popFrontRet(); - m_vUpdate[v] = false; - - bool possible = isPossNode(v); - if (possible && !m_vLink[v].valid()) - m_vLink[v] = m_possNodes.pushBack(v); - else if (!possible && m_vLink[v].valid()) { - m_possNodes.del(m_vLink[v]); - m_vLink[v] = ListIterator(); - } - possible = isPossVirt(v); - if (possible && !m_virtLink[v].valid()) - m_virtLink[v] = m_possVirt.pushBack(v); - else if (!possible && m_virtLink[v].valid()) { - m_possVirt.del(m_virtLink[v]); - m_virtLink[v] = ListIterator(); - } - } -} - - -int ComputeBicOrder::getBaseChain(ConstCombinatorialEmbedding &E, - face f, - double baseRatio, - adjEntry &adjLeft, - adjEntry &adjRight) -{ - int len; - adjLeft = findMaxBaseChain(E, f, len); - len = max(2, min(len, (int)(baseRatio*f->size()+0.5))); - - adjRight = adjLeft; - for (int i = 2; i < len; i++) - adjRight = adjRight->faceCycleSucc(); - - return len; -} - - -struct QType -{ - QType (adjEntry adj, int i) { - m_start = adj; - m_limit = i; - } - QType () { - m_start = 0; - m_limit = 0; - } - - adjEntry m_start; - int m_limit; -}; - - -adjEntry ComputeBicOrder::findMaxBaseChain(ConstCombinatorialEmbedding &E, - face f, - int &length) -{ - const Graph &G = (const Graph &) E; - int p = f->size(); - - NodeArray num(G,-1); - - int i = 0, j, d; - - adjEntry adj; - forall_face_adj(adj,f) - num[adj->theNode()] = i++; - - Array > diag(0,p-1); - forall_face_adj(adj,f) - { - i = num[adj->theNode()]; - adjEntry adj2; - for (adj2 = adj->cyclicPred(); adj2 != adj->cyclicSucc(); - adj2 = adj2->cyclicPred()) - { - j = num[adj2->twinNode()]; - if (j != -1) - diag[i].pushBack(j); - } - } - - SListPure Q; - Array > posInQ (0,p-1,SListIterator()); - - length = 0; - bool firstRun = true; - adj = f->firstAdj(); - i = num[adj->theNode()]; - - adjEntry adjStart = 0; - do { - if (posInQ[i].valid()) { - adjEntry adj2 = Q.front().m_start; - d = (i-num[adj2->theNode()]+p) % p +1; - if (d > length || (d == length && adj2->theNode()->index() < adjStart->theNode()->index())) { - length = d; - adjStart = adj2; - } - SListIterator it, itLimit = posInQ[i]; - do { - it = Q.begin(); - posInQ[(*it).m_limit] = SListIterator(); - Q.popFront(); - } while (it != itLimit); - } - - if (diag[i].empty()) - j = (i-2+p) % p; - else { - int m = p; - SListConstIterator it; - for(it = diag[i].begin(); it.valid(); ++it) { - int k = *it; - d = (k-i+p)%p; - if (d < m) { - m = d; - j = k; - } - } - j = (j-1+p) % p; - if (!firstRun) { - posInQ[Q.back().m_limit] = 0; - Q.back().m_limit = j; - posInQ[j] = Q.rbegin(); - } - } - - if (firstRun) - posInQ[j] = Q.pushBack(QType(adj,j)); - - adj = adj->faceCycleSucc(); - i = num[adj->theNode()]; - if (i == 0) firstRun = false; - } while (!Q.empty()); - - return adjStart; -} - - -//--------------------------------------------------------- -// BiconnectedShellingOrder -//--------------------------------------------------------- - -void BiconnectedShellingOrder::doCall(const Graph &G, - adjEntry adj, - List &partition) -{ - OGDF_ASSERT(isBiconnected(G) == true); - OGDF_ASSERT(G.representsCombEmbedding() == true); - - ConstCombinatorialEmbedding E(G); - - face extFace = (adj != 0) ? E.rightFace(adj) : E.maximalFace(); - ComputeBicOrder cpo(G,E,extFace,m_baseRatio); - - cpo.initPossibles(); - -#ifdef OUTPUT_BSO - cout << "after initialization:\n"; - cpo.print(); -#endif - - while(cpo.getPossible()) - { - switch(cpo.nextPoss()) - { - case ComputeBicOrder::typeFace: - partition.pushFront(ShellingOrderSet()); - cpo.removeNextFace(partition.front()); - break; - - case ComputeBicOrder::typeNode: - partition.pushFront(ShellingOrderSet()); - cpo.removeNextNode(partition.front()); - break; - - case ComputeBicOrder::typeEdge: - partition.pushFront(ShellingOrderSet()); - cpo.removeNextVirt(partition.front()); - break; - } - - cpo.doUpdate(); - -#ifdef OUTPUT_BSO - cout << "after update:\n"; - cpo.print(); -#endif - } - - partition.pushFront(ShellingOrderSet(2)); - cpo.setV1(partition.front()); -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarlayout/FPPLayout.cpp b/ext/OGDF/src/planarlayout/FPPLayout.cpp deleted file mode 100644 index 700a87733..000000000 --- a/ext/OGDF/src/planarlayout/FPPLayout.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definition of the Fraysseix, Pach, Pollack Algorithm (FPPLayout) - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include - -namespace ogdf { - -FPPLayout::FPPLayout() : PlanarGridLayoutModule() { -} - -void FPPLayout::doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) -{ - // check for double edges & self loops - OGDF_ASSERT(isSimple(G)); - - // handle special case of graphs with less than 3 nodes - if (G.numberOfNodes() < 3) { - node v1, v2; - switch (G.numberOfNodes()) { - case 0: - boundingBox = IPoint(0, 0); - return; - - case 1: - v1 = G.firstNode(); - gridLayout.x(v1) = gridLayout.y(v1) = 0; - boundingBox = IPoint(0, 0); - return; - - case 2: - v1 = G.firstNode(); - v2 = G.lastNode(); - gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0; - gridLayout.x(v2) = 1; - boundingBox = IPoint(1, 0); - return; - } - } - - // make a copy for triangulation - GraphCopy GC(G); - - // embed - if (!fixEmbedding) { - if (planarEmbed(GC) == false) { - OGDF_THROW_PARAM(PreconditionViolatedException, pvcPlanar); - } - } - - triangulate(GC); - - // get edges for outer face (triangle) - adjEntry e_12; - if (adjExternal != 0) { - edge eG = adjExternal->theEdge(); - edge eGC = GC.copy(eG); - e_12 = (adjExternal == eG->adjSource()) ? eGC->adjSource() : eGC->adjTarget(); - } - else { - e_12 = GC.firstEdge()->adjSource(); - } - adjEntry e_2n = e_12->faceCycleSucc(); - - NodeArray num(GC); - - NodeArray e_wp(GC); // List of predecessors on circle C_k - NodeArray e_wq(GC); // List of successors on circle C_k - - computeOrder(GC, num , e_wp, e_wq, e_12, e_2n, e_2n->faceCycleSucc()); - computeCoordinates(GC, boundingBox, gridLayout, num, e_wp, e_wq); -} - - -void FPPLayout::computeOrder( - const GraphCopy &G, - NodeArray &num, - NodeArray &e_wp, - NodeArray &e_wq, - adjEntry e_12, - adjEntry e_2n, - adjEntry e_n1) -{ - NodeArray num_diag(G, 0); // number of chords - // link[v] = Iterator in possible, that points to v (if diag[v] = 0 and outer[v] = TRUE) - NodeArray > link(G, 0); - // outer[v] = TRUE <=> v is a node of the actual outer face - NodeArray outer(G, false); - // List of all nodes v with outer[v] = TRUE and diag[v] = 0 - List possible; - - // nodes of the outer triangle (v_1,v_2,v_n) - node v_1 = e_12->theNode(); - node v_2 = e_2n->theNode(); - node v_n = e_n1->theNode(); - node v_k, wp, wq, u; - adjEntry e, e2; - int k; - - // initialization: beginn with outer face (v_1,v_2,v_n) - // v_n is the only possible node - num[v_1] = 1; - num[v_2] = 2; - - outer[v_1] = true; - outer[v_2] = true; - outer[v_n] = true; - - link[v_n] = possible.pushBack(v_n); - - e_wq[v_1] = e_n1->twin(); - e_wp[v_2] = e_2n; - - e_wq[v_n] = e_2n->twin(); - e_wp[v_n] = e_n1; - - // select next v_k and delete it - for (k = G.numberOfNodes(); k >= 3; k--) { - v_k = possible.popFrontRet(); // select arbitrary node from possible as v_k - - num[v_k] = k; - - // predecessor wp and successor wq from vk in C_k (actual outer face) - wq = (e_wq [v_k])->twinNode(); - wp = (e_wp [v_k])->twinNode(); - - // v_k not in C_k-1 anymore - outer[v_k] = false; - - // shortfall of a chord? - if (e_wq[wp]->cyclicSucc()->twinNode() == wq) { // wp, wq is the only successor of vk in G_k - // wp, wq loose a chord - if (--num_diag[wp] == 0) { - link[wp] = possible.pushBack(wp); - } - if (--num_diag[wq] == 0) { - link[wq] = possible.pushBack(wq); - } - } - - // update or initialize e_wq, e_wp - e_wq[wp] = e_wq[wp]->cyclicSucc(); - - e_wp[wq] = e_wp[wq]->cyclicPred(); - e = e_wq[wp]; - for (u = e->twinNode(); u != wq; u = e->twinNode()) { - outer[u] = true; - e_wp[u] = e->twin(); - e = e_wq[u] = e_wp[u]->cyclicSucc()->cyclicSucc(); - - // search for new chords - for (e2 = e_wp[u]->cyclicPred(); e2 != e_wq[u]; e2 = e2->cyclicPred()) { - node w = e2->twinNode(); - if (outer[w] == true) { - ++num_diag[u]; - if (w != v_1 && w != v_2) - if (++num_diag[w] == 1) possible.del(link[w]); - } - } - - if (num_diag[u] == 0) { - link[u] = possible.pushBack(u); - } - } - } -} - - -void FPPLayout::computeCoordinates(const GraphCopy &G, IPoint &boundingBox, GridLayout &gridLayout, NodeArray &num, - NodeArray &e_wp, NodeArray &e_wq) { - NodeArray &x = gridLayout.x(); - NodeArray &y = gridLayout.y(); - - const int n = G.numberOfNodes(); - NodeArray x_rel(G); - NodeArray upper(G); - NodeArray next(G); - Array v(1, n); - node w, vk, wp, wq; - int k, xq, dx; - - forall_nodes(w, G) { - v[num[w]] = (node) w; - } - - x_rel[v[1]] = 0; - x_rel[v[2]] = 0; - y[G.original(v[1])] = 0; - y[G.original(v[2])] = 0; - - next[v[1]] = v[2]; - next[v[2]] = 0; - - for (k = 3; k <= n; k++) { - vk = v[k]; - wp = e_wp [vk]->twinNode(); - wq = e_wq [vk]->twinNode(); - - xq = 2; - w = wp; - do { - w = next [w]; - xq += x_rel[w]; - } - while (w != wq); - - x_rel[vk] = (xq + y[G.original(wq)] - y[G.original(wp)]) / 2; - y[G.original(vk)] = (xq + y[G.original(wq)] + y[G.original(wp)]) / 2; - x_rel[wq] = xq - x_rel[vk]; - - dx = 1; - for (w = next[wp]; w != wq; w = next[w]) { - dx += x_rel[w]; - x[G.original(w)] = dx - x_rel[vk]; - upper[w] = vk; - } - - next[wp] = vk; - next[vk] = wq; - } - - // calculate absolute x-coordinate off the outer face - x[G.original(v[n])] = x_rel[v[n]]; - x[G.original(v[2])] = x[G.original(v[n])] + x_rel[v[2]]; - x[G.original(v[1])] = 0; - - // calculate absolute x-coordinate for all inner nodes - for (k = n - 1; k >= 3; k--) { - x[G.original(v[k])] += x[G.original(upper[v[k]])]; - } - - // compute grid bounding box - int xr = 0, yt = 0; - switch (n) { - case 0: - case 1: - break; - case 2: - xr = 1; - break; - default: - yt = n - 2; - xr = 2 * (n - 2); - } - - boundingBox = IPoint(xr, yt); -} - - -} //namespace ogdf diff --git a/ext/OGDF/src/planarlayout/IOPoints.cpp b/ext/OGDF/src/planarlayout/IOPoints.cpp deleted file mode 100644 index 4bf53b098..000000000 --- a/ext/OGDF/src/planarlayout/IOPoints.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation in-/out-points management. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "IOPoints.h" - - -namespace ogdf { - - -ListConstIterator IOPoints::searchRealForward( - ListConstIterator it) const -{ - while (it.valid() && marked((*it).m_adj)) - ++it; - - return it; -} - -ListConstIterator IOPoints::searchRealBackward( - ListConstIterator it) const -{ - while (it.valid() && marked((*it).m_adj)) - --it; - - return it; -} - - -void IOPoints::restoreDeg1Nodes(PlanRep &PG, Stack &S) -{ - List deg1s; - - PG.restoreDeg1Nodes(S,deg1s); - - ListConstIterator it; - for(it = deg1s.begin(); it.valid(); ++it) { - adjEntry adj = (*it)->firstAdj(); - m_mark[adj] = m_mark[adj->twin()] = true; - } -} - - -adjEntry IOPoints::switchBeginIn(node v) -{ - List &Lin = m_in [v]; - List &Lout = m_out[v]; - - ListConstIterator it; - adjEntry adj; - - while ((it = Lin.begin()).valid() && marked(adj = (*it).m_adj)) - m_pointOf[adj] = &(*Lout.pushFront(Lin.popFrontRet())); - - return it.valid() ? adj : 0; -} - - -adjEntry IOPoints::switchEndIn(node v) -{ - List &Lin = m_in [v]; - List &Lout = m_out[v]; - - ListConstIterator it; - adjEntry adj; - - while ((it = Lin.rbegin()).valid() && marked(adj = (*it).m_adj)) - m_pointOf[adj] = &(*Lout.pushBack(Lin.popBackRet())); - - return it.valid() ? adj : 0; -} - - -void IOPoints::switchBeginOut(node v) -{ - List &Lin = m_in [v]; - List &Lout = m_out[v]; - - adjEntry adj = (*Lout.begin()).m_adj; - m_pointOf[adj] = &(*Lin.pushFront(Lout.popFrontRet())); -} - - -void IOPoints::switchEndOut(node v) -{ - List &Lin = m_in [v]; - List &Lout = m_out[v]; - - adjEntry adj = (*Lout.rbegin()).m_adj; - m_pointOf[adj] = &(*Lin.pushBack(Lout.popBackRet())); -} - - -void IOPoints::numDeg1(node v, int &xl, int &xr, - bool doubleCount) const -{ - const List &L = m_out[v]; - ListConstIterator it; - - xl = xr = 0; - for (it = L.begin(); it.valid() && marked((*it).m_adj); ++it) - ++xl; - - if (doubleCount || it.valid()) // avoid double counting if all are marked - for (it = L.rbegin(); it.valid() && marked((*it).m_adj); --it) - ++xr; -} - -InOutPoint IOPoints::middleNeighbor(node z1) const -{ - const List &L = m_in[z1]; - - ListConstIterator it, itFound; - int i, pos = (L.size()-1)/2; - - for (it = L.begin().succ(), i = 1; i <= pos || !itFound.valid(); ++it, ++i) - if (!marked((*it).m_adj)) - itFound = it; - - return *itFound; -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/IOPoints.h b/ext/OGDF/src/planarlayout/IOPoints.h deleted file mode 100644 index 66b6bd6fb..000000000 --- a/ext/OGDF/src/planarlayout/IOPoints.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * $Revision: 2571 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 17:25:20 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of classes InOutPoint and IOPoints which - * implement the management of in-/out-points - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_IO_POINTS_H -#define OGDF_IO_POINTS_H - - -#include - - -namespace ogdf { - - -/******************************************************************** - representation of an in- or outpoint -********************************************************************/ - -struct InOutPoint -{ - int m_dx, m_dy; - adjEntry m_adj; - - InOutPoint() { - m_dx = m_dy = 0; m_adj = 0; - } - InOutPoint(adjEntry adj) { - m_adj = adj; m_dx = m_dy = 0; - } -}; - - -/******************************************************************** - representation of in- and outpoint lists -********************************************************************/ - -class IOPoints { -public: - IOPoints() { } - IOPoints(const Graph &G) : m_depth(G,0), m_height(G,0), m_in(G), m_out(G), - m_mark(G,false), m_pointOf(G,0) { } - - ~IOPoints () { } - - - // length of in- or outpoint list - int out(node v) const { - return m_out[v].size(); - } - int in(node v) const { - return m_in[v].size(); - } - - // getting a const-reference to in- or outpoint list - const List &inpoints(node v) const { - return m_in [v]; - } - List &inpoints(node v) { - return m_in [v]; - } - - const List &outpoints(node v) const { - return m_out [v]; - } - List &outpoints(node v) { - return m_out [v]; - } - - // getting the in-/outpoint belonging to an adjacency entry - const InOutPoint *pointOf(adjEntry adj) const { - return m_pointOf[adj]; - } - - // marking adjacency entries - bool marked(adjEntry adj) const { - return m_mark[adj]; - } - - bool marked(node v) { - return (v->outdeg() == 1 && marked(v->firstAdj())); - } - - // finding outpoints belonging to non-marked edges - ListConstIterator firstRealOut(node v) const { - return searchRealForward(m_out[v].begin()); - } - - ListConstIterator lastRealOut(node v) const { - return searchRealBackward(m_out[v].rbegin()); - } - - ListConstIterator nextRealOut(ListConstIterator it) const { - return searchRealForward(it.succ()); - } - - ListConstIterator prevRealOut(ListConstIterator it) const { - return searchRealBackward(it.pred()); - } - - // building in-/outpoint lists - void appendInpoint(adjEntry adj) { - node v = adj->theNode(); - m_pointOf[adj] = &(*m_in[v].pushBack(InOutPoint(adj))); - } - void appendOutpoint(adjEntry adj) { - node v = adj->theNode(); - m_pointOf[adj] = &(*m_out[v].pushBack(InOutPoint(adj))); - } - void pushInpoint(adjEntry adj) { - node v = adj->theNode(); - m_pointOf[adj] = &(*m_in[v].pushFront(InOutPoint(adj))); - } - - // setting relative coordinates - void setOutCoord (ListIterator it, int dx, int dy) { - (*it).m_dx = dx; - (*it).m_dy = dy; - } - void setInCoord (ListIterator it, int dx, int dy) { - (*it).m_dx = dx; - (*it).m_dy = dy; - } - - void setOutDx(ListIterator it, int dx) { - (*it).m_dx = dx; - } - - void restoreDeg1Nodes(PlanRep &PG, Stack &S); - - void changeEdge(node v, adjEntry adj_new) { - m_out[v].popBack(); - appendInpoint(adj_new); - } - - // belongs v to a chain (= at most to non-marked incoming edges - bool isChain(node v) const { - int i = 0; - ListConstIterator it; - for(it = m_in[v].begin(); it.valid(); ++it) - if (!marked((*it).m_adj)) ++i; - return (i <= 2); - } - - // width of the left-/right side of an in-/outpoint list - int outLeft(node v) const { - return (m_out[v].empty()) ? 0 : (-m_out[v].front().m_dx); - } - - int outRight(node v) const { - return (m_out[v].empty()) ? 0 : (m_out[v].back().m_dx); - } - - int inLeft(node v) const { - return (m_in[v].empty()) ? 0 : (-m_in[v].front().m_dx); - } - - int inRight(node v) const { - return (m_in[v].empty()) ? 0 : (m_in[v].back().m_dx); - } - - int maxLeft(node v) const { - return max(inLeft(v), outLeft(v)); - } - - int maxRight(node v) const { - return max(inRight(v), outRight(v)); - } - - int maxPlusLeft(node v) const { - return (in(v) >= 3) ? - max(inLeft(v)+1, outLeft(v)) : maxLeft(v); - } - - int maxPlusRight(node v) const { - return (in(v) >= 3) ? - max(inRight(v)+1, outRight(v)) : maxRight(v); - } - - InOutPoint middleNeighbor(node z1) const; - - void numDeg1(node v, int &xl, int &xr, - bool doubleCount) const; - - adjEntry switchBeginIn(node v); - adjEntry switchEndIn (node v); - - void switchBeginOut(node v); - void switchEndOut (node v); - - - NodeArray m_depth, m_height; - - -private: - NodeArray > m_in, m_out; - AdjEntryArray m_mark; - AdjEntryArray m_pointOf; - - ListConstIterator searchRealForward (ListConstIterator it) const; - ListConstIterator searchRealBackward(ListConstIterator it) const; -}; - - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/src/planarlayout/MMCBBase.cpp b/ext/OGDF/src/planarlayout/MMCBBase.cpp deleted file mode 100644 index abc44de6f..000000000 --- a/ext/OGDF/src/planarlayout/MMCBBase.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Mixed-Model crossings beautifiers. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - - -namespace ogdf { - - -//------------------------------------------------------------------ -// MMCBBase -//------------------------------------------------------------------ - -void MMCBBase::insertBend(GridLayout &gl, edge e, node v, int x, int y) -{ - if (v == e->target()) { - gl.bends(e).pushBack(IPoint(x,y)); - } else { - gl.bends(e).pushFront(IPoint(x,y)); - } -} - - -void MMCBBase::copyOn(int old_a[] , int new_a[]) -{ - for (int i = 0; i < 3; ++i) - new_a[i] = old_a[i]; -} - - -int MMCBBase::workOn(GridLayout &gl, node v) -{ - edge L[4]; - int ev[4][3]; - int count = 0; - - adjEntry adj; - forall_adj(adj,v) - { - edge e = adj->theEdge(); - - IPolyline &ip = gl.bends(e); - int xc = gl.x(v), yc = gl.y(v); - int xxc = gl.x(v), yyc = gl.y(v); - int add_l = 0; - do { - if (ip.size() < (1+add_l) ) { - if (v == e->target()) { - xc = gl.x(e->source()); - yc = gl.y(e->source()); - } else { - xc = gl.x(e->target()); - yc = gl.y(e->target()); - } - } else { - IPoint p; - if (v == e->target()) { - p = *ip.get(ip.size()-add_l -1); - } else { - p = *ip.get(1+add_l -1); - } - xc = p.m_x; - yc = p.m_y; - } - ++add_l; - } while((xc == xxc) && (yc == yyc)); - - if (xc < gl.x(v)) - ev[count][0] = -1; - else if (xc == gl.x(v)) - ev[count][0] = 0; - else - ev[count][0] = 1; - - if (yc < gl.y(v)) - ev[count][1] = -1; - else if (yc == gl.y(v)) - ev[count][1] = 0; - else - ev[count][1] = 1; - - L[count] = e; - ++count; - if (3 < count) - break; - } - - for (int i = 0; i < 4 ; i++) - { - if (ev[i][0] > 0) { - ev[i][2] = 4 + ev[i][1] + 2; - - } else if (ev[i][0] == 0) { - if(ev[i][1] > 0) { - ev[i][2] = 0; - } else { - ev[i][2] = 4; - } - - } else { - ev[i][2] = -ev[i][1]+2; - } - } - - int ew[4][3]; - edge Lw[4]; - - int k = 4; - for (int i = 0; (i < 8) && (k >= 0) ; i++) - { - for (int j = 0; j < 4; j++) - { - if (i == ev[j][2]) { - copyOn(ev[j],ew[4-k]); - edge edge_k = L[j]; - Lw[4-k] = edge_k; - --k; - } - } - } - - //so now in ew the edges are in an order against the clock starting at position 0,1 - int ea, eb; - int crossingCase = 0; - - ea = ew[2][2] - ew[0][2]; - if (ea > 4) - ea = 8 - ea; - eb = ew[3][2] - ew[1][2]; - if (eb > 4) - eb = 8 - eb; - - // first case: there is an edge with angle of pi/2 - // in this case i'm going to, well, cut this edge - // e4 O _/e3 Ooo _/ - // O _/ Ooo _/ - // \ O _/ \ OXo - // O / _/ Ooo - // -- *ooooooo^ ==> -- / Ooo - // e2 - // / | \ / | \_ - // e1 - - int lw_add = 0; - if (ea <= 2) { - if (ew[2][2] - ew[0][2] > 4) { - lw_add = 2; - crossingCase = 1; - } else { - crossingCase = 1; - } - } else if (eb <=2) { - if (ew[3][2] - ew[1][2] > 4) { - lw_add = 1; - crossingCase = 1; - } else { - lw_add = 3; - crossingCase = 1; - } - - // second case: both angles are 3pi/4, in this case - // i'm going to take both of them back with a row - // ^ _/ ooO _/ - // O _/ ooO _/ - // O _/ Ooo _/ - // O/ Ooo _/ - // *o ==> OXo - // |Ooo _/ Ooo - // | Oo _/ Ooo - // | Ooo \_ Ooo - // | Oo \_ Oo - // - } else if (ea == 3) { - if (eb == 3) { - if (ew[1][2]-ew[0][2] >= 3) { - if (ew[1][2]-ew[0][2] == 3) - crossingCase = 2; - else - crossingCase = 3; - } - else if (ew[2][2]-ew[1][2] >= 3) { - lw_add = 3; - if (ew[2][2]-ew[1][2] == 3) - crossingCase=2; - else - crossingCase=3; - } else if (ew[3][2]-ew[2][2] >= 3) { - lw_add = 2; - if (ew[3][2]-ew[2][2] == 3) - crossingCase=2; - else - crossingCase=3; - } else { - lw_add = 1; - if (ew[3][2]-ew[0][2] == 3) - crossingCase=2; - else - crossingCase=3; - } - - // third case: one of the angles is 3pi/4 and the other one is pi - // ^ O - // O O - // O O - // O O - // --------*o------- ==> ---------X-------- - // Ooo O - // Ooo O - // Ooo O - // Oo Ooooooooo - // - } else { - if (ew[1][2]-ew[0][2] == 2) { - crossingCase=4; - } - else { - lw_add = 2; - crossingCase=4; - } - } - } else if (eb == 3) { - if (ew[2][2]-ew[1][2] == 2) { - lw_add = 3; - crossingCase=4; - } else { - lw_add = 1; - crossingCase=4; - } - } - - // v, Lw, ev - copyOn(ew[(0+lw_add) %4],ev[0]); - copyOn(ew[(1+lw_add) %4],ev[1]); - copyOn(ew[(2+lw_add) %4],ev[2]); - copyOn(ew[(3+lw_add) %4],ev[3]); - - edge e0 = Lw[(0+lw_add) %4]; - edge e1 = Lw[(1+lw_add) %4]; - edge e2 = Lw[(2+lw_add) %4]; - edge e3 = Lw[(3+lw_add) %4]; - - int retVal = 0; - - switch(crossingCase) - { - case 4: - if ((ev[0][0]*ev[0][1] == 0) || (gl.bends(e3).size() > 0)) { - insertBend(gl,e3,v,gl.x(v)-ev[1][0],gl.y(v)-ev[1][1]); - } else { - insertBend(gl,e0,v,gl.x(v)+ev[3][0],gl.y(v)+ev[3][1]); - insertBend(gl,e2,v,gl.x(v)-ev[3][0],gl.y(v)-ev[3][1]); - insertBend(gl,e1,v,gl.x(v)+ev[0][0]+ev[3][0],gl.y(v)+ev[0][1]+ev[3][1]); - } - break; - - case 3: - if (ev[0][0]*ev[0][1] != 0) { - insertBend(gl,e0,v,gl.x(v)-ev[2][0],gl.y(v)-ev[2][1]); - insertBend(gl,e1,v,gl.x(v)-ev[3][0],gl.y(v)-ev[3][1]); - } else { - gl.x(v) = gl.x(v)+ev[2][0]-ev[1][0]; - gl.y(v) = gl.y(v)+ev[2][1]-ev[1][1]; - if (ev[2][0]-ev[1][0] == 0) { - retVal = 2; - } else { - retVal = 1; - } - } - break; - - case 2: - insertBend(gl,e1,v,gl.x(v)-ev[3][0],gl.y(v)-ev[3][1]); - insertBend(gl,e2,v,gl.x(v)-ev[0][0],gl.y(v)-ev[0][0]); - break; - - case 1: - if (ev[0][0]*ev[0][1] == 0) { - int old_x = gl.x(v); - int old_y = gl.y(v); - int x_plus = (ev[0][0]+ev[2][0]); - int y_plus = (ev[0][1]+ev[2][1]); - insertBend(gl,e0,v,old_x+2*ev[0][0],old_y+2*ev[0][1]); - insertBend(gl,e2,v,old_x+2*ev[2][0],old_y+2*ev[2][1]); - insertBend(gl,e1,v,old_x,old_y); - insertBend(gl,e3,v,old_x,old_y); - gl.x(v) = old_x+x_plus; - gl.y(v) = old_y+y_plus; - retVal = 3; - } else { - int old_x = gl.x(v); - int old_y = gl.y(v); - - gl.x(v) = gl.x(v)+ev[1][0]; - gl.y(v) = gl.y(v)+ev[1][1]; - insertBend(gl,e3,v,old_x,old_y); - insertBend(gl,e1,v,gl.x(v)+ev[1][0],gl.y(v)+ev[1][1]); - if (ev[1][0] != 0) { - retVal = 1; - } else { - retVal = 2; - } - - } - break; - - case 0: - retVal = 0; - break; - - OGDF_NODEFAULT - } - - return retVal; -} - - -//------------------------------------------------------------------ -// MMCBDoubleGrid -//------------------------------------------------------------------ - -void MMCBDoubleGrid::doCall(const PlanRep &PG, GridLayout &gl, const List &L) -{ - edge e; - forall_edges(e,PG) { - ListIterator it; - for(it = gl.bends(e).begin(); it.valid(); ++it) { - IPoint &p = *it; - p.m_x *= 2; - p.m_y *= 2; - } - } - - node v; - forall_nodes(v,PG) { - gl.x(v) *= 2; - gl.y(v) *= 2; - } - - ListConstIterator itV; - for(itV = L.begin(); itV.valid(); ++itV) - workOn(gl,*itV); -} - - -//------------------------------------------------------------------ -// MMCBLocalStretch -//------------------------------------------------------------------ - -void MMCBLocalStretch::doCall(const PlanRep &PG, GridLayout &gl, const List &L) -{ - int max_x = 0, max_y = 0; - - edge e; - forall_edges(e,PG) { - ListIterator it; - for(it = gl.bends(e).begin(); it.valid(); ++it) { - IPoint &p = *it; - if (p.m_x > max_x) max_x = p.m_x; - if (p.m_y > max_y) max_y = p.m_y; - p.m_x *= 2; - p.m_y *= 2; - } - } - - node v; - forall_nodes(v,PG) { - if (gl.x(v) > max_x) max_x = gl.x(v); - if (gl.y(v) > max_y) max_y = gl.y(v); - gl.x(v) *= 2; - gl.y(v) *= 2; - } - - Array change_x(0,max_x,1); - Array change_y(0,max_y,1); - - change_x[0] = 0; - change_y[0] = 0; - - ListConstIterator itV; - for(itV = L.begin(); itV.valid(); ++itV) { - v = *itV; - int val = workOn(gl,v); - if (val > 0) { - if (val != 2) - change_x[(gl.x(v)+1)/2] = 0; - if (val != 1) - change_y[(gl.y(v)+1)/2] = 0; - } - } - - if (max_x > 1) - for (int i = 1; i <= max_x; i++) { - change_x[i] = change_x[i] + change_x[i-1]; - } - if (max_y > 1) - for (int i = 1; i <= max_y; i++) { - change_y[i] = change_y[i] + change_y[i-1]; - } - - forall_edges(e,PG) { - ListIterator it; - for(it = gl.bends(e).begin(); it.valid(); ++it) { - IPoint &p = *it; - p.m_x = p.m_x - change_x[(p.m_x+1)/2]; - p.m_y = p.m_y - change_y[(p.m_y+1)/2]; - } - } - - forall_nodes(v,PG) { - gl.x(v)=gl.x(v)-change_x[(gl.x(v)+1)/2]; - gl.y(v)=gl.y(v)-change_y[(gl.y(v)+1)/2]; - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/MMOrder.h b/ext/OGDF/src/planarlayout/MMOrder.h deleted file mode 100644 index 78f7a2c64..000000000 --- a/ext/OGDF/src/planarlayout/MMOrder.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * $Revision: 2571 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 17:25:20 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Declaration of shelling order used by the Mixed-Model - * layout algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MM_ORDER_H -#define OGDF_MM_ORDER_H - - -#include - - -namespace ogdf { - - -class MMOrder -{ -public: - MMOrder() { } - - void init(PlanRep &PG, ShellingOrderModule &compOrder, adjEntry adjExternal); - - int rank(node v) const { - return m_lmc.rank(v); - } - - int length() const { - return m_lmc.length(); - } - - const ShellingOrderSet &operator[](int k) const { - return m_lmc[k]; - } - - node operator()(int k, int i) const { - return m_lmc(k,i); - } - - int len(int k) const { - return m_lmc.len(k); - } - - Array m_left, m_right; - - -private: - ShellingOrder m_lmc; -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/src/planarlayout/MixedModelBase.cpp b/ext/OGDF/src/planarlayout/MixedModelBase.cpp deleted file mode 100644 index 6cc7666fb..000000000 --- a/ext/OGDF/src/planarlayout/MixedModelBase.cpp +++ /dev/null @@ -1,1122 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Mixed-Model basic functionality. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include "MixedModelBase.h" -#include -#include - - -namespace ogdf { - - -/******************************************************************** - hasLeft, hasRight - - Determine if the kth set in the ordered partition has a "real" - left or right vertex, respectively. -********************************************************************/ - -bool MixedModelBase::hasLeft (int k) const -{ - const ShellingOrderSet &V = m_mmo[k]; - const List &L = m_iops.inpoints(V[1]); - - ListConstIterator it = L.begin(); - return (it.valid() && (*it).m_adj->twinNode() == m_mmo.m_left[k]); -} - -bool MixedModelBase::hasRight(int k) const -{ - const ShellingOrderSet &V = m_mmo[k]; - const List &L = m_iops.inpoints(V[V.len()]); - - ListConstIterator it = L.rbegin(); - return (it.valid() && (*it).m_adj->twinNode() == m_mmo.m_right[k]); -} - - -/******************************************************************** - computeOrder - - Computes the ordered partition (incl. m_left[k], m_right[k]) and - constructs the in- and outpoint lists. -********************************************************************/ - - -void MixedModelBase::computeOrder( - AugmentationModule &augmenter, - EmbedderModule *pEmbedder, - adjEntry adjExternal, - ShellingOrderModule &compOrder) -{ - // remove (temporary) deg-1-nodes; - removeDeg1Nodes(); - - // augment PG (temporary) to achieve required connectivity - List augmentedEdges; - augmenter.call(m_PG,augmentedEdges); - - // embed augmented graph (if required) - if(pEmbedder) - pEmbedder->call(m_PG,adjExternal); - - // compute ordering of biconnected plane graph - m_mmo.init(m_PG, compOrder, adjExternal); - - // restore deg1-nodes and mark incident edges - m_iops.restoreDeg1Nodes(m_PG,m_deg1RestoreStack); - - // compute in- and outpoint lists - for (int k = 1; k <= m_mmo.length(); ++k) - { - const ShellingOrderSet &V = m_mmo[k]; - for (int i = 1; i <= V.len(); ++i) - { - node v = V[i]; - node cl = (i == 1) ? V.left () : V[i-1]; - node cr = (i == V.len()) ? V.right() : V[i+1]; - - //edge e, er = 0, el = 0; - adjEntry adj, adjR = 0, adjL = 0; - forall_adj(adj,v) - { - node t = adj->twinNode(); - if (t == cr) adjR = adj; - if (t == cl) adjL = adj; - } - // one of adjL and adjR is not 0 by definition of the ordering - if (adjR == 0) adjR = adjL; - if (adjL == 0) adjL = adjR; - - adj = adjR; - do { - if (exists(adj)) - m_iops.pushInpoint(adj); - adj = adj->cyclicSucc(); - } while (m_iops.marked(adj) || (m_mmo.rank(adj->twinNode()) <= k && adj != adjR)); - - for ( ; m_iops.marked(adj) || m_mmo.rank(adj->twinNode()) > k; adj = adj->cyclicSucc()) - if (exists(adj)) - m_iops.appendOutpoint(adj); - - // move In-/Outpoints to deg1-nodes to appropriate places - adjL = m_iops.switchBeginIn(v); - adjR = m_iops.switchEndIn (v); - - // has a left- or right edge ? - bool has_el = (adjL != 0); - bool has_er = (adjR != 0); - if (adjL && adjL == adjR) { - has_el = (adjL->twinNode() != cr); - has_er = !has_el; - } - - // determine left(k) and right(k) - if (i == 1) m_mmo.m_left [k] = (has_el) ? adjL->twinNode() : cl; - if (i == V.len()) m_mmo.m_right[k] = (has_er) ? adjR->twinNode() : cr; - - int xl, xr; - m_iops.numDeg1(v,xl,xr,has_el || has_er); - - int x = 0; - if (!has_el) x += xl; - if (!has_er) x += xr; - - int x_alpha = max(0,min(x, (m_iops.in(v)-m_iops.out(v)+1+2*x-2)/2)); - int x_beta = x - x_alpha; - - if (!has_el) - for( ; x_beta > 0 && xl > 0; --x_beta, --xl) - m_iops.switchBeginOut(v); - if (!has_er) - for( ; x_beta > 0 && xr > 0; --x_beta, --xr) - m_iops.switchEndOut(v); - } - } - - // remove augmented edges - ListConstIterator itE; - for(itE = augmentedEdges.begin(); itE.valid(); ++itE) - m_PG.delEdge(*itE); -} - - -/******************************************************************** - removeDeg1Nodes - - Removes deg-1-nodes and store informations for restoring them. -********************************************************************/ - -void MixedModelBase::removeDeg1Nodes() -{ - NodeArray mark(m_PG,false); - node v; - - // mark all deg-1-nodes we want to remove - int n = m_PG.numberOfNodes(); - forall_nodes(v,m_PG) { - if (n <= 3) break; - if ((mark[v] = (v->degree() == 1)) == true) { - node w = v->firstAdj()->twinNode(); - if (mark[w]) mark[w] = false; else --n; - } - } - - m_PG.removeDeg1Nodes(m_deg1RestoreStack,mark); -} - - -/******************************************************************** - assignIopCoords - - Computes the relative coordinates of the in- and outpoints, - incl. height(v), depth(v). -********************************************************************/ - -void MixedModelBase::assignIopCoords() -{ - for (int k = 1; k <= m_mmo.length(); ++k) - { - const ShellingOrderSet &V = m_mmo[k]; - - for (int i = 1; i <= V.len(); ++i) - { - node v = V[i]; - - bool onlyLeft = (m_iops.in(v) == 2 && - i >= 2 && m_iops.inpoints(v).front().m_adj->twinNode() == V[i-1] && - m_iops.marked(m_iops.inpoints(v).back().m_adj)); - bool onlyRight = (m_iops.in(v) == 2 && - i < V.len() && m_iops.inpoints(v).back().m_adj->twinNode() == V[i+1] && - m_iops.marked(m_iops.inpoints(v).front().m_adj)); - - if (m_iops.out(v) >= 1) - { - int outL = 0, outR = 0; - - int outPlus = m_iops.out(v)/2; - int outMinus = m_iops.out(v) - 1 - outPlus; - int deltaL = 0, deltaR = 0; - outL = outMinus; - - if (m_iops.in(v) == 2) { - deltaL = (onlyRight) ? 0 : 1; - deltaR = (onlyLeft) ? 0 : 1; - - } else if (m_iops.in(v) >= 3) { - deltaL = deltaR = 1; - - } else if (m_iops.in(v) == 1) { - node vl = (i == 1) ? m_mmo.m_left[k] : V[i-1]; - if (m_iops.inpoints(v).front().m_adj->twinNode() != vl) { - outL = outPlus; - deltaR = 1; - - } else { - deltaL = 1; - } - } - - outR = m_iops.out(v) - 1 - outL; - - List &opl = m_iops.outpoints(v); - int j; - ListIterator it = opl.begin(); - for (j = 0; j < outL; j++, ++it) - m_iops.setOutCoord(it,-outL+j,deltaL+j); - m_iops.m_height[v] = max(outL+deltaL,outR+deltaR)-1; - if (m_iops.m_height[v] == 0 && m_iops.marked((*it).m_adj)) - m_iops.m_height[v] = 1; - m_iops.setOutCoord(it,0,m_iops.m_height[v]); - for (j = 1, ++it; j <= outR; j++, ++it) - m_iops.setOutCoord(it,j,outR+deltaR-j); - } - - if (m_iops.in(v) <= 3) - { - List &ipl = m_iops.inpoints(v); - int in_v = m_iops.in(v); - - if (in_v == 3 || (in_v == 2 && !onlyRight)) { - if (m_iops.marked(ipl.front().m_adj)) - m_iops.setInCoord(ipl.begin(),-1,0); - } - if (in_v == 3 || (in_v == 2 && !onlyLeft)) { - if (m_iops.marked(ipl.back().m_adj)) - m_iops.setInCoord(ipl.rbegin(), 1,0); - } - if (in_v != 0 && (in_v != 2 || onlyLeft || onlyRight)) { - ListIterator it = ipl.begin(); - if (in_v == 3 || (in_v == 2 && onlyLeft)) - ++it; - if (m_iops.marked((*it).m_adj)) { - m_iops.setInCoord(it,0,-1); - m_iops.m_depth[v] = 1; - } - } - - } else { - int in_l = (m_iops.in(v)-3) / 2; - int in_r = m_iops.in(v)-3 - in_l; - - int j; - List &ipl = m_iops.inpoints(v); - ListIterator it = ipl.begin(); - m_iops.setInCoord(it,(in_l == 0 && m_iops.marked((*it).m_adj)) ? -1 : -in_l,0); - for (j = 1, ++it; j <= in_l; ++j, ++it) - m_iops.setInCoord(it,j-in_l-1,-j); - m_iops.setInCoord(it,0,-in_r); - m_iops.m_depth[v] = in_r; // inpoint with smallest y-coordinate - for (j = 1, ++it; j <= in_r; ++j, ++it) - m_iops.setInCoord(it,j,j-in_r-1); - m_iops.setInCoord(it,in_r,0); - } - } - } -} - - -/******************************************************************** - placeNodes - - Implements the placement step. Computes x[v] and y[v]. -********************************************************************/ - -void MixedModelBase::placeNodes() -{ - m_dyl.init(2,m_mmo.length()); - m_dyr.init(2,m_mmo.length()); - - m_leftOp .init(2,m_mmo.length()); - m_rightOp.init(2,m_mmo.length()); - - m_nextLeft .init(m_PG); - m_nextRight.init(m_PG); - m_dxla.init(m_PG,0); - m_dxra.init(m_PG,0); - - computeXCoords(); - computeYCoords(); -} - - -/******************************************************************** - computeXCoords - - Computes the absolute x-coordinates x[v] of all nodes in the - ordering, furthermore dyla[k] and dyra[k] (used by compute_y_coordinates) -********************************************************************/ - -void MixedModelBase::computeXCoords() -{ - NodeArray &x = m_gridLayout.x(); - - int k, i; - node v; - - // representation of the contour - NodeArray prev(m_PG), next(m_PG); - NodeArray father(m_PG, 0); - - // maintaining of free space for shifting - Array shiftSpace(1,m_mmo.length(), 0); - NodeArray comp(m_PG,0); - - forall_nodes(v,m_PG) { - m_nextLeft [v] = m_iops.firstRealOut(v); - m_nextRight[v] = m_iops.lastRealOut (v); - } - - // last_right[v] = last vertex of highest set with right vertex v - NodeArray lastRight(m_PG,0); - for(k = 2; k <= m_mmo.length(); ++k) { - const ShellingOrderSet &V = m_mmo[k]; - lastRight[m_mmo.m_right[k]] = V[V.len()]; - } - - NodeArray high(m_PG,0); - forall_nodes(v,m_PG) { - InOutPoint op; - ListConstIterator it; - for(it = m_iops.outpoints(v).begin(); it.valid(); ++it) { - if (!m_iops.marked((*it).m_adj)) - high[v] = max(m_mmo.rank((*it).m_adj->twinNode()), high[v]); - } - } - - // initialization - const ShellingOrderSet &V1 = m_mmo[1]; - int p = V1.len(); - - x[V1[1]] = m_iops.outLeft(V1[1]); - for (i = 2; i <= p; i++) { - x[V1[i]] = m_iops.maxRight(V1[i-1]) + m_iops.maxLeft(V1[i]) + 1; - } - - for (i = 1; i <= p; i++) { - if (i < p) next[V1[i]] = V1[i+1]; - if (i > 1) prev[V1[i]] = V1[i-1]; - } - prev [V1[1]] = next [V1[p]] = 0; - - // main loop - for(k = 2; k <= m_mmo.length(); ++k) - { - // consider set Vk - const ShellingOrderSet &Vk = m_mmo[k]; - p = Vk.len(); - node z1 = Vk[1]; - node cl = m_mmo.m_left[k]; - node cr = m_mmo.m_right[k]; - - if (!hasLeft(k)) { - while(lastRight[cl] && high[cl] < k && !hasRight(m_mmo.rank(lastRight[cl]))) - cl = m_mmo.m_left[k] = lastRight[cl]; - } - - // determine temporarily the x-coordinates of c_l+1,...,c_r relative to cl - int sum = 0; - for (v = next[cl]; v != cr; v = next[v]) { - sum += x[v]; x[v] = sum; - } - x[cr] += sum; - - m_leftOp [k] = m_nextRight[cl]; - m_rightOp[k] = m_nextLeft [cr]; - - // compute dxl, dxr, dyl, dyr - int dxl, dxr; - m_dyl[k] = m_dyr[k] = 0; - - ListConstIterator it; - if ((it = m_nextRight[cl]).valid()) { - dxl = (*it).m_dx; - if ((*it).m_adj->twinNode() != z1) - dxl++; - else - m_nextRight[cl] = m_iops.prevRealOut(it); - - if (dxl < 0) - m_dyl[k] = m_iops.m_height[cl]; - else if ((++it).valid()) - m_dyl[k] = (*it).m_dy; - } else { - dxl = (m_iops.out(cl) == 0) ? 0 : -m_iops.outLeft(cl); - } - if ((it = m_nextLeft[cr]).valid()) { - dxr = (*it).m_dx; - if ((*it).m_adj->twinNode() != Vk[p]) - dxr--; - else - m_nextLeft[cr] = m_iops.nextRealOut(it); - - if (dxr > 0) - m_dyr[k] = m_iops.m_height[cr]; - else if ((it = it.pred()).valid()) - m_dyr[k] = (*it).m_dy; - } else { - dxr = (m_iops.out(cr) == 0) ? 0 : m_iops.outRight(cr); - } - - m_dxla[Vk[1]] = dxl; m_dxra[Vk[p]] = dxr; - - int old_x_cr; - - // vertex case - if (!m_iops.isChain(z1)) - { - InOutPoint ip_ct = m_iops.middleNeighbor(z1); - InOutPoint op_ct = *m_iops.pointOf(ip_ct.m_adj->twin()); - node ct = ip_ct.m_adj->twinNode(); - - int delta = dxl + m_iops.maxPlusLeft(z1) + ip_ct.m_dx - (x[ct] + op_ct.m_dx); - if (delta < 0) delta = 0; - x[ct] += delta; - - int x_0 = x[ct] + op_ct.m_dx - ip_ct.m_dx; - - int sum = 0; - for (v = prev[ct]; v != cl; v = prev[v]) { - x[v] -= sum; - if (m_nextRight[v].valid() && (*m_nextRight[v]).m_adj->twinNode() == z1) { - InOutPoint op_v = *m_nextRight[v]; - InOutPoint ip_v = *m_iops.pointOf(op_v.m_adj->twin()); - int diff = x[v] + op_v.m_dx - x_0 - ip_v.m_dx; - if (diff > 0) { - sum += diff; - x[v] -= diff; - } - } - } - - for (v = next[cl]; v != next[ct]; v = next[v]) - x[v] += sum; - x_0 += sum; - - sum += delta; - - for (v = next[ct]; v != next[cr]; v = next[v]) { - x[v] += sum; - if (m_nextRight[v].valid() && (*m_nextRight[v]).m_adj->twinNode() == z1) { - InOutPoint op_v = *m_nextRight[v]; - InOutPoint ip_v = *m_iops.pointOf(op_v.m_adj->twin()); - int diff = x[v] + op_v.m_dx - x_0 - ip_v.m_dx; - if (diff < 0) { - sum -= diff; - x[v] -= diff; - } - } - } - - x[z1] = x_0; - - old_x_cr = x[cr] - x[z1]; - x[cr] = max(old_x_cr, m_iops.maxPlusRight(z1) - dxr); - - for (v = next[cl]; v != cr; v = next[v]) { - x[v] = x[v] - x[z1]; - father[v] = z1; - } - - // chain case - } else { - int sum = x[z1] = m_iops.maxPlusLeft(z1) + dxl; - for (i = 2; i <= p; i++) - sum += (x[Vk[i]] = m_iops.maxRight(Vk[i-1]) + m_iops.maxLeft(Vk[i]) + 1); - - old_x_cr = x[cr] - sum; - int new_x_cr = m_iops.maxPlusRight(Vk[p]) - dxr; - x[cr] = max(old_x_cr, new_x_cr); - shiftSpace[k] = max(0, old_x_cr - new_x_cr); - - for (v = next[cl]; v != cr; v = next[v]) { - x[v] = x[v] - x[z1]; - father[v] = z1; - } - } - - int need = x[cr] - old_x_cr; - int k_cr = m_mmo.rank(cr); - if (shiftSpace[k_cr] > 0) { - int use = min(shiftSpace[k_cr], need); - shiftSpace[k_cr] -= use; - comp[cr] += use; - x[m_mmo.m_right[k_cr]] -= use; - } - - // update contour after insertion of z1,...,zp - for (i = 1; i <= p; i++) { - if (i < p) next[Vk[i]] = Vk[i+1]; - if (i > 1) prev[Vk[i]] = Vk[i-1]; - } - - next [prev [z1] = cl] = z1; - prev [next [Vk[p]] = cr] = Vk[p]; - - } - - // compute final x-coordinates for nodes on final contour - int sum = 0; - for (v = V1[1]; v != 0; v = next[v]) - x [v] = (sum += x[v]); - - // compute final x-coordinates for inner nodes - for (k = m_mmo.length(); k >= 1; k--) { - for (i = 1; i <= m_mmo.len(k); i++) { - v = m_mmo(k,i); - if (father[v] != 0) { - x[v] = x[v] + x[father[v]] - comp[father[v]]; - } - } - } -} - - -/******************************************************************** - computeYCoords - - Computes the absolute y-coordinates y[v] of all nodes in the - ordering. -********************************************************************/ - -class SetYCoords -{ -public: - SetYCoords(const Graph &G, const IOPoints &iops, const MMOrder &mmo, - const NodeArray &x, const NodeArray &y) : - m_G(G), m_iops(iops), m_mmo(mmo), m_x(x), m_y(y) { - } - - void init(int k); - - void checkYCoord (int xleft, int xright, int ys, bool nodeSep); - void checkYCoord (int xs, int ys, bool nodeSep ) { - checkYCoord (xs, xs, ys, nodeSep); - } - - int getYmax() const { - return m_ymax; - } - - // avoid automatic creation of assignment operator - SetYCoords &operator=(const SetYCoords &); - -private: - void getNextRegion(); - node z(int j) const { - return (*m_V)[j]; - } - - bool marked(adjEntry adj) const { - return m_iops.marked(adj); - } - - const InOutPoint &outpoint(const InOutPoint &ip) { - return *m_iops.pointOf(ip.m_adj->twin()); - } - - void searchNextInpoint(); - - const Graph &m_G; - const IOPoints &m_iops; - const MMOrder &m_mmo; - const NodeArray &m_x; - const NodeArray &m_y; - const ShellingOrderSet *m_V; - - int m_k; - node m_cl, m_cr; - - int m_ymax, m_xNext, m_lookAheadX, m_lookAheadNextX; - int m_i, m_iNext, m_deltaY, m_infinity; - ListConstIterator m_itIp, m_itIpNext, m_itLookAhead; - bool m_onBase; -}; - -void SetYCoords::init(int k) -{ - m_k = k; m_V = &m_mmo[k]; - m_ymax = 0; - m_lookAheadX = 0; - - m_i = 0; - m_cl = m_mmo.m_left[k]; m_cr = m_mmo.m_right[k]; - - m_onBase = true; m_xNext = -1; - m_infinity = m_x[m_cr] + m_iops.outRight(m_cr) + 1; - - searchNextInpoint(); - m_itIp = m_itIpNext; m_i = m_iNext; - - getNextRegion(); -} - -void SetYCoords::searchNextInpoint() -{ - m_iNext = m_i; m_itIpNext = m_itIp; - - do { - if (!m_itIpNext.valid()) { - if (++m_iNext > m_V->len()) { - m_itIpNext = ListConstIterator(); - return; - } - m_itIpNext = m_iops.inpoints(z(m_iNext)).begin(); - } else { - ++m_itIpNext; - } - } while (!m_itIpNext.valid() || (*m_itIpNext).m_dy == 0); - - if (m_itIpNext.valid() && m_iops.marked((*m_itIpNext).m_adj)) { - int ipX = m_x[z(m_iNext)] + (*m_itIpNext).m_dx; - - if (m_lookAheadX <= ipX) { - for (m_itLookAhead = m_itIpNext; - (*m_itLookAhead).m_dx < 0 && m_iops.marked((*m_itLookAhead).m_adj); - ++m_itLookAhead) ; - - const InOutPoint &ipLookAhead = *m_itLookAhead; - m_lookAheadX = m_x[z(m_iNext)] + ipLookAhead.m_dx; - if(ipLookAhead.m_dx < 0) { - m_lookAheadNextX = m_x[ipLookAhead.m_adj->twinNode()] + outpoint(ipLookAhead).m_dx; - } else { - m_lookAheadNextX = m_lookAheadX; - } - } - - if (m_lookAheadNextX <= ipX) { - m_itIpNext = m_itLookAhead; - } - } -} - - -void SetYCoords::getNextRegion() -{ - int xOld = m_xNext; - - do { - if (m_onBase) { - m_deltaY = 0; - if (!m_itIp.valid()) { - m_xNext = m_infinity; - } else { - const InOutPoint &ip = *m_itIp; - m_xNext = (marked(ip.m_adj)) ? (m_x[z(m_i)] + ip.m_dx) : - (m_x[ip.m_adj->twinNode()] + outpoint(ip).m_dx); - } - m_onBase = (m_iNext != m_i); - - } else { - const InOutPoint &ip = *m_itIp; - m_deltaY = -ip.m_dy; - searchNextInpoint(); - if (m_itIpNext.valid() && ip.m_dx < 0) { - const InOutPoint &m_ipNext = *m_itIpNext; - m_xNext = (marked(m_ipNext.m_adj)) ? (m_x[z(m_i)] + m_ipNext.m_dx) : - (m_x[m_ipNext.m_adj->twinNode()] + outpoint(m_ipNext).m_dx); - } else { - m_xNext = (marked(ip.m_adj)) ? (m_x[z(m_i)] + ip.m_dx + 1) : - (m_x[ip.m_adj->twinNode()] + outpoint(ip).m_dx + 1); - } - - m_onBase = (m_iNext != m_i); - m_i = m_iNext; m_itIp = m_itIpNext; - } - } while (m_xNext <= xOld); -} - -void SetYCoords::checkYCoord(int xleft, int xright, int ys, bool nodeSep) -{ - while (m_xNext <= xleft) - getNextRegion(); - - int maxDy = m_deltaY; - - while (m_xNext <= xright) { - getNextRegion(); - if (m_deltaY > maxDy) maxDy = m_deltaY; - } - - if (nodeSep && maxDy == 0) - maxDy = 1; - - if (ys + maxDy > m_ymax) - m_ymax = ys + maxDy; -} - -void MixedModelBase::computeYCoords() -{ - NodeArray &x = m_gridLayout.x(), &y = m_gridLayout.y(); - - int k, i; - - // representation of the contour - NodeArray prev(m_PG), next(m_PG); - - // initialization - SetYCoords setY(m_PG,m_iops,m_mmo,x,y); - - const ShellingOrderSet &V1 = m_mmo[1]; - int p = V1.len(); - - for (i = 1; i <= p; ++i) { - if (i < p) next[V1[i]] = V1[i+1]; - if (i > 1) prev[V1[i]] = V1[i-1]; - } - prev [V1[1]] = next [V1[p]] = 0; - - // main loop - for (k = 2; k <= m_mmo.length(); ++k) - { - // consider set Vk - const ShellingOrderSet &Vk = m_mmo[k]; - p = Vk.len(); - node cl = m_mmo.m_left[k]; - node cr = m_mmo.m_right[k]; - - setY.init(k); - - for(node v = cl; v != next[cr]; v = next[v]) - { - ListConstIterator itFirst, itLast; - - const List &out = m_iops.outpoints(v); - - if (v == cl) { - if (!(itFirst = m_leftOp[k]).valid()) - itFirst = out.begin(); - else if ((*itFirst).m_adj->twinNode() != Vk[1]) - ++itFirst; - - for(itLast = itFirst; itLast.valid() && (m_iops.marked((*itLast).m_adj) || - (*itLast).m_adj->twinNode() == Vk[1]); ++itLast) ; - - } else if (v == cr) { - itLast = m_rightOp[k]; - if (itLast.valid() && (*itLast).m_adj->twinNode() == Vk[p]) - ++itLast; - itFirst = (itLast.valid()) ? itLast.pred() : out.rbegin(); - - while(itFirst.valid() && (m_iops.marked((*itFirst).m_adj) || - (*itFirst).m_adj->twinNode() == Vk[p])) - --itFirst; - itFirst = (itFirst.valid()) ? itFirst.succ() : out.begin(); - - } else { - itFirst = m_nextLeft[v]; - itFirst = (itFirst.valid()) ? itFirst.pred() : out.rbegin(); - - while (itFirst.valid() && m_iops.marked((*itFirst).m_adj)) - --itFirst; - - itFirst = (itFirst.valid()) ? itFirst.succ() : out.begin(); - - if (m_nextRight[v].valid() && m_nextLeft[v] == m_nextRight[v]) { - for (itLast = m_nextRight[v].succ(); itLast.valid() && m_iops.marked((*itLast).m_adj); - ++itLast) ; - } else { - itLast = m_nextLeft[v]; - } - } - if (v != cr && itFirst != itLast && m_mmo.rank(next[v]) > m_mmo.rank(v)) { - int x_n_v = x[next[v]] - m_iops.outLeft(next[v]); - ListConstIterator it = (itLast.valid()) ? itLast.pred() : out.rbegin(); - for( ; ; ) { - if(x[v]+(*it).m_dx >= x_n_v) - itLast = it; - else break; - if (it == itFirst) break; - --it; - } - } - - if (v != cl) { - int xl = x[prev[v]], xr = x[v]; - int r_p_v = m_mmo.rank(prev[v]), r_v = m_mmo.rank(v); - - if (r_p_v >= r_v) { - if (m_iops.out(prev[v]) > 0) - xl += 1+m_iops.outRight(prev[v]); - } else { - xl += m_dxla[v]; - } - if (r_p_v <= r_v) { - if (m_iops.out(v) > 0) - xr -= 1+m_iops.outLeft(v); - } else { - xr += m_dxra[prev[v]]; - } - - if (xl <= xr) - setY.checkYCoord(xl, xr, 1+max(y[prev[v]],y[v]), false); - } - - for (ListConstIterator it = itFirst; it != itLast; ++it) { - const InOutPoint &op = *it; - - if (m_iops.marked(op.m_adj)) - setY.checkYCoord(x[v]+op.m_dx, y[v]+op.m_dy+1, false); - else - setY.checkYCoord(x[v]+op.m_dx, y[v]+op.m_dy, - (op.m_dx == 0 && op.m_dy == 0 && x[v] == x[op.m_adj->twinNode()])); - } - } - - for (i = 1; i <= p; i++) { - y[Vk[i]] = setY.getYmax(); - } - - // update contour after insertion of z1,...,zp - for (i = 1; i <= p; i++) { - if (i < p) next[Vk[i]] = Vk[i+1]; - if (i > 1) prev[Vk[i]] = Vk[i-1]; - } - - next [prev [Vk[1]] = cl] = Vk[1]; - prev [next [Vk[p]] = cr] = Vk[p]; - } -} - - -/******************************************************************** - setBends - - Assigns polylines to edges of the original graph and computes the - x- and y-coordinates of deg-1-nodes not in the ordering. -********************************************************************/ - -void MixedModelBase::setBends () -{ - //printMMOrder(cout); - //printInOutPoints(cout); - //cout.flush(); - - NodeArray &x = m_gridLayout.x(), &y = m_gridLayout.y(); - EdgeArray &bends = m_gridLayout.bends(); - - for(int k = 1; k <= m_mmo.length(); ++k) - { - for (int i = 1; i <= m_mmo[k].len(); ++i) - { - node v_s = m_mmo(k,i); - adjEntry adj; - forall_adj(adj,v_s) - { - node v_t = adj->twinNode(); - edge e = adj->theEdge(); - const InOutPoint &p_s = *m_iops.pointOf(adj); - if (m_iops.marked(adj)) { - x[v_t] = x[v_s] + p_s.m_dx; - y[v_t] = y[v_s] + p_s.m_dy; - } - else if(e->source() == adj->theNode()) - { - const InOutPoint &p_t = *m_iops.pointOf(adj->twin()); - IPoint p1 (x[v_s] + p_s.m_dx, y[v_s] + p_s.m_dy); - IPoint p2 (x[v_t] + p_t.m_dx, y[v_t] + p_t.m_dy); - - bends[e].pushBack(p1); - if (m_mmo.rank(v_s) < m_mmo.rank(v_t)) { - bends[e].pushBack(IPoint(p1.m_x,p2.m_y)); - } else { - bends[e].pushBack(IPoint(p2.m_x,p1.m_y)); - } - bends[e].pushBack(p2); - } - } - } - } -} - - -/******************************************************************** - postprocessing1 - - Tries to reduce the number of bends by changing the outpoints of - nodes with indeg and outdeg 2. -********************************************************************/ - -void MixedModelBase::postprocessing1() -{ - NodeArray &x = m_gridLayout.x(); - - for(int k = 2; k <= m_mmo.length(); ++k) { - const ShellingOrderSet &V = m_mmo[k]; - node v = V[V.len()]; - - if (m_iops.in(v) != 2 || m_iops.out(v) != 2) continue; - - const List &in = m_iops.inpoints (v); - List &out = m_iops.outpoints(v); - adjEntry adjL = (*in.begin ()).m_adj; - adjEntry adjR = (*in.rbegin()).m_adj; - - if (!m_iops.marked(adjL) && !m_iops.marked(adjR) && - x[adjL->twinNode()] + m_iops.pointOf(adjL->twin())->m_dx < x[v] && - x[adjR->twinNode()] + m_iops.pointOf(adjR->twin())->m_dx == x[v]+1 && - m_gridLayout.y(adjR->twinNode()) < m_gridLayout.y(v)) - { - x[v] += 1; - m_iops.setOutDx(out.begin (),-1); - m_iops.setOutDx(out.rbegin(), 0); - } - } -} - - -/******************************************************************** - postprocessing2 - - Tries to reduce the number of bends by moving degree-2 nodes on - bend points. -********************************************************************/ - -void MixedModelBase::firstPoint(int &x, int &y, adjEntry adj) -{ - edge e = adj->theEdge(); - bool sameDirection = (adj->theNode() == e->source()); - - if (m_gridLayout.bends(e).empty()) { - node t = (sameDirection) ? e->target() : e->source(); - x = m_gridLayout.x(t); - y = m_gridLayout.y(t); - } else { - if(sameDirection) { - x = m_gridLayout.bends(e).front().m_x; - y = m_gridLayout.bends(e).front().m_y; - } else { - x = m_gridLayout.bends(e).back().m_x; - y = m_gridLayout.bends(e).back().m_y; - } - } -} - -bool MixedModelBase::isRedundant(int x1, int y1, int x2, int y2, int x3, int y3) -{ - int dzy1 = x3 - x2; - int dzy2 = y3 - y2; - int dyx1 = x2 - x1; - - if (dzy1 == 0) return (dyx1 == 0); - - int f = dyx1 * dzy2; - - return (f % dzy1 == 0 && (y2 - y1) == f / dzy1); -} - -void MixedModelBase::postprocessing2() -{ - m_gridLayout.compactAllBends(); - - node v; - forall_nodes(v,m_PG) - { - if(v->degree() != 2) continue; - - adjEntry adj1 = v->firstAdj(); - edge e1 = adj1->theEdge(); - adjEntry adj2 = v->lastAdj(); - edge e2 = adj2->theEdge(); - - IPolyline &bends1 = m_gridLayout.bends(e1); - IPolyline &bends2 = m_gridLayout.bends(e2); - - if (bends1.empty() && bends2.empty()) continue; - - int x1,y1,x3,y3; - firstPoint(x1,y1,adj1); - firstPoint(x3,y3,adj2); - - if (isRedundant(x1,y1,m_gridLayout.x(v),m_gridLayout.y(v),x3,y3)) { - if (!bends1.empty()) { - m_gridLayout.x(v) = x1; - m_gridLayout.y(v) = y1; - if(adj1->theNode() == e1->source()) - bends1.popFront(); - else - bends1.popBack(); - } else { - m_gridLayout.x(v) = x3; - m_gridLayout.y(v) = y3; - if(adj2->theNode() == e2->source()) - bends2.popFront(); - else - bends2.popBack(); - } - } - } -} - - -/******************************************************************** - debugging output -********************************************************************/ - -void MixedModelBase::printMMOrder(ostream &os) -{ - int k, i; - - os << "left and right:\n\n"; - for (k = 1; k <= m_mmo.length(); ++k) - { - const ShellingOrderSet &V = m_mmo[k]; - - os << k << ": { "; - for (i = 1; i <= V.len(); i++) - os << V[i] << " "; - os << "};"; - if (k >= 2) - os << " cl = " << m_mmo.m_left[k] << - ", cr = " << m_mmo.m_right[k]; - os << endl; - - } - os.flush(); -} - -void MixedModelBase::printInOutPoints(ostream &os) -{ - node v; - - os << "\n\nin- and outpoint lists:\n"; - forall_nodes(v,m_PG) { - const List &in = m_iops.inpoints (v); - const List &out = m_iops.outpoints(v); - - os << "\n" << v << ":\n"; - os << " outpoints: "; - ListConstIterator it; - for(it = out.begin(); it.valid(); ++it) { - print(os,*it); - os << " "; - } - os << "\n inpoints: "; - for(it = in.begin(); it.valid(); ++it) { - print(os,*it); - os << " "; - } - } - os << endl; -} - -void MixedModelBase::print(ostream &os, const InOutPoint &iop) -{ - if(iop.m_adj) - os << "[(" << m_PG.original(iop.m_adj->theNode()) << "," << - m_PG.original(iop.m_adj->twinNode()) << ")," << - iop.m_dx << "," << iop.m_dy << "]"; - else - os << "[ ]"; -} - -void MixedModelBase::printNodeCoords(ostream &os) -{ - node v; - - os << "\nx- and y-coordinates:\n\n"; - forall_nodes(v,m_PG) - os << v << ": (" << m_gridLayout.x(v) << "," << m_gridLayout.y(v) << ")\n"; -} - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/MixedModelBase.h b/ext/OGDF/src/planarlayout/MixedModelBase.h deleted file mode 100644 index 9a8f4890c..000000000 --- a/ext/OGDF/src/planarlayout/MixedModelBase.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * $Revision: 2571 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-10 17:25:20 +0200 (Di, 10. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Base functionality of Mixed-Model layout algorithm - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef OGDF_MIXED_MODEL_BASE_H -#define OGDF_MIXED_MODEL_BASE_H - - -#include -#include -#include -#include -#include - -#include "MMOrder.h" -#include "IOPoints.h" - - -namespace ogdf { - - -class MixedModelBase -{ -public: - MixedModelBase(PlanRep &PG, GridLayout &gridLayout) : - m_PG(PG), m_adjExternal(0), m_gridLayout(gridLayout), m_iops(PG) { } - - virtual ~MixedModelBase() { } - - void computeOrder( - AugmentationModule &augmenter, - EmbedderModule *pEmbedder, - adjEntry adjExternal, - ShellingOrderModule &compOrder); - - void assignIopCoords(); - - void placeNodes(); - void computeXCoords(); - void computeYCoords(); - - void setBends(); - void postprocessing1(); - void postprocessing2(); - - - // functions for debugging output - - void printMMOrder(std::ostream &os); - void printInOutPoints(std::ostream &os); - void print(std::ostream &os, const InOutPoint &iop); - void printNodeCoords(std::ostream &os); - - // avoid creation of assignment operator - MixedModelBase &operator=(const MixedModelBase &); - -private: - PlanRep &m_PG; - adjEntry m_adjExternal; - - GridLayout &m_gridLayout; - - MMOrder m_mmo; - IOPoints m_iops; - Stack m_deg1RestoreStack; - - Array m_dyl, m_dyr; - Array > m_leftOp, m_rightOp; - NodeArray > m_nextLeft, m_nextRight; - NodeArray m_dxla, m_dxra; - - - bool exists(adjEntry adj) { - return m_PG.isDummy(adj->theEdge()) == false; - } - - bool hasLeft (int k) const; - bool hasRight(int k) const; - - void removeDeg1Nodes(); - - void firstPoint(int &x, int &y, adjEntry adj); - bool isRedundant(int x1, int y1, int x2, int y2, int x3, int y3); -}; - - -} // end namespace ogdf - - -#endif diff --git a/ext/OGDF/src/planarlayout/MixedModelCrossingsBeautifierModule.cpp b/ext/OGDF/src/planarlayout/MixedModelCrossingsBeautifierModule.cpp deleted file mode 100644 index 0a685bcf1..000000000 --- a/ext/OGDF/src/planarlayout/MixedModelCrossingsBeautifierModule.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief The interface for mixed-model crossings beautifier - * algorithms - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void MixedModelCrossingsBeautifierModule::call (const PlanRep &PG, GridLayout &gl) -{ - node v; - List crossings; - forall_nodes(v,PG) { - if (PG.isDummy(v)) - crossings.pushBack(v); - } - - gl.compactAllBends(); - doCall(PG,gl,crossings); - m_nCrossings = crossings.size(); - gl.compactAllBends(); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/MixedModelLayout.cpp b/ext/OGDF/src/planarlayout/MixedModelLayout.cpp deleted file mode 100644 index 6ffee5725..000000000 --- a/ext/OGDF/src/planarlayout/MixedModelLayout.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of Mixed-Model layout algorithm. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - -#include "MixedModelBase.h" - - -namespace ogdf { - - -void MMOrder::init( - PlanRep &PG, - ShellingOrderModule &compOrder, - adjEntry adjExternal) -{ - compOrder.callLeftmost(PG, m_lmc, adjExternal); - m_left .init(1,m_lmc.length()); - m_right.init(1,m_lmc.length()); -} - - -MixedModelLayout::MixedModelLayout() -{ - m_augmenter.set(new PlanarAugmentation); - m_compOrder.set(new BiconnectedShellingOrder); - m_crossingsBeautifier.set(new MMDummyCrossingsBeautifier); - m_embedder.set(new SimpleEmbedder); -} - - -void MixedModelLayout::doCall( - PlanRep &PG, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) -{ - // handle graphs with less than 3 nodes - node v1, v2; - switch (PG.numberOfNodes()) { - case 0: - boundingBox = IPoint(0,0); - return; - - case 1: - v1 = PG.firstNode(); - gridLayout.x(v1) = gridLayout.y(v1) = 0; - boundingBox = IPoint(0,0); - return; - - case 2: - v1 = PG.firstNode(); - v2 = v1->succ(); - gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0; - gridLayout.x(v2) = 1; - boundingBox = IPoint(1,0); - return; - } - - MixedModelBase mm(PG,gridLayout); - - if(fixEmbedding) { - OGDF_ASSERT(PG.representsCombEmbedding()); - PlanarAugmentationFix fixAugmenter; - mm.computeOrder(fixAugmenter, 0, adjExternal, m_compOrder.get()); - } else - mm.computeOrder(m_augmenter.get(),&m_embedder.get(),0,m_compOrder.get()); - - mm.assignIopCoords(); - mm.placeNodes(); - mm.postprocessing1(); - mm.setBends(); - mm.postprocessing2(); - - m_crossingsBeautifier.get().call(PG,gridLayout); - - int xmin, ymin; - gridLayout.computeBoundingBox(xmin,boundingBox.m_x,ymin,boundingBox.m_y); -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/PlanarDrawLayout.cpp b/ext/OGDF/src/planarlayout/PlanarDrawLayout.cpp deleted file mode 100644 index 5bdba1dcb..000000000 --- a/ext/OGDF/src/planarlayout/PlanarDrawLayout.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class PlanarDrawLayout - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ogdf { - - -PlanarDrawLayout::PlanarDrawLayout() -{ - m_sizeOptimization = true; - m_sideOptimization = false; - m_baseRatio = 0.33; - - m_augmenter.set(new PlanarAugmentation); - m_computeOrder.set(new BiconnectedShellingOrder); - m_embedder.set(new SimpleEmbedder); -} - - -void PlanarDrawLayout::doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) -{ - // require to have a planar graph without multi-edges and self-loops; - // planarity is checked below - OGDF_ASSERT(isSimple(G) && isLoopFree(G)); - - // handle special case of graphs with less than 3 nodes - if(G.numberOfNodes() < 3) - { - node v1, v2; - switch(G.numberOfNodes()) - { - case 0: - boundingBox = IPoint(0,0); - return; - - case 1: - v1 = G.firstNode(); - gridLayout.x(v1) = gridLayout.y(v1) = 0; - boundingBox = IPoint(0,0); - return; - - case 2: - v1 = G.firstNode(); - v2 = G.lastNode (); - gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0; - gridLayout.x(v2) = 1; - boundingBox = IPoint(1,0); - return; - } - } - - // we make a copy of G since we use planar biconnected augmentation - GraphCopySimple GC(G); - - if(fixEmbedding) { - PlanarAugmentationFix augmenter; - augmenter.call(GC); - - } else { - // augment graph planar biconnected - m_augmenter.get().call(GC); - - // embed augmented graph - m_embedder.get().call(GC,adjExternal); - } - - // compute shelling order - m_computeOrder.get().baseRatio(m_baseRatio); - - ShellingOrder order; - m_computeOrder.get().call(GC,order,adjExternal); - - // compute grid coordinates for GC - NodeArray x(GC), y(GC); - computeCoordinates(GC,order,x,y); - - boundingBox.m_x = x[order(1,order.len(1))]; - boundingBox.m_y = 0; - node v; - forall_nodes(v,GC) - if(y[v] > boundingBox.m_y) boundingBox.m_y = y[v]; - - // copy coordinates from GC to G - forall_nodes(v,G) { - node vCopy = GC.copy(v); - gridLayout.x(v) = x[vCopy]; - gridLayout.y(v) = y[vCopy]; - } -} - -void PlanarDrawLayout::computeCoordinates(const Graph &G, - ShellingOrder &order, - NodeArray &x, - NodeArray &y) -{ - // let c_1,...,c_q be the the current contour, then - // next[c_i] = c_i+1, prev[c_i] = c_i-1 - NodeArray next(G), prev(G); - - // upper[v] = w means x-coord. of v is relative to w - // (abs. x-coord. of v = x[v] + abs. x-coord of w) - NodeArray upper(G,0); - - // maximal rank of a neighbour - NodeArray maxNeighbour(G,0); - // internal nodes (nodes not on contour) - BoundedStack internals(G.numberOfNodes()); - - node v; - forall_nodes(v,G) - { - adjEntry adj; - forall_adj(adj,v) { - int r = order.rank(adj->twinNode()); - if (r > maxNeighbour[v]) - maxNeighbour[v] = r; - } - } - - // initialize contour with base - const ShellingOrderSet &V1 = order[1]; - node v1 = V1[1]; - node v2 = V1[V1.len()]; - node rightSide = v2; - - int i; - for (i = 1; i <= V1.len(); ++i) - { - y[V1[i]] = 0; - x[V1[i]] = (i == 1) ? 0 : 1; - if (i < V1.len()) - next[V1[i]] = V1[i+1]; - if (i > 1) - prev[V1[i]] = V1[i-1]; - } - prev[v1] = next[v2] = 0; - - // process shelling order from bottom to top - for (int k = 2; k <= order.length(); k++) - { - // Referenz auf aktuelle Menge Vk (als Abk?rzung) - const ShellingOrderSet &Vk = order[k]; // Vk = { z_1,...,z_l } - int l = Vk.len(); - - node z1 = Vk[1]; - node cl = Vk.left(); // left vertex - node cr = Vk.right(); // right vertex - - bool isOuter; - if (m_sideOptimization && cr == rightSide && maxNeighbour[cr] <= k) - { - isOuter = true; - rightSide = Vk[l]; - } else - isOuter = false; - - // compute relative x-distance from c_i to cl for i = l+1, ..., r - int sum = 0; - for (v = next[cl]; v != cr; v = next[v]) { - sum += x[v]; - x[v] = sum; - } - x[cr] += sum; - - int eps = (maxNeighbour [cl] <= k && k > 2) ? 0 : 1; - - int x_cr, y_z; - if (m_sizeOptimization) - { - int yMax; - if (isOuter) - { - yMax = max(y[cl]+1-eps, - y[cr] + ((x[cr] == 1 && eps == 1) ? 1 : 0)); - for (v = next[cl]; v != cr; v = next[v]) { - if (x[v] < x[cr]) { - int y1 = (y[cr]-y[v])*(eps-x[cr])/(x[cr]-x[v])+y[cr]; - if (y1 >= yMax) - yMax = 1+y1; - } - } - for (v = cr; v != cl; v = prev[v]) { - if (y[prev[v]] > y[v] && maxNeighbour[v] >= k) { - if (yMax <= y[v] + x[v] - eps) { - eps = 1; - yMax = y[v] + x[v]; - } - break; - } - } - x_cr = max(x[cr]-eps-l+1, (y[cr] == yMax) ? 1 : 0); - y_z = yMax; - - } else { - // yMax = max { y[c_i] | l <= i <= r } - yMax = y[cl] - eps; - for (v = cr; v != cl; v = prev[v]) { - if (y[v] > yMax) - yMax = y[v]; - } - int offset = max (yMax-x[cr]+l+eps-y[cr], - (y[prev[cr]] > y[cr]) ? 1 : 0); - y_z = y[cr] + x[cr] + offset - l + 1 - eps; - x_cr = y_z - y[cr]; - } - - } else { - y_z = y[cr] + x[cr] + 1 - eps; - x_cr = y_z - y[cr]; - } - - node alpha = cl; - for (v = next[cl]; - maxNeighbour[v] <= k-1 && order.rank(v) <= order.rank(prev[v]); - v = next[v]) - { - if (order.rank (v) < order.rank (alpha)) - alpha = v; - if (v == cr) - break; - } - - node beta = prev[cr]; - for (v = prev[cr]; - maxNeighbour[v] <= k-1 && order.rank(v) <= order.rank(next[v]); - v = prev[v]) - { - if (order.rank (v) <= order.rank (beta)) - beta = v; - if (v == cl) - break; - } - - for (i = 1; i <= l; ++i) { - x[Vk[i]] = 1; - y[Vk[i]] = y_z; - } - x[z1] = eps; - - for (v = alpha; v != cl; v = prev [v]) { - upper[v] = cl; - internals.push (v); - } - for (v = next [beta]; v != cr; v = next [v]) { - upper[v] = cr; - x [v] -= x[cr]; - internals.push (v); - } - for (v = beta; v != alpha; v = prev[v]) { - upper[v] = z1; - x [v] -= x[z1]; - internals.push (v); - } - - x[cr] = x_cr; - - // update contour after insertion of z_1,...,z_l - for (i = 1; i <= l; i++) { - if (i < l) - next[Vk[i]] = Vk[i+1]; - if (i > 1) - prev[Vk[i]] = Vk[i-1]; - } - next [cl] = z1; - next [Vk[l]] = cr; - prev [cr] = Vk[l]; - prev [z1] = cl; - } - - // compute final x-coordinates for the nodes on the (final) contour - int sum = 0; - for (v = v1; v != 0; v = next[v]) - x [v] = (sum += x[v]); - - // compute final x-coordinates for the internal nodes - while (!internals.empty()) { - v = internals.pop(); - x[v] += x[upper[v]]; - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/planarlayout/PlanarStraightLayout.cpp b/ext/OGDF/src/planarlayout/PlanarStraightLayout.cpp deleted file mode 100644 index 584e0d0c7..000000000 --- a/ext/OGDF/src/planarlayout/PlanarStraightLayout.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class PlanarStraightLayout - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ogdf { - - -PlanarStraightLayout::PlanarStraightLayout() -{ - m_sizeOptimization = true; - m_baseRatio = 0.33; - - m_augmenter.set(new PlanarAugmentation); - m_computeOrder.set(new BiconnectedShellingOrder); - m_embedder.set(new SimpleEmbedder); -} - - -void PlanarStraightLayout::doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) -{ - // require to have a planar graph without multi-edges and self-loops; - // planarity is checked below - OGDF_ASSERT(isSimple(G) && isLoopFree(G)); - - // handle special case of graphs with less than 3 nodes - if(G.numberOfNodes() < 3) - { - node v1, v2; - switch(G.numberOfNodes()) - { - case 0: - boundingBox = IPoint(0,0); - return; - - case 1: - v1 = G.firstNode(); - gridLayout.x(v1) = gridLayout.y(v1) = 0; - boundingBox = IPoint(0,0); - return; - - case 2: - v1 = G.firstNode(); - v2 = G.lastNode (); - gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0; - gridLayout.x(v2) = 1; - boundingBox = IPoint(1,0); - return; - } - } - - // we make a copy of G since we use planar biconnected augmentation - GraphCopySimple GC(G); - - if(fixEmbedding) { - // determine adjacency entry on external face of GC (if required) - if(adjExternal != 0) { - edge eG = adjExternal->theEdge(); - edge eGC = GC.copy(eG); - adjExternal = (adjExternal == eG->adjSource()) ? eGC->adjSource() : eGC->adjTarget(); - } - - PlanarAugmentationFix augmenter; - augmenter.call(GC); - - } else { - adjExternal = 0; - - // augment graph planar biconnected - m_augmenter.get().call(GC); - - // embed augmented graph - m_embedder.get().call(GC,adjExternal); - } - - // compute shelling order with shelling order module - m_computeOrder.get().baseRatio(m_baseRatio); - - ShellingOrder order; - m_computeOrder.get().callLeftmost(GC,order,adjExternal); - - // compute grid coordinates for GC - NodeArray x(GC), y(GC); - computeCoordinates(GC,order,x,y); - - boundingBox.m_x = x[order(1,order.len(1))]; - boundingBox.m_y = 0; - node v; - forall_nodes(v,GC) - if(y[v] > boundingBox.m_y) boundingBox.m_y = y[v]; - - // copy coordinates from GC to G - forall_nodes(v,G) { - node vCopy = GC.copy(v); - gridLayout.x(v) = x[vCopy]; - gridLayout.y(v) = y[vCopy]; - } -} - - -void PlanarStraightLayout::computeCoordinates(const Graph &G, - ShellingOrder &lmc, - NodeArray &x, - NodeArray &y) -{ - // let c_1,...,c_q be the the current contour, then - // next[c_i] = c_i+1, prev[c_i] = c_i-1 - NodeArray next(G), prev(G); - - // upper[v] = w means x-coord. of v is relative to w - // (abs. x-coord. of v = x[v] + abs. x-coord of w) - NodeArray upper(G,0); - - // initialize contour with base - const ShellingOrderSet &V1 = lmc[1]; - node v1 = V1[1]; - node v2 = V1[V1.len()]; - - int i; - for (i = 1; i <= V1.len(); ++i) - { - y [V1[i]] = 0; - x [V1[i]] = (i == 1) ? 0 : 2; - if (i < V1.len()) - next[V1[i]] = V1[i+1]; - if (i > 1) - prev[V1[i]] = V1[i-1]; - } - prev[v1] = next[v2] = 0; - - // process shelling order from bottom to top - const int n = lmc.length(); - int k; - for (k = 2; k <= n; ++k) - { - const ShellingOrderSet &Vk = lmc[k]; // Vk = { z_1,...,z_l } - int l = Vk.len(); - node z1 = Vk[1]; - node cl = Vk.left(); // left vertex - node cr = Vk.right(); // right vertex - - // compute relative x-distance from c_i to cl for i = l+1, ..., r - int x_cr = 0; - node v; - for (v = next[cl]; v != cr; v = next[v]) - { - x_cr += x[v]; - x[v] = x_cr; - } - x_cr += x[cr]; // x_cr = abs. x-coord(cr) - abs. x-coord(cl) - - int offset; - if (m_sizeOptimization == true) - { - // optimization: compute minimal value offset by which cr must be - // shift to right - int yMax = y[cr]; - - // if there is an edge from cl to right with slope +1, or from cr - // to left with slope -1, then offset must be at least 2 - offset = (y[cl] < y[next[cl]] || y[cr] < y[prev[cr]]) ? 2 : 0; - - // y_max = max { y[c_i] | l <= i <= r } - for (v = cl; v != cr; v = next[v]) { - if (y[v] > yMax) - yMax = y[v]; - } - - // offset must be at least so large, such that - // y[z_i] > y_max for all i - offset = max (offset, 2*(yMax+l) - x_cr - y[cl] - y[cr]); - - } else // no size optimization - offset = 2*l; - - x_cr += offset; - - // compute insert coordinates of z_i for 1 <= i <= l - x[z1] = (x_cr + y[cr] - y[cl]) / 2 - l + 1; - y[z1] = (x_cr + y[cr] + y[cl]) / 2 - l + 1; - - for (i = 2; i <= l; i++) { - x[Vk[i]] = 2; - y[Vk[i]] = y[z1]; - } - - // Compute shift values for cl,...,cr and relative x-coord. to a node - // upper[v] for inner nodes - // Let l <= c_alpha <= c_beta <= r max. with - // y[cl] > ... > y[c_alpha] and y[c_beta] < ... < y[cr] - // Shift c_alpha,...,c_beta by offset/2 (c_alpha,c_beta only if != cl, - // cr) - // Shift c_beta+1,...,cr by offset - // x-coord. of c_l+1, ...,c_alpha relative to cl - // -"- c_alpha+1,...,c_beta-1 relative to z1 - // -"- c_beta, ...,cr relative to cr - node c_alpha, c_beta; - if (y[cl] <= y[next[cl]]) { - c_alpha = cl; - - } else { - for (c_alpha = next[cl], v = next[c_alpha]; - c_alpha != cr && y[v] < y[c_alpha]; - c_alpha = v, v = next[v]) - { - x [c_alpha] += 0; - upper[c_alpha] = cl; - } - if (c_alpha != cr) { - x [c_alpha] += (offset/2); - upper[c_alpha] = cl; - } - } - - if (y[cr] <= y[prev[cr]]) { - c_beta = cr; - - } else { - for (c_beta = prev[cr], v = prev[c_beta]; - c_beta != cl && y[v] < y[c_beta]; - c_beta = v, v = prev[v]) - { - x [c_beta] += offset - x_cr; - upper[c_beta] = cr; - } - if (c_beta != cl && c_beta != c_alpha) { - x [c_beta] += (offset/2) - x_cr; - upper[c_beta] = cr; - } - } - - if (c_alpha != c_beta) - for (v = next[c_alpha]; v != c_beta; v = next[v]) { - x [v] += (offset/2) - x[z1]; - upper[v] = z1; - } - - x[cr] = x_cr - (x[z1] + 2*(l-1)); - - // update contour after insertion of z_1,...,z_l - for (i = 1; i <= l; i++) - { - if (i < l) - next[Vk[i]] = Vk[i+1]; - if (i > 1) - prev[Vk[i]] = Vk[i-1]; - } - next [cl] = z1; - next [Vk[l]] = cr; - prev [cr] = Vk[l]; - prev [z1] = cl; - } - - // compute final x-coordinates for the nodes on the (final) contour - int sum = 0; - for (node v = v1; v != 0; v = next[v]) { - x[v] = (sum += x[v]); - } - - // compute final x-coordinates for the inner nodes - for (k = n-1; k >= 1; k--) - { - for (i = 1; i <= lmc.len(k); i++) - { - node zi = lmc (k,i); - if (upper[zi] != 0) // upper[zi] == 0 <=> z_i on contour - x[zi] += x[upper[zi]]; - } - } -} - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarlayout/SchnyderLayout.cpp b/ext/OGDF/src/planarlayout/SchnyderLayout.cpp deleted file mode 100644 index 6b7607e28..000000000 --- a/ext/OGDF/src/planarlayout/SchnyderLayout.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Definition of the Schnyder Layout Algorithm (SchnyderLayout) - * - * \author Till Schäfer - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - -namespace ogdf { - -SchnyderLayout::SchnyderLayout() : PlanarGridLayoutModule() { -} - - -void SchnyderLayout::doCall( - const Graph &G, - adjEntry adjExternal, - GridLayout &gridLayout, - IPoint &boundingBox, - bool fixEmbedding) -{ - // check for double edges & self loops - OGDF_ASSERT(isSimple(G)); - - // handle special case of graphs with less than 3 nodes - if (G.numberOfNodes() < 3) { - node v1, v2; - switch (G.numberOfNodes()) { - case 0: - boundingBox = IPoint(0, 0); - return; - - case 1: - v1 = G.firstNode(); - gridLayout.x(v1) = gridLayout.y(v1) = 0; - boundingBox = IPoint(0, 0); - return; - - case 2: - v1 = G.firstNode(); - v2 = G.lastNode(); - gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0; - gridLayout.x(v2) = 1; - boundingBox = IPoint(1, 0); - return; - } - } - - // make a copy for triangulation - GraphCopy GC(G); - - // embed - if (!fixEmbedding) { - if (planarEmbed(GC) == false) { - OGDF_THROW_PARAM(PreconditionViolatedException, pvcPlanar); - } - } - - triangulate(GC); - - schnyderEmbedding(GC, gridLayout, adjExternal); -} - - -void SchnyderLayout::schnyderEmbedding( - GraphCopy& GC, - GridLayout &gridLayout, - adjEntry adjExternal) -{ - NodeArray &xcoord = gridLayout.x(); - NodeArray &ycoord = gridLayout.y(); - - node v; - List L; // (un)contraction order - GraphCopy T = GraphCopy(GC); // the realizer tree (reverse direction of edges!!!) - EdgeArray rValues(T); // the realizer values - - // choose outer face a,b,c - adjEntry adja; - if (adjExternal != 0) { - edge eG = adjExternal->theEdge(); - edge eGC = GC.copy(eG); - adja = (adjExternal == eG->adjSource()) ? eGC->adjSource() : eGC->adjTarget(); - } - else { - adja = GC.firstEdge()->adjSource(); - } - adjEntry adjb = adja->faceCyclePred(); - adjEntry adjc = adjb->faceCyclePred(); - - node a = adja->theNode(); - node b = adjb->theNode(); - node c = adjc->theNode(); - - node a_in_T = T.copy(GC.original(a)); - node b_in_T = T.copy(GC.original(b)); - node c_in_T = T.copy(GC.original(c)); - - contract(GC, a, b, c, L); - - realizer(GC, L, a, b, c, rValues, T); - - //DEBUG CODE !!! - /* edge ex; - GraphAttributes GA(T,GraphAttributes::edgeLabel | GraphAttributes::edgeArrow); - forall_edges(ex, T) { - char buffer[10]; - int n = sprintf(buffer, 10, "%d", rValues[ex]); - GA.labelEdge(ex) = buffer; - GA.arrowEdge(ex) = GraphAttributes::last; - } - - GC.writeGML("/home/till/temp/gml/after_realizer_gc.gml"); - GA.writeGML("/home/till/temp/gml/tree.gml");*/ - - NodeArray t1(T); - NodeArray t2(T); - NodeArray val(T, 1); - - NodeArray P1(T); - NodeArray P3(T); - NodeArray v1(T); - NodeArray v2(T); - - subtreeSizes(rValues, 1, a_in_T, t1); - subtreeSizes(rValues, 2, b_in_T, t2); - - prefixSum(rValues, 1, a_in_T, val, P1); - prefixSum(rValues, 3, c_in_T, val, P3); - // now Pi = depth of all nodes in Tree T(i) (depth[root] = 1) - - prefixSum(rValues, 2, b_in_T, t1, v1); - // special treatment for a - v1[a_in_T] = t1[a_in_T]; - - /* - * v1[v] now is the sum of the - * "count of nodes in t1" minus the "subtree size for node x" - * for every node x on a path from b to v in t2 - */ - - prefixSum(rValues, 3, c_in_T, t1, val); - // special treatment for a - val[a_in_T] = t1[a_in_T]; - - /* - * val[v] now is the sum of the - * "count of nodes in t1" minus the "subtree size for node x" - * for every node x on a path from c to v in t3 - */ - - // r1[v]=v1[v]+val[v]-t1[v] is the number of nodes in region 1 from v - forall_nodes(v, T) { - // calc v1' - v1[v] += val[v] - t1[v] - P3[v]; - } - - prefixSum(rValues, 3, c_in_T, t2, v2); - // special treatment for b - v2[b_in_T] = t2[b_in_T]; - - prefixSum(rValues, 1, a_in_T, t2, val); - // special treatment for b - val[b_in_T] = t2[b_in_T]; - - forall_nodes(v, T) { - // calc v2' - v2[v] += val[v] - t2[v] - P1[v]; - } - - // copy coordinates to the GridLayout - forall_nodes(v, GC) { - xcoord[GC.original(v)] = v1[T.copy(GC.original(v))]; - ycoord[GC.original(v)] = v2[T.copy(GC.original(v))]; - } -} - - -/* - * Constructs List L - * L is the ordering for uncontracting the nodes in realizer - */ -void SchnyderLayout::contract(Graph& G, node a, node b, node c, List& L) -{ - adjEntry adj1, adj2; - List candidates; - NodeArray marked(G, false); // considered nodes - NodeArray deg(G, 0); // # virtual neighbours - - int N = G.numberOfEdges(); - - marked[a] = marked[b] = marked[c] = true; // init outer face - - deg[a] = deg[b] = deg[c] = N; - - // mark neighbours of a and calc the degree of the second (virtual) neighbours - forall_adj(adj1, a) { - marked[adj1->twinNode()] = true; - forall_adj(adj2, adj1->twinNode()) { - deg[adj2->twinNode()]++; - } - } - - // find first candidates - forall_adj(adj1, a) { - if (deg[adj1->twinNode()] <= 2) { - candidates.pushBack(adj1->twinNode()); - } - } - - while (!candidates.empty()) { - node u = candidates.popFrontRet(); - if (deg[u] == 2) { - L.pushFront(u); - deg[u] = N; - forall_adj(adj1, u) { - node v = adj1->twinNode(); - deg[v]--; // u is virtualy deleted - if (!marked[v]) { // v is new neighbour of a - marked[v] = true; - forall_adj(adj2, v) { - deg[adj2->twinNode()]++; // degree of virtaul neighbours increase - } - if (deg[v] <= 2) candidates.pushBack(v); // next candidate v - } - else - if (deg[v] == 2) candidates.pushBack(v); // next candidate v - } - } - } -} - - -/* - * Construct the realiszer and the Tree T - * rValues = realizer value - * T = Tree - */ -void SchnyderLayout::realizer( - GraphCopy& G, - const List& L, - node a, - node b, - node c, - EdgeArray& rValues, - GraphCopy& T) -{ - int i = 0; - edge e; - NodeArray ord(G, 0); - adjEntry adj; - - // ordering: b,c,L,a - ord[b] = i++; - ord[c] = i++; - - forall_listiterators(node, it, L) { - ord[*it] = i++; // enumerate V(G) - } - ord[a] = i++; - - // remove all edges (they will be re-added later with different orientation) - while (T.numberOfEdges() > 0) { - e = T.firstEdge(); - T.delCopy(e); - } - - forall_listiterators(node, it, L) { - node v = *it; - node u = T.copy(G.original(v)); // u is copy of v in T - - forall_adj(adj, v) { - if (ord[adj->twinNode()] > ord[v]) { - break; - } - } - - adjEntry adj1 = adj; - while (ord[adj1->twinNode()] > ord[v]) { - adj1 = adj1->cyclicSucc(); - } - e = T.newEdge(T.copy(G.original(adj1->twinNode())), u); - rValues[e] = 2; - - adjEntry adj2 = adj; - while (ord[adj2->twinNode()] > ord[v]) { - adj2 = adj2->cyclicPred(); - } - e = T.newEdge(T.copy(G.original(adj2->twinNode())), u); - rValues[e] = 3; - - for (adj = adj1->cyclicSucc(); adj != adj2; adj = adj->cyclicSucc()) { - e = T.newEdge(u, T.copy(G.original(adj->twinNode()))); - rValues[e] = 1; - } - } - - // special treatement of a,b,c - node a_in_T = T.copy(G.original(a)); - node b_in_T = T.copy(G.original(b)); - node c_in_T = T.copy(G.original(c)); - - // all edges to node a get realizer value 1 - forall_adj(adj, a) { - e = T.newEdge(a_in_T, T.copy(G.original(adj->twinNode()))); - rValues[e] = 1; - } - - // rest of outer triangle (reciprocal linked, realizer values 2 and 3) - e = T.newEdge(b_in_T, a_in_T); - rValues[e] = 2; - e = T.newEdge(b_in_T, c_in_T); - rValues[e] = 2; - - e = T.newEdge(c_in_T, a_in_T); - rValues[e] = 3; - e = T.newEdge(c_in_T, b_in_T); - rValues[e] = 3; -} - - -/* - * computes the sizes of all subtrees of a tree with root r - */ -void SchnyderLayout::subtreeSizes( - EdgeArray& rValues, - int i, - node r, - NodeArray& size) -{ - int sum = 0; - adjEntry adj; - forall_adj(adj, r) { - if (adj->theEdge()->source() == r && rValues[adj->theEdge()] == i) { - node w = adj->twinNode(); - subtreeSizes(rValues, i, w, size); - sum += size[w]; - } - } - size[r] = sum + 1; -} - -/* - * computes for every node u in the subtree of T(i) with root r - * the sum of all val[v] where v is a node on the path from r to u - */ -void SchnyderLayout::prefixSum( - EdgeArray& rValues, - int i, - node r, - const NodeArray& val, - NodeArray& sum) -{ - List Q; - - Q.pushBack(r); - sum[r] = val[r]; - - while (!Q.empty()) { - node v = Q.popFrontRet(); - adjEntry adj; - forall_adj(adj, v) - if (adj->theEdge()->source() == v && rValues[adj->theEdge()] == i) { - node w = adj->twinNode(); - Q.pushBack(w); - sum[w] = val[w] + sum[v]; - } - } -} - - -} //namespace ogdf diff --git a/ext/OGDF/src/planarlayout/ShellingOrder.cpp b/ext/OGDF/src/planarlayout/ShellingOrder.cpp deleted file mode 100644 index a813656a8..000000000 --- a/ext/OGDF/src/planarlayout/ShellingOrder.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class ShellingOrder. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - - -namespace ogdf { - - -void ShellingOrder::init(const Graph &G, const List &partition) -{ - m_pGraph = &G; - m_V.init(1,partition.size()); - m_rank.init(G); - - int i = 1; - ListConstIterator it; - for(it = partition.begin(); it.valid(); ++it) - { - const ShellingOrderSet &S = *it; - for(int j = 1; j <= S.len(); ++j) - m_rank[S[j]] = i; - - m_V[i++] = *it; - } -} - - -void ShellingOrder::initLeftmost( - const Graph &G, - const List &partition) -{ - m_pGraph = &G; - m_V.init(1,partition.size()); - m_rank.init(G); - - NodeArray > crSets(G); - BoundedStack outerfaceStack(G.numberOfNodes()); - - int i, j; - - ListConstIterator it; - for(it = partition.begin(); it.valid(); ++it) { - node cr = (*it).right(); - if (cr != 0) - crSets[cr].pushBack(&(*it)); - } - - const ShellingOrderSet &V1 = partition.front(); - for (j = V1.len(); j >= 2; j--) - outerfaceStack.push(V1[j]); - - m_V[1] = V1; - - i = 2; - while (!outerfaceStack.empty()) { - node cr = outerfaceStack.top(); - if (crSets[cr].empty()) - outerfaceStack.pop(); - else { - m_V[i] = *(crSets[cr].popFrontRet()); - for (j = len(i); j >= 1; j--) - outerfaceStack.push ( (m_V[i])[j] ); - i++; - } - } - - - for (i = 1; i <= length(); i++) { - for (j = 1; j <= m_V[i].len(); ++j) { - m_rank [(m_V[i])[j]] = i; - } - } -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarlayout/ShellingOrderModule.cpp b/ext/OGDF/src/planarlayout/ShellingOrderModule.cpp deleted file mode 100644 index 83f2fc5c6..000000000 --- a/ext/OGDF/src/planarlayout/ShellingOrderModule.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class ShellingOrderModule. - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void ShellingOrderModule::call(const Graph &G, - ShellingOrder &order, - adjEntry adj) -{ - List partition; - doCall(G,adj,partition); - - order.init(G,partition); -} - - -void ShellingOrderModule::callLeftmost(const Graph &G, - ShellingOrder &order, - adjEntry adj) -{ - List partition; - doCall(G,adj,partition); - - order.initLeftmost(G,partition); -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/planarlayout/TriconnectedShellingOrder.cpp b/ext/OGDF/src/planarlayout/TriconnectedShellingOrder.cpp deleted file mode 100644 index f557a6b37..000000000 --- a/ext/OGDF/src/planarlayout/TriconnectedShellingOrder.cpp +++ /dev/null @@ -1,733 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class TriconnectedShellingOrder which computes - * a shelling order for a triconnected planar graph. - * - * \author Bernd Zey - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include - -// define for debugging -//#define OUTPUT_TSO - -namespace ogdf { - - - -//--------------------------------------------------------- -// class ComputeTricOrder -//--------------------------------------------------------- -class ComputeTricOrder -{ -public: - // constructor - ComputeTricOrder ( - const Graph& G, // biconnected planar graph - ConstCombinatorialEmbedding& E, // combinatorial embedding of G - face outerFace, // outer face - double baseRatio, // size of base (baseRatio * size(extFace) - bool preferNodes = false); // boolean value if nodes are prefered to faces - - - - // initialize the nodes of the external face - void initOuterNodes(node v1, node v2); - // initialize the edges of the external face - void initOuterEdges(); - - // compute the node n of face f that belongs to the outer face and has degree 2 or is node v2 - node getOuterNodeDeg2(face f, NodeArray& adjPred, NodeArray& adjSucc); - - // gets the next possible face or node - // ordering depends on m_preferNodes - void getNextPossible(node& v, face& f); - - // update all nodes/faces depending on m_updateNodes/Faces - void doUpdate(); - - - // initialize the possible lists with v:=v_n - void initPossible(node v){ - m_nodesLink[v] = m_possibleNodes.pushBack(v); - } - - // returns true <=> there are possible nodes or faces - bool isPossible(){ - return (!(m_possibleNodes.empty() && m_possibleFaces.empty())); - } - - // returns true <=> the current selection is a node - bool isNode(){ - return m_currentIsNode; - } - - // test if face f has only one edge on outer face - bool isOnlyEdge(face f){ - return ((m_outv[f] == 2) && (m_oute[f] == 1)); - } - - // add a node v of face f to the outer face - void addOuterNode(node v, face f){ - incOutv(f); - m_outerNodes[f].pushBack(v); - if (m_isSeparationFace[f]) - m_sepf[v]++; - } - - void incVisited(node v){ - m_visited[v]++; - setUpdate(v); - } - - void incSepf(node v){ - m_sepf[v]++; - setUpdate(v); - } - - void decSepf(node v){ - m_sepf[v]--; - setUpdate(v); - } - - void incOutv(face f){ - m_outv[f]++; - setUpdate(f); - } - - void incOute(face f){ - m_oute[f]++; - setUpdate(f); - } - - int getOutv (face f) { - return m_outv[f]; - } - - void output(){ - cout << "ComputeTricOrder::output():" << endl; - cout << "nodes: " << endl; - node n; - forall_nodes(n, (*m_pGraph)){ - cout << " node " << n << ": "; - cout << "m_visited == " << m_visited[n] << ", "; - cout << "m_sepf == " << m_sepf[n] << endl; - } - cout << "faces: " << endl; - face f; - forall_faces(f, (*m_pEmbedding)){ - cout << " face " << f->index() << ": "; - cout << " outv == " << m_outv[f] << ", "; - cout << " oute == " << m_oute[f] << ", "; - cout << " isSpearationFace == " << m_isSeparationFace[f] << endl; - cout << " nodes in outerNodes: "; - ListIterator it = m_outerNodes[f].begin(); - while (it.valid()){ - cout << " " << (*it) << ", "; - it++; - } - cout << ". " << endl; - cout << " edges in outerNodes: "; - ListIterator itE = m_outerEdges[f].begin(); - while (itE.valid()){ - cout << " " << (*itE) << ", "; - itE++; - } - cout << ". " << endl; - } - } - -private: - - void setUpdate(node n); - - void setUpdate(face f); - - - // member variables - - const Graph *m_pGraph; // the graph - ConstCombinatorialEmbedding *m_pEmbedding; // the embedding of the graph - - face m_outerFace; // the outer/external face - - node m_v1, m_v2; // the two nodes on the "bottom edge" - - bool m_preferNodes; // m_preferNodes = true <=> nodes are prefered to faces - // in selection of getNextPossible(..) - - NodeArray m_visited, m_sepf; // number of visited neighbours and separation faces - NodeArray< ListIterator > m_link; // item in m_possibleNodes containing v - - List m_possibleNodes; // the possible nodes for the next step - List m_possibleFaces; // the possible faces for the next step - - NodeArray< ListIterator > m_nodesLink; // list-iterator in m_possibleNodes for each node, or NULL if it doesn't exist - FaceArray< ListIterator > m_facesLink; // list-iterator in m_possibleNodes for each node, or NULL - - List m_updateNodes; // list of actual changed nodes - List m_updateFaces; // list of actual changed faces - - NodeArray m_nodeUpdate; // m_nodeUpdate[v] = true <=> v \in m_updateNodes - FaceArray m_faceUpdate; // m_faceUpdate[f] = true <=> f \in m_updateFaces - - FaceArray m_isSeparationFace; - - bool m_currentIsNode; // m_currentIsNode == true <=> in the current step a node was picked - // => V_k is a singleton. The Variable == false <=> V_k is a node set - - FaceArray m_outv; // number of nodes... - FaceArray m_oute; //... and edges of a face that also belong to the outer face - - FaceArray< List > m_outerNodes; // nodes of each face that also belong to the outer face - FaceArray< List > m_outerEdges; // edges of each face that also belong to the outer face - -}; // class ComputeTricOrder - - -// constructor -ComputeTricOrder::ComputeTricOrder( - const Graph& G, // the graph - ConstCombinatorialEmbedding &E, // embedding of the graph - face outerFace, // the outer face - double baseRatio, // size of base (baseRatio * size(extFace)) - bool preferNodes) // boolean value if nodes are prefered to faces -{ - m_pGraph = &G; - m_pEmbedding = &E; - m_outerFace = outerFace; - m_preferNodes = preferNodes; - - // initialize member variables - m_visited .init(G, 0); - m_sepf .init(G, 0); - m_link .init(G, 0); - m_nodeUpdate .init(G, false); - m_faceUpdate .init(E, false); - m_isSeparationFace .init(E, false); - m_nodesLink .init(G, 0); - m_facesLink .init(E, 0); - m_outv .init(E, 0); - m_oute .init(E, 0); - m_outerNodes .init(E); - m_outerEdges .init(E); -} - - -// gets the next possible face or node -// ordering depends on m_preferNodes -void ComputeTricOrder::getNextPossible(node& v, face& f){ - if (m_preferNodes){ - if (m_possibleNodes.empty()){ - m_currentIsNode = false; - f = m_possibleFaces.popFrontRet(); - } - else{ - m_currentIsNode = true; - v = m_possibleNodes.popFrontRet(); - } - } - else{ - if (m_possibleFaces.empty()){ - m_currentIsNode = true; - v = m_possibleNodes.popFrontRet(); - } - else{ - m_currentIsNode = false; - f = m_possibleFaces.popFrontRet(); - } - } -} - - -// initialize the nodes of the outer face -// and the corresponding faces -void ComputeTricOrder::initOuterNodes(node v1, node v2){ - // set nodes v1 and v2 on the "base" - m_v1 = v1; - m_v2 = v2; - - node v; - - adjEntry firstAdj = m_outerFace->firstAdj(); - adjEntry adjV; - // set firstAdj, so outerface is on the right - if (m_pEmbedding->rightFace(firstAdj) == m_outerFace) - firstAdj = firstAdj->cyclicSucc(); - - adjEntry adjRun = firstAdj; - // traverse all nodes of the outer face - do { - v = adjRun->theNode(); - // now traverse the faces f of v - // and increase outv[f] and add v to outerNodes[f] - forall_adj(adjV, v){ - face f = m_pEmbedding->rightFace(adjV); - if (f != m_outerFace){ - m_outv[f]++; - m_outerNodes[f].pushBack(v); - } - } - adjRun = adjRun->twin()->cyclicSucc(); - } while (adjRun != firstAdj); -} - - -// initialize the edges of the external face -// and the corresponding faces -void ComputeTricOrder::initOuterEdges(){ - edge e; - face f; - - adjEntry firstAdj = m_outerFace->firstAdj(); - // set firstAdj, so outerface is on the right - if (m_pEmbedding->rightFace(firstAdj) == m_outerFace) - firstAdj = firstAdj->cyclicSucc(); - adjEntry adjRun = firstAdj; - // traverse all edges of the outer face - do { - e = adjRun->theEdge(); - f = m_pEmbedding->rightFace(adjRun); - // verify that actual edge is not edge (v1,v2) - if (!((e->source() == m_v1 && e->target() == m_v2) || ((e->source() == m_v2 && e->target() == m_v1)))){ - m_oute[f]++; - m_outerEdges[f].pushBack(e); - } - adjRun = adjRun->twin()->cyclicSucc(); - } while (adjRun != firstAdj); -} - - -// compute the node n of face f that belongs to the outer face and has actually degree 2 or is node v2 -// adjPred is the adjElement in clockwise order on the outerface -// adjSucc is the adjElement in counterclockwise order on the outerface -node ComputeTricOrder::getOuterNodeDeg2(face f, NodeArray& adjPred, NodeArray& adjSucc){ - // need the boolean value if v2 is found before another node with degree 2 - bool foundV2; - node v; - ListIterator it = m_outerNodes[f].begin(); - for (it = m_outerNodes[f].begin(); it.valid(); it++){ - v = *it; - if (v == m_v2){ - foundV2 = true; - continue; - } - if (v == m_v1) - continue; - // check if node v has degree 2 - // not so easy, because we do not delete nodes from the graph, so - // node v has degree 2 iff - // adjSucc[v]->cyclicSucc() == adjPred[v] - // adjPred[v]->cyclicPred() == adjSucc[v] - if ((adjSucc[v])->cyclicSucc() == adjPred[v]){ - return v; - } - } - if (foundV2) - return m_v2; - // no node found - return 0; -} - - -// set update-value of node v true and append v to the update-nodes -void ComputeTricOrder::setUpdate(node v){ - if (!m_nodeUpdate[v]){ - m_nodeUpdate[v] = true; - m_updateNodes.pushBack(v); - } -} - -// set update-value of face f true and append f to the update-faces -void ComputeTricOrder::setUpdate(face f){ - if (!m_faceUpdate[f]){ - m_faceUpdate[f] = true; - m_updateFaces.pushBack(f); - } -} - - -// update if -// - v or f need to be inserted in possible list -// - v or f need to be deleted from possible list -// - f is becoming a separation face in the current step -void ComputeTricOrder::doUpdate(){ - bool isPossible, isSepFace; - node v; - face f; - - // first update faces, because variables for nodes can change here - while (!m_updateFaces.empty()){ - f = m_updateFaces.popFrontRet(); - - m_faceUpdate[f] = false; - // check if face f is a possible face - isPossible = ((m_outv[f] == m_oute[f] + 1) && (m_oute[f] >= 2) && (f != m_outerFace)); - - // insert face f if it is not in possible-faces-list - // and is a possible face - if (!m_facesLink[f].valid()){ - if (isPossible){ - m_facesLink[f] = m_possibleFaces.pushBack(f); - } - } - else - // delete f in possible-faces-list if it's not possible anymore - if (!isPossible){ - m_possibleFaces.del(m_facesLink[f]); - m_facesLink[f] = 0; - } - - // test if face f is a separation face - isSepFace = ((m_outv[f] >= 3) || ((m_outv[f] == 2) && (m_oute[f] == 0))); - - if (!m_isSeparationFace[f]){ - // f wasn't a separation face... - if (isSepFace){ - // ... and is now one - m_isSeparationFace[f] = true; - // increase seperation-faces (->sepf) for all outer-nodes v in f - ListIterator it; - for (it = m_outerNodes[f].begin(); it.valid(); it++) - incSepf(*it); - } - } - else{ - // face f was a separation face - if (!isSepFace) - // and isn't a separation face anymore - // need only to set array-index to false - // decrease of sepf is done before in main function - m_isSeparationFace[f] = false; - } - }// while (!m_updateFaces.empty()) - - // now update nodes - while (!m_updateNodes.empty()){ - v = m_updateNodes.popFrontRet(); - - m_nodeUpdate[v] = false; - // check if v is a possible node - isPossible = ((m_visited[v] >= 1) && (m_sepf[v] == 0) && (v != m_v1) && (v != m_v2)); - - if (!m_nodesLink[v].valid()){ - // v is not in possible list, but v is a possible node - if (isPossible){ - m_nodesLink[v] = m_possibleNodes.pushBack(v); - } - } - else{ - // v is in the possible list but actually not possible - if (!isPossible){ - m_possibleNodes.del(m_nodesLink[v]); - m_nodesLink[v] = 0; - } - } - }// while (!m_updateNodes.empty()) -}; - - - -//--------------------------------------------------------- -// TriconnectedShellingOrder -//--------------------------------------------------------- - -void TriconnectedShellingOrder::doCall( - const Graph& G, - adjEntry adj, - List& partition) -{ - - // prefer nodes to faces? - bool preferNodes = false; - - #ifdef OUTPUT_TSO - cout << "Graph G is planar == " << isPlanar(G) << endl; - cout << "Graph G has no self loops == " << isLoopFree(G) << endl; - cout << "Graph G is connected == " << isConnected(G) << endl; - cout << "Graph G is triconnected == " << isTriconnected(G) << endl; - #endif - - OGDF_ASSERT(isPlanar(G) == true); - OGDF_ASSERT(isLoopFree(G) == true); - OGDF_ASSERT(isTriconnected(G) == true); - - // crate an embedding for G - ConstCombinatorialEmbedding E(G); - - // set outerFace so adj is on it or to face with maximal size - face outerFace = (adj != 0) ? E.rightFace(adj) : E.maximalFace(); - - #ifdef OUTPUT_TSO - cout << "faces:" << endl; - face fh; - forall_faces(fh,E) { - if (fh == outerFace) - cout << " face *" << fh->index() << ":"; - else - cout << " face " << fh->index() << ":"; - adjEntry adj; - forall_face_adj(adj,fh) - cout << " " << adj; - cout << endl; - } - - cout << "adjacency lists:" << endl; - node vh; - forall_nodes(vh,G) { - cout << " node " << vh << ":"; - adjEntry adj; - forall_adj(adj,vh) - cout << " " << adj; - cout << endl; - } - #endif - - adjEntry firstAdj = outerFace->firstAdj(); - // set firstAdj that the outer face is on the left of firstAdj - if (E.rightFace(firstAdj) == outerFace) - firstAdj = firstAdj->cyclicSucc(); - - // set "base" nodes v1, v2 on outer face with edge [v1,v2] - node v1 = firstAdj->theNode(); - node v2 = firstAdj->cyclicPred()->twinNode(); - - ComputeTricOrder cto(G, E, outerFace, m_baseRatio, preferNodes); - - // if outerFace == {v_1,...,v_q} - // adjPred(v_i) == v_i -> v_{i-1} - // adjSucc(v_i) == v_1 -> v_{i+1} - // these arrays will be updated during the algo so they define the outer face - NodeArray adjPred(G), - adjSucc(G); - - // init adjPred and adjSucc for the nodes of the outer face - adjSucc[v1] = firstAdj; - adjEntry adjRun = firstAdj->twin()->cyclicSucc(); - do { - adjPred[adjRun->theNode()] = adjRun->cyclicPred(); - adjSucc[adjRun->theNode()] = adjRun; - adjRun = adjRun->twin()->cyclicSucc(); - } while (adjRun != firstAdj); - adjPred[v1] = adjSucc[v2] = 0; - - // init outer nodes and outer edges - cto.initOuterNodes(v1, v2); - cto.initOuterEdges(); - - // init the first possible node as the node in the middle of v_1 - // and v_2 on the outer face - int l = (outerFace->size() -2)/2; - if (l == 0) - l = 1; - adjRun = firstAdj; - for (int i=1; i <= l; i++) - adjRun = adjRun->twin()->cyclicSucc(); - - cto.initPossible(adjRun->theNode()); - - // node and face that are selected during the algorithm - node vk; - face Fk; - // left and right node of current nodeset - node cl, cr; - // the actual nodeset V in the shelling order - ShellingOrderSet V; - // further auxiliary variables - adjEntry adj1, adj2; - node u; - - #ifdef OUTPUT_TSO - cout << "finished initialization of cto, adjSucc, adjPred." << endl << flush; - cout << "v1 = " << v1 << ", v2 = " << v2 << ", first possible node = " << adjRun->theNode() << endl; - - forall_face_adj(adj1, outerFace){ - cout << " node " << adj1->theNode() << ": adjPred=(" << adjPred[adj1->theNode()] - << "), adjSucc=" << adjSucc[adj1->theNode()] << endl; - } - cto.output(); - cout << "starting main loop" << endl; - #endif - - // main loop - while (cto.isPossible()){ - - // get the next possible nodeset for the order - cto.getNextPossible(vk, Fk); - - // check if the current selection is a node or a face - if (cto.isNode()){ - - #ifdef OUTPUT_TSO - cout << " nextPossible is node " << vk << endl << flush; - #endif - - // current item is a node - V = ShellingOrderSet(1, adjPred[vk], adjSucc[vk]); - V[1] = vk; - cl = (adjPred[vk])->twinNode(); - cr = (adjSucc[vk])->twinNode(); - // insert actual nodeset to the front of the shelling order - partition.pushFront(V); - } - else{ - - #ifdef OUTPUT_TSO - cout << " nextPossible is face " << Fk->index() << endl << flush; - #endif - - // current item is a face - // create set with chain {z_1,...,z_l} - V = ShellingOrderSet(cto.getOutv(Fk)-2); - - // now find node v on Fk with degree 2 - cl = cto.getOuterNodeDeg2(Fk, adjPred, adjSucc); - // find end of chain cl and cr - // traverse to left while degree == 2 - while ((cl != v1) && (adjPred[cl] == adjSucc[cl]->cyclicSucc())) - cl = (adjPred[cl])->twinNode(); - - // traverse to the right while degree == 2 - // and insert nodes into the ShellingOrderSet - cr = adjSucc[cl]->twinNode(); - int i = 1; - while ((cr != v2) && (adjPred[cr] == adjSucc[cr]->cyclicSucc())){ - V[i] = cr; - cr = (adjSucc[cr])->twinNode(); - i++; - } - cto.decSepf(cl); - cto.decSepf(cr); - // set left and right node in the shelling order set - V.left(cl); - V.right(cr); - // set left and right adjacency entry - V.leftAdj((adjPred[cr])->twin()); - V.rightAdj((adjSucc[cl])->twin()); - // insert actual nodeset to the front of the shelling order - partition.pushFront(V); - }// current item is a face - - #ifdef OUTPUT_TSO - cout << " set cl = " << cl << endl; - cout << " set cr = " << cr << endl; - #endif - - // update adjSucc[cl] and adjPred[cr] - adjSucc[cl] = adjSucc[cl]->cyclicSucc(); - adjPred[cr] = adjPred[cr]->cyclicPred(); - // increase number of outer edges of face left of adjPred[cr] - cto.incOute(E.leftFace(adjPred[cr])); - cto.incVisited(cl); - cto.incVisited(cr); - - // traverse from cl to cr on the new outer face - // and update adjSucc[] and adjPred[] - adj1 = adjSucc[cl]->twin(); - - for (u = adj1->theNode(); u != cr; u = adj1->theNode()){ - // increase oute for the right face of adj1 - cto.incOute(E.leftFace(adj1)); - - // set new predecessor - adjPred[u] = adj1; - - // go to next adj-entry - adj1 = adj1->cyclicSucc(); - - // if the actual node has an edge to the deleted node - // increase the visited value for the actual node... - if (adj1->twinNode() == vk){ - cto.incVisited(u); - // ... and skip the actual adjEntry - adj1 = adj1->cyclicSucc(); - } - adjSucc[u] = adj1; - - // add actual node to outerNodes[f] - for (adj2 = adjPred[u]; adj2 != adjSucc[u]; adj2 = adj2->cyclicPred()){ - cto.addOuterNode(u, E.leftFace(adj2)); - } - adj1 = adj1->twin(); - } - - if (!cto.isNode()){ - if ( ((adjSucc[cl])->twinNode() == cr) - && ( cto.isOnlyEdge(E.rightFace(adjSucc[cl])) ) ){ - cto.decSepf(cl); - cto.decSepf(cr); - } - } - - // update cto - cto.doUpdate(); - - #ifdef OUTPUT_TSO - cto.output(); - #endif - }// while (cto.isPossible()) - - // finally push the base (v1,v2) to the order - V = ShellingOrderSet(2); - V[1] = v1; - V[2] = v2; - partition.pushFront(V); - - #ifdef OUTPUT_TSO - cout << "output of the computed partition:" << endl; - ListIterator it; - int k = 1; - for (it = partition.begin(); it.valid(); it++){ - int size = (*it).len(); - cout << "nodeset with nr " << k << ":" << endl; - for (int j=1; j<=size; j++) - cout << " node " << (*it)[j] <<", "; - cout << "." << endl; - } - #endif -}// void TriconnectedShellingOrder::doCall - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/simultaneous/SimDraw.cpp b/ext/OGDF/src/simultaneous/SimDraw.cpp deleted file mode 100644 index 6c0685453..000000000 --- a/ext/OGDF/src/simultaneous/SimDraw.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Base class for simultaneous drawing. - * - * \author Michael Schulz and Daniel Lueckerath - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -//************************************************************* -// default constructor -SimDraw::SimDraw() -{ - m_GA.init(m_G, GraphAttributes::edgeSubGraph); - m_compareBy = index; - m_isDummy.init(m_G, false); - -} // end constructor - - -//************************************************************* -// checks whether node is a proper dummy node -// proper dummy means that node is marked as dummy and -// incident edges have at least one common input graph -bool SimDraw::isProperDummy(node v) const -{ - if(!isDummy(v)) - return false; - int sgb = m_GA.subGraphBits(v->firstAdj()->theEdge()); - edge e; - forall_adj_edges(e, v) - sgb &= m_GA.subGraphBits(e); - - return (sgb != 0); - -} // end isProperDummy - - -//************************************************************* -// returns number of dummies -int SimDraw::numberOfDummyNodes() const -{ - int counter = 0; - node v; - forall_nodes(v, m_G) - if(isDummy(v)) - counter++; - return counter; - -} // end numberOfDummyNodes - - -//************************************************************* -// returns number of phantom dummies -int SimDraw::numberOfPhantomDummyNodes() const -{ - int counter = 0; - node v; - forall_nodes(v, m_G) - if(isPhantomDummy(v)) - counter++; - return counter; - -} // end numberOfProperDummyNodes - - -//************************************************************* -// returns number of proper dummies -int SimDraw::numberOfProperDummyNodes() const -{ - int counter = 0; - node v; - forall_nodes(v, m_G) - if(isProperDummy(v)) - counter++; - return counter; - -} // end numberOfNonProperDummyNodes - - -//************************************************************* -// checks whether graph and graphattributes belong to each other -// checks whether all edges have nonzero edgesubgraph value -// returns true if instance is ok -bool SimDraw::consistencyCheck() const -{ - if(&m_G != &(m_GA.constGraph())) - return false; - edge e; - forall_edges(e, m_G) - if(m_GA.subGraphBits(e) == 0) - return false; - return true; - -} // end consistencyCheck - - -//************************************************************* -// calculates maximum number of input graphs -// -int SimDraw::maxSubGraph() const -{ - int max = -1; - edge e; - forall_edges(e, m_G) - { - for(int i = 31; i > max; i--) - if(m_GA.inSubGraph(e, i)) - max = i; - } - return max; - -} // end maxSubGraph - - -//************************************************************* -//returns number of basic graphs -// -int SimDraw::numberOfBasicGraphs() const -{ - if(m_G.empty()) - return 0; - return maxSubGraph()+1; - -}//end numberOfBasicGraphs - - -//************************************************************* -// returns Graph consisting of all edges and nodes from SubGraph i -// -const Graph SimDraw::getBasicGraph(int i) const -{ - //get a copy of m_G - GraphCopy GC(m_G); - - //delete all edges that are not in SubGraph i - List LE; - GC.allEdges(LE); - forall_listiterators(edge, it, LE) - if(!(m_GA.inSubGraph(GC.original(*it),i))) - GC.delCopy(*it); - - //delete all Nodes where degree = 0 - List LN; - GC.allNodes(LN); - forall_listiterators(node, it, LN) - if((*it)->degree() == 0) - GC.delCopy(*it); - - return GC; - -}//end getBasicGraph - - -//************************************************************* -// returns GraphAttributes associated with basic graph i -// -void SimDraw::getBasicGraphAttributes(int i, GraphAttributes &GA, Graph &G) -{ - G = m_G; - GA.init(G,m_GA.attributes()); - - List LE; - m_G.allEdges(LE); - forall_listiterators(edge,it,LE) - if(m_GA.inSubGraph(*it,i)) - { - node v; - forall_nodes(v,G) - { - if(compare(GA,v,m_GA,(*it)->source())) - { - if(m_GA.attributes() & GraphAttributes::nodeGraphics) - { - GA.x(v) = m_GA.x((*it)->source()); - GA.y(v) = m_GA.y((*it)->source()); - GA.height(v) = m_GA.height((*it)->source()); - GA.width(v) = m_GA.width((*it)->source()); - } - - if(m_GA.attributes() & GraphAttributes::nodeId) - GA.idNode(v) = m_GA.idNode((*it)->source()); - - if(m_GA.attributes() & GraphAttributes::nodeLabel) - GA.labelNode(v) = m_GA.labelNode((*it)->source()); - } - - if(compare(GA,v,m_GA,(*it)->target())) - { - if(m_GA.attributes() & GraphAttributes::nodeGraphics) - { - GA.x(v) = m_GA.x((*it)->target()); - GA.y(v) = m_GA.y((*it)->target()); - GA.height(v) = m_GA.height((*it)->target()); - GA.width(v) = m_GA.width((*it)->target()); - } - - if(m_GA.attributes() & GraphAttributes::nodeId) - GA.idNode(v) = m_GA.idNode((*it)->target()); - - if(m_GA.attributes() & GraphAttributes::nodeLabel) - GA.labelNode(v) = m_GA.labelNode((*it)->target()); - } - } - - edge e; - forall_edges(e,G) - { - if(compare(GA,e->source(),m_GA,(*it)->source()) - && compare(GA,e->target(),m_GA,(*it)->target())) - { - if(m_GA.attributes() & GraphAttributes::edgeIntWeight) - GA.intWeight(e) = m_GA.intWeight(*it); - - if(m_GA.attributes() & GraphAttributes::edgeLabel) - GA.labelEdge(e) = m_GA.labelEdge(*it); - - if(m_GA.attributes() & GraphAttributes::edgeColor) - GA.colorEdge(e) = m_GA.colorEdge(*it); - - if(m_GA.attributes() & GraphAttributes::edgeGraphics) - GA.bends(e) = m_GA.bends(*it); - } - } - } - else - { - List LE2; - G.allEdges(LE2); - forall_listiterators(edge, it2, LE2) - { - if(compare(GA,(*it2)->source(),m_GA,(*it)->source()) - && compare(GA,(*it2)->target(),m_GA,(*it)->target())) - { - G.delEdge(*it2); - } - } - } - - //remove all Nodes with degree == 0 - //this can change the IDs of the nodes in G. - List LN; - G.allNodes(LN); - forall_listiterators(node, it3, LN) - if((*it3)->degree() == 0) - G.delNode(*it3); - -}//end getBasicGraphAttributes - - -//************************************************************* -//adds new GraphAttributes to m_G if maxSubgraph() < 32 -// -bool SimDraw::addGraphAttributes(const GraphAttributes & GA) -{ - if(maxSubGraph() >= 31) - return false; - - //if(compareBy() == label) - OGDF_ASSERT((compareBy() != label) || (m_GA.attributes() & GraphAttributes::edgeLabel)); - - int max = numberOfBasicGraphs(); - bool foundEdge = false; - node v; - edge e, f; - Graph G = GA.constGraph(); - - forall_edges(e,G) - { - forall_edges(f,m_G) - { - if(compare(m_GA, f->source(), GA, e->source()) && - compare(m_GA, f->target(), GA, e->target())) - { - foundEdge = true; - m_GA.addSubGraph(f,max); - } - } - - if(!foundEdge) - { - node s, t; - bool srcFound = false; - bool tgtFound = false; - forall_nodes(v,m_G) - { - if(compare(m_GA, v, GA, e->source())) - { - s = v; - srcFound = true; - } - - if(compare(m_GA, v, GA, e->target())) - { - t = v; - tgtFound = true; - } - } - - if(!srcFound) - s = m_G.newNode(e->source()->index()); - - if(!tgtFound) - t = m_G.newNode(e->target()->index()); - - edge d = m_G.newEdge(s,t); - if(compareBy() == label) - m_GA.labelEdge(d) = GA.labelEdge(e); - - m_GA.addSubGraph(d, max); - } - } - return true; - -}// end addGraphAttributes - - -//************************************************************* -//adds the new Graph G to the instance m_G if maxSubGraph < 32 -//and CompareMode = index. -bool SimDraw::addGraph(const Graph & G) -{ - if(compareBy() == label) - return false; - else - { - GraphAttributes newGA(G); - return(addGraphAttributes(newGA)); - } - -}//end addGraph - - -//************************************************************* -//compares two nodes depending on the mode in m_CompareBy -// -bool SimDraw::compare(const GraphAttributes & vGA, node v, - const GraphAttributes & wGA, node w) const -{ - if(m_compareBy == index) - return compareById(v,w); - else if(m_compareBy == label) - return compareByLabel(vGA, v, wGA, w); - else - { - OGDF_ASSERT( false ); // m_compareBy is not set correctly - return false; - } - -} // end compare - -} // end namespace ogdf diff --git a/ext/OGDF/src/simultaneous/SimDrawCaller.cpp b/ext/OGDF/src/simultaneous/SimDrawCaller.cpp deleted file mode 100644 index 49b1a8c30..000000000 --- a/ext/OGDF/src/simultaneous/SimDrawCaller.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers variety of possible algorithm calls for simultaneous - * drawing. - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - -#include - -namespace ogdf { - -//************************************************************* -// refreshes m_esg -// -void SimDrawCaller::updateESG() -{ - edge e; - forall_edges(e, *m_G) - (*m_esg)[e] = m_GA->subGraphBits(e); - -} // end updateESG - - -//************************************************************* -// Constructor -// -SimDrawCaller::SimDrawCaller(SimDraw &SD) : SimDrawManipulatorModule(SD) -{ - m_esg = OGDF_NEW EdgeArray(*m_G); - updateESG(); - -} // end constructor - - -//************************************************************* -// call for SugiyamaLayout -void SimDrawCaller::callSugiyamaLayout() -{ - m_SD->addAttribute(GraphAttributes::nodeGraphics); - m_SD->addAttribute(GraphAttributes::edgeGraphics); - - // nodes get default size - node v; - forall_nodes(v, *m_G) - m_GA->height(v) = m_GA->width(v) = 5.0; - - // actual call of SugiyamaLayout - updateESG(); - SugiyamaLayout SL; - SL.setSubgraphs(m_esg); // needed to call SimDraw mode - SL.call(*m_GA); - -} // end callSugiyamaLayout - - -//************************************************************* -// call for PlanarizationLayout -void SimDrawCaller::callUMLPlanarizationLayout() -{ - // build corresponding UMLGraph - UMLGraph UG(*m_G, GraphAttributes::edgeSubGraph); - node v; - forall_nodes(v,*m_G) - UG.width(v) = UG.height(v) = 5.0; - edge e; - forall_edges(e,*m_G) - UG.subGraphBits(e) = m_GA->subGraphBits(e); - - // actual call on UMLGraph - PlanarizationLayout PL; - PL.callSimDraw(UG); - - // transfer coordinats and edge bends to original - m_SD->addAttribute(GraphAttributes::nodeGraphics); - m_SD->addAttribute(GraphAttributes::edgeGraphics); - forall_nodes(v,*m_G) - { - m_GA->x(v) = UG.x(v); - m_GA->y(v) = UG.y(v); - } - forall_edges(e,*m_G) - m_GA->bends(e) = UG.bends(e); - -} // end callUMLPlanarizationLayout - - -//************************************************************* -// call for SubgraphPlanarizer -// returns crossing number -int SimDrawCaller::callSubgraphPlanarizer(int cc, int numberOfPermutations) -{ - // transfer edge costs if existent - EdgeArray ec(*m_G, 1); - if(m_GA->attributes() & GraphAttributes::edgeIntWeight) - { - edge e; - forall_edges(e,*m_G) - ec[e] = m_GA->intWeight(e); - } - - // initialize - updateESG(); - int crossNum = 0; - PlanRep PR(*m_G); - - // actual call for connected component cc - SubgraphPlanarizer SP; - VariableEmbeddingInserter* vei = new VariableEmbeddingInserter(); - vei->removeReinsert(VariableEmbeddingInserter::rrIncremental); - SP.setInserter(vei); - SP.permutations(numberOfPermutations); - SP.call(PR, cc, crossNum, &ec, 0, m_esg); - - // insert all dummy nodes into original graph *m_G - NodeArray newOrigNode(PR); - node vPR; - forall_nodes(vPR, PR) - { - if(PR.isDummy(vPR)) - { - node vOrig = m_G->newNode(); - newOrigNode[vPR] = vOrig; - m_SD->isDummy(vOrig) = true; - } - else - newOrigNode[vPR] = PR.original(vPR); - //original nodes are saved - } - - // insert all edges incident to dummy nodes into *m_G - EdgeArray toBeDeleted(*m_G, false); - EdgeArray visited(PR, false); - forall_nodes(vPR, PR) - { - if(PR.isDummy(vPR)) - { - node vNewOrig = newOrigNode[vPR]; //lebt in *m_G - edge e; - forall_adj_edges(e, vPR) //lebt in PR - { - if(!visited[e]) - { - node w = e->opposite(vPR); //lebt in PR - node wNewOrig = newOrigNode[w]; //lebt in *m_G - edge eNewOrig = m_G->newEdge(vNewOrig,wNewOrig); - m_GA->subGraphBits(eNewOrig) = m_GA->subGraphBits(PR.original(e)); - toBeDeleted[PR.original(e)] = true; - visited[e] = true; - } - } - } - } - - // delete all old edges in *m_G that are replaced by dummy node edges - List LE; - m_G->allEdges(LE); - forall_listiterators(edge, it, LE) - { - if(toBeDeleted[ (*it) ]) - m_G->delEdge( (*it) ); - } - - return crossNum; - -} // end callSubgraphPlanarizer - -} // end namespace ogdf diff --git a/ext/OGDF/src/simultaneous/SimDrawColorizer.cpp b/ext/OGDF/src/simultaneous/SimDrawColorizer.cpp deleted file mode 100644 index d758ae755..000000000 --- a/ext/OGDF/src/simultaneous/SimDrawColorizer.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers coloring of graphs for SimDraw. - * - * \author Michael Schulz and Tobias Dehling - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include - -namespace ogdf -{ - -//************************************************************* -// adds some color to the edges and to the nodes -void SimDrawColorizer::addColorNodeVersion() -{ - m_SD->addAttribute(GraphAttributes::nodeGraphics); - m_SD->addAttribute(GraphAttributes::nodeColor); - node v; - forall_nodes(v, *m_G) - { - if(m_SD->isDummy(v)) - { - if(m_SD->isProperDummy(v)) - m_GA->colorNode(v) = "#AAAAAA"; - else - m_GA->colorNode(v) = "#000000"; - } - else - m_GA->colorNode(v) = "#FFFF00"; - } - addColor(); -} // end addColorNodeVersion - - -//************************************************************* -// adds some color to the edges -void SimDrawColorizer::addColor() -{ - m_SD->addAttribute(GraphAttributes::edgeGraphics); - m_SD->addAttribute(GraphAttributes::edgeColor); - - SimDrawColorScheme SDCS(m_colorScheme, m_SD->numberOfBasicGraphs()); - edge e; - forall_edges(e,*m_G) - m_GA->colorEdge(e) = SDCS.getColor(m_GA->subGraphBits(e), m_SD->numberOfBasicGraphs()); -} // end addColor - - -//************************************************************** -// -//Implementation of class ColorScheme -// -//************************************************************** - - -//************************************************************** -// SimDrawColorScheme Constructor -SimDrawColorizer::SimDrawColorScheme::SimDrawColorScheme(enum colorScheme colorScm, int numberOfGraphs) -{ - OGDF_ASSERT( numberOfGraphs>0 && numberOfGraphs<31 ); - m_intScheme = colorScm; - red = new int[numberOfGraphs]; - green = new int[numberOfGraphs]; - blue = new int[numberOfGraphs]; - assignColScm(numberOfGraphs); -} // end SimDrawColorScheme Constructor - - -//*************************************************************** -// SimDrawColorScheme Destructor -SimDrawColorizer::SimDrawColorScheme::~SimDrawColorScheme() -{ - delete[] red; - delete[] green; - delete[] blue; -} - - -//*************************************************************** -// Calculates the number of overlapping graphs in one edge and gives them -// a color calculated from the choosen colorscheme -String SimDrawColorizer::SimDrawColorScheme::getColor(int subGraphBits, int numberOfGraphs) -{ - String color = "#", s; - int r = 0x00, g = 0x00, b = 0x00; - int numberOfGraphsInEdge = 0; - Array graphs(numberOfGraphs); //Ueberlagerungen von Graphen bei dieser Kante - - /* Loest den Integerwert SubGraphBits in die einzelnen Bits auf und - findet somit heraus, welche Graphen sich in dieser Kante ueberlagern */ - for (int i = 0; i < numberOfGraphs; i++) - { - graphs[i] = 0; - if((subGraphBits & (1 << i)) != 0) - graphs[i]=1; - } - - /* Bestimmt den Mittelwert der Farben der uebereinanderliegenden Graphen */ - for (int i = 0; i < numberOfGraphs; i++) - { - if (graphs[i] == 1) - { - r += red[i]; - g += green[i]; - b += blue[i]; - numberOfGraphsInEdge++; - } - } - if (numberOfGraphsInEdge == numberOfGraphs) - { - r = 0x00; // Kanten werden schwarz eingefaerbt - g = 0x00; // wenn sie zu allen Graphen gehoeren - b = 0x00; - } - else - { - OGDF_ASSERT(numberOfGraphsInEdge > 0); - r /= numberOfGraphsInEdge; - g /= numberOfGraphsInEdge; - b /= numberOfGraphsInEdge; - } - - /* Setzt die einzelnen Farben zu eine Hex Farbcode zusammen */ - s.sprintf("%x",r); - if (s.length() == 1) color += "0"; - color += s; - s.sprintf("%x",g); - if (s.length() == 1) color += "0"; - color += s; - s.sprintf("%x",b); - if (s.length() == 1) color += "0"; - color += s; - - return color; - -} // end getColor - - -//*************************************************************** -// Stores colorscheme colors and assigns them to colorscheme objects -void SimDrawColorizer::SimDrawColorScheme::assignColScm(int numberOfGraphs) -{ - // Die einzelnen Farbwerte zu den Farbschemata sind - // in diesen Arrays hinterlegt, in der Form: - // {FarbeArray1 R, G, B, FarbeArray2 R, G, B, ... } - int bluYel_colors[6] = {0x1f,0x00,0xfa,0xfe,0xff,0x02}; - int redGre_colors[6] = {0xff,0x22,0x18,0x3a,0xd1,0x00}; - int bluOra_colors[6] = {0x00,0x33,0xcc,0xff,0x99,0x00}; - int teaLil_colors[6] = {0x48,0xfd,0xff,0xbc,0x02,0xbc}; - int redBluYel_colors[9] = {0xff,0x00,0x00,0x34,0x4e,0xff,0xfe,0xff,0x19}; - int greLilOra_colors[9] = {0x33,0xff,0x00,0xfa,0x00,0x99,0xff,0x70,0x00}; - /* Die Farben werden immer aus dem Array colors genommen, wenn es - fuer die gegebene Anzahl Graphen kein vorgefertigtes Schema gibt */ - int colors[96] = { - 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xa5, - 0x00,0x00,0xff,0x00,0x8a,0x2b,0xe2,0xdc,0x14,0x3c,0x00, - 0xff,0xff,0xff,0x00,0xff,0x00,0x00,0x80,0x80,0x00,0x80, - 0xb8,0x86,0x0b,0xff,0x14,0x93,0x1e,0x90,0xff,0xff,0x63, - 0x47,0x80,0x80,0x80,0xa5,0x2a,0x2a,0xff,0x69,0x84,0x20, - 0xb2,0xaa,0x00,0xbf,0xff,0xe9,0x96,0x7a,0x64,0x95,0xed, - 0x00,0xce,0xd1,0xff,0xd7,0x00,0x32,0xcd,0x32,0x6b,0x8e, - 0x23,0xde,0xb8,0x87,0x55,0x6b,0x2f,0x19,0x19,0x70,0xa0, - 0x52,0x2d,0x69,0x69,0x69,0x4b,0x00,0x82 - }; - - /* Hier werden die Farben dem Farbschema entsprechend zugewiesen */ - switch (m_intScheme) - { - case bluYel: - OGDF_ASSERT(numberOfGraphs <= 2); - for (int i=0; i - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -namespace ogdf { - -//************************************************************* -//sets all edgeSubGraph values to zero -// -void SimDrawCreator::clearESG() -{ - edge e; - forall_edges(e,*m_G) - m_GA->subGraphBits(e) = 0; - -}//end clearESG - - -//************************************************************* -//gives each edge in m_G a random edgeSubGraph value -//works with two graphs -void SimDrawCreator::randomESG2(int doubleESGProbability) -{ - OGDF_ASSERT( doubleESGProbability <= 100 ); - OGDF_ASSERT( doubleESGProbability >= 0 ); - - clearESG(); - - edge e; - forall_edges(e,*m_G) - { - //all edges have a chance of doubleESGProbability (in percent) - //to belong to both input graphs - int doubleESGRandom = rand() % 100; - if(doubleESGRandom < doubleESGProbability) - { - m_GA->addSubGraph(e, 0); - m_GA->addSubGraph(e, 1); - } - else - { - // all edges, which do not belong to both input graphs - // have a 50/50 chance to belong to graph 0 or to graph 1 - int singleESGRandom = rand() % 2; - m_GA->addSubGraph(e, singleESGRandom); - } - } - -}//end randomESG2 - - -//************************************************************* -//gives each edge in m_G a random edgeSubGraph value -//works with three graphs -void SimDrawCreator::randomESG3(int doubleESGProbability, int tripleESGProbability) -{ - OGDF_ASSERT( doubleESGProbability + tripleESGProbability <= 100 ); - OGDF_ASSERT( doubleESGProbability >= 0 ); - OGDF_ASSERT( tripleESGProbability >= 0 ); - - clearESG(); - - edge e; - forall_edges(e,*m_G) - { - /*All edges have a chance of tripleESGProbability (in percent) - to belong to all three graphs.*/ - int multipleESGRandom = rand() % 100; - if(multipleESGRandom < doubleESGProbability + tripleESGProbability) - { - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - /*Furthermore, all edges have a chance of doubleESGProbability - to belong to two of three graphs.*/ - if(multipleESGRandom >= tripleESGProbability) - { - int removeESGRandom = rand() % 3; - m_GA->removeSubGraph(e, removeESGRandom); - } - } - else - { - //all edges, which do not belong to two or three graphs - //have a 33 percent chance to belong to one of the three graphs. - int singleESGRandom = rand() % 3; - m_GA->addSubGraph(e, singleESGRandom); - } - } - -}//end randomESG3 - - -//************************************************************* -//gives each edge a random edgeSubgraph value -//works with graphNumber number of graphs -void SimDrawCreator::randomESG(int graphNumber) -{ - OGDF_ASSERT( 0 < graphNumber && graphNumber < 32 ); - - int max = (int)pow((double)2,graphNumber+1)-1; - edge e; - forall_edges(e,*m_G) - { - int randomESGValue = 1 + rand() % max; - m_GA->subGraphBits(e) = randomESGValue; - } - -}//end randomESG - - -//************************************************************* -// -// -void SimDrawCreator::createRandom(int numberOfNodes, - int numberOfEdges, - int numberOfBasicGraphs) -{ - OGDF_ASSERT( 0 < numberOfBasicGraphs && numberOfBasicGraphs < 32 ); - randomSimpleGraph(*m_G, numberOfNodes, numberOfEdges); - randomESG(numberOfBasicGraphs); - -}//end createRandom - - -} // end namespace ogdf diff --git a/ext/OGDF/src/simultaneous/SimDrawCreatorSimple.cpp b/ext/OGDF/src/simultaneous/SimDrawCreatorSimple.cpp deleted file mode 100644 index 74081cce0..000000000 --- a/ext/OGDF/src/simultaneous/SimDrawCreatorSimple.cpp +++ /dev/null @@ -1,616 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Offers variety of possible SimDraw creations. - * - * \author Michael Schulz and Daniel Lueckerath - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -namespace ogdf { - -//************************************************************* -// creates simultaneous graph given by two trees with n^2+n+1 nodes -// see Geyer,Kaufmann,Vrto (GD'05) for description of graph -void SimDrawCreatorSimple::createTrees_GKV05(int n) -{ - OGDF_ASSERT( n>=1 ); - - node v0 = m_G->newNode(); - Array v(n); - Array2D w(0,n,0,n); - edge e; - - for(int i=0; inewNode(); - for(int j=0; jnewNode(); - } - - for(int i=0; inewEdge(v0,v[i]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - for(int j=0; jnewEdge(v[i],w(i,j)); - m_GA->addSubGraph(e,0); - e = m_G->newEdge(v[j],w(i,j)); - m_GA->addSubGraph(e,1); - } - } - -} // end createGKV - - -//************************************************************* -// creates simultaneous graph given by a path and a planar graph -// see Erten, Kobourov (GD'04) for description of instance -void SimDrawCreatorSimple::createPathPlanar_EK04() -{ - node v[10]; - edge e; - - for(int i= 1; i< 10; i++) - v[i] = m_G->newNode(); - - e = m_G->newEdge(v[1],v[2]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[1],v[3]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[1],v[4]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[1],v[5]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[1],v[6]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[2],v[3]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[2],v[4]); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[2],v[5]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[2],v[6]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[2],v[7]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[2],v[8]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[2],v[9]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[3],v[4]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[3],v[5]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[4],v[5]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[5],v[6]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[5],v[9]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[6],v[7]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[6],v[9]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[6],v[8]); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[7],v[8]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[7],v[9]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[8],v[9]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - -}//end createPathPlanar_EK04 - - -//************************************************************* -// creates simultaneous graph given by a colored K5 -// see Erten, Kobourov (GD'04) for description of instance -void SimDrawCreatorSimple::createK5_EK04() -{ - int number = 5; - Array v(number); - edge e; - - for(int i = 0; i < number; i++) - v[i] = m_G->newNode(); - - for(int i = 0; i < number-1; i++) - { - for(int j = i+1; j < number; j++) - { - e = m_G->newEdge(v[i],v[j]); - if ((j == i+1) || ((j == number-1) && (i == 0))) - m_GA->addSubGraph(e,0); - else - m_GA->addSubGraph(e,1); - } - } - -}//end createK5_EK04 - - -//************************************************************* -// creates simultaneous graph given by a colored K5 -// see Gassner, Juenger, Percan, Schaefer, Schulz (WG'06) for description of instance -void SimDrawCreatorSimple::createK5_GJPSS06() -{ - int number = 5; - Array v(number); - edge e; - - for(int i = 0; i < number; i++) - v[i] = m_G->newNode(); - - for(int i = 0; i < 3; i++) - { - for(int j = i+1; j <= 2; j++) - { - e = m_G->newEdge(v[i],v[j]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - } - } - - for(int i = 3; i < number; i++) - { - for(int j = 0; j < i; j++) - { - e = m_G->newEdge(v[i],v[j]); - if(j == 3) - m_GA->addSubGraph(e,0); - else - m_GA->addSubGraph(e,1); - } - } - -}//end createK5_GJPSS06 - - -//************************************************************* -// creates simultaneous graph given by two outerplanar graphs -// see Brass et al. (WADS '03) for description of instance -void SimDrawCreatorSimple::createOuterplanar_BCDEEIKLM03() -{ - int number = 6; - Array v(number); - edge e; - - for(int i = 0; i < number; i++) - v[i] = m_G->newNode(); - - for(int i = 0; i < number-1; i++) - { - e = m_G->newEdge(v[i],v[i+1]); - if(!(i == 2)) - { - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - } - else - { - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[i],v[number-1]); - m_GA->addSubGraph(e,1); - } - } - e = m_G->newEdge(v[number-1],v[0]); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(v[0],v[3]); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(v[1],v[4]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - -}// end createOuterplanar_BCDEEIKLM03 - - -//************************************************************* -// creates simultaneous graph with crossing number 0 but -// with multicrossings of adjacent edges in mincross drawing -// see Kratochvil (GD '98) for description of instance -void SimDrawCreatorSimple::createKrat98(int N, int nodeNumber) -{ - OGDF_ASSERT( N>=1 && nodeNumber>=1 ); - - Array p(nodeNumber); - Array q(nodeNumber); - Array r(nodeNumber); - Array outerNodes(4); - Array outerOuterNodes(4); - node a = m_G->newNode(); - node b = m_G->newNode(); - node nodeC = m_G->newNode(); - edge e; - - for(int i = 0; i < nodeNumber; i++) - { - p[i] = m_G->newNode(); - q[i] = m_G->newNode(); - r[i] = m_G->newNode(); - } - - for(int i = 0; i < 4; i++) - { - outerNodes[i] = m_G->newNode(); - outerOuterNodes[i] = m_G->newNode(); - } - - if(N > 1) - { - Array c(N); - for(int i = 0; i < N; i++) - { - c[i] = m_G->newNode(); - - e = m_G->newEdge(c[i],nodeC); - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(a,c[i]); - m_GA->addSubGraph(e,1); - - //eventuell unnoetig? - e = m_G->newEdge(outerNodes[1],c[i]); - m_GA->addSubGraph(e,1); - } - } - else - { - e = m_G->newEdge(a,nodeC); - m_GA->addSubGraph(e,1); - } - - e = m_G->newEdge(a,b); - m_GA->addSubGraph(e,0); - - e = m_G->newEdge(b,nodeC); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - for(int i = 0; i < nodeNumber-1; i++) - { - e = m_G->newEdge(p[i],p[i+1]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(r[i],r[i+1]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - } - - for(int i = 0; i < nodeNumber; i++) - { - e = m_G->newEdge(p[i],q[i]); - m_GA->addSubGraph(e,2); - if(i%2) - m_GA->addSubGraph(e,0); - else - m_GA->addSubGraph(e,1); - - e = m_G->newEdge(r[i],q[i]); - m_GA->addSubGraph(e,2); - if(i%2) - m_GA->addSubGraph(e,1); - else - m_GA->addSubGraph(e,0); - } - - e = m_G->newEdge(a,p[0]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(a,r[0]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(r[nodeNumber-1],b); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(p[nodeNumber-1],nodeC); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - for(int i = 0; i < 4; i++) - { - e = m_G->newEdge(outerOuterNodes[i],outerNodes[i]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - if(i < 3) - { - e = m_G->newEdge(outerOuterNodes[i],outerOuterNodes[i+1]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - } - } - - e = m_G->newEdge(outerOuterNodes[3],outerOuterNodes[0]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(outerNodes[1],outerNodes[2]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(outerNodes[3],outerNodes[0]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(outerNodes[0],a); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(outerNodes[3],a); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(outerNodes[1],nodeC); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - - e = m_G->newEdge(outerNodes[2],b); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,1); - m_GA->addSubGraph(e,2); - -}// end createKrat - - -//************************************************************* -// creates Graph with numberofBasic*2 outer, numberOfParallels*numberOfBasic -// inner Nodes and one Root. -void SimDrawCreatorSimple::createWheel(int numberOfParallels, int numberOfBasic ) -{ - OGDF_ASSERT(numberOfBasic > 0 && numberOfParallels >= 0); - - node root = m_G->newNode(); - Array v(numberOfBasic*2); - edge e; - - for(int i = 0; i < numberOfBasic*2; i++) - { - v[i] = m_G->newNode(); - e = m_G->newEdge(root,v[i]); - for(int j = 0; j < numberOfBasic; j++) - m_GA->addSubGraph(e,j); - } - - for(int i = 0; i < numberOfBasic*2; i++) - { - if((i >= 0) && (i < (numberOfBasic*2)-1)) - { - e = m_G->newEdge(v[i],v[i+1]); - for(int j = 0; j < numberOfBasic; j++) - m_GA->addSubGraph(e,j); - } - if(i == (numberOfBasic*2)-1) - { - e = m_G->newEdge(v[i],v[0]); - for(int j = 0; j < numberOfBasic; j++) - m_GA->addSubGraph(e,j); - } - - if((numberOfBasic+i) < (numberOfBasic*2)) - { - for(int j = 0; j < numberOfParallels; j++) - { - node tmpNOP = m_G->newNode(); - e = m_G->newEdge(v[i],tmpNOP); - m_GA->addSubGraph(e,i); - e = m_G->newEdge(v[numberOfBasic+i],tmpNOP); - m_GA->addSubGraph(e,i); - } - } - } - -}//end createWheel - - -//************************************************************* -// creates simultaneously planar simulatenous graph with n+1 basic graphs. -// -void SimDrawCreatorSimple::createExpo(int n) -{ - - OGDF_ASSERT(n>0 && n<31); - - Array u(n+1); - Array v(n+1); - Array twinNodesU(n+1); - Array outerNodes(6); - edge e; - - for(int i = 0; i < n+1; i++) - { - u[i] = m_G->newNode(); - v[i] = m_G->newNode(); - twinNodesU[i] = m_G->newNode(); - } - - for(int i = 0; i < 6; i++) - outerNodes[i] = m_G->newNode(); - - for(int i = 1; i < 3 ; i++) - { - e = m_G->newEdge(outerNodes[i],outerNodes[i+1]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - } - - e = m_G->newEdge(outerNodes[4],outerNodes[5]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - - e = m_G->newEdge(outerNodes[5],outerNodes[0]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - - for(int i = 0; i < n+1; i++) - { - e = m_G->newEdge(u[i],twinNodesU[i]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - } - - for(int i = 0; i < n; i++) - { - e = m_G->newEdge(twinNodesU[i],twinNodesU[i+1]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - - if(i == 0) - { - e = m_G->newEdge(outerNodes[3],twinNodesU[i]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - } - } - - e = m_G->newEdge(outerNodes[4],twinNodesU[n]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - - e = m_G->newEdge(v[0],outerNodes[0]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - - e = m_G->newEdge(v[0],outerNodes[1]); - for(int j = 0; j < 4; j++) - m_GA->addSubGraph(e,j); - - for(int i = 0; i < n+1; i++) - { - e = m_G->newEdge(u[i],v[i]); - if(i == 0) - m_GA->addSubGraph(e,0); - else - { - m_GA->addSubGraph(e,1); - if(i == 1) - m_GA->addSubGraph(e,2); - if(i == 2) - m_GA->addSubGraph(e,3); - } - } - - e = m_G->newEdge(outerNodes[5],u[n]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,2); - m_GA->addSubGraph(e,3); - - e = m_G->newEdge(outerNodes[2],v[1]); - m_GA->addSubGraph(e,0); - - for(int i = 1; i < n+1; i++) - { - e = m_G->newEdge(v[i],u[i-1]); - m_GA->addSubGraph(e,0); - if(i == 3) - m_GA->addSubGraph(e,2); - } - - for(int i = 0; i < 2; i++) - { - e = m_G->newEdge(u[i],v[i+2]); - m_GA->addSubGraph(e,0); - m_GA->addSubGraph(e,2); - if(i == 1) - m_GA->addSubGraph(e,3); - } - - e = m_G->newEdge(u[n-1],u[n]); - for(int j = 0; j < 4; j++) - if(j != 1) - m_GA->addSubGraph(e,j); - -}//end createExpo - -} // end namespace ogdf diff --git a/ext/OGDF/src/simultaneous/SimDrawManipulatorModule.cpp b/ext/OGDF/src/simultaneous/SimDrawManipulatorModule.cpp deleted file mode 100644 index 0aa0e7e92..000000000 --- a/ext/OGDF/src/simultaneous/SimDrawManipulatorModule.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * $Revision: 2554 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 11:39:38 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Module for simdraw manipulator classes - * - * \author Michael Schulz - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include - -namespace ogdf { - -//************************************************************* -// default constructor -// -SimDrawManipulatorModule::SimDrawManipulatorModule() -{ - m_SD = new SimDraw; - m_G = &(m_SD->m_G); - m_GA = &(m_SD->m_GA); -} //end default constructor - - -//************************************************************* -// initializing base instance -// -void SimDrawManipulatorModule::init(SimDraw &SD) -{ - m_SD = &SD; - m_G = &(SD.m_G); - m_GA = &(SD.m_GA); - OGDF_ASSERT( &(*m_G) == &(m_GA->constGraph()) ); -} //end constructor - - -} // end namespace ogdf diff --git a/ext/OGDF/src/tree/RadialTreeLayout.cpp b/ext/OGDF/src/tree/RadialTreeLayout.cpp deleted file mode 100644 index 0df381d03..000000000 --- a/ext/OGDF/src/tree/RadialTreeLayout.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Linear time layout algorithm for free trees (RadialTreeLayout). - * - * Based on chapter 3.1.1 Radial Drawings of Graph Drawing by - * Di Battista, Eades, Tamassia, Tollis - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -#include -#include -#include -#include - - -namespace ogdf { - - -RadialTreeLayout::RadialTreeLayout() - :m_levelDistance(50), - m_connectedComponentDistance(50), - m_selectRoot(rootIsCenter) -{ } - - -RadialTreeLayout::RadialTreeLayout(const RadialTreeLayout &tl) - :m_levelDistance(tl.m_levelDistance), - m_connectedComponentDistance(tl.m_connectedComponentDistance), - m_selectRoot(tl.m_selectRoot) -{ } - - -RadialTreeLayout::~RadialTreeLayout() -{ } - - -RadialTreeLayout &RadialTreeLayout::operator=(const RadialTreeLayout &tl) -{ - m_levelDistance = tl.m_levelDistance; - m_connectedComponentDistance = tl.m_connectedComponentDistance; - m_selectRoot = tl.m_selectRoot; - - return *this; -} - - -void RadialTreeLayout::call(GraphAttributes &AG) -{ - const Graph &tree = AG.constGraph(); - if(tree.numberOfNodes() == 0) return; - - if (!isTree(tree)) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest); - - OGDF_ASSERT(m_levelDistance > 0); - - // determine root of tree (m_root) - FindRoot(tree); - - // compute m_level[v], m_parent[v], m_leaves[v], m_numLevels - ComputeLevels(tree); - - // computes diameter of each node - ComputeDiameters(AG); - - // computes m_angle[v] and m_wedge[v] - ComputeAngles(tree); - - // computes final coordinates of nodes - ComputeCoordinates(AG); -} - - -void RadialTreeLayout::FindRoot(const Graph &G) -{ - node v; - - switch(m_selectRoot) { - case rootIsSource: - forall_nodes(v,G) - if(v->indeg() == 0) - m_root = v; - break; - - case rootIsSink: - forall_nodes(v,G) - if(v->outdeg() == 0) - m_root = v; - break; - - case rootIsCenter: - { - NodeArray degree(G); - Queue leaves; - - forall_nodes(v,G) { - if((degree[v] = v->degree()) == 1) - leaves.append(v); - } - - while(!leaves.empty()) { - v = leaves.pop(); - - adjEntry adj; - forall_adj(adj, v) { - node u = adj->twinNode(); - if(--degree[u] == 1) - leaves.append(u); - } - } - - m_root = v; - } - break; - } -} - - -void RadialTreeLayout::ComputeLevels(const Graph &G) -{ - m_parent.init(G); - m_level.init(G); - m_leaves.init(G,0); - - Queue Q; - Stack S; - - Q.append(m_root); - m_parent[m_root] = 0; - m_level [m_root] = 0; - - int maxLevel = 0; - - while(!Q.empty()) - { - node v = Q.pop(); - S.push(v); - int levelV = m_level[v]; - - bool isLeaf = true; - - adjEntry adj; - forall_adj(adj, v) { - node u = adj->twinNode(); - if(u == m_parent[v]) - continue; - - isLeaf = false; - - Q.append(u); - m_parent[u] = v; - m_level[u] = maxLevel = levelV+1; - } - - // number of leaves in a subtree rooted at a leaf is 1 - if(isLeaf) - m_leaves[v] = 1.0 / levelV; - } - - m_numLevels = maxLevel + 1; - - // compute number of leaves in subtree (already computed for leaves) - while(!S.empty()) - { - node v = S.pop(); - node p = m_parent[v]; - - if(p != 0) - m_leaves[p] += m_leaves[v]; - } -} - - -void RadialTreeLayout::ComputeDiameters(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - - m_diameter.init(G); - m_nodes.init(m_numLevels); - m_width.init(m_numLevels); - m_width.fill(0); - - node v; - forall_nodes(v,G) - { - int i = m_level[v]; - m_nodes[i].pushBack(v); - - double w = AG.width(v); - double h = AG.height(v); - - m_diameter[v] = sqrt(w*w+h*h); - - double m = max(w, h); - m = max(m, sqrt(w*w+h*h)); - - if(m_diameter[v] > m_width[i]) - m_width[i] = m_diameter[v]; - } -} - - - -void RadialTreeLayout::ComputeAngles(const Graph &G) -{ - m_angle.init(G); - m_wedge.init(G); - m_radius.init(m_numLevels); - m_grouping.init(G); - - Queue Q; - NodeArray restWeight(G); - - Q.append(m_root); - m_angle[m_root] = 0; - m_wedge[m_root] = 2*Math::pi; - m_radius[0] = 0; - - //Grouping grouping; - //double D, W; - - NodeArray D(G), W(G); - - int iProcessed = 0; - - while(!Q.empty()) - { - node v = Q.pop(); - node p = m_parent[v]; - - // nothing to do if v is a leaf - if(p != 0 && v->degree() == 1) - continue; - - int i = m_level[v]; - if(i+1 > iProcessed) { - m_radius[i+1] = m_radius[i] + 0.5*(m_width[i+1]+m_width[i]) + m_levelDistance; - - ComputeGrouping(i); - - SListConstIterator it; - for(it = m_nodes[i].begin(); it.valid(); ++it) - { - node w = *it; - - m_grouping[w].computeAdd(D[w],W[w]); - - double deltaL = 0.0; - ListConstIterator itG; - for(itG = m_grouping[w].begin(); itG.valid(); ++itG) - { - const Group &g = *itG; - if(g.m_leafGroup) - continue; - - double deltaLG; - double weightedAdd = W[w] / g.m_sumW * g.add(); - - deltaLG = 2 * W[w] / m_leaves[g.leftVertex()] * g.m_leftAdd - weightedAdd; - if(deltaLG > deltaL) - deltaL = deltaLG; - - deltaLG = 2 * W[w] / m_leaves[g.rightVertex()] * g.m_rightAdd - weightedAdd; - if(deltaLG > deltaL) - deltaL = deltaLG; - } - - double r = (deltaL + D[w]) / m_wedge[w]; - if(r > m_radius[i+1]) - m_radius[i+1] = r; - } - - // ******** - /*deltaL = (m_radius[i+1] * 2*Math::pi) - D; - - double offset = 0; - for(itG = grouping.begin(); itG.valid(); ++itG) - { - const Group &g = *itG; - - SListConstIterator itV; - for(itV = g.m_nodes.begin(); itV.valid(); ++itV) - { - node v = *itV; - - double s = m_diameter[v] + m_levelDistance; - if(g.m_leafGroup == false) - s += m_leaves[v] / g.m_sumW * g.add() + m_leaves[v] / W * deltaL; - - double desiredWedge = s / m_radius[i+1]; - - double allowedWedge = 2 * acos(m_radius[i] / m_radius[i+1]); - m_wedge[v] = min(desiredWedge,allowedWedge); - - m_angle[v] = offset + 0.5*desiredWedge; - offset += desiredWedge; - - Q.append(v); - } - } -*/ - - //************************* -/* SListConstIterator it; - for(it = m_nodes[i].begin(); it.valid(); ++it) - { - node w = *it; - - // compute weight of all non-leaves - double weight = 0.0; - - adjEntry adjSon; - forall_adj(adjSon,w) - { - node u = adjSon->twinNode(); - if(u == m_parent[w]) - continue; - if(u->degree() > 1) - weight += m_leaves[u]; - } - - restWeight[w] = weight; - - double D = (w->degree() - 1) * m_levelDistance; - - forall_adj(adjSon,w) - { - node u = adjSon->twinNode(); - if(u == m_parent[w]) - continue; - - D += m_diameter[u]; - } - - double r = D / m_wedge[w]; - if(r > m_radius[i+1]) - m_radius[i+1] = r; - }*/ - - iProcessed = i+1; - } - - - double deltaL = (m_radius[i+1] * m_wedge[v]) - D[v]; - double offset = m_angle[v] - 0.5*m_wedge[v]; - - ListConstIterator itG; - for(itG = m_grouping[v].begin(); itG.valid(); ++itG) - { - const Group &g = *itG; - - SListConstIterator it; - for(it = g.m_nodes.begin(); it.valid(); ++it) - { - node u = *it; - - double s = m_diameter[u] + m_levelDistance; - if(g.m_leafGroup == false) - s += m_leaves[u] / g.m_sumW * g.add() + m_leaves[u] / W[v] * deltaL; - - double desiredWedge = s / m_radius[i+1]; - - double allowedWedge = 2 * acos(m_radius[i] / m_radius[i+1]); - m_wedge[u] = min(desiredWedge,allowedWedge); - - m_angle[u] = offset + 0.5*desiredWedge; - offset += desiredWedge; - - Q.append(u); - } - } - - -/* - double restWedge = m_wedge[v]; - adjEntry adj; - forall_adj(adj,v) - { - node u = adj->twinNode(); - if(u == m_parent[v]) - continue; - - m_wedge[u] = (m_diameter[u] + m_levelDistance) / m_radius[i+1]; - restWedge -= m_wedge[u]; - } - - double offset = m_angle[v] - 0.5*m_wedge[v]; - - adj = v->firstAdj(); - adjEntry adjStop; - if(p != 0) { - while(adj->twinNode() != p) - adj = adj->cyclicSucc(); - adjStop = adj; - adj = adj->cyclicSucc(); - } else { - adjStop = adj; - } - - do - { - node u = adj->twinNode(); - - double desiredWedge; - - if(u->degree() == 1) { - desiredWedge = m_wedge[u]; - - } else { - desiredWedge = m_wedge[u] + m_leaves[u] / restWeight[v] * restWedge; - - double allowedWedge = 2 * acos(m_radius[i] / m_radius[i+1]); - m_wedge[u] = min(desiredWedge,allowedWedge); - } - - m_angle[u] = offset + 0.5*desiredWedge; - offset += desiredWedge; - - Q.append(u); - - adj = adj->cyclicSucc(); - } while(adj != adjStop);*/ - } - - m_outerRadius = m_radius[m_numLevels-1] + 0.5*m_width[m_numLevels-1]; -} - -void RadialTreeLayout::Grouping::computeAdd(double &D, double &W) -{ - D = W = 0; - - ListIterator it; - for(it = begin(); it.valid(); ++it) - { - Group &g = *it; - - D += g.m_sumD; - - if(g.m_leafGroup == true) - continue; - - W += g.m_sumW; - - ListIterator itL; - - itL = it.pred(); - if(itL.valid() == false) { - g.m_leftAdd = 0.0; - } else { - ListIterator itR = itL.pred(); - if(itR.valid() == false) - g.m_leftAdd = (*itL).m_sumD; - else - g.m_leftAdd = (*itL).m_sumD * g.m_sumW / (*itR).m_sumW; - } - - itL = it.succ(); - if(itL.valid() == false) { - g.m_leftAdd = 0.0; - } else { - ListIterator itR = itL.succ(); - if(itR.valid() == false) - g.m_leftAdd = (*itL).m_sumD; - else - g.m_leftAdd = (*itL).m_sumD * g.m_sumW / (*itR).m_sumW; - } - } -} - -// compute grouping for sons of nodes on level i -void RadialTreeLayout::ComputeGrouping(int i) -{ - SListConstIterator it; - for(it = m_nodes[i].begin(); it.valid(); ++it) - { - node v = *it; - node p = m_parent[v]; - - Grouping &grouping = m_grouping[v]; - ListIterator currentGroup; - - adjEntry adj = v->firstAdj(); - adjEntry adjStop; - if(p != 0) { - while(adj->twinNode() != p) - adj = adj->cyclicSucc(); - adjStop = adj; - adj = adj->cyclicSucc(); - } else { - adjStop = adj; - } - - do - { - node u = adj->twinNode(); - - if(!currentGroup.valid() || (*currentGroup).isSameType(u) == false) - { - currentGroup = grouping.pushBack(Group(this,u)); - - } else { - (*currentGroup).append(u); - } - - adj = adj->cyclicSucc(); - } while(adj != adjStop); - } -} - - -void RadialTreeLayout::ComputeCoordinates(GraphAttributes &AG) -{ - const Graph &G = AG.constGraph(); - - //double mx = m_outerRadius + 0.5*m_connectedComponentDistance; - //double my = mx; - - node v; - forall_nodes(v,G) { - double r = m_radius[m_level[v]]; - double alpha = m_angle[v]; - - AG.x(v) = r * cos(alpha); - AG.y(v) = r * sin(alpha); - } - - AG.clearAllBends(); -} - -} diff --git a/ext/OGDF/src/tree/TreeLayout.cpp b/ext/OGDF/src/tree/TreeLayout.cpp deleted file mode 100644 index 660e6020b..000000000 --- a/ext/OGDF/src/tree/TreeLayout.cpp +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Linear time layout algorithm for trees (TreeLayout) - * based on Walker's algorithm - * - * \author Christoph Buchheim - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -#include -#include - - -#include -#include - - -namespace ogdf { - - -TreeLayout::TreeLayout() - :m_siblingDistance(20), - m_subtreeDistance(20), - m_levelDistance(50), - m_treeDistance(50), - m_orthogonalLayout(false), - m_orientation(topToBottom), - m_selectRoot(rootIsSource), - m_pGraph(0) -{ } - - -TreeLayout::TreeLayout(const TreeLayout &tl) - :m_siblingDistance(tl.m_siblingDistance), - m_subtreeDistance(tl.m_subtreeDistance), - m_levelDistance(tl.m_levelDistance), - m_treeDistance(tl.m_treeDistance), - m_orthogonalLayout(tl.m_orthogonalLayout), - m_orientation(tl.m_orientation), - m_selectRoot(tl.m_selectRoot) -{ } - - -TreeLayout::~TreeLayout() -{ } - - -TreeLayout &TreeLayout::operator=(const TreeLayout &tl) -{ - m_siblingDistance = tl.m_siblingDistance; - m_subtreeDistance = tl.m_subtreeDistance; - m_levelDistance = tl.m_levelDistance; - m_treeDistance = tl.m_treeDistance; - m_orthogonalLayout = tl.m_orthogonalLayout; - m_orientation = tl.m_orientation; - m_selectRoot = tl.m_selectRoot; - return *this; -} - - -// comparer class used for sorting adjacency entries according to their angle -class TreeLayout::AdjComparer -{ -public: - AdjComparer(const AdjEntryArray &angle) { - m_pAngle = ∠ - } - - int compare(const adjEntry &adjX, const adjEntry &adjY) const { - if ((*m_pAngle)[adjX] < (*m_pAngle)[adjY]) - return -1; - else - if ((*m_pAngle)[adjX] > (*m_pAngle)[adjY]) - return 1; - else - return 0; - } - OGDF_AUGMENT_COMPARER(adjEntry) - -private: - const AdjEntryArray *m_pAngle; -}; - - - -void TreeLayout::setRoot(GraphAttributes &AG, Graph &tree) -{ - m_pGraph = &tree; - - NodeArray visited(tree,false); - StackPure S; - - node v; - forall_nodes(v,tree) - { - if(visited[v]) continue; - - // process a new connected component - node root = 0; - S.push(v); - - while(!S.empty()) - { - node x = S.pop(); - visited[x] = true; - - if(!root) { - if(m_selectRoot == rootIsSource) { - if (x->indeg() == 0) - root = x; - } else if (m_selectRoot == rootIsSink) { - if (x->outdeg() == 0) - root = x; - } else { // selectByCoordinate - root = x; - } - - } else if(m_selectRoot == rootByCoord) { - switch(m_orientation) - { - case bottomToTop: - if(AG.y(x) < AG.y(root)) - root = x; - break; - case topToBottom: - if(AG.y(x) > AG.y(root)) - root = x; - break; - case leftToRight: - if(AG.x(x) < AG.x(root)) - root = x; - break; - case rightToLeft: - if(AG.x(x) > AG.x(root)) - root = x; - break; - } - } - - adjEntry adj; - forall_adj(adj,x) { - node w = adj->twinNode(); - if(!visited[w]) - S.push(w); - } - } - - if(root == 0) { - undoReverseEdges(AG); - OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest); - } - - adjustEdgeDirections(tree,root,0); - } -} - - -void TreeLayout::adjustEdgeDirections(Graph &G, node v, node parent) -{ - adjEntry adj; - forall_adj(adj,v) { - node w = adj->twinNode(); - if(w == parent) continue; - edge e = adj->theEdge(); - if(w != e->target()) { - G.reverseEdge(e); - m_reversedEdges.pushBack(e); - } - adjustEdgeDirections(G,w,v); - } -} - -void TreeLayout::callSortByPositions(GraphAttributes &AG, Graph &tree) -{ - OGDF_ASSERT(&tree == &(AG.constGraph())); - - if (!isFreeForest(tree)) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest); - - setRoot(AG,tree); - - // stores angle of adjacency entry - AdjEntryArray angle(tree); - - AdjComparer cmp(angle); - - node v; - forall_nodes(v,tree) - { - // position of node v - double cx = AG.x(v); - double cy = AG.y(v); - - adjEntry adj; - forall_adj(adj,v) - { - // adjacent node - node w = adj->twinNode(); - - // relative position of w to v - double dx = AG.x(w) - cx; - double dy = AG.y(w) - cy; - - // if v and w lie on the same point ... - if (dx == 0 && dy == 0) { - angle[adj] = 0; - continue; - } - - if(m_orientation == leftToRight || m_orientation == rightToLeft) - swap(dx,dy); - if(m_orientation == topToBottom || m_orientation == rightToLeft) - dy = -dy; - - // compute angle of adj - double alpha = atan2(fabs(dx),fabs(dy)); - - if(dx < 0) { - if(dy < 0) - angle[adj] = alpha; - else - angle[adj] = Math::pi - alpha; - } else { - if (dy > 0) - angle[adj] = Math::pi + alpha; - else - angle[adj] = 2*Math::pi - alpha; - } - } - - // get list of all adjacency entries at v - SListPure entries; - tree.adjEntries(v, entries); - - // sort entries according to angle - entries.quicksort(cmp); - - // sort entries accordingly in tree - tree.sort(v,entries); - } - - // adjacency lists are now sorted, so we can apply the usual call - call(AG); -} - - -void TreeLayout::call(GraphAttributes &AG) -{ - const Graph &tree = AG.constGraph(); - if(tree.numberOfNodes() == 0) return; - - if (!isForest(tree)) - OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest); - - OGDF_ASSERT(m_siblingDistance > 0); - OGDF_ASSERT(m_subtreeDistance > 0); - OGDF_ASSERT(m_levelDistance > 0); - - // compute the tree structure - List roots; - initializeTreeStructure(tree,roots); - - if(m_orientation == topToBottom || m_orientation == bottomToTop) - { - ListConstIterator it; - double minX = 0, maxX = 0; - for(it = roots.begin(); it.valid(); ++it) - { - node root = *it; - - // compute x-coordinates - firstWalk(root,AG,true); - secondWalkX(root,-m_preliminary[root],AG); - - // compute y-coordinates - computeYCoordinatesAndEdgeShapes(root,AG); - - if(it != roots.begin()) - { - findMinX(AG,root,minX); - - double shift = maxX + m_treeDistance - minX; - - shiftTreeX(AG,root,shift); - } - - findMaxX(AG,root,maxX); - } - - // The computed layout draws a tree upwards. If we want to draw the - // tree downwards, we simply invert all y-coordinates. - if(m_orientation == topToBottom) - { - node v; - forall_nodes(v,tree) - AG.y(v) = -AG.y(v); - - edge e; - forall_edges(e,tree) { - ListIterator it; - for(it = AG.bends(e).begin(); it.valid(); ++it) - (*it).m_y = -(*it).m_y; - } - } - - } else { - ListConstIterator it; - double minY = 0, maxY = 0; - for(it = roots.begin(); it.valid(); ++it) - { - node root = *it; - - // compute y-coordinates - firstWalk(root,AG,false); - secondWalkY(root,-m_preliminary[root],AG); - - // compute y-coordinates - computeXCoordinatesAndEdgeShapes(root,AG); - - if(it != roots.begin()) - { - findMinY(AG,root,minY); - - double shift = maxY + m_treeDistance - minY; - - shiftTreeY(AG,root,shift); - } - - findMaxY(AG,root,maxY); - } - - // The computed layout draws a tree upwards. If we want to draw the - // tree downwards, we simply invert all y-coordinates. - if(m_orientation == rightToLeft) - { - node v; - forall_nodes(v,tree) - AG.x(v) = -AG.x(v); - - edge e; - forall_edges(e,tree) { - ListIterator it; - for(it = AG.bends(e).begin(); it.valid(); ++it) - (*it).m_x = -(*it).m_x; - } - } - - } - - // delete the tree structure - deleteTreeStructure(); - - // restore temporarily removed edges again - undoReverseEdges(AG); -} - -void TreeLayout::undoReverseEdges(GraphAttributes &AG) -{ - if(m_pGraph) { - while(!m_reversedEdges.empty()) { - edge e = m_reversedEdges.popFrontRet(); - m_pGraph->reverseEdge(e); - AG.bends(e).reverse(); - } - - m_pGraph = 0; - } -} - -void TreeLayout::findMinX(GraphAttributes &AG, node root, double &minX) -{ - Stack S; - S.push(root); - - while(!S.empty()) - { - node v = S.pop(); - - double left = AG.x(v) - AG.width(v)/2; - if(left < minX) minX = left; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) S.push(w); - } - } -} - -void TreeLayout::findMinY(GraphAttributes &AG, node root, double &minY) -{ - Stack S; - S.push(root); - - while(!S.empty()) - { - node v = S.pop(); - - double left = AG.y(v) - AG.height(v)/2; - if(left < minY) minY = left; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) S.push(w); - } - } -} - - -void TreeLayout::shiftTreeX(GraphAttributes &AG, node root, double shift) -{ - Stack S; - S.push(root); - while(!S.empty()) - { - node v = S.pop(); - - AG.x(v) += shift; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) { - ListIterator itP; - for(itP = AG.bends(e).begin(); itP.valid(); ++itP) - (*itP).m_x += shift; - S.push(w); - } - } - } -} - -void TreeLayout::shiftTreeY(GraphAttributes &AG, node root, double shift) -{ - Stack S; - S.push(root); - while(!S.empty()) - { - node v = S.pop(); - - AG.y(v) += shift; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) { - ListIterator itP; - for(itP = AG.bends(e).begin(); itP.valid(); ++itP) - (*itP).m_y += shift; - S.push(w); - } - } - } -} - - -void TreeLayout::findMaxX(GraphAttributes &AG, node root, double &maxX) -{ - Stack S; - S.push(root); - while(!S.empty()) - { - node v = S.pop(); - - double right = AG.x(v) + AG.width(v)/2; - if(right > maxX) maxX = right; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) S.push(w); - } - } -} - -void TreeLayout::findMaxY(GraphAttributes &AG, node root, double &maxY) -{ - Stack S; - S.push(root); - while(!S.empty()) - { - node v = S.pop(); - - double right = AG.y(v) + AG.height(v)/2; - if(right > maxY) maxY = right; - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if(w != v) S.push(w); - } - } -} - - -//node TreeLayout::initializeTreeStructure(const Graph &tree) -void TreeLayout::initializeTreeStructure(const Graph &tree, List &roots) -{ - node v; - - // initialize node arrays - m_number .init(tree,0); - m_parent .init(tree,0); - m_leftSibling.init(tree,0); - m_firstChild .init(tree,0); - m_lastChild .init(tree,0); - m_thread .init(tree,0); - m_ancestor .init(tree,0); - m_preliminary.init(tree,0); - m_modifier .init(tree,0); - m_change .init(tree,0); - m_shift .init(tree,0); - - // compute the tree structure - - // find the roots - //node root = 0; - forall_nodes(v,tree) { - if(v->indeg() == 0) - roots.pushBack(v); - } - - int childCounter; - forall_nodes(v,tree) { - - // determine - // - the parent node of v - // - the leftmost and rightmost child of v - // - the numbers of the children of v - // - the left siblings of the children of v - // and initialize the actual ancestor of v - - m_ancestor[v] = v; - if(isLeaf(v)) { - if(v->indeg() == 0) { // is v a root - m_parent[v] = 0; - m_leftSibling[v] = 0; - } - else { - m_firstChild[v] = m_lastChild[v] = 0; - m_parent[v] = v->firstAdj()->theEdge()->source(); - } - } - else { - - // traverse the adjacency list of v - adjEntry first; // first leaving edge - adjEntry stop; // successor of last leaving edge - first = v->firstAdj(); - if(v->indeg() == 0) { // is v a root - stop = first; - m_parent[v] = 0; - m_leftSibling[v] = 0; - } - else { - - // search for first leaving edge - while(first->theEdge()->source() == v) - first = first->cyclicSucc(); - m_parent[v] = first->theEdge()->source(); - stop = first; - first = first->cyclicSucc(); - } - - // traverse the children of v - m_firstChild[v] = first->theEdge()->target(); - m_number[m_firstChild[v]] = childCounter = 0; - m_leftSibling[m_firstChild[v]] = 0; - adjEntry previous = first; - while(first->cyclicSucc() != stop) { - first = first->cyclicSucc(); - m_number[first->theEdge()->target()] = ++childCounter; - m_leftSibling[first->theEdge()->target()] - = previous->theEdge()->target(); - previous = first; - } - m_lastChild[v] = first->theEdge()->target(); - } - } -} - - -void TreeLayout::deleteTreeStructure() -{ - m_number .init(); - m_parent .init(); - m_leftSibling.init(); - m_firstChild .init(); - m_lastChild .init(); - m_thread .init(); - m_ancestor .init(); - m_preliminary.init(); - m_modifier .init(); - m_change .init(); - m_shift .init(); -} - - -int TreeLayout::isLeaf(node v) const -{ - OGDF_ASSERT(v != 0); - - // node v is a leaf if and only if no edge leaves v - return v->outdeg() == 0; -} - - -node TreeLayout::nextOnLeftContour(node v) const -{ - OGDF_ASSERT(v != 0); - OGDF_ASSERT(v->graphOf() == m_firstChild.graphOf()); - OGDF_ASSERT(v->graphOf() == m_thread.graphOf()); - - // if v has children, the successor of v on the left contour - // is its leftmost child, - // otherwise, the successor is the thread of v (may be 0) - if(m_firstChild[v] != 0) - return m_firstChild[v]; - else - return m_thread[v]; -} - - -node TreeLayout::nextOnRightContour(node v) const -{ - OGDF_ASSERT(v != 0); - OGDF_ASSERT(v->graphOf() == m_lastChild.graphOf()); - OGDF_ASSERT(v->graphOf() == m_thread.graphOf()); - - // if v has children, the successor of v on the right contour - // is its rightmost child, - // otherwise, the successor is the thread of v (may be 0) - if(m_lastChild[v] != 0) - return m_lastChild[v]; - else - return m_thread[v]; -} - - -void TreeLayout::firstWalk(node subtree,const GraphAttributes &AG,bool upDown) -{ - OGDF_ASSERT(subtree != 0); - OGDF_ASSERT(subtree->graphOf() == m_leftSibling.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_preliminary.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_firstChild.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_lastChild.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_change.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_shift.graphOf()); - - // compute a preliminary x-coordinate for subtree - if(isLeaf(subtree)) { - - // place subtree close to the left sibling - node leftSibling = m_leftSibling[subtree]; - if(leftSibling != 0) { - if(upDown) { - m_preliminary[subtree] = m_preliminary[leftSibling] - + (AG.width(subtree) + AG.width(leftSibling)) / 2 - + m_siblingDistance; - } else { - m_preliminary[subtree] = m_preliminary[leftSibling] - + (AG.height(subtree) + AG.height(leftSibling)) / 2 - + m_siblingDistance; - } - } - else m_preliminary[subtree] = 0; - } - else { - node defaultAncestor = m_firstChild[subtree]; - - // collect the children of subtree - List children; - node v = m_lastChild[subtree]; - do { - children.pushFront(v); - v = m_leftSibling[v]; - } while(v != 0); - - ListIterator it; - - // apply firstwalk and apportion to the children - for(it = children.begin(); it.valid(); it = it.succ()) { - firstWalk(*it,AG,upDown); - apportion(*it,defaultAncestor,AG,upDown); - } - - // shift the small subtrees - double shift = 0; - double change = 0; - children.reverse(); - for(it = children.begin(); it.valid(); it = it.succ()) { - m_preliminary[*it] += shift; - m_modifier[*it] += shift; - change += m_change[*it]; - shift += m_shift[*it] + change; - } - - // place the parent node - double midpoint = (m_preliminary[children.front()] + m_preliminary[children.back()]) / 2; - node leftSibling = m_leftSibling[subtree]; - if(leftSibling != 0) { - if(upDown) { - m_preliminary[subtree] = m_preliminary[leftSibling] - + (AG.width(subtree) + AG.width(leftSibling)) / 2 - + m_siblingDistance; - } else { - m_preliminary[subtree] = m_preliminary[leftSibling] - + (AG.height(subtree) + AG.height(leftSibling)) / 2 - + m_siblingDistance; - } - m_modifier[subtree] = - m_preliminary[subtree] - midpoint; - } - else m_preliminary[subtree] = midpoint; - } -} - -void TreeLayout::apportion( - node subtree, - node &defaultAncestor, - const GraphAttributes &AG, - bool upDown) -{ - OGDF_ASSERT(subtree != 0); - OGDF_ASSERT(subtree->graphOf() == defaultAncestor->graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_leftSibling.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_firstChild.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_ancestor.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_change.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_shift.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_thread.graphOf()); - - if(m_leftSibling[subtree] == 0) return; - - // check distance to the left of the subtree - // and traverse left/right inside/outside contour - - double leftModSumOut = 0; // sum of modifiers on left outside contour - double leftModSumIn = 0; // sum of modifiers on left inside contour - double rightModSumIn = 0; // sum of modifiers on right inside contour - double rightModSumOut = 0; // sum of modifiers on right outside contour - - double moveDistance; - int numberOfSubtrees; - node leftAncestor,rightAncestor; - - // start the traversal at the actual level - node leftContourOut = m_firstChild[m_parent[subtree]]; - node leftContourIn = m_leftSibling[subtree]; - node rightContourIn = subtree; - node rightContourOut = subtree; - bool stop = false; - do { - - // add modifiers - leftModSumOut += m_modifier[leftContourOut]; - leftModSumIn += m_modifier[leftContourIn]; - rightModSumIn += m_modifier[rightContourIn]; - rightModSumOut += m_modifier[rightContourOut]; - - // actualize ancestor for right contour - m_ancestor[rightContourOut] = subtree; - - if(nextOnLeftContour(leftContourOut) != 0 && nextOnRightContour(rightContourOut) != 0) - { - // continue traversal - leftContourOut = nextOnLeftContour(leftContourOut); - leftContourIn = nextOnRightContour(leftContourIn); - rightContourIn = nextOnLeftContour(rightContourIn); - rightContourOut = nextOnRightContour(rightContourOut); - - // check if subtree has to be moved - if(upDown) { - moveDistance = m_preliminary[leftContourIn] + leftModSumIn - + (AG.width(leftContourIn) + AG.width(rightContourIn)) / 2 - + m_subtreeDistance - - m_preliminary[rightContourIn] - rightModSumIn; - } else { - moveDistance = m_preliminary[leftContourIn] + leftModSumIn - + (AG.height(leftContourIn) + AG.height(rightContourIn)) / 2 - + m_subtreeDistance - - m_preliminary[rightContourIn] - rightModSumIn; - } - if(moveDistance > 0) { - - // compute highest different ancestors of leftContourIn - // and rightContourIn - if(m_parent[m_ancestor[leftContourIn]] == m_parent[subtree]) - leftAncestor = m_ancestor[leftContourIn]; - else leftAncestor = defaultAncestor; - rightAncestor = subtree; - - // compute the number of small subtrees in between (plus 1) - numberOfSubtrees = - m_number[rightAncestor] - m_number[leftAncestor]; - - // compute the shifts and changes of shift - m_change[rightAncestor] -= moveDistance / numberOfSubtrees; - m_shift[rightAncestor] += moveDistance; - m_change[leftAncestor] += moveDistance / numberOfSubtrees; - - // move subtree to the right by moveDistance - m_preliminary[rightAncestor] += moveDistance; - m_modifier[rightAncestor] += moveDistance; - rightModSumIn += moveDistance; - rightModSumOut += moveDistance; - } - } - else stop = true; - } while(!stop); - - // adjust threads - if(nextOnRightContour(rightContourOut) == 0 && nextOnRightContour(leftContourIn) != 0) - { - // right subtree smaller than left subforest - m_thread[rightContourOut] = nextOnRightContour(leftContourIn); - m_modifier[rightContourOut] += leftModSumIn - rightModSumOut; - } - - if(nextOnLeftContour(leftContourOut) == 0 && nextOnLeftContour(rightContourIn) != 0) - { - // left subforest smaller than right subtree - m_thread[leftContourOut] = nextOnLeftContour(rightContourIn); - m_modifier[leftContourOut] += rightModSumIn - leftModSumOut; - defaultAncestor = subtree; - } -} - - -void TreeLayout::secondWalkX(node subtree, - double modifierSum, - GraphAttributes &AG) -{ - OGDF_ASSERT(subtree != 0); - OGDF_ASSERT(subtree->graphOf() == m_preliminary.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf()); - - // compute final x-coordinates for the subtree - // by recursively aggregating modifiers - AG.x(subtree) = m_preliminary[subtree] + modifierSum; - modifierSum += m_modifier[subtree]; - edge e; - forall_adj_edges(e,subtree) if(e->target() != subtree) - secondWalkX(e->target(),modifierSum,AG); -} - -void TreeLayout::secondWalkY(node subtree, - double modifierSum, - GraphAttributes &AG) -{ - OGDF_ASSERT(subtree != 0); - OGDF_ASSERT(subtree->graphOf() == m_preliminary.graphOf()); - OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf()); - - // compute final y-coordinates for the subtree - // by recursively aggregating modifiers - AG.y(subtree) = m_preliminary[subtree] + modifierSum; - modifierSum += m_modifier[subtree]; - edge e; - forall_adj_edges(e,subtree) if(e->target() != subtree) - secondWalkY(e->target(),modifierSum,AG); -} - - -void TreeLayout::computeYCoordinatesAndEdgeShapes(node root, GraphAttributes &AG) -{ - OGDF_ASSERT(root != 0); - - // compute y-coordinates and edge shapes - node v,w; - edge e; - List oldLevel; // the nodes of the old level - List newLevel; // the nodes of the new level - ListIterator it; - double yCoordinate; // the y-coordinate for the new level - double edgeCoordinate; // the y-coordinate for edge bends - double oldHeight; // the maximal node height on the old level - double newHeight; // the maximal node height on the new level - - // traverse the tree level by level - newLevel.pushBack(root); - AG.y(root) = yCoordinate = 0; - newHeight = AG.height(root); - while(!newLevel.empty()) { - oldHeight = newHeight; - newHeight = 0; - oldLevel.conc(newLevel); - while(!oldLevel.empty()) { - v = oldLevel.popFrontRet(); - forall_adj_edges(e,v) if(e->target() != v) { - w = e->target(); - newLevel.pushBack(w); - - // compute the shape of edge e - DPolyline &edgeBends = AG.bends(e); - edgeBends.clear(); - if(m_orthogonalLayout) { - edgeCoordinate = - yCoordinate + (oldHeight + m_levelDistance) / 2; - edgeBends.pushBack(DPoint(AG.x(v),edgeCoordinate)); - edgeBends.pushBack(DPoint(AG.x(w),edgeCoordinate)); - } - - // compute the maximal node height on the new level - if(AG.height(e->target()) > newHeight) - newHeight = AG.height(e->target()); - } - } - - // assign y-coordinate to the nodes of the new level - yCoordinate += (oldHeight + newHeight) / 2 + m_levelDistance; - for(it = newLevel.begin(); it.valid(); it = it.succ()) - AG.y(*it) = yCoordinate; - } -} - -void TreeLayout::computeXCoordinatesAndEdgeShapes(node root, GraphAttributes &AG) -{ - OGDF_ASSERT(root != 0); - - // compute y-coordinates and edge shapes - node v,w; - edge e; - List oldLevel; // the nodes of the old level - List newLevel; // the nodes of the new level - ListIterator it; - double xCoordinate; // the x-coordinate for the new level - double edgeCoordinate; // the x-coordinate for edge bends - double oldWidth; // the maximal node width on the old level - double newWidth; // the maximal node width on the new level - - // traverse the tree level by level - newLevel.pushBack(root); - AG.x(root) = xCoordinate = 0; - newWidth = AG.width(root); - while(!newLevel.empty()) { - oldWidth = newWidth; - newWidth = 0; - oldLevel.conc(newLevel); - while(!oldLevel.empty()) { - v = oldLevel.popFrontRet(); - forall_adj_edges(e,v) if(e->target() != v) { - w = e->target(); - newLevel.pushBack(w); - - // compute the shape of edge e - DPolyline &edgeBends = AG.bends(e); - edgeBends.clear(); - if(m_orthogonalLayout) { - edgeCoordinate = - xCoordinate + (oldWidth + m_levelDistance) / 2; - edgeBends.pushBack(DPoint(edgeCoordinate,AG.y(v))); - edgeBends.pushBack(DPoint(edgeCoordinate,AG.y(w))); - } - - // compute the maximal node width on the new level - if(AG.width(e->target()) > newWidth) - newWidth = AG.width(e->target()); - } - } - - // assign x-coordinate to the nodes of the new level - xCoordinate += (oldWidth + newWidth) / 2 + m_levelDistance; - for(it = newLevel.begin(); it.valid(); it = it.succ()) - AG.x(*it) = xCoordinate; - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/upward/DominanceLayout.cpp b/ext/OGDF/src/upward/DominanceLayout.cpp deleted file mode 100644 index f2b75bc73..000000000 --- a/ext/OGDF/src/upward/DominanceLayout.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of dominance layout algorithm. - * - * \author Hoi-Ming Wong and Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include - -namespace ogdf { - -void DominanceLayout::call(GraphAttributes &GA) -{ - if (GA.constGraph().numberOfNodes() <= 1) - return; - - //call upward planarizer - UpwardPlanRep UPR; - UPR.createEmpty(GA.constGraph()); - m_upPlanarizer.get().call(UPR); - layout(GA, UPR); -} - - -void DominanceLayout::layout(GraphAttributes &GA, const UpwardPlanRep &UPROrig) -{ - - UpwardPlanRep UPR = UPROrig; - - //clear some data - edge e; - forall_edges(e, GA.constGraph()) { - GA.bends(e).clear(); - } - - //compute and splite transitiv edges - List splitMe; - findTransitiveEdges(UPR, splitMe); - - forall_listiterators(edge, it, splitMe) { - UPR.getEmbedding().split(*it); - } - - // set up first-/lastout, first-/lastin - firstout.init(UPR, 0); - lastout.init(UPR, 0); - firstin.init(UPR, 0); - lastin.init(UPR, 0); - - node s = UPR.getSuperSource(); - node t = UPR.getSuperSink(); - - firstout[t] = lastout[t] = 0; - firstin[s] = lastin[s] = 0; - firstin[t] = lastin[t] =t->firstAdj()->theEdge(); - adjEntry adjRun = s->firstAdj(); - while (UPR.getEmbedding().rightFace(adjRun) != UPR.getEmbedding().externalFace()) { - adjRun = adjRun->cyclicSucc(); - } - lastout[s] = adjRun->theEdge(); - firstout[s] = adjRun->cyclicSucc()->theEdge(); - - node v; - forall_nodes(v, UPR) { - if (v == t || v == s) continue; - - adjEntry adj = UPR.leftInEdge(v); - firstin[v] = adj->theEdge(); - firstout[v] = adj->cyclicSucc()->theEdge(); - - adjEntry adjRightIn = adj; - while (adjRightIn->cyclicPred()->theEdge()->source() != v) - adjRightIn = adjRightIn->cyclicPred(); - - lastin[v] = adjRightIn->theEdge(); - lastout[v] = adjRightIn->cyclicPred()->theEdge(); - } - - - //compute m_L and m_R for min. area drawing - m_L = 0; - m_R = 0; - forall_edges(e, UPR) { - node src = e->source(); - node tgt = e->target(); - if (lastin[tgt] == e && firstout[src] == e) - m_L++; - if (firstin[tgt] == e && lastout[src] == e) - m_R++; - } - - // compute preleminary coordinate - xPreCoord.init(UPR); - yPreCoord.init(UPR); - int count = 0; - labelX(UPR, s, count); - count = 0; - labelY(UPR, s, count); - - // compaction - compact(UPR, GA); - - // map coordinate to GA - forall_nodes(v, GA.constGraph()) { - node vUPR = UPR.copy(v); - GA.x(v) = xCoord[vUPR]; - GA.y(v) = yCoord[vUPR]; - } - // add bends to original edges - forall_edges(e, GA.constGraph()) { - List chain = UPR.chain(e); - forall_nonconst_listiterators(edge, it, chain) { - node tgtUPR = (*it)->target(); - if (tgtUPR != chain.back()->target()) { - DPoint p(xCoord[tgtUPR], yCoord[tgtUPR]); - GA.bends(e).pushBack(p); - } - } - } - - - //rotate the drawing - forall_nodes(v, GA.constGraph()) { - double r = sqrt(GA.x(v)*GA.x(v) + GA.y(v)*GA.y(v)); - if (r == 0) - continue; - double alpha = asin(GA.y(v)/r); - double yNew = sin(alpha + m_angle)*r; - double xNew = cos(alpha + m_angle)*r; - GA.x(v) = xNew; - GA.y(v) = yNew; - } - - forall_edges(e, GA.constGraph()) { - DPolyline &poly = GA.bends(e); - DPoint pSrc(GA.x(e->source()), GA.y(e->source())); - DPoint pTgt(GA.x(e->target()), GA.y(e->target())); - poly.normalize(pSrc, pTgt); - - forall_nonconst_listiterators(DPoint, it, poly) { - double r = (*it).distance(DPoint(0,0)); - - if (r == 0) - continue; - - double alpha = asin( (*it).m_y/r); - double yNew = sin(alpha + m_angle)*r; - double xNew = cos(alpha + m_angle)*r; - (*it).m_x = xNew; - (*it).m_y = yNew; - } - - } -} - - -void DominanceLayout::labelX(const UpwardPlanRep &UPR, node v, int &count) -{ - xNodes.pushBack(v); - xPreCoord[v] = count; - count++; - if (v != UPR.getSuperSink()) { - adjEntry adj = firstout[v]->adjSource(); - do { - node w = adj->theEdge()->target(); - if (adj->theEdge() == lastin[w]) - labelX(UPR, w, count); - adj = adj->cyclicSucc(); - } while (adj->cyclicPred()->theEdge() != lastout[v]); - } -} - - - -void DominanceLayout::labelY(const UpwardPlanRep &UPR, node v, int &count) -{ - yNodes.pushBack(v); - yPreCoord[v] = count; - count++; - if (v != UPR.getSuperSink()) { - adjEntry adj = lastout[v]->adjSource(); - do { - node w = adj->theEdge()->target(); - if (adj->theEdge() == firstin[w]) - labelY(UPR, w, count); - adj = adj->cyclicPred(); - } while (adj->cyclicSucc()->theEdge() != firstout[v]); - } -} - - -void DominanceLayout::compact(const UpwardPlanRep &UPR, GraphAttributes &GA) -{ - double maxNodeSize = 0; - node v; - forall_nodes(v, GA.constGraph()) { - if (GA.width(v) > maxNodeSize || GA.height(v) > maxNodeSize) - maxNodeSize = max(GA.width(v), GA.height(v)); - } - - int gridDist = m_grid_dist; - if (gridDist < maxNodeSize+1) - gridDist = (int) maxNodeSize+1; - - xCoord.init(UPR); - yCoord.init(UPR); - - //ASSIGN X COORDINATE - - OGDF_ASSERT(!xNodes.empty()); - - v = xNodes.popFrontRet(); - xCoord[v] = 0; - while (!xNodes.empty()) { - node u = xNodes.popFrontRet(); - if ( (yPreCoord[v] > yPreCoord[u]) || (firstout[v] == lastout[v] && firstin[u] == lastin[u] && m_L <= m_R)) { - xCoord[u] = xCoord[v] + gridDist; - } - else - xCoord[u] = xCoord[v]; - v = u; - } - - //ASSIGN Y COORDINATE - OGDF_ASSERT(!yNodes.empty()); - - v = yNodes.popFrontRet(); - yCoord[v] = 0; - while (!yNodes.empty()) { - node u = yNodes.popFrontRet(); - if ( (xPreCoord[v] > xPreCoord[u]) || (firstout[v] == lastout[v] && firstin[u] == lastin[u] && m_L > m_R)) { - yCoord[u] = yCoord[v] + gridDist; - } - else - yCoord[u] = yCoord[v]; - v = u; - } -} - - - -void DominanceLayout::findTransitiveEdges(const UpwardPlanRep &UPR, List &edges) -{ - // for st-graphs: - // e = (u,v) transitive <=> ex. face f: e in f and u source-switch and v = sink-switch - face f; - forall_faces(f, UPR.getEmbedding()) { - if (f == UPR.getEmbedding().externalFace()) - continue; - - adjEntry adj; - forall_face_adj(adj, f) { - node src = adj->theEdge()->source(); - node tgt = adj->theEdge()->target(); - if ( (adj->faceCycleSucc()->theEdge()->source() == src && adj->faceCyclePred()->theEdge()->target() == tgt) - || (adj->faceCycleSucc()->theEdge()->target() == tgt && adj->faceCyclePred()->theEdge()->source() == src)) { - edges.pushBack(adj->theEdge()); - break; - } - } - } -} - - -}//namespace diff --git a/ext/OGDF/src/upward/ExpansionGraph.cpp b/ext/OGDF/src/upward/ExpansionGraph.cpp deleted file mode 100644 index 682ff615a..000000000 --- a/ext/OGDF/src/upward/ExpansionGraph.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class ExpansionGraph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include - - -namespace ogdf { - - -// constructor -// computes biconnected componets of original graph -// does not create a copy graph -ExpansionGraph::ExpansionGraph(const Graph &G) : - m_compNum(G), m_adjComponents(G), m_vCopy(G,0) -{ - m_vOrig.init(*this,0); - m_vRep .init(*this,0); - m_eOrig.init(*this,0); - - // compute biconnected components - int numComp = biconnectedComponents(G,m_compNum); - - // for each component, build list of contained edges - m_component.init(numComp); - - edge e; - forall_edges(e,G) - m_component[m_compNum[e]].pushBack(e); - - // for each vertex v, build list of components containing v - NodeSetSimple contained(G); - for(int i = 0; i < numComp; ++i) - { - SListConstIterator it; - for(it = m_component[i].begin(); it.valid(); ++it) - { - e = *it; - node v = e->source(); - if (contained.isMember(v) == false) { - contained.insert(v); - m_adjComponents[v].pushBack(i); - } - - v = e->target(); - if (contained.isMember(v) == false) { - contained.insert(v); - m_adjComponents[v].pushBack(i); - } - } - - contained.clear(); - } -} - - -// builds expansion graph of i-th biconnected component of the original graph -void ExpansionGraph::init(int i) -{ - OGDF_ASSERT(0 <= i && i <= m_component.high()); - - // remove previous component - node v; - forall_nodes(v,*this) { - node vOrig = m_vOrig[v]; - if (vOrig) - m_vCopy[vOrig] = 0; - } - clear(); - - - // create new component - SListConstIterator it; - for(it = m_component[i].begin(); it.valid(); ++it) - { - edge e = *it; - - edge eCopy = newEdge(getCopy(e->source()),getCopy(e->target())); - m_eOrig[eCopy] = e; - } - - // expand vertices - forall_nodes(v,*this) - { - if (original(v) && v->indeg() >= 1 && v->outdeg() >= 1) { - node vPrime = newNode(); - m_vRep[vPrime] = m_vOrig[v]; - - SListPure edges; - outEdges(v,edges); - - SListConstIterator it; - for(it = edges.begin(); it.valid(); ++it) - moveSource(*it,vPrime); - - newEdge(v,vPrime); - } - } -} - - -// builds expansion graph of graph G -// for debugging purposes only -void ExpansionGraph::init(const Graph &G) -{ - // remove previous component - node v; - forall_nodes(v,*this) { - node vOrig = m_vOrig[v]; - if (vOrig) - m_vCopy[vOrig] = 0; - } - clear(); - - - // create new component - forall_nodes(v,G) - getCopy(v); - - edge e; - forall_edges(e,G) - { - edge eCopy = newEdge(getCopy(e->source()),getCopy(e->target())); - m_eOrig[eCopy] = e; - } - - // expand vertices - forall_nodes(v,*this) - { - if (original(v) && v->indeg() >= 1 && v->outdeg() >= 1) { - node vPrime = newNode(); - - SListPure edges; - outEdges(v,edges); - - SListConstIterator it; - for(it = edges.begin(); it.valid(); ++it) - moveSource(*it,vPrime); - - newEdge(v,vPrime); - } - } -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/upward/FUPSSimple.cpp b/ext/OGDF/src/upward/FUPSSimple.cpp deleted file mode 100644 index 94a8516ad..000000000 --- a/ext/OGDF/src/upward/FUPSSimple.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of FUPSSimple class. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - - -namespace ogdf { - -Module::ReturnType FUPSSimple::doCall( - UpwardPlanRep &UPR, - List &delEdges) -{ - - delEdges.clear(); - computeFUPS(UPR, delEdges); - for (int i = 1; i < m_nRuns; ++i) { - UpwardPlanRep UPR_cur = UPR; - List delEdges_cur; - computeFUPS(UPR_cur, delEdges_cur); - - // use new result?? - if (delEdges_cur.size() < delEdges.size()) { - UPR = UPR_cur; - delEdges = delEdges_cur; - } - } - return Module::retFeasible; -} - - - -void FUPSSimple::computeFUPS(UpwardPlanRep &UPR, List &delEdges) -{ - const Graph &G = UPR.original(); - GraphCopy FUPS(G); - node s_orig; - hasSingleSource(G, s_orig); - List nonTreeEdges_orig; - bool random = (m_nRuns != 0); - - getSpanTree(FUPS, nonTreeEdges_orig, random); - - CombinatorialEmbedding Gamma(FUPS); - - if (random) - nonTreeEdges_orig.permute(); // random order - - adjEntry extFaceHandle = 0; - - //insert nonTreeEdges - UpwardPlanarModule upMod; - while (!nonTreeEdges_orig.empty()) { - - /* - //------------------------------------debug - GraphAttributes AG(FUPS, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - node v; - // label the nodes with their index - forall_nodes(v, AG.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", v->index()); // convert to string - AG.labelNode(v) = str; - } - AG.writeGML("c:/temp/spannTree.gml"); - */ - - // make identical copy FUPSCopy of FUPS - //and insert e_orig in FUPSCopy - GraphCopy FUPSCopy((const GraphCopy &) FUPS); - edge e_orig = nonTreeEdges_orig.popFrontRet(); - FUPSCopy.newEdge(e_orig); - - if (upMod.upwardPlanarEmbed(FUPSCopy)) { //upward embedded the fups and check feasibility - CombinatorialEmbedding Beta(FUPSCopy); - - //choose a arbitrary feasibel ext. face - FaceSinkGraph fsg(Beta, FUPSCopy.copy(s_orig)); - SList ext_faces; - fsg.possibleExternalFaces(ext_faces); - - OGDF_ASSERT(!ext_faces.empty()); - - Beta.setExternalFace(ext_faces.front()); - - -#if 0 - //*************************** debug ******************************** - cout << endl << "FUPS : " << endl; - face ff; - forall_faces(ff, Beta) { - cout << "face " << ff->index() << ": "; - adjEntry adjNext = ff->firstAdj(); - do { - cout << adjNext->theEdge() << "; "; - adjNext = adjNext->faceCycleSucc(); - } while(adjNext != ff->firstAdj()); - cout << endl; - } - if (Beta.externalFace() != 0) - cout << "ext. face of the graph is: " << Beta.externalFace()->index() << endl; - else - cout << "no ext. face set." << endl; -#endif - - GraphCopy M((const GraphCopy &) FUPSCopy); // use a identical copy of FUPSCopy to construct the merge graph of FUPSCopy - adjEntry extFaceHandle_cur = getAdjEntry(Beta, FUPSCopy.copy(s_orig), Beta.externalFace()); - adjEntry adj_orig = FUPSCopy.original(extFaceHandle_cur->theEdge())->adjSource(); - - List missingEdges = nonTreeEdges_orig, listTmp = delEdges; - missingEdges.conc(listTmp); - if (constructMergeGraph(M, adj_orig, missingEdges)) { - FUPS = FUPSCopy; - extFaceHandle = FUPS.copy(FUPSCopy.original(extFaceHandle_cur->theEdge()))->adjSource(); - continue; - } - else { - //Beta is not feasible - delEdges.pushBack(e_orig); - } - } - else { - // not ok, GC is not feasible - delEdges.pushBack(e_orig); - } - } - UpwardPlanRep fups_tmp (FUPS, extFaceHandle); - UPR = fups_tmp; -} - - -void FUPSSimple::getSpanTree(GraphCopy &GC, List &delEdges, bool random) -{ - if (GC.numberOfNodes() == 1) - return; // nothing to do - - node s; - hasSingleSource(GC, s); - NodeArray visited(GC, false); - EdgeArray isTreeEdge(GC,false); - List toDo; - - //mark the incident edges e1..e_i of super source s and the incident edges of the target node of the edge e1.._e_i as tree edge. - visited[s] = true; - adjEntry adj; - forall_adj(adj, s) { - isTreeEdge[adj] = true; - visited[adj->theEdge()->target()]; - adjEntry adjTmp; - forall_adj(adjTmp, adj->theEdge()->target()) { - isTreeEdge[adjTmp] = true; - node tgt = adjTmp->theEdge()->target(); - if (!visited[tgt]) { - toDo.pushBack(tgt); - visited[tgt] = true; - } - } - } - - //traversing with dfs - forall_listiterators(node, it, toDo) { - node start = *it; - adjEntry adj; - forall_adj(adj, start) { - node v = adj->theEdge()->target(); - if (!visited[v]) - dfs_visit(GC, adj->theEdge(), visited, isTreeEdge, random); - } - } - - // delete all non tree edgesEdges to obtain a span tree - List l; - edge e; - forall_edges(e, GC) { - if (!isTreeEdge[e]) - l.pushBack(e); - } - while (!l.empty()) { - e = l.popFrontRet(); - delEdges.pushBack(GC.original(e)); - GC.delCopy(e); - } -} - - - -void FUPSSimple::dfs_visit( - const Graph &G, - edge e, - NodeArray &visited, - EdgeArray &treeEdges, - bool random) -{ - treeEdges[e] = true; - List elist; - G.outEdges(e->target(), elist); - if (!elist.empty()) { - if (random) - elist.permute(); - ListIterator it; - for (it = elist.begin(); it.valid(); ++it) { - edge ee = *it; - if (!visited[ee->target()]) - dfs_visit(G, ee, visited, treeEdges, random); - } - } - visited[e->target()] = true; -} - - -bool FUPSSimple::constructMergeGraph(GraphCopy &M, adjEntry adj_orig, const List &orig_edges) -{ - CombinatorialEmbedding Beta(M); - - //set ext. face of Beta - adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource(); - Beta.setExternalFace(Beta.rightFace(ext_adj)); - - //*************************** debug ******************************** - /* - cout << endl << "FUPS : " << endl; - face ff; - forall_faces(ff, Beta) { - cout << "face " << ff->index() << ": "; - adjEntry adjNext = ff->firstAdj(); - do { - cout << adjNext->theEdge() << "; "; - adjNext = adjNext->faceCycleSucc(); - } while(adjNext != ff->firstAdj()); - cout << endl; - } - if (Beta.externalFace() != 0) - cout << "ext. face of the graph is: " << Beta.externalFace()->index() << endl; - else - cout << "no ext. face set." << endl; - */ - - FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode())); - SList aug_nodes; - SList aug_edges; - SList fList; - fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest() - node v_ext = fsg.faceNodeOf(Beta.externalFace()); - - OGDF_ASSERT(v_ext != 0); - - fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges); - - /* - //------------------------------------debug - GraphAttributes AG(M, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - node v; - // label the nodes with their index - forall_nodes(v, AG.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", v->index()); // convert to string - AG.labelNode(v) = str; - } - AG.writeGML("c:/temp/MergeFUPS.gml"); - */ - - - OGDF_ASSERT(isStGraph(M)); - - //add the deleted edges - forall_listiterators(edge, it, orig_edges) { - node a = M.copy((*it)->source()); - node b = M.copy((*it)->target()); - M.newEdge(a, b); - } - return (isAcyclic(M)); -} - -} // end namespace ogdf - diff --git a/ext/OGDF/src/upward/FaceSinkGraph.cpp b/ext/OGDF/src/upward/FaceSinkGraph.cpp deleted file mode 100644 index a884dc402..000000000 --- a/ext/OGDF/src/upward/FaceSinkGraph.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class FaceSinkGraph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -// construction of face sink graph with cross references -FaceSinkGraph::FaceSinkGraph( - const ConstCombinatorialEmbedding &E, // given embedding - node s) : // single source - m_pE (&E), - m_source (s), - m_T (0) -{ - m_originalNode .init(*this, 0); - m_originalFace .init(*this, 0); - m_containsSource.init(*this, false); - doInit(); -} - - -void FaceSinkGraph::init( - const ConstCombinatorialEmbedding &E, // given embedding - node s) // single source -{ - m_pE = &E; - m_source = s; - m_T = 0; - m_originalNode .init(*this,0); - m_originalFace .init(*this,0); - m_containsSource.init(*this,false); - - doInit(); -} - - -void FaceSinkGraph::doInit() -{ - const ConstCombinatorialEmbedding &E = *m_pE; - - NodeArray sinkSwitch(E,0); // corresponding node in F (if any) - NodeArray isSinkSwitch(E,true); - - face f; - NodeArray visited(E,-1); - int faceNo = -1; - forall_faces(f,E) - { - faceNo++; - node faceNode = newNode(); - m_originalFace[faceNode] = f; - - SListPure nodesInF; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - do { - node v = adj->theNode(); - // if the graph is not biconnected, then node v can visited more than once - if (visited[v] != faceNo) { - nodesInF.pushBack(v); - visited[v] = faceNo; - } - - if (v == m_source) - m_containsSource[faceNode] = true; - - isSinkSwitch[adj->theEdge()->source()] = false; - - adj = adj->twin()->cyclicPred(); - } while (adj != adj1); - - SListConstIterator it; - for(it = nodesInF.begin(); it.valid(); ++it) - { - node v = *it; - if(isSinkSwitch[v]) { - if (sinkSwitch[v] == 0) { - node vF = newNode(); - m_originalNode[vF] = v; - sinkSwitch[v] = vF; - } - - newEdge(faceNode,sinkSwitch[v]); - } - } - - for(it = nodesInF.begin(); it.valid(); ++it) - isSinkSwitch[*it] = true; - } -} - - - - -/* original: -void FaceSinkGraph::doInit() -{ - const ConstCombinatorialEmbedding &E = *m_pE; - - NodeArray sinkSwitch(E,0); // corresponding node in F (if any) - - face f; - forall_faces(f,E) - { - node faceNode = newNode(); - m_originalFace[faceNode] = f; - - adjEntry adj1 = f->firstAdj(), adj = adj1; - adjEntry adjPred = adj->cyclicSucc(); - do { - node v = adj->theNode(); - - if (v == m_source) - m_containsSource[faceNode] = true; - - // v is a sink-switch iff both adjacent edges (there are only two - // in f since G is biconnected) are directed towards v - if(adj->theEdge()->target() == v && - adjPred->theEdge()->target() == v) - { - if (sinkSwitch[v] == 0) { - node vF = newNode(); - m_originalNode[vF] = v; - sinkSwitch[v] = vF; - } - - newEdge(faceNode,sinkSwitch[v]); - } - - adjPred = adj->twin(); - adj = adjPred->cyclicPred(); - } while (adj != adj1); - } -}*/ - - -// checks if F is a forest with -// 1) there exactly one tree T containing no internal vertex of G -// 2) all other trees contain exactly one internal vertex of G -// a node in tree T is returned as representative -node FaceSinkGraph::checkForest() -{ - // representative of tree T (0 indicates none found yet) - m_T = 0; - - // we perform a dfs traversal on F and check if there are backwards edges - // (then F is not a forest) - NodeArray visited(*this,false); - - node v; - forall_nodes(v,*this) - { - if (visited[v]) continue; - - // number of internal vertices in current tree - int nInternalVertices = 0; - if (dfsCheckForest(v,0,visited,nInternalVertices) == 0) - return 0; - - // either we have a unique tree with no internal vertices - if(nInternalVertices == 0) { - if(m_T) - return 0; - else - m_T = v; - - // or we have exactly one internal vertex - } else if (nInternalVertices != 1) - return 0; - } - - return m_T; -} - - -// performs dfs-traversal and checks for backwards edges -bool FaceSinkGraph::dfsCheckForest( - node v, // current node - node parent, // its parent in tree - NodeArray &visited, // not already visited ? - int &nInternalVertices) // number of internal vertices of G in current tree -{ - visited[v] = true; - - // check if original node of v is an internal vertex in G - node vOrig = m_originalNode[v]; - if(vOrig && vOrig->indeg() >= 1 && vOrig->outdeg() >= 1) - ++nInternalVertices; - - // iterate over all adjacent nodes of v different from parent - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - if (w == parent) continue; - if(visited[w]) return false; - - if(dfsCheckForest(w,v,visited,nInternalVertices) == false) - return false; - } - - return true; -} - - - -// builds list of possible external faces (all faces in tree T containing -// the single source s) by a dfs traversal of T -void FaceSinkGraph::gatherExternalFaces( - node v, // current node - node parent, // its parent - SList &externalFaces) // returns list of possible external faces -{ - if (m_containsSource[v]) - externalFaces.pushBack(m_originalFace[v]); - - // since we already know that T is a tree we can omit the visited array - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - if (w != parent) - gatherExternalFaces(w,v,externalFaces); - } -} - - -node FaceSinkGraph::dfsFaceNodeOf(node v, node parent, face f1, face f2) -{ - face f = m_originalFace[v]; - if (m_containsSource[v] && (f == f1 || f == f2)) - return v; - - // since we already know that T is a tree we can omit the visited array - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - if (w != parent) { - node found = dfsFaceNodeOf(w,v,f1,f2); - if (found != 0) - return found; - } - } - - return 0; -} - - -// original variant of st-augmentation -// Inserts also new nodes representing faces into G. -void FaceSinkGraph::stAugmentation( - node h, // node corresponding to external face - Graph &G, // original graph (not const) - SList &augmentedNodes, // list of augmented nodes - SList &augmentedEdges) // list of augmented edges -{ - SListPure roots; - node v; - forall_nodes(v,*this) { - node vOrig = m_originalNode[v]; - if (vOrig != 0 && vOrig->indeg() > 0 && vOrig->outdeg() > 0) - roots.pushBack(v); - } - - node vh = dfsStAugmentation(h,0,G,augmentedNodes,augmentedEdges); - - SListConstIterator it; - for(it = roots.begin(); it.valid(); ++it) - dfsStAugmentation(*it,0,G,augmentedNodes,augmentedEdges); - - augmentedEdges.pushBack(G.newEdge(m_source,vh)); - -} - - -node FaceSinkGraph::dfsStAugmentation( - node v, // current node - node parent, // its parent - Graph &G, // original graph (not const) - SList &augmentedNodes, // list of augmented nodes - SList &augmentedEdges) // list of augmented edges -{ - bool isFace = (m_originalFace[v] != 0); - node vf = 0; - - // since we already know that T is a tree we can omit the visited array - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - if (w == parent) continue; - - if (isFace) { - if (vf == 0) { - vf = G.newNode(); - augmentedNodes.pushBack(vf); - if (parent) { - edge eParent = G.newEdge(vf,m_originalNode[parent]); - augmentedEdges.pushBack(eParent); - } - } - - edge ew = G.newEdge(m_originalNode[w],vf); - augmentedEdges.pushBack(ew); - } - - dfsStAugmentation(w,v,G,augmentedNodes,augmentedEdges); - } - - return vf; -} - - -// improved variant of st-augmentation -// Inserts also one new node representing the super sink into G. -void FaceSinkGraph::stAugmentation( - node h, // node corresponding to external face - Graph &G, // original graph (not const) - node &superSink, // super sink - SList &augmentedEdges) // list of augmented edges -{ - SListPure roots; - node v; - forall_nodes(v,*this) { - node vOrig = m_originalNode[v]; - if (vOrig != 0 && vOrig->indeg() > 0 && vOrig->outdeg() > 0) - roots.pushBack(v); - } - - - superSink = dfsStAugmentation(h,0,G,augmentedEdges); - - SListConstIterator it; - for(it = roots.begin(); it.valid(); ++it) - dfsStAugmentation(*it,0,G,augmentedEdges); - - augmentedEdges.pushBack(G.newEdge(m_source,superSink)); - -} - - -node FaceSinkGraph::dfsStAugmentation( - node v, // current node - node parent, // its parent - Graph &G, // original graph (not const) - SList &augmentedEdges) // list of augmented edges -{ - bool isFace = (m_originalFace[v] != 0); - node vf = (parent != 0) ? m_originalNode[parent] : 0; - - // since we already know that T is a tree we can omit the visited array - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - if (w == parent) continue; - - if (isFace) { - if (vf == 0) { - vf = G.newNode(); - } - - edge ew = G.newEdge(m_originalNode[w],vf); - augmentedEdges.pushBack(ew); - } - - dfsStAugmentation(w,v,G,augmentedEdges); - } - - return vf; -} - - - -void FaceSinkGraph::sinkSwitches(FaceArray< List > &faceSwitches) { - OGDF_ASSERT(m_pE->externalFace() != 0); - - List dummyList; - faceSwitches.init(*m_pE, dummyList); - - NodeArray visited(m_pE->getGraph(), false); - List toDo; - FaceArray faceDone(*m_pE, false); - - //debug - //m_pE->getGraph().writeGML("c:/temp/debug.gml"); - - //compute sink-switches for the ext. face - adjEntry adj; - forall_face_adj(adj, m_pE->externalFace()) { - node u = adj->theNode(); - if (u->outdeg() == 0 && !visited[u]) - faceSwitches[m_pE->externalFace()].pushBack(adj); - - if (u->indeg() > 1 && !visited[u]) { - List outEdges; - m_pE->getGraph().outEdges(u, outEdges); - if (outEdges.empty()) { - adjEntry run; - forall_adj(run, u) { - if (m_pE->rightFace(run) != m_pE->externalFace()) - toDo.pushBack(m_pE->rightFace(run)); - } - - } - else { - edge e = outEdges.front(); - adjEntry run = e->adjSource(); - run = run->cyclicSucc(); - while (run->theEdge() != e) { - adjEntry next = run->cyclicSucc(); - if (next->theEdge()->target() == u && run->theEdge()->target() == u) - toDo.pushBack(m_pE->rightFace(run)); - run = run->cyclicSucc(); - } - } - } - visited[u] = true; - } - - faceDone[m_pE->externalFace()] = true; - - while (!toDo.empty()) { - face f = toDo.popFrontRet(); - if (faceDone[f]) - continue; - - forall_face_adj(adj, f) { - node u = adj->theNode(); - if (visited[u] && adj->theEdge()->target() == adj->faceCyclePred()->theEdge()->target() - && m_pE->rightFace(adj) != m_pE->leftFace(adj)) - faceSwitches[f].pushFront(adj); // the top sink switch of f - - else { - if (u->outdeg() == 0) - faceSwitches[f].pushBack(adj); // the non top sink switch of f - } - - - if (u->indeg() > 1) { - List outEdges; - m_pE->getGraph().outEdges(u, outEdges); - if (outEdges.empty()) { - adjEntry run; - forall_adj(run, u) { - if (m_pE->rightFace(run) != f) - toDo.pushBack(m_pE->rightFace(run)); - } - } - else { - edge e = outEdges.front(); - adjEntry run = e->adjSource(); - run = run->cyclicSucc(); - while (run->theEdge() != e) { - adjEntry next = run->cyclicSucc(); - if (next->theEdge()->target() == u && run->theEdge()->target() == u) - toDo.pushBack(m_pE->rightFace(run)); - run = run->cyclicSucc(); - } - } - } - visited[u] = true; - } - faceDone[f] = true; - - OGDF_ASSERT(!faceSwitches[f].empty()); - } - - - - /* - //-------------------------------------debug - cout << endl; - cout << "switche (FaceSinkGraph::sinkSwitches) : " << endl; - face f; - forall_faces(f, *m_pE) { - cout << "face : " << f->index() << endl; - List adjList = faceSwitches[f]; - forall_listiterators(adjEntry, it, adjList) { - cout << (*it)->theNode() << "; "; - } - cout << endl; - } - // --------------------------------end debug - - */ -} - - - -adjEntry FaceSinkGraph::getAdjEntry(node v, face f) { - adjEntry adj = 0; - forall_adj(adj, v) { - if (m_pE->rightFace(adj) == f) - break; - } - - OGDF_ASSERT(m_pE->rightFace(adj) == f); - - return adj; - } - -} // end namespace ogdf - diff --git a/ext/OGDF/src/upward/FeasibleUpwardPlanarSubgraph.cpp b/ext/OGDF/src/upward/FeasibleUpwardPlanarSubgraph.cpp deleted file mode 100644 index 8c2d885db..000000000 --- a/ext/OGDF/src/upward/FeasibleUpwardPlanarSubgraph.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class UpwardPlanarSubgraphSimple which computes - * an upward planar subgraph of a single-source acyclic digraph - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - -namespace ogdf { - - -Module::ReturnType FeasibleUpwardPlanarSubgraph::call( - Graph &G, - GraphCopy &FUPS, - adjEntry &extFaceHandle, - List &delEdges, - bool multisources, - int runs) -{ - -#ifdef OGDF_DEBUG - UpwardPlanarModule upMod; - OGDF_ASSERT(!upMod.upwardPlanarityTest(G)); -#endif - - delEdges.clear(); - - //current fups, its embedding and the removed edges - GraphCopy FUPS_cur; - List delEdges_cur; - - call(G, FUPS, extFaceHandle, delEdges, multisources); - - for (int i = 1; i < runs; ++i) { - adjEntry extFaceHandle_cur; - call(G, FUPS_cur, extFaceHandle_cur, delEdges_cur, multisources); - - // use new result?? - if (delEdges_cur.size() < delEdges.size()) { - FUPS = FUPS_cur; - extFaceHandle = FUPS.copy(FUPS_cur.original(extFaceHandle_cur->theEdge()))->adjSource(); - delEdges = delEdges_cur; - } - } - return Module::retFeasible; -} - - -Module::ReturnType FeasibleUpwardPlanarSubgraph::call( - const Graph &G, - GraphCopy &FUPS, - adjEntry &extFaceHandle, - List &delEdges, - bool multisources) -{ - FUPS = GraphCopy(G); - delEdges.clear(); - node s_orig; - hasSingleSource(G, s_orig); - List nonTreeEdges_orig; - getSpanTree(FUPS, nonTreeEdges_orig, true, multisources); - CombinatorialEmbedding Gamma(FUPS); - nonTreeEdges_orig.permute(); // random order - - //insert nonTreeEdges - UpwardPlanarModule upMod; - while (!nonTreeEdges_orig.empty()) { - // make identical copy GC of Fups - //and insert e_orig in GC - GraphCopy GC = FUPS; - edge e_orig = nonTreeEdges_orig.popFrontRet(); - //node a = GC.copy(e_orig->source()); - //node b = GC.copy(e_orig->target()); - GC.newEdge(e_orig); - - if (upMod.upwardPlanarEmbed(GC)) { //upward embedded the fups and check feasibility - CombinatorialEmbedding Beta(GC); - - //choose a arbitrary feasibel ext. face - FaceSinkGraph fsg(Beta, GC.copy(s_orig)); - SList ext_faces; - fsg.possibleExternalFaces(ext_faces); - OGDF_ASSERT(!ext_faces.empty()); - Beta.setExternalFace(ext_faces.front()); - - GraphCopy M = GC; // use a identical copy of GC to constrcut the merge graph of GC - adjEntry extFaceHandle_cur = getAdjEntry(Beta, GC.copy(s_orig), Beta.externalFace()); - adjEntry adj_orig = GC.original(extFaceHandle_cur->theEdge())->adjSource(); - - if (constructMergeGraph(M, adj_orig, nonTreeEdges_orig)) { - FUPS = GC; - extFaceHandle = FUPS.copy(GC.original(extFaceHandle_cur->theEdge()))->adjSource(); - continue; - } - else { - //Beta is not feasible - delEdges.pushBack(e_orig); - } - } - else { - // not ok, GC is not feasible - delEdges.pushBack(e_orig); - } - } - - return Module::retFeasible; -} - - -void FeasibleUpwardPlanarSubgraph::getSpanTree(GraphCopy &GC, List &delEdges, bool random, bool multisource) -{ - delEdges.clear(); - if (GC.numberOfNodes() == 1) - return; // nothing to do - node s; - hasSingleSource(GC, s); - NodeArray visited(GC, false); - EdgeArray isTreeEdge(GC,false); - List toDo; - - // the original graph is a multisource graph. The sources are connected with the super source s. - // so do not delete the incident edges of s - if (multisource){ - // put all incident edges of the source to treeEdges - adjEntry adj; - forall_adj(adj, s) { - isTreeEdge[adj->theEdge()] = true; - visited[adj->theEdge()->target()]; - toDo.pushBack(adj->theEdge()->target()); - } - } - else - toDo.pushBack(s); - - - //traversing with dfs - forall_listiterators(node, it, toDo) { - node start = *it; - adjEntry adj; - forall_adj(adj, start) { - node v = adj->theEdge()->target(); - if (!visited[v]) - dfs_visit(GC, adj->theEdge(), visited, isTreeEdge, random); - } - } - - // delete all non tree edgesEdges to obtain a span tree - List l; - edge e; - forall_edges(e, GC) { - if (!isTreeEdge[e]) - l.pushBack(e); - } - while (!l.empty()) { - e = l.popFrontRet(); - delEdges.pushBack(GC.original(e)); - GC.delCopy(e); - } -} - - - -void FeasibleUpwardPlanarSubgraph::dfs_visit( - const Graph &G, - edge e, - NodeArray &visited, - EdgeArray &treeEdges, - bool random) -{ - treeEdges[e] = true; - List elist; - G.outEdges(e->target(), elist); - if (!elist.empty()) { - if (random) - elist.permute(); - ListIterator it; - for (it = elist.begin(); it.valid(); ++it) { - edge ee = *it; - if (!visited[ee->target()]) - dfs_visit(G, ee, visited, treeEdges, random); - } - } - visited[e->target()] = true; -} - - -bool FeasibleUpwardPlanarSubgraph::constructMergeGraph( - GraphCopy &M, - adjEntry adj_orig, - const List &orig_edges) -{ - CombinatorialEmbedding Beta(M); - - //set ext. face of Beta - adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource(); - Beta.setExternalFace(Beta.rightFace(ext_adj)); - - FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode())); - SList aug_nodes; - SList aug_edges; - SList fList; - fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest() - node v_ext = fsg.faceNodeOf(Beta.externalFace()); - - OGDF_ASSERT(v_ext != 0); - - fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges); - - //add the deleted edges - forall_listiterators(edge, it, orig_edges) { - node a = M.copy((*it)->source()); - node b = M.copy((*it)->target()); - M.newEdge(a, b); - } - return (isAcyclic(M)); -} - - - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/upward/FixedEmbeddingUpwardEdgeInserter.cpp b/ext/OGDF/src/upward/FixedEmbeddingUpwardEdgeInserter.cpp deleted file mode 100644 index 08a8553b4..000000000 --- a/ext/OGDF/src/upward/FixedEmbeddingUpwardEdgeInserter.cpp +++ /dev/null @@ -1,832 +0,0 @@ -/* - * $Revision: 2565 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of FixedEmbeddingUpwardInserter class. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - - -//debug only -#include - - -namespace ogdf { - -Module::ReturnType FixedEmbeddingUpwardEdgeInserter::doCall( - UpwardPlanRep &UPR, - const List &origEdges, - const EdgeArray *costOrig, - const EdgeArray *forbiddenEdgeOrig) -{ - if (origEdges.empty()) - return Module::retFeasible; - - List toInsert = origEdges; - - if (!UPR.augmented()) - UPR.augment(); - - EdgeArray cost; - if (costOrig != 0) - cost = *costOrig; - else - cost.init(UPR.original(), 1); - - if (forbiddenEdgeOrig != 0) { - edge e; - forall_edges(e, UPR.original()) { - if ((*forbiddenEdgeOrig)[e]) - cost[e] = INT_MAX; - } - } - - /* - debug - */ - //cout << endl << endl << "edge to insert " << toInsert.size() << " : " << endl; - //forall_listiterators(edge, it, toInsert) { - // cout << "edge : " << *it << endl; - //} - //cout << endl << endl << "number of edges to insert: " << toInsert.size() << endl; - - return insertAll(UPR, toInsert, cost); -} - - - -Module::ReturnType FixedEmbeddingUpwardEdgeInserter::insertAll( - UpwardPlanRep &UPR, - List &toInsert, - EdgeArray &costOrig) -{ - if (toInsert.empty()) - return Module::retFeasible; - - List l; - int size_new = toInsert.size(); - int size_old = 0; - while (size_old != size_new) { - size_old = size_new; - while (!toInsert.empty()) { - edge e_orig = toInsert.popFrontRet(); - SList path; - - /* - //debug - cout << endl; - cout << " insertion path for e_orig :" << e_orig << "; e_UPR: (" << UPR.copy(e_orig->source()) << "," - << UPR.copy(e_orig->target()) << ")" << endl; - */ - - minFIP(UPR, toInsert, costOrig, e_orig, path); - - - /* - //--------------------------------------debug - forall_slistiterators(adjEntry, it, path) { - cout << (*it)->theEdge() << "; node: " << (*it)->theNode() << endl; - } - //--------------------------------------end debug - */ - - List lEdges = toInsert, lTmp = l; - lEdges.conc(lTmp); - bool ok = isConstraintFeasible(UPR, lEdges, e_orig, path); - if (ok) { - UPR.insertEdgePathEmbedded(e_orig, path, costOrig); - - OGDF_ASSERT(isUpwardPlanar(UPR)); - OGDF_ASSERT(isSimple(UPR)); - OGDF_ASSERT(isConnected(UPR)); - OGDF_ASSERT(hasSingleSource(UPR)); - - } - else - l.pushBack(e_orig); - - /* - if (false) { - //---------------------------------------------------debug - //UPR.outputFaces(UPR.getEmbedding()); - //UPR.writeGML("c:/temp/bug5.gml"); - - LayerBasedUPRLayout uprLayout; - Graph GTmp( (const Graph &) UPR); - CombinatorialEmbedding embTmp(GTmp); - node tTmp = 0; - //GTmp.writeGML("c:/temp/bug4.gml"); - hasSingleSink(GTmp, tTmp); - OGDF_ASSERT(tTmp != 0); - embTmp.setExternalFace(embTmp.rightFace(tTmp->firstAdj())); - //adjEntry adjTmp = GCTmp.copy(UPR.extFaceHandle->theEdge())->adjTarget(); - UpwardPlanRep upr_bug(embTmp); - adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); - node s_upr_bug = upr_bug.newNode(); - upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); - upr_bug.m_isSourceArc.init(upr_bug, false); - upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; - upr_bug.s_hat = s_upr_bug; - upr_bug.augment(); - - GraphAttributes GA_UPR_tmp(GTmp, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - GA_UPR_tmp.setAllHeight(30.0); - GA_UPR_tmp.setAllWidth(30.0); - - uprLayout.call(upr_bug, GA_UPR_tmp); - - // label the nodes with their index - node z; - forall_nodes(z, GA_UPR_tmp.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - GA_UPR_tmp.labelNode(z) = str; - GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); - GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); - } - edge eee; - forall_edges(eee, GA_UPR_tmp.constGraph()) { - DPolyline &line = GA_UPR_tmp.bends(eee); - ListIterator it; - for(it = line.begin(); it.valid(); it++) { - (*it).m_y = -(*it).m_y; - (*it).m_x = -(*it).m_x; - } - } - GA_UPR_tmp.writeGML("c:/temp/UPR_int.gml"); - //cout << "face of UPR_int :" << endl; - //upr_bug.outputFaces(upr_bug.getEmbedding()); - //end -----------------------------------------------debug - } - */ - - } - size_new = l.size(); - toInsert = l; - l.clear(); - } - - /* - * some edges cannot be inserted, so use heuristic insertion methods - */ - if (!toInsert.empty()) { - - //cout << endl << "\a\a\a\a\aheuristical call!! " << endl; - - edge e_orig = toInsert.popFrontRet(); - - /* - cout << endl; - cout << "heuristical insertion path for e_orig :" << e_orig << "; e_UPR: (" << UPR.copy(e_orig->source()) << "," - << UPR.copy(e_orig->target()) << ")" << endl; - */ - - - /* - if (false) { - //---------------------------------------------------debug - //UPR.outputFaces(UPR.getEmbedding()); - //UPR.writeGML("c:/temp/bug5.gml"); - - LayerBasedUPRLayout uprLayout; - Graph GTmp( (const Graph &) UPR); - CombinatorialEmbedding embTmp(GTmp); - node tTmp = 0; - //GTmp.writeGML("c:/temp/bug4.gml"); - hasSingleSink(GTmp, tTmp); - OGDF_ASSERT(tTmp != 0); - embTmp.setExternalFace(embTmp.rightFace(tTmp->firstAdj())); - //adjEntry adjTmp = GCTmp.copy(UPR.extFaceHandle->theEdge())->adjTarget(); - UpwardPlanRep upr_bug(embTmp); - adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); - node s_upr_bug = upr_bug.newNode(); - upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); - upr_bug.m_isSourceArc.init(upr_bug, false); - upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; - upr_bug.s_hat = s_upr_bug; - upr_bug.augment(); - - GraphAttributes GA_UPR_tmp(GTmp, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - GA_UPR_tmp.setAllHeight(30.0); - GA_UPR_tmp.setAllWidth(30.0); - - uprLayout.call(upr_bug, GA_UPR_tmp); - - // label the nodes with their index - node z; - forall_nodes(z, GA_UPR_tmp.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - GA_UPR_tmp.labelNode(z) = str; - GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); - GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); - } - edge eee; - forall_edges(eee, GA_UPR_tmp.constGraph()) { - DPolyline &line = GA_UPR_tmp.bends(eee); - ListIterator it; - for(it = line.begin(); it.valid(); it++) { - (*it).m_y = -(*it).m_y; - (*it).m_x = -(*it).m_x; - } - } - GA_UPR_tmp.writeGML("c:/temp/UPR_int.gml"); - //cout << "face of UPR_int :" << endl; - //upr_bug.outputFaces(upr_bug.getEmbedding()); - //end -----------------------------------------------debug - } - */ - - SList path; - constraintFIP(UPR, toInsert, costOrig, e_orig, path); - - /* - //--------------------------------------debug - - forall_slistiterators(adjEntry, it, path) { - cout << (*it)->theEdge() << "; node: " << (*it)->theNode() << endl;; - } - //--------------------------------------end debug - */ - - UPR.insertEdgePathEmbedded(e_orig, path, costOrig); - - OGDF_ASSERT(isUpwardPlanar(UPR)); - - return insertAll(UPR, toInsert, costOrig); - } - return Module::retFeasible; -} - - - -void FixedEmbeddingUpwardEdgeInserter::staticLock( - UpwardPlanRep &UPR, - EdgeArray &locked, - const List &origEdges, - edge e_orig) -{ - // construct merge graph M - GraphCopy M((const Graph &) UPR); - - // add deleted edges to M - forall_listiterators(edge, it, origEdges) { - edge e = *it; - node u = M.copy(UPR.copy(e->source())); - node v = M.copy(UPR.copy(e->target())); - M.newEdge(u,v); - } - - EdgeArray markedEdges(M, false); - markUp(M, M.copy(UPR.copy(e_orig->target())), markedEdges); - markDown(M, M.copy(UPR.copy(e_orig->source())), markedEdges); - - edge e; - forall_edges(e, M) { - if (markedEdges[e] && M.original(e) != 0) { - locked[M.original(e)] = true; - } - } -} - - - -void FixedEmbeddingUpwardEdgeInserter::getPath( - UpwardPlanRep &UPR, - List &origEdges, - EdgeArray &cost, - edge e_orig, - SList &path, - bool heuristic) -{ - path.clear(); - node x_1 = UPR.copy(e_orig->source()); - node y_1 = UPR.copy(e_orig->target()); - const CombinatorialEmbedding &Gamma = UPR.getEmbedding(); - - EdgeArray locked(UPR, false); - staticLock(UPR, locked, origEdges, e_orig); - - //locked the adjacent edges of x_1 and y_1 - adjEntry adjTmp; - forall_adj(adjTmp, x_1) - locked[adjTmp->theEdge()] = true; - forall_adj(adjTmp, y_1) - locked[adjTmp->theEdge()] = true; - - EdgeArray predAdj(UPR, 0); // for path reconstruction - EdgeArray dist(UPR, INT_MAX); // current distance to an edge - EdgeArray toAdjEntry(UPR, 0); - - - /* - * compute the adjEntry of the adjacent edges of x_1 - * this is necessary for the initiliazation of priorQ - */ - List outEdges; - List adjOut; - UPR.outEdges(x_1, outEdges); - forall_listiterators(edge, it, outEdges) { - adjEntry adj = (*it)->adjSource(); - adjOut.pushBack(adj); - if (adj->cyclicPred()->theEdge()->target() == x_1) - adjOut.pushBack(adj->cyclicPred()); // right face of the left in edge of x_1 - } - - List initEdges; - forall_listiterators(adjEntry, it, adjOut) { - feasibleEdges(UPR, Gamma.rightFace(*it), *it, locked, initEdges, heuristic); - forall_listiterators(adjEntry, iu, initEdges) { - edge ee = (*iu)->theEdge(); - if (!locked[ee]) { - if (UPR.isSinkArc(ee) || UPR.isSourceArc(ee)) - dist[ee] = 0; - else - dist[ee] = 1; - predAdj[ee] = *it; - // mappe ee to the "correct" adjEntry - toAdjEntry[ee] = *iu; - } - - //check if ee contains the target source y_1 - if ((*iu)->twin()->theNode() == y_1) { - adjEntry adjTgt = UPR.getAdjEntry(UPR.getEmbedding(), y_1, UPR.getEmbedding().rightFace(*it)); - - //for the case if there are two adjEntry of y_1 which right face is the external face - if (Gamma.rightFace(*it) == Gamma.externalFace()) { - //we have to compute the correct adjEntry - adjEntry tgtLeft = 0, tgtRight = 0, runAdj; - forall_adj(runAdj, y_1) { - if (Gamma.rightFace(runAdj) == Gamma.externalFace()) { - if (runAdj->theEdge()->target() == y_1) - tgtLeft = runAdj; - else - tgtRight = runAdj; - } - } - if ((*it)->theNode() == (*it)->theEdge()->source()) - adjTgt = tgtRight; // *it->theEdge() is on the right face side - else - adjTgt = tgtLeft; // *it->theEdge() is on the left face side - } - - if (Gamma.rightFace(*it) != Gamma.rightFace(adjTgt)) - adjTgt = adjTgt->cyclicPred(); - path.pushFront((*it)); - path.pushBack(adjTgt); - - OGDF_ASSERT(Gamma.rightFace(*it) == Gamma.rightFace(adjTgt)); - - break; - } - } - if (path.size() == 2) // edge can be inserted without crossing - break; //leave forall_listiterators(adjEntry, it, adjOut) loop - - initEdges.clear(); - } - - // if path.size == 2 then we can insert e_orig without crossing (the path is not necessary constrain feasible) - if (path.size() != 2) { - // init the priority queque - BinaryHeap priorQ(UPR.numberOfEdges()); - EdgeArray< const BinaryHeap::Element * > elemArray(UPR, 0); // reference to the elements of priorQ - edge e; - forall_edges(e, UPR) { - if (!locked[e]) { - int priority = dist[e]; - elemArray[e] = &(priorQ.insert(e, priority)); - } - } - adjEntry adjLast = 0; - while (!priorQ.empty()) { - - adjEntry adj_cur = toAdjEntry[priorQ.pop()]; - - OGDF_ASSERT(adj_cur != 0); - - face f = Gamma.rightFace(adj_cur); //current face f - List nextAdjs; - feasibleEdges(UPR, f, adj_cur, locked, nextAdjs, heuristic); - - bool reached = false; - forall_listiterators(adjEntry, it, nextAdjs) { - adjEntry adjNext = *it; - - if (adjNext->theNode() == y_1) { // y_1 reached ? - - adjLast = UPR.getAdjEntry(UPR.getEmbedding(), y_1, f); - reached = true; - - if (Gamma.rightFace(adj_cur) == Gamma.externalFace()) { - //we have to compute the correct adjEntry - adjEntry tgtLeft = 0, tgtRight = 0, runAdj; - forall_adj(runAdj, y_1) { - if (Gamma.rightFace(runAdj) == Gamma.externalFace()) { - if (runAdj->theEdge()->target() == y_1) - tgtLeft = runAdj; - else - tgtRight = runAdj; - } - } - if (adj_cur->theNode() == adj_cur->theEdge()->source()) - adjLast = tgtRight; // adj_cur->theEdge() is on the right face side - else - adjLast = tgtLeft; // adj_cur->theEdge() is on the left face side - } - - OGDF_ASSERT(adjLast != 0) - - predAdj[adjLast->theEdge()] = adj_cur; - break; // leave forall-loop - } - - bool ok = !locked[adjNext->theEdge()]; - - //use heuristic to check curent path - if (ok && heuristic) - ok = isConstraintFeasible(UPR, origEdges, e_orig, adj_cur, adjNext, predAdj); - - //relax if ok - if (ok) { - int c = 0; - if (UPR.original(adjNext->theEdge()) != 0) - c = cost[UPR.original(adjNext->theEdge())]; - - int new_dist = dist[adj_cur->theEdge()] + c; - if (dist[adjNext->theEdge()] > new_dist) { - const BinaryHeap::Element &el = *(elemArray[adjNext->theEdge()]); - priorQ.decPriority(el, new_dist); - predAdj[adjNext->theEdge()] = adj_cur; - dist[adjNext->theEdge()] = new_dist; - toAdjEntry[adjNext->theEdge()] = adjNext; - } - } - } //forall - - if (reached) - break; // leave while-loop if y_1 is found - - }//while - - //construct the path - path.pushBack(adjLast); - adjEntry run = predAdj[adjLast]; - while (run != 0) { - path.pushFront(run); - run = predAdj[run]; - } - } - - OGDF_ASSERT(path.size() >= 2); -} - - - -bool FixedEmbeddingUpwardEdgeInserter::isConstraintFeasible( - UpwardPlanRep &UPR, - const List &orig_edges, - edge e_orig, - adjEntry adjCurrent, - adjEntry adjNext, - EdgeArray &predAdj) -{ - //contruct path to adj->theEdge() - SList path; - path.pushBack(adjNext); - path.pushFront(adjCurrent); - adjEntry run = predAdj[adjCurrent]; - while (run != 0) { - path.pushFront(run); - run = predAdj[run->theEdge()]; - } - - /* - //debug - cout << endl << endl << "current insertion path: " << endl; - forall_slistiterators(adjEntry, it, path) { - cout << (*it)->theEdge() << "; node: " << (*it)->theNode() << endl; - } - */ - - GraphCopy M( (const Graph &) UPR); // merge graph - - //convert adjEntry of path to adjEntry of M - SList path_M; - forall_slistiterators(adjEntry, it, path) { - adjEntry a = *it; - edge e_M = M.copy(a->theEdge()); - node v = M.copy(a->theNode()); - if (e_M->source() == v) - path_M.pushBack(e_M->adjSource()); - else - path_M.pushBack(e_M->adjTarget()); - } - - // construct a partial path from src to adjNext - path_M.popFrontRet(); - node src = M.copy(UPR.copy(e_orig->source())); - node tgt = M.copy(UPR.copy(e_orig->target())); - while (!path_M.empty()) { - edge eM = path_M.popFrontRet()->theEdge(); - node d = M.split(eM)->source(); - M.newEdge(src, d); - src = d; - } - - M.newEdge(src, tgt); - //add the deleted edges - forall_listiterators(edge, it, orig_edges) { - node a = M.copy(UPR.copy((*it)->source())); - node b = M.copy(UPR.copy((*it)->target())); - M.newEdge(a, b); - } - - return isAcyclic(M); -} - - -bool FixedEmbeddingUpwardEdgeInserter::isConstraintFeasible( - UpwardPlanRep &UPR, - List &origEdges, - edge e_orig, - SList &path) -{ - GraphCopy GC( (const Graph &) UPR); - GraphCopy M((const Graph &)GC); // merge graph - - //convert adjEntry of path to adjEntry of M - SList path_M; - forall_slistiterators(adjEntry, it, path) { - adjEntry a = *it; - edge e_M = M.copy( GC.copy(a->theEdge()) ); - node v = M.copy(GC.copy(a->theNode())); - if (e_M->source() == v) - path_M.pushBack(e_M->adjSource()); - else - path_M.pushBack(e_M->adjTarget()); - } - - //debug - /* - cout << " insertion path for " << e_orig << endl; - forall_slistiterators(adjEntry, it, path_M) { - cout << (*it)->theEdge() << "; node: " << (*it)->theNode() << endl; - } - */ - - edge e = GC.newEdge(GC.copy(UPR.copy(e_orig->source())), GC.copy(UPR.copy(e_orig->target()))); - - CombinatorialEmbedding Gamma(M); - M.insertEdgePathEmbedded(e, Gamma, path_M); - - OGDF_ASSERT(isAcyclic(M)); - - //add the deleted edges - forall_listiterators(edge, it, origEdges) { - node a = M.copy(GC.copy(UPR.copy((*it)->source()))); - node b = M.copy(GC.copy(UPR.copy((*it)->target()))); - M.newEdge(a, b); - } - - return isAcyclic(M); -} - - -void FixedEmbeddingUpwardEdgeInserter::feasibleEdges( - UpwardPlanRep &UPR, - face f, - adjEntry adj, - EdgeArray &locked, - List &feasible, - bool heuristic) -{ - const CombinatorialEmbedding &Gamma = UPR.getEmbedding(); - - OGDF_ASSERT(Gamma.rightFace(adj) == f); - - adjEntry start = adj, run = adj; - if (f == Gamma.externalFace()) { - bool stop = false; - - if (adj->theNode() == adj->theEdge()->source()) { - /* - *adj->theEdge() is on the right path of f, so walk ccw - *all edges between adj->theEdge() and the super sink t_hat on the right path are feasible. - */ - do { - if (run->theEdge()->target() == UPR.getSuperSink()) - stop = true; - if (run != start) - feasible.pushBack(run->twin()); - run = run->faceCycleSucc(); - } while (!stop); - - //dynamic lock; all edges between super source and adj->theEdge() of the corredponding right path muss be locked - if (!heuristic) { - run = start; - stop = false; - do { - if (run->theEdge()->source() == UPR.getSuperSource()) - stop = true; - locked[run->theEdge()] = true; - run = run->faceCyclePred(); - } while (!stop); - } - } - - else { - /* - *currentEdge is on the left path of f, so walk cw - *All edges between adj->theEdge() and the super sink t_hat on the left path are feasible. - */ - do { - if (run->theEdge()->target()== UPR.getSuperSink()) - stop = true; - if (run != start) - feasible.pushBack(run->twin()); - run = run->faceCyclePred(); - } while (!stop); - - //dynamic lock; all edges between super source and adj->theEdge() of the corredponding left path muss be locked - if (!heuristic) { - run = start; - stop = false; - do { - if (run->theEdge()->source() == UPR.getSuperSource()) - stop = true; - locked[run->theEdge()] = true; - run = run->faceCycleSucc(); - } while (!stop); - } - } - } - - // internal face - else { - bool stop = false; - - if (adj->theNode() == adj->theEdge()->source()) { - /* - *adj->theEdge() is on the left path of f; walk cw to the source-witch of f. - *All edges traversing by this walk are feasible. - */ - do { - if (run->theEdge()->source() == run->faceCycleSucc()->theEdge()->source()) //reach source-switch of f - stop = true; - if (run != start) - feasible.pushBack(run->twin()); - run = run->faceCycleSucc(); - } while (!stop); - - //dynamic lock; all edges between source-switch and adj->theEdge() of the corredponding left path muss be locked - if (!heuristic) { - run = start; - stop = false; - do { - locked[run->theEdge()] = true; - if (run->theEdge()->source() == run->faceCyclePred()->theEdge()->source()) //reach source-switch of f - stop = true; - run = run->faceCyclePred(); - } while (!stop); - } - } - - else { - /* - *adj->theEdge() is on the right path of f; walk ccw to the source-witch of f. - *All edges traversing by this walk are feasible. - */ - do { - if (run->theEdge()->source() == run->faceCyclePred()->theEdge()->source()) //reach source-switch of f - stop = true; - if (run != start) - feasible.pushBack(run->twin()); - run = run->faceCyclePred(); - } while (!stop); - - //dynamic lock; all edges between source-switch and adj->theEdge() of the corredponding right path muss be locked - if (!heuristic) { - run = start; - stop = false; - do { - locked[run->theEdge()] = true; - if (run->theEdge()->source() == run->faceCycleSucc()->theEdge()->source()) //reach source-switch of f - stop = true; - run = run->faceCycleSucc(); - } while (!stop); - } - } - } -} - - -void FixedEmbeddingUpwardEdgeInserter::markUp( - const Graph &G, - node v, - //NodeArray &markedNodes, - EdgeArray &markedEdges ) -{ - // traversing G from v - Queue nodesToDo; - nodesToDo.append(v); - NodeArray inQueue(G, false); - while(!nodesToDo.empty()) { - node w = nodesToDo.pop(); - List outEdges; - G.outEdges(w, outEdges); - ListIterator it; - for (it = outEdges.begin(); it.valid(); ++it) { - edge e = *it; - if (!inQueue[e->target()]) { // put the next node in queue if it is not already in queue - nodesToDo.append( e->target() ); - inQueue[e->target()] = true; - } - markedEdges[e] = true; // mark edge - } - } -} - - -void FixedEmbeddingUpwardEdgeInserter::markDown( - const Graph &G, - node v, - //NodeArray &markedNodes, - EdgeArray &markedEdges) -{ - // mark the subgraph, i.e all nodes and edges, which dominate node v - Queue nodesToDo; - nodesToDo.append(v); - NodeArray inQueue(G, false); - while(!nodesToDo.empty()) { - node w = nodesToDo.pop(); - List inEdges; - G.inEdges(w, inEdges); - ListIterator it; - for (it = inEdges.begin(); it.valid(); ++it) { - edge e = *it; - if (!inQueue[e->source()]) { - nodesToDo.append(e->source() ); // put the next node in queue if it is not already in queue - inQueue[e->source()] = true; - } - markedEdges[e] = true; // mark the edge - } - } -} - - - -} // namespace - diff --git a/ext/OGDF/src/upward/LayerBasedUPRLayout.cpp b/ext/OGDF/src/upward/LayerBasedUPRLayout.cpp deleted file mode 100644 index 486d9ed30..000000000 --- a/ext/OGDF/src/upward/LayerBasedUPRLayout.cpp +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of OrderComparer and LayerBasedUPRLayout classes. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include - - -namespace ogdf { - - -OrderComparer::OrderComparer(const UpwardPlanRep &_UPR, Hierarchy &_H) : UPR(_UPR), H(_H) -{ - dfsNum.init(UPR, -1); - crossed.init(UPR, false); - - //compute dfs number - node start; - hasSingleSource(UPR, start); - NodeArray visited(UPR, false); - adjEntry rightAdj = UPR.getAdjEntry(UPR.getEmbedding(), start, UPR.getEmbedding().externalFace()); - int num = 0; - dfsNum[start] = num++; - adjEntry run = rightAdj; - do { - run = run->cyclicSucc(); - if (!visited[run->theEdge()->target()]) - dfs_LR(run->theEdge(), visited, dfsNum, num); - } while(run != rightAdj); - -} - - - -bool OrderComparer::left(edge e1UPR, edge e2UPR) const -{ - OGDF_ASSERT(e1UPR->source() == e2UPR->source() || e1UPR->target() == e2UPR->target()); - OGDF_ASSERT(e1UPR != e2UPR); - - node v = e1UPR->source(); - if (e2UPR->source() != v) - v = e1UPR->target(); - - adjEntry inLeft = 0, outLeft = 0; - //compute left in and left out edge of the common node v if exist - if (v->indeg() != 0) { - adjEntry run; - forall_adj(run, v) { - if (run->cyclicSucc()->theEdge()->source() == v) - break; - } - inLeft = run; - } - if (v->outdeg() != 0) { - adjEntry run; - forall_adj(run, v) { - if (run->cyclicPred()->theEdge()->target() == v) - break; - if (UPR.getEmbedding().leftFace(run) == UPR.getEmbedding().externalFace()) - break; - } - outLeft = run; - } - - //same source; - if (v == e2UPR->source()) { - do { - if (outLeft->theEdge() == e1UPR) - return false; - if (outLeft->theEdge() == e2UPR) - return true; - outLeft = outLeft->cyclicSucc(); - } while (true); - } - //same target - else { - do { - if (inLeft->theEdge() == e1UPR) - return false; - if (inLeft->theEdge() == e2UPR) - return true; - inLeft = inLeft->cyclicPred(); - } while (true); - } -} - - - -bool OrderComparer::left(node v1UPR, List chain1, node v2UPR , List chain2) const -{ - //mark the edges an nodes of chain2 list - NodeArray visitedNode(UPR, false); - EdgeArray visitedEdge(UPR, false); - forall_listiterators(edge, it, chain2) { - edge e = *it; - visitedNode[e->source()] = visitedNode[e->target()] = true; - visitedEdge[e] = true; - } - - // traverse from vUPR2 to the super source using left path p and marks it. - visitedNode[v2UPR] = true; - adjEntry run = UPR.leftInEdge(v2UPR); - while (run != 0) { - visitedNode[run->theEdge()->source()] = visitedNode[run->theEdge()->target()] = true; - visitedEdge[run->theEdge()] = true; - run = UPR.leftInEdge(run->theEdge()->source()); - } - - //is one of the node of chain1 marked? - ListIterator it; - for(it = chain1.rbegin(); it.valid(); --it) { - node u = (*it)->source(); - if (visitedNode[u]) { - adjEntry run; - forall_adj(run, u) { - if (visitedEdge[run->theEdge()] && run->theEdge()->source() == run->theNode()) // outgoing edges only - return left(*it, run->theEdge()); //(outEdgeOrder[*it] > outEdgeOrder[run->theEdge()]); - } - } - } - - // traverse from vUPR1 to a node of path p (using left path). - adjEntry adj_v1 = 0, adj_v2 = 0; - run = UPR.leftInEdge(v1UPR); - while (run != 0) { - if (visitedNode[run->theEdge()->source()]) { - adj_v1 = run->twin(); //reached a marked node - break; - } - run = UPR.leftInEdge(run->theEdge()->source()); - } - - OGDF_ASSERT(adj_v1 != 0); - - forall_adj(run, adj_v1->theNode()) { - if (visitedEdge[run->theEdge()] && run->theEdge()->source() == run->theNode()){ // outgoing edges only - adj_v2 = run; - break; - } - } - - OGDF_ASSERT(adj_v2 != 0); - - return left(adj_v1->theEdge(), adj_v2->theEdge()); -} - - - -bool OrderComparer::checkUp(node vUPR, int level) const -{ - const GraphCopy &GC = H; - - //traverse from vUPR (going up) - NodeArray inList(UPR, false); - List l; - l.pushBack(vUPR); - inList[vUPR] = true; - while (!l.empty()) { - node v = l.popFrontRet(); - node vOrig = UPR.original(v); - if (vOrig != 0 && H.rank(GC.copy(vOrig)) <= level) - return true; - List outEdges; - UPR.outEdges(v, outEdges); - forall_listiterators(edge, it, outEdges) { - node tgt = (*it)->target(); - if (!inList[tgt]) { - l.pushBack(tgt); - inList[tgt] = true; - } - } - } - return false; -} - - - -bool OrderComparer::left(List &chain1, List &chain2, int level) const -{ - //mark the source nodes of the edges of chain1 - NodeArray markedNodes(UPR, false); - EdgeArray markedEdges(UPR, false); - forall_listiterators(edge, iter, chain1) { - node v = (*iter)->source(); - markedNodes[v] = true; - markedEdges[*iter] = true; - } - - //compute the list of common nodes of chain1 and chain2 - List< Tuple2 > commonNodeList; // first: common node; second: true if vH1 (associated with chain1) is on the left hand side - forall_listiterators(edge, iter, chain2) { - node v = (*iter)->source(); - if (markedNodes[v]) { - edge e = *iter; - bool value = true; - adjEntry adj = e->adjSource(); - while (true) { - adj = adj->cyclicSucc(); - if (adj->theEdge()->target() == v) { - value = false; - break; - } - if (markedEdges[adj->theEdge()]) { - break; - } - - } - Tuple2 tulp(v, value); - commonNodeList.pushFront(tulp); - } - } - - //no crossings between the associated edges - if (commonNodeList.empty()) { - if (chain1.front()->source() == chain2.front()->source()) { - return left(chain1.front(), chain2.front()); - } - else - return left(chain1.front()->source(), chain1, chain2.front()->source(), chain2); - } - - // there is a least one crossing - ListIterator< Tuple2 > it = commonNodeList.begin(); - while(it.valid()) { - Tuple2 tulp = *it; - // is there a node above which level is lower or equal the given level? - // if so, then return the value - if (checkUp(tulp.x1(), level)) { - // there is a node above, which is lower or equal the given level - return tulp.x2(); - } - it = it.succ(); - } - - // the both edges are on the "first segment" of the crossing - Tuple2 tulp = *(commonNodeList.rbegin()); - return !tulp.x2(); -} - - - -bool OrderComparer::less(node vH1, node vH2) const -{ - if (vH1 == vH2) - return false; - - /* - case:vH1 and vH2 are not long-edge dummies. - */ - const GraphCopy &GC = H; - if (!H.isLongEdgeDummy(vH1) && !H.isLongEdgeDummy(vH2)) { - node v1 = UPR.copy(GC.original(vH1)); - node v2 = UPR.copy(GC.original(vH2)); - if (dfsNum[v1] > dfsNum[v2]) - return true; - else - return false; - } - - /* - vH1 and vH2 are long-edge-dummies - */ - if (H.isLongEdgeDummy(vH1) && H.isLongEdgeDummy(vH2)) { - List chain1 = UPR.chain(GC.original(vH1->firstAdj()->theEdge())); - List chain2 = UPR.chain(GC.original(vH2->firstAdj()->theEdge())); - - OGDF_ASSERT(!chain1.empty() && !chain2.empty()); - - int level = H.rank(vH1); - return (left(chain1, chain2, level)); - }//end both are long edge dummies - - /* - only vH1 or vH2 is a long-edge dummy - */ - node v; - List chain1, chain2; - if (H.isLongEdgeDummy(vH1)) { - chain1 = UPR.chain(GC.original(vH1->firstAdj()->theEdge())); - v = UPR.copy(GC.original(vH2)); - - OGDF_ASSERT(!chain1.empty()); - - return left(chain1.front()->source(), chain1, v, chain2); - } - else { - chain2 = UPR.chain(GC.original(vH2->firstAdj()->theEdge())); - v = UPR.copy(GC.original(vH1)); - - OGDF_ASSERT(!chain2.empty()); - - return left(v, chain1, chain2.front()->source(), chain2); - } -} - - - -void OrderComparer::dfs_LR( - edge e, - NodeArray &visited, - NodeArray &dfsNum, - int &num) -{ - node v = e->target(); - //outEdgeOrder[e] = num++; - dfsNum[v] = num++; - if (e->target()->outdeg() > 0) { - // compute left out edge - adjEntry run; - forall_adj(run, v) { - adjEntry adj_pred = run->cyclicPred(); - if (adj_pred->theEdge()->target() == v && run->theEdge()->source() == v) - break; // run is the left out-edge - } - - do { - if (!visited[run->theEdge()->target()]) { - dfs_LR(run->theEdge(), visited, dfsNum, num); - } - run = run->cyclicSucc(); - } while(run->theEdge()->target() != e->target()); - } - visited[v] = true; -} - - - -void LayerBasedUPRLayout::doCall(const UpwardPlanRep &UPR, GraphAttributes &AG) -{ - OGDF_ASSERT(UPR.augmented()); - - numberOfLevels = 0; - m_numLevels = 0; - m_crossings = 0; - - const Graph &G = UPR.original(); - NodeArray rank_G(G); - computeRanking(UPR, rank_G); - Hierarchy H(G, rank_G); - const GraphCopy &GC = H; - - /* - //debug - //UPR.outputFaces(UPR.getEmbedding()); - node x; - forall_nodes(x, G) { - cout << "vOrig " << x << "; vUPR " << UPR.copy(x) << endl; - } - forall_nodes(x, UPR) { - cout << "UPR edge order:" << endl; - adjEntry adj = x->firstAdj(); - cout << "node " << x << endl; - do { - cout << " edge : " << adj->theEdge() << endl; - adj = adj->cyclicSucc(); - } while (adj != x->firstAdj()); - } - */ - - //adjust order - OrderComparer oComparer(UPR, H); - for(int i = 0; i < H.size(); ++i) { - Level &l = H[i]; - l.sortOrder(oComparer); - } - - - // ********************** postprocessing ******************************************* - node vTmp; - List sources; - forall_nodes(vTmp, GC) { - if (vTmp->indeg() == 0) - sources.pushBack(vTmp); - } - - RankComparer comp; - comp.H = &H; - sources.quicksort(comp); - sources.reverse(); - - - - postProcessing_reduceLED(H, sources); - H.buildAdjNodes(); - - /* - //debug - cout << endl << endl; - for(int i = 0; i <= H.high(); i++) { - Level &lvl = H[i]; - cout << "level : " << lvl.index() << endl; - cout << "nodes : "; - for(int j = 0; j <= lvl.high(); j++) { - cout << lvl[j] << " "; - } - cout << endl; - } - */ - - postProcessing_sourceReorder(H, sources); - m_crossings = H.calculateCrossings(); - - OGDF_ASSERT(m_crossings <= UPR.numberOfCrossings()); - OGDF_ASSERT(m_layout.valid()); - - GraphCopyAttributes AGC(H, AG); - m_layout.get().call(H,AG); - // ********************** end postprocessing ******************************************* - - numberOfLevels = H.size(); - m_maxLevelSize = 0; - for(int i = 0; i <= H.high(); i++) { - Level &l = H[i]; - if (m_maxLevelSize < l.size()) - m_maxLevelSize = l.size(); - } -} - - -void LayerBasedUPRLayout::computeRanking(const UpwardPlanRep &UPR, NodeArray &rank) -{ - OGDF_ASSERT(UPR.augmented()); - - GraphCopy GC = UPR.original(); - edge e; - forall_edges(e, UPR.original()) { - if (UPR.isReversed(e)) { - GC.reverseEdge(GC.copy(e)); - } - } - - // compute auxiliary edges - EdgeArray cost(GC,1); - List< Tuple2 > auxEdges; - NodeArray inL(UPR, -1); - int num = -1; - node v; - forall_nodes(v, UPR) { - - if (UPR.isDummy(v) || v->indeg()==0) - continue; - - num = num +1; - //compute all "adjacent" non dummy nodes - List toDo, srcNodes; - toDo.pushBack(v); - inL[v] = num; - while (!toDo.empty()) { - node u = toDo.popFrontRet(); - List inEdges; - UPR.inEdges(u, inEdges); - forall_listiterators(edge, it, inEdges) { - node w = (*it)->source(); - if (UPR.isDummy(w)) { - if (inL[w] != num) { - toDo.pushBack(w); - inL[w] = num; - } - } - else { - - OGDF_ASSERT(UPR.original(w) != 0 && UPR.original(v) != 0); - - node wGC = GC.copy(UPR.original(w)); - node vGC = GC.copy(UPR.original(v)); - edge eNew = GC.newEdge(wGC, vGC); - cost[eNew] = 0; - } - } - } - } - - makeSimple(GC); - - OGDF_ASSERT(isAcyclic(GC)); - - - // ****************************debug******************************* - /* - GraphAttributes GA(GC, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel); - node vTmp; - // label the nodes with their index - forall_nodes(vTmp, GC) { - char str[255]; - node w = GC.original(vTmp); - sprintf_s(str, 255, "%d", w->index()); // convert to string - GA.labelNode(vTmp) = str; - } - GA.writeGML("c:/temp/ranking_graph.gml"); - */ - //******************************************************************** - - - NodeArray ranking(GC, 0); - EdgeArray length(GC,1); - - m_ranking.get().call(GC, length, cost, ranking); - - // adjust ranking - int minRank = INT_MAX; - forall_nodes(v,GC) { - if(ranking[v] < minRank) - minRank = ranking[v]; - } - - if(minRank != 0) { - forall_nodes(v, GC) - ranking[v] -= minRank; - } - - forall_nodes(v, GC){ - node vOrig = GC.original(v); - rank[vOrig] = ranking[v]; - } - - /* - //debug output ranking - cout << "Ranking GOrig: " << endl; - forall_nodes(v, UPR.original()) - cout << "node :" << v << " ranking : "<< rank[v] << endl; - */ -} - - - -void LayerBasedUPRLayout::postProcessing_sourceReorder(Hierarchy &H, List &sources) -{ - //reorder the sources; - forall_listiterators(node, it, sources) { - node s = *it; - Level &l = H[H.rank(s)]; - - //compute the desire position (heuristic) - int wantedPos = 0; - adjEntry adj; - if (s->outdeg() == 1) { - node tgt = s->firstAdj()->theEdge()->target(); - List nodes; - - forall_adj(adj, tgt) { - if (adj->theEdge()->target() == tgt) - nodes.pushBack(adj->theEdge()->source()); - } - - RankComparer comp; - comp.H = &H; - nodes.quicksort(comp); - - //postion of the median - node v = *nodes.get(nodes.size()/2); - wantedPos = H.pos(v); - } - else { - List nodes; - - forall_adj(adj, s) - nodes.pushBack(adj->theEdge()->source()); - - RankComparer comp; - comp.H = &H; - nodes.quicksort(comp); - - //postion of the median - node v = *nodes.get(nodes.size()/2); - wantedPos = H.pos(v); - } - - //move s to front of the array - int pos = H.pos(s); - while (pos != 0) { - l.swap(pos-1, pos); - pos--; - } - - // compute the position of s, which cause min. crossing - int minPos = pos; - int oldCr = H.calculateCrossings(l.index());; - while(pos != l.size()-1) { - l.swap(pos, pos+1); - int newCr = H.calculateCrossings(l.index()); - if (newCr <= oldCr) { - if (newCr < oldCr) { - minPos = H.pos(s); - oldCr = newCr; - } - else { - if (abs(minPos - wantedPos) > abs(pos+1 - wantedPos)) { - minPos = H.pos(s); - oldCr = newCr; - } - - } - } - pos++; - } - - //move s to minPos - while (pos != minPos) { - if (minPos > pos) { - l.swap(pos, pos+1); - pos++; - } - if (minPos < pos) { - l.swap(pos, pos-1); - pos--; - } - } - } -} - - - -void LayerBasedUPRLayout::postProcessing_markUp(Hierarchy &H, node s, NodeArray &markedNodes) -{ - const GraphCopy &GC = H; - NodeArray inQueue(GC, false); - Queue nodesToDo; - nodesToDo.append(s); - - while(!nodesToDo.empty()) { - node w = nodesToDo.pop(); - markedNodes[w] = true; - List outEdges; - GC.outEdges(w, outEdges); - ListIterator it; - for (it = outEdges.begin(); it.valid(); ++it) { - edge e = *it; - if (!inQueue[e->target()] && !markedNodes[e->target()]) { // put the next node in queue if it is not already in queue - nodesToDo.append( e->target() ); - inQueue[e->target()] = true; - } - } - } -} - - - -void LayerBasedUPRLayout::postProcessing_reduceLED(Hierarchy &H, node s) -{ - const GraphCopy &GC = H; - NodeArray markedNodes(GC, false); - - // mark all nodes dominated by s, we call the graph induced by the marked node G* - // note that not necessary all nodes are marked. - postProcessing_markUp(H, s, markedNodes); - - - for (int i = H.rank(s) + 1; i <= H.high(); i++) { - const Level &lvl = H[i]; - - // Compute the start and end index of the marked graph on this level. - int minIdx = INT_MAX; - int maxIdx = -1; - List sList; - - int numEdges = 0; - int sumInDeg = 0; - int numMarkedNodes = 0; - int numDummies = 0; - for(int j = 0; j <= lvl.high(); j++) { - node u = lvl[j]; - - if (markedNodes[u]) { - numMarkedNodes++; - - if (H.isLongEdgeDummy(u)) - numDummies++; - - if (H.pos(u)< minIdx) - minIdx = H.pos(u); - if (H.pos(u) > maxIdx) - maxIdx = H.pos(u); - - sumInDeg += u->indeg(); - adjEntry adj; - forall_adj(adj, u) { - if (adj->theEdge()->target()==u && markedNodes[adj->theEdge()->source()]) - numEdges++; - } - } - } - if (numEdges!=sumInDeg || maxIdx-minIdx+1!=numMarkedNodes ) - return; - - if (numDummies!=numMarkedNodes) - continue; - - //delete long edge dummies - for (int k = minIdx; k <= maxIdx; k++) { - node u = lvl[k]; - - OGDF_ASSERT(H.isLongEdgeDummy(u)); - - edge inEdge = u->firstAdj()->theEdge(); - edge outEdge = u->lastAdj()->theEdge(); - if (inEdge->target() != u) - swap(inEdge, outEdge); - H.m_GC.unsplit(inEdge, outEdge); - } - - /* - //debug - cout << endl << endl; - cout << "vor : " << endl; - for(int ii = 0; ii <= H.high(); ii++) { - Level &lvl = H[ii]; - cout << endl; - cout << "level : " << lvl.index() << endl; - cout << "nodes : "; - for(int jj = 0; jj <= lvl.high(); jj++) { - cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " "; - } - cout << endl; - } - */ - - post_processing_reduce(H, i, s, minIdx, maxIdx, markedNodes); - - /* - //debug - cout << endl << endl; - cout << endl << endl; - cout << "nach : " << endl; - for(int ii = 0; ii <= H.high(); ii++) { - Level &lvl = H[ii]; - cout << endl; - cout << "level : " << lvl.index() << endl; - cout << "nodes : "; - for(int jj = 0; jj <= lvl.high(); jj++) { - cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " "; - } - cout << endl; - } - */ - - } -} - - -void LayerBasedUPRLayout::post_processing_reduce( - Hierarchy &H, - int &i, - node s, - int minIdx, - int maxIdx, - NodeArray &markedNodes) -{ - const Level &lvl = H[i]; - - if (maxIdx-minIdx+1 == lvl.size()) { - post_processing_deleteLvl(H, i); - i--; - return; - } - - // delete the dummies in interval[minIdx,maxIdx] and copy the nodes in lvl i-1 to lvl i for i={0,..,i-1} - int startLvl = H.rank(s); - for (int j = i; j > startLvl; j--) { - - int idxl1 = INT_MAX; - int idxl2 = INT_MAX; - int idxh1 = -1; - int idxh2 = -1; - for (int k = 0; k<=H[j].high(); k++) { - node u = H[j][k]; - - if (markedNodes[u]) { - if (kidxh1) - idxh1 = k; - } - } - - for (int k = 0; k<=H[j-1].high(); k++) { - node u = H[j-1][k]; - - if (markedNodes[u]) { - if (kidxh2) - idxh2 = k; - } - } - - int jTmp = j; - post_processing_deleteInterval(H, idxl1, idxh1, j); - if (jTmp!=j) { - i--; - return; //a level was deleted, we are done - } - - /* - //debug - cout << endl << endl; - cout << "nach delete : " << endl; - for(int ii = 0; ii <= H.high(); ii++) { - Level &lvl = H[ii]; - cout << endl; - cout << "level : " << lvl.index() << endl; - cout << "nodes : "; - for(int jj = 0; jj <= lvl.high(); jj++) { - cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " "; - } - cout << endl; - } - */ - - post_processing_CopyInterval(H, j, idxl2, idxh2, idxl1); - - /* - //debug - cout << endl << endl; - cout << "nach copy : " << endl; - for(int ii = 0; ii <= H.high(); ii++) { - Level &lvl = H[ii]; - cout << endl; - cout << "level : " << lvl.index() << endl; - cout << "nodes : "; - for(int jj = 0; jj <= lvl.high(); jj++) { - cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " "; - } - cout << endl; - } - */ - - } - - int idxl1 = INT_MAX; - int idxh1 = -1; - for (int k = 0; k<=H[startLvl].high(); k++) { - node u = H[startLvl][k]; - - if (markedNodes[u]) { - if (kidxh1) - idxh1 = k; - } - } - int tmp = startLvl; - post_processing_deleteInterval(H, idxl1, idxh1, startLvl); - if (tmp!=startLvl) - i--; -} - - -void LayerBasedUPRLayout::post_processing_CopyInterval(Hierarchy &H, int i, int beginIdx, int endIdx, int pos) -{ - Level &lvl_cur = H[i]; - int intervalSize = endIdx - beginIdx +1; - int lastIdx = lvl_cur.high(); - - OGDF_ASSERT(intervalSize > 0); - - // grow array - lvl_cur.m_nodes.grow(intervalSize); - //move all the data block [pos,lvl_cur.high()] to the end of the array - for (int k = 0; k < (lastIdx - pos + 1) ; k++) { - //update position - H.m_pos[lvl_cur[lastIdx - k]] = lvl_cur.high() - k; - lvl_cur[lvl_cur.high() - k] = lvl_cur[lastIdx - k]; - } - - /* - //debug - cout << endl << endl; - cout << "level after shift block to end of array : " << lvl.index() << endl; - cout << "nodes : "; - for(int j = 0; j <= lvl.high(); j++) { - cout << lvl[j] << " ; pos() " << pos(lvl[j]) << " "; - } - cout << endl; - */ - - //copy the nodes of nodeList into the array - Level &lvl_low = H[i-1]; - int idx = pos; - for (int k = beginIdx; k <= endIdx; k++) { - node u = lvl_low[k]; - lvl_cur[idx] = u; - // update member data - H.m_pos[u] = idx; - H.m_rank[u] = lvl_cur.index(); - idx++; - } -} - - - -void LayerBasedUPRLayout::post_processing_deleteInterval(Hierarchy &H, int beginIdx, int endIdx, int &j) -{ - Level &lvl = H[j]; - - int i = 0; - while ((endIdx + i) < lvl.high()) { - lvl[beginIdx + i] = lvl[endIdx + i +1]; - H.m_pos[lvl[endIdx + i +1]] = beginIdx + i; - i++; - } - - int blockSize = endIdx - beginIdx + 1; - - if (lvl.m_nodes.size()==blockSize) { - int l = lvl.index(); - post_processing_deleteLvl(H, l); //delete the lvl - j--; - } - else - lvl.m_nodes.grow(-blockSize); // reduce the size of the lvl -} - - - -void LayerBasedUPRLayout::post_processing_deleteLvl(Hierarchy &H, int i) -{ - //move the pointer to end, then delete the lvl - int curPos = i; - while (curPos < H.high()) { - swap(H.m_pLevel[curPos], H.m_pLevel[curPos+1]); - Level &lvlTmp = H[curPos]; - lvlTmp.m_index = curPos; - //update rank - for(int i = 0; i <= lvlTmp.high(); i++) { - H.m_rank[lvlTmp[i]] = curPos; - } - curPos++; - } - //delete - delete H.m_pLevel[H.high()]; - H.m_pLevel.grow(-1); -} - - - - -void LayerBasedUPRLayout::UPRLayoutSimple(const UpwardPlanRep &UPR, GraphAttributes &GA) -{ - //clear some data - edge e; - forall_edges(e, GA.constGraph()) { - GA.bends(e).clear(); - } - - // -------------layout the representation------------------- - GraphAttributes GA_UPR(UPR); - node v; - forall_nodes(v, GA.constGraph()) { - node vUPR = UPR.copy(v); - GA_UPR.height(vUPR) = GA.height(v); - GA_UPR.width(vUPR) = GA.width(v); - } - - - //compute the left edge - adjEntry adj; - forall_adj(adj, UPR.getSuperSource()) { - if (UPR.getEmbedding().rightFace(adj) == UPR.getEmbedding().externalFace()) - break; - } - adj = adj->cyclicSucc(); - callSimple(GA_UPR, adj); - - //map to AG - forall_nodes(v, GA.constGraph()) { - double vX = GA_UPR.x(UPR.copy(v)); - double vY = GA_UPR.y(UPR.copy(v)); - GA.x(v) = vX; - GA.y(v) = vY; - } - - // add bends to original edges - forall_edges(e, GA.constGraph()) { - List chain = UPR.chain(e); - forall_nonconst_listiterators(edge, it, chain) { - edge eUPR = *it; - node tgtUPR = eUPR->target(); - - //add bend point of eUPR to original edge - ListIterator iter; - DPolyline &line = GA_UPR.bends(eUPR); - for(iter = line.begin(); iter.valid(); iter++) { - double x2 = (*iter).m_x; - double y2 = (*iter).m_y; - DPoint p(x2, y2); - GA.bends(e).pushBack(p); - } - //add target node of a edge segment as bend point - if (tgtUPR != chain.back()->target()) { - double pX = GA_UPR.x(tgtUPR); - double pY = GA_UPR.y(tgtUPR); - DPoint p(pX, pY); - GA.bends(e).pushBack(p); - } - } - - DPolyline &poly = GA.bends(e); - DPoint pSrc(GA.x(e->source()), GA.y(e->source())); - DPoint pTgt(GA.x(e->target()), GA.y(e->target())); - poly.normalize(pSrc, pTgt); - } - - //layers and max. layer size -} - - -void LayerBasedUPRLayout::callSimple(GraphAttributes &GA, adjEntry adj) -{ - m_numLevels = -1; //not implemented yet! - m_maxLevelSize = -1; //not implemented yet! - - const Graph &G = GA.constGraph(); - - OGDF_ASSERT(adj->graphOf() == &G); - - // We make a copy stGraph of the input graph G - - GraphCopySimple stGraph(G); - - // determine single source s, single sink t and edge (s,t) - node s, t; - hasSingleSource(G, s); - hasSingleSink(G, t); - s = stGraph.copy(s); - t = stGraph.copy(t); - - adjEntry adjCopy = stGraph.copy(adj->theEdge())->adjSource(); - - /*cout << "stGraph:" << endl; - node x; - forall_nodes(x,stGraph) { - cout << x << ":"; - edge e; - forall_adj_edges(e,x) - cout << " " << e; - cout << endl; - }*/ - - // For the st-graph, we compute a longest path ranking. Since the graph - // is st-planar, it is also level planar for the computed rank assignment. - NodeArray stRank(stGraph); - longestPathRanking(stGraph,stRank); - - edge e; - forall_edges(e,stGraph) - OGDF_ASSERT(stRank[e->source()] < stRank[e->target()]); - - - // We translate the rank assignment for stGraph to a rank assignment of G - // a compute a proper hierarchy for G with this ranking. Since G is a - // subgraph of stGraph, G is level planar with this ranking. - NodeArray rank(G); - - node vG; - forall_nodes(vG,G) - rank[vG] = stRank[stGraph.copy(vG)]; - - - /*cout << "rank assignment G:" << endl; - forall_nodes(vG,G) { - cout << vG << ": " << rank[vG] << endl; - }*/ - - Hierarchy H(G,rank); - - // GC is the underlying graph of the proper hierarchy H. - const GraphCopy &GC = H; - - - // We compute the positions of the nodes of GC on each level. It is - // important to determine also the positions of the dummy nodes which - // resulted from splitting edges. The node array st2GC maps the nodes in - // stGraph to the nodes in GC. - NodeArray st2GC(stGraph,0); - - // For nodes representing real nodes in G this is simple. - forall_nodes(vG,G) { - OGDF_ASSERT(H.rank(GC.copy(vG)) == stRank[stGraph.copy(vG)]); - st2GC[stGraph.copy(vG)] = GC.copy(vG); - } - - // For the dummy nodes, we first have to split edges in stGraph. - // For an edge e=(v,w), we have to split e stRank[w]-stRank[v]-1 times. - edge eG; - forall_edges(eG,G) { - edge eSt = stGraph.copy(eG); - const List &pathGC = GC.chain(eG); - - ListConstIterator it; - int r = stRank[eSt->source()]; - for(it = pathGC.begin().succ(); it.valid(); ++it) { - eSt = stGraph.split(eSt); - node v = eSt->source(); - node vGC = (*it)->source(); - stRank[v] = ++r; - st2GC[v] = vGC; - - OGDF_ASSERT(stRank[v] == H.rank(vGC)); - } - } - - node v; - forall_nodes(v,stGraph) { - node vGC = st2GC[v]; - OGDF_ASSERT(vGC == 0 || stRank[v] == H.rank(vGC)); - } - - /*cout << "mapping stGraph -> GC -> G:" << endl; - node v; - forall_nodes(v,stGraph) - cout << v << ": " << st2GC[v] << " " << stGraph.original(v) << endl;*/ - - - // The array nodes contains the sorted nodes of stGraph on each level. - Array > nodes(stRank[s],stRank[t]); - - dfsSortLevels(adjCopy,stRank,nodes); - - /*for(int i = stRank[s]; i <= stRank[t]; ++i) { - cout << i << ": "; - SListPure &L = nodes[i]; - SListConstIterator it; - for(it = L.begin(); it.valid(); ++it) { - cout << stGraph.original(*it) << " "; - node vGC = st2GC[*it]; - OGDF_ASSERT(vGC == 0 || H.rank(vGC) == i); - } - cout << endl; - }*/ - - // We translate the node lists to node lists of nodes in GC using node - // array st2GC. Note that there are also nodes in stGraph which have - // no counterpart in GC (these are face nodes of the face-sink graph - // introduced by the augmentation). We can simply ignore such nodes. - int i; - for (i = 0; i <= H.high(); ++i) { - Level &level = H[i]; - - //cout << i << endl; - //cout << level << endl; - - int j = 0; - SListConstIterator itSt; - for(itSt = nodes[i].begin(); itSt.valid(); ++itSt) { - node vGC = st2GC[*itSt]; - if(vGC != 0) - level[j++] = vGC; - } - - //cout << level << endl; - //cout << endl; - - level.recalcPos(); // Recalculate some internal data structures in H - } - - H.check(); - - - //cout << "crossings: " << H.calculateCrossings() << endl; - OGDF_ASSERT(H.calculateCrossings() == 0); - - // Finally, we draw the computed hierarchy applying a hierarchy layout - // module. - m_layout.get().call(H,GA); -} - - -// This procedure computes the sorted nodes lists on each level of an st-graph. -// adj1 corresponds to the leftmost outgoing edge of v = adj1->theNode(). -// Levels are build from left to right. -void LayerBasedUPRLayout::dfsSortLevels( - adjEntry adj1, // leftmost outgoing edge - const NodeArray &rank, // ranking - Array > &nodes) // sorted nodes on levels -{ - node v = adj1->theNode(); - - nodes[rank[v]].pushBack(v); - - // iterate over all outgoing edges from left to right - adjEntry adj = adj1; - do { - node w = adj->theEdge()->target(); - OGDF_ASSERT(v != w); - - // Is adjW the leftmost outgoing edge of w ? - adjEntry adjW = adj->twin()->cyclicSucc(); - if(adjW->theEdge()->source() == w) - dfsSortLevels(adjW,rank,nodes); - - adj = adj->cyclicSucc(); - } while (adj != adj1 && adj->theEdge()->source() == v); -} - - -// for UPRLayoutSimple -void LayerBasedUPRLayout::longestPathRanking( - const Graph &G, - NodeArray &rank) -{ - StackPure sources; - NodeArray indeg(G); - - node v; - forall_nodes(v,G) { - indeg[v] = v->indeg(); - rank[v] = 0; - if(indeg[v] == 0) { - sources.push(v); - } - } - - while(!sources.empty()) - { - v = sources.pop(); - - edge e; - forall_adj_edges(e,v) { - node w = e->target(); - if (w == v) continue; - - if(rank[w] < rank[v]+1) - rank[w] = rank[v]+1; - - if(--indeg[w] == 0) { - sources.push(w); - } - } - } -} - - - -}// end namespace ogdf diff --git a/ext/OGDF/src/upward/SubgraphUpwardPlanarizer.cpp b/ext/OGDF/src/upward/SubgraphUpwardPlanarizer.cpp deleted file mode 100644 index 22d7cb75c..000000000 --- a/ext/OGDF/src/upward/SubgraphUpwardPlanarizer.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* - * $Revision: 2564 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-07 00:03:48 +0200 (Sa, 07. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of SubgraphUpwardPlanarizer class. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef OGDF_DEBUG -#include -#include -#endif - - -namespace ogdf { - -Module::ReturnType SubgraphUpwardPlanarizer::doCall(UpwardPlanRep &UPR, - const EdgeArray &cost, - const EdgeArray &forbid) -{ - const Graph &G = UPR.original(); - GraphCopy GC(G); - - //reverse some edges in order to obtain a DAG - List feedBackArcSet; - m_acyclicMod.get().call(GC, feedBackArcSet); - forall_listiterators(edge, it, feedBackArcSet) { - GC.reverseEdge(*it); - } - - OGDF_ASSERT(isSimple(G)); - - //mapping cost - EdgeArray cost_GC(GC); - edge e; - forall_edges(e, GC) { - if (forbid[GC.original(e)]) - cost_GC[e] = INT_MAX; - else - cost_GC[e] = cost[GC.original(e)]; - } - - // tranform to single source graph by adding a super source s_hat and connect it with the other sources - EdgeArray sourceArcs(GC, false); - node s_hat = GC.newNode(); - node v; - forall_nodes(v, GC) { - if (v->indeg() == 0 && v != s_hat) { - edge e_tmp = GC.newEdge(s_hat, v); - cost_GC[e_tmp] = 0; // crossings source arcs cause not cost - sourceArcs[e_tmp] = true; - } - } - - - /* - //------------------------------------------------debug - GraphAttributes AG_GC(GC, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - AG_GC.setAllHeight(30.0); - AG_GC.setAllWidth(30.0); - node z; - forall_nodes(z, AG_GC.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - AG_GC.labelNode(z) = str; - } - AG_GC.writeGML("c:/temp/GC.gml"); - // --------------------------------------------end debug - */ - - BCTree BC(GC); - const Graph &bcTree = BC.bcTree(); - - GraphCopy G_dummy; - G_dummy.createEmpty(G); - NodeArray biComps(bcTree, G_dummy); // bicomps of G; init with an empty graph - UpwardPlanRep UPR_dummy; - UPR_dummy.createEmpty(G); - NodeArray uprs(bcTree, UPR_dummy); // the upward planarized representation of the bicomps; init with an empty UpwarPlanRep - - constructComponentGraphs(BC, biComps); - - forall_nodes(v, bcTree) { - - if (BC.typeOfBNode(v) == BCTree::CComp) - continue; - - GraphCopy &block = biComps[v]; - - OGDF_ASSERT(m_subgraph.valid()); - - // construct a super source for this block - node s, s_block; - hasSingleSource(block, s); - s_block = block.newNode(); - block.newEdge(s_block, s); //connect s - - UpwardPlanarModule upMod; - UpwardPlanRep bestUPR; - - //upward planarize if not upward planar - if (!upMod.upwardPlanarEmbed(block)) { - - for(int i = 0; i < m_runs; i++) {// i multistarts - UpwardPlanRep UPR_tmp; - UPR_tmp.createEmpty(block); - List delEdges; - - m_subgraph.get().call(UPR_tmp, delEdges); - - UPR_tmp.augment(); - - //mark the source arcs of block - UPR_tmp.m_isSourceArc[UPR_tmp.copy(s_block->firstAdj()->theEdge())] = true; - adjEntry adj_tmp; - forall_adj(adj_tmp, UPR_tmp.copy(s_block->firstAdj()->theEdge()->target())) { - edge e_tmp = UPR_tmp.original(adj_tmp->theEdge()); - if (e_tmp != 0 && block.original(e_tmp) != 0 && sourceArcs[block.original(e_tmp)]) - UPR_tmp.m_isSourceArc[adj_tmp->theEdge()] = true; - } - - //assign "crossing cost" - EdgeArray cost_Block(block); - forall_edges(e, block) { - if (block.original(e) == 0 || GC.original(block.original(e)) == 0 ) - cost_Block[e] = 0; - else - cost_Block[e] = cost_GC[block.original(e)]; - } - - /* - if (false) { - //---------------------------------------------------debug - LayerBasedUPRLayout uprLayout; - UpwardPlanRep upr_bug(UPR_tmp.getEmbedding()); - adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); - node s_upr_bug = upr_bug.newNode(); - upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); - upr_bug.m_isSourceArc.init(upr_bug, false); - upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; - upr_bug.s_hat = s_upr_bug; - upr_bug.augment(); - - GraphAttributes GA_UPR_tmp(UPR_tmp, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - GA_UPR_tmp.setAllHeight(30.0); - GA_UPR_tmp.setAllWidth(30.0); - - uprLayout.call(upr_bug, GA_UPR_tmp); - - // label the nodes with their index - node z; - forall_nodes(z, GA_UPR_tmp.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - GA_UPR_tmp.labelNode(z) = str; - GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); - GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); - } - edge eee; - forall_edges(eee, GA_UPR_tmp.constGraph()) { - DPolyline &line = GA_UPR_tmp.bends(eee); - ListIterator it; - for(it = line.begin(); it.valid(); it++) { - (*it).m_y = -(*it).m_y; - (*it).m_x = -(*it).m_x; - } - } - GA_UPR_tmp.writeGML("c:/temp/UPR_tmp_fups.gml"); - cout << "UPR_tmp/fups faces:"; - UPR_tmp.outputFaces(UPR_tmp.getEmbedding()); - //end -----------------------------------------------debug - } - */ - - delEdges.permute(); - m_inserter.get().call(UPR_tmp, cost_Block, delEdges); - - if (i != 0) { - if (UPR_tmp.numberOfCrossings() < bestUPR.numberOfCrossings()) { - //cout << endl << "new cr_nr:" << UPR_tmp.numberOfCrossings() << " old cr_nr : " << bestUPR.numberOfCrossings() << endl; - bestUPR = UPR_tmp; - } - } - else - bestUPR = UPR_tmp; - }//for - } - else { //block is upward planar - CombinatorialEmbedding Gamma(block); - FaceSinkGraph fsg((const CombinatorialEmbedding &)Gamma, s_block); - SList faceList; - fsg.possibleExternalFaces(faceList); - Gamma.setExternalFace(faceList.front()); - - UpwardPlanRep UPR_tmp(Gamma); - UPR_tmp.augment(); - - //mark the source arcs of block - UPR_tmp.m_isSourceArc[UPR_tmp.copy(s->firstAdj()->theEdge())] = true; - adjEntry adj_tmp; - forall_adj(adj_tmp, UPR_tmp.copy(s->firstAdj()->theEdge()->target())) { - edge e_tmp = UPR_tmp.original(adj_tmp->theEdge()); - if (e_tmp != 0 && block.original(e_tmp) != 0 && sourceArcs[block.original(e_tmp)]) - UPR_tmp.m_isSourceArc[adj_tmp->theEdge()] = true; - } - - bestUPR = UPR_tmp; - - /* - //debug - //---------------------------------------------------debug - GraphAttributes GA_UPR_tmp(UPR_tmp, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - GA_UPR_tmp.setAllHeight(30.0); - GA_UPR_tmp.setAllWidth(30.0); - - // label the nodes with their index - forall_nodes(z, GA_UPR_tmp.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - GA_UPR_tmp.labelNode(z) = str; - GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); - GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); - } - edge eee; - forall_edges(eee, GA_UPR_tmp.constGraph()) { - DPolyline &line = GA_UPR_tmp.bends(eee); - ListIterator it; - for(it = line.begin(); it.valid(); it++) { - (*it).m_y = -(*it).m_y; - (*it).m_x = -(*it).m_x; - } - } - GA_UPR_tmp.writeGML("c:/temp/UPR_tmp_fups.gml"); - cout << "UPR_tmp/fups faces:"; - UPR_tmp.outputFaces(UPR_tmp.getEmbedding()); - //end -----------------------------------------------debug - */ - - } - uprs[v] = bestUPR; - }//forall_nodes - - // compute the number of crossings - int nr_cr = 0; - forall_nodes(v, bcTree) { - if (BC.typeOfBNode(v) != BCTree::CComp) - nr_cr = nr_cr + uprs[v].numberOfCrossings(); - } - - //merge all component to a graph - node parent_BC = BC.bcproper(s_hat); - NodeArray nodesDone(bcTree, false); - dfsMerge(GC, BC, biComps, uprs, UPR, 0, parent_BC, nodesDone); // start with the component which contains the super source s_hat - - //augment to single sink graph - UPR.augment(); - - //set crossings - UPR.crossings = nr_cr; - - - //------------------------------------------------debug - /* - LayerBasedUPRLayout uprLayout; - UpwardPlanRep upr_bug(UPR.getEmbedding()); - adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); - node s_upr_bug = upr_bug.newNode(); - upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); - upr_bug.m_isSourceArc.init(upr_bug, false); - upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; - upr_bug.s_hat = s_upr_bug; - upr_bug.augment(); - GraphAttributes AG(UPR, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - AG.setAllHeight(30.0); - AG.setAllWidth(30.0); - - uprLayout.call(upr_bug, AG); - - forall_nodes(v, AG.constGraph()) { - int idx; - idx = v->index(); - - - if (UPR.original(v) != 0) - idx = UPR.original(v)->index(); - - - char str[255]; - sprintf_s(str, 255, "%d", idx); // convert to string - AG.labelNode(v) = str; - if (UPR.isDummy(v)) - AG.colorNode(v) = "#ff0000"; - AG.y(v)=-AG.y(v); - } - // label the edges with their index - forall_edges(e, AG.constGraph()) { - char str2[255]; - sprintf_s(str2, 255, "%d", e->index()); // convert to string - AG.labelEdge(e) = str2; - if (UPR.isSourceArc(e)) - AG.colorEdge(e) = "#00ff00"; - if (UPR.isSinkArc(e)) - AG.colorEdge(e) = "#ff0000"; - - DPolyline &line = AG.bends(e); - ListIterator it; - for(it = line.begin(); it.valid(); it++) { - (*it).m_y = -(*it).m_y; - } - } - AG.writeGML("c:/temp/upr_res.gml"); - //cout << "UPR_RES"; - //UPR.outputFaces(UPR.getEmbedding()); - //cout << "Mapping :" << endl; - //forall_nodes(v, UPR) { - // if (UPR.original(v) != 0) { - // cout << "node UPR " << v << " node G " << UPR.original(v) << endl; - // } - //} - // --------------------------------------------end debug - */ - -#ifdef OGDF_DEBUG - UpwardPlanarModule upMod; -#endif - OGDF_ASSERT(hasSingleSource(UPR)); - OGDF_ASSERT(isSimple(UPR)); - OGDF_ASSERT(isAcyclic(UPR)); - OGDF_ASSERT(upMod.upwardPlanarityTest(UPR)); - -/* - edge eee; - forall_edges(eee, UPR.original()) { - if (UPR.isReversed(eee)) - cout << endl << eee << endl; - } -*/ - return Module::retFeasible; -} - - - -void SubgraphUpwardPlanarizer::dfsMerge( - const GraphCopy &GC, - BCTree &BC, - NodeArray &biComps, - NodeArray &uprs, - UpwardPlanRep &UPR_res, - node parent_BC, - node current_BC, - NodeArray &nodesDone) -{ - // only one component. - if (current_BC->degree() == 0) { - merge(GC, UPR_res, biComps[current_BC], uprs[current_BC]); - return; - } - - adjEntry adj; - forall_adj(adj, current_BC) { - node next_BC = adj->twin()->theNode(); - if (BC.typeOfBNode(current_BC) == BCTree::CComp) { - if (parent_BC != 0 && !nodesDone[parent_BC]) { - merge(GC, UPR_res, biComps[parent_BC], uprs[parent_BC]); - nodesDone[parent_BC] = true; - } - if (!nodesDone[next_BC]) { - merge(GC, UPR_res, biComps[next_BC], uprs[next_BC]); - nodesDone[next_BC] = true; - } - } - if (next_BC != parent_BC ) - dfsMerge(GC, BC, biComps, uprs, UPR_res, current_BC, next_BC, nodesDone); - } -} - - - -void SubgraphUpwardPlanarizer::merge( - const GraphCopy &GC, - UpwardPlanRep &UPR_res, - const GraphCopy &block, - UpwardPlanRep &UPR) -{ - node startUPR = UPR.getSuperSource()->firstAdj()->theEdge()->target(); - node startRes; - - node startG = GC.original(block.original(UPR.original(startUPR))); - - bool empty = UPR_res.empty(); - - if (empty) { - - OGDF_ASSERT(startG == 0); - - // contruct a node in UPR_res assocciated with startUPR - startRes = UPR_res.newNode(); - UPR_res.m_isSinkArc.init(UPR_res, false); - UPR_res.m_isSourceArc.init(UPR_res, false); - UPR_res.s_hat = startRes; - } - else { - startRes = UPR_res.copy(startG); - } - - OGDF_ASSERT(startRes != 0); - - // compute the adjEntry position (in UPR_res) of the cutvertex startRes - adjEntry pos = 0; - if (!empty) { - adjEntry run, adj_ext = 0, adj_int = 0; - forall_adj(run, startRes) { - if (UPR_res.getEmbedding().rightFace(run) == UPR_res.getEmbedding().externalFace()) { - adj_ext = run; - break; - } - if (run->theEdge()->source() == startRes) - adj_int = run; - } - // cutvertex is a sink in UPR_res - if (adj_ext == 0 && adj_int == 0) { - pos = UPR_res.sinkSwitchOf(startRes); - } - else { - if (adj_ext == 0) - pos = adj_int; - else - pos = adj_ext; - } - OGDF_ASSERT(pos != 0); - } - - // construct for each node (except the two super sink and the super source) of UPR a associated of UPR to UPR_res - NodeArray nodeUPR2UPR_res(UPR, 0); - nodeUPR2UPR_res[startUPR] = startRes; - node v; - forall_nodes(v, UPR) { - - // allready constructed or is super sink or super source - if (v == startUPR || v == UPR.getSuperSink() || v == UPR.getSuperSink()->firstAdj()->theEdge()->source() || v == UPR.getSuperSource()) - continue; - - node vNew; - if (UPR.original(v) != 0 ) { - node vG = GC.original(block.original((UPR.original(v)))); - if (vG != 0) - vNew = UPR_res.newNode(vG); - else - vNew = UPR_res.newNode(); //vG is the super source - } - else // crossing dummy, no original node - vNew = UPR_res.newNode(); - nodeUPR2UPR_res[v] = vNew; - } - - //add edges of UPR to UPR_res - EdgeArray edgeUPR2UPR_res(UPR, 0); - edge e; - forall_edges(e, block) { - - if (e->source()->indeg()==0) // the artificial edge with the super source - continue; - - List chains = UPR.chain(e); - edge eG = 0, eGC = block.original(e); - eG = GC.original(eGC); - - OGDF_ASSERT(!chains.empty()); - - //construct new edges in UPR_res - forall_listiterators(edge, it, chains) { - node tgt = nodeUPR2UPR_res[(*it)->target()]; - node src = nodeUPR2UPR_res[(*it)->source()]; - edge eNew = UPR_res.newEdge(src, tgt); - edgeUPR2UPR_res[*it] = eNew; - - if (UPR.isSinkArc(UPR.copy(e))) - UPR_res.m_isSinkArc[eNew] = true; - if (UPR.isSourceArc(UPR.copy(e))) - UPR_res.m_isSourceArc[eNew] = true; - - if (eG == 0) { // edge is associated with a sink arc - UPR_res.m_eOrig[eNew] = 0; - continue; - } - - UPR_res.m_eOrig[eNew] = eG; - if (chains.size() == 1) { // e is not split - UPR_res.m_eCopy[eG].pushBack(eNew); - UPR_res.m_eIterator[eNew] = UPR_res.m_eCopy[eG].begin(); - break; - } - UPR_res.m_eCopy[eG].pushBack(eNew); - UPR_res.m_eIterator[eNew] = UPR_res.m_eCopy[eG].rbegin(); - } - } - - - ///* - //* embed the new component in UPR_res with respect to the embedding of UPR - //*/ - - // for the cut vertex - if (!empty) { - adjEntry run = UPR.getAdjEntry(UPR.getEmbedding(), startUPR, UPR.getEmbedding().externalFace()); - run = run->cyclicSucc(); - adjEntry adjStart = run; - do { - if (edgeUPR2UPR_res[run->theEdge()] != 0) { - adjEntry adj_UPR_res = edgeUPR2UPR_res[run->theEdge()]->adjSource(); - UPR_res.moveAdjAfter(adj_UPR_res, pos); - pos = adj_UPR_res; - } - run = run->cyclicSucc(); - } while(run != adjStart); - } - - forall_nodes(v, UPR) { - if (v == startUPR && !empty) - continue; - - node v_UPR_res = nodeUPR2UPR_res[v]; - List adj_UPR, adj_UPR_res; - UPR.adjEntries(v, adj_UPR); - - // convert adj_UPR of v to adj_UPR_res of v_UPR_res - forall_listiterators(adjEntry, it, adj_UPR) { - edge e_res = edgeUPR2UPR_res[(*it)->theEdge()]; - if (e_res == 0) // associated edges in UPR_res - continue; - adjEntry adj_res = e_res->adjSource(); - if (adj_res->theNode() != v_UPR_res) - adj_res = adj_res->twin(); - adj_UPR_res.pushBack(adj_res); - } - - UPR_res.sort(v_UPR_res, adj_UPR_res); - } - - /* - //---------------------------------------------------debug - if (!UPR_res.empty()) { - GraphAttributes GA_UPR_res(UPR_res, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - GA_UPR_res.setAllHeight(30.0); - GA_UPR_res.setAllWidth(30.0); - node z; - // label the nodes with their index - forall_nodes(z, GA_UPR_res.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - GA_UPR_res.labelNode(z) = str; - } - GA_UPR_res.writeGML("c:/temp/UPR_res_tmp.gml"); - cout << "UPR_res_tmp faces:"; - UPR_res.outputFaces(UPR_res.getEmbedding()); - } - - GraphAttributes GA_UPR(UPR, GraphAttributes::nodeGraphics| - GraphAttributes::edgeGraphics| - GraphAttributes::nodeColor| - GraphAttributes::edgeColor| - GraphAttributes::nodeLabel| - GraphAttributes::edgeLabel - ); - GA_UPR.setAllHeight(30.0); - GA_UPR.setAllWidth(30.0); - node z; - // label the nodes with their index - forall_nodes(z, GA_UPR.constGraph()) { - char str[255]; - sprintf_s(str, 255, "%d", z->index()); // convert to string - GA_UPR.labelNode(z) = str; - } - GA_UPR.writeGML("c:/temp/UPR_tmp.gml"); - cout << "UPR_tmp faces:"; - UPR.outputFaces(UPR.getEmbedding()); - //end -----------------------------------------------debug - */ - - // update UPR_res - UPR_res.initMe(); -} - - -void SubgraphUpwardPlanarizer::constructComponentGraphs(BCTree &BC, NodeArray &biComps) -{ - NodeArray constructed(BC.originalGraph(), -1); - const Graph &bcTree = BC.bcTree(); - node v; - int i = 0; // comp. number - forall_nodes(v, bcTree) { - - if (BC.typeOfBNode(v) == BCTree::CComp) - continue; - - const SList &edges_comp = BC.hEdges(v); //bicomp edges - List edges_orig; - forall_slistiterators(edge, it, edges_comp) - edges_orig.pushBack(BC.original(*it)); - - GraphCopy GC; - GC.createEmpty(BC.originalGraph()); - // construct i-th component graph - forall_listiterators(edge, it, edges_orig) { - node srcOrig = (*it)->source(); - node tgtOrig = (*it)->target(); - if (constructed[srcOrig] != i) { - constructed[srcOrig] = i; - GC.newNode(srcOrig); - } - if (constructed[tgtOrig] != i) { - constructed[tgtOrig] = i; - GC.newNode(tgtOrig); - } - GC.newEdge(*it); - } - biComps[v] = GC; - i++; - } -} - -} diff --git a/ext/OGDF/src/upward/UpwardPlanRep.cpp b/ext/OGDF/src/upward/UpwardPlanRep.cpp deleted file mode 100644 index 3bc931585..000000000 --- a/ext/OGDF/src/upward/UpwardPlanRep.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of PlanRep base class for planar rep. - * - * \author Hoi-Ming Wong - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - - - -namespace ogdf { - - -UpwardPlanRep::UpwardPlanRep(const CombinatorialEmbedding &Gamma) : - GraphCopy(Gamma.getGraph()), - isAugmented(false), - t_hat(0), - extFaceHandle(0), - crossings(0) -{ - OGDF_ASSERT(Gamma.externalFace() != 0); - OGDF_ASSERT(hasSingleSource(*this)); - OGDF_ASSERT(isSimple(*this)); - - m_isSourceArc.init(*this, false); - m_isSinkArc.init(*this, false); - hasSingleSource(*this, s_hat); - m_Gamma.init(*this); - - //compute the ext. face; - adjEntry adj; - node v = this->original(s_hat); - adj = getAdjEntry(Gamma, v, Gamma.externalFace()); - adj = this->copy(adj->theEdge())->adjSource(); - m_Gamma.setExternalFace(m_Gamma.rightFace(adj)); - - //outputFaces(Gamma); - - computeSinkSwitches(); -} - - -UpwardPlanRep::UpwardPlanRep(const GraphCopy &GC, ogdf::adjEntry adj_ext) : - GraphCopy(GC), - isAugmented(false), - t_hat(0), - extFaceHandle(0), - crossings(0) -{ - OGDF_ASSERT(adj_ext != 0); - OGDF_ASSERT(hasSingleSource(*this)); - - m_isSourceArc.init(*this, false); - m_isSinkArc.init(*this, false); - hasSingleSource(*this, s_hat); - m_Gamma.init(*this); - - //compute the ext. face; - node v = copy(GC.original(adj_ext->theNode())); - extFaceHandle = copy(GC.original(adj_ext->theEdge()))->adjSource(); - if (extFaceHandle->theNode() != v) - extFaceHandle = extFaceHandle->twin(); - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); - - adjEntry adj; - forall_adj(adj, s_hat) - m_isSourceArc[adj->theEdge()] = true; - - computeSinkSwitches(); -} - - -//copy constructor -UpwardPlanRep::UpwardPlanRep(const UpwardPlanRep &UPR) : - GraphCopy(), - isAugmented(UPR.isAugmented), - crossings(UPR.crossings) -{ - copyMe(UPR); -} - - -void UpwardPlanRep::copyMe(const UpwardPlanRep &UPR) -{ - NodeArray vCopy; - EdgeArray eCopy; - - Graph::construct(UPR,vCopy,eCopy); - - // initGC - m_pGraph = UPR.m_pGraph; - - m_vOrig.init(*this,0); m_eOrig.init(*this,0); - m_vCopy.init(*m_pGraph,0); m_eCopy.init(*m_pGraph); - m_eIterator.init(*this,0); - - node v, w; - forall_nodes(v,UPR) - m_vOrig[vCopy[v]] = UPR.m_vOrig[v]; - - edge e; - forall_edges(e,UPR) - m_eOrig[eCopy[e]] = UPR.m_eOrig[e]; - - forall_nodes(v,*this) - if ((w = m_vOrig[v]) != 0) m_vCopy[w] = v; - - forall_edges(e,*m_pGraph) { - ListConstIterator it; - for (it = UPR.m_eCopy[e].begin(); it.valid(); ++it) - m_eIterator[eCopy[*it]] = m_eCopy[e].pushBack(eCopy[*it]); - } - - //GraphCopy::initGC(UPR,vCopy,eCopy); - m_Gamma.init(*this); - m_isSinkArc.init(*this, false); - m_isSourceArc.init(*this, false); - - if (UPR.numberOfNodes() == 0) - return; - - s_hat = vCopy[UPR.getSuperSource()]; - if (UPR.augmented()) - t_hat = vCopy[UPR.getSuperSink()]; - - OGDF_ASSERT(UPR.extFaceHandle != 0); - - e = eCopy[UPR.extFaceHandle->theEdge()]; - v = vCopy[UPR.extFaceHandle->theNode()]; - if (e->adjSource()->theNode() == v) - extFaceHandle = e->adjSource(); - else - extFaceHandle = e->adjTarget(); - - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); - - forall_edges(e, UPR) { - edge a = eCopy[e]; - if (UPR.isSinkArc(e)) - m_isSinkArc[a] = true; - if (UPR.isSourceArc(e)) - m_isSourceArc[a] = true; - } - - computeSinkSwitches(); -} - - - -UpwardPlanRep & UpwardPlanRep::operator =(const UpwardPlanRep &cp) -{ - clear(); - createEmpty(cp.original()); - isAugmented = cp.isAugmented; - extFaceHandle = 0; - crossings = cp.crossings; - copyMe(cp); - return *this; -} - - -void UpwardPlanRep::augment() -{ - if (isAugmented) - return; - - OGDF_ASSERT(hasSingleSource(*this)); - - List< Tuple2 > l; - List switches; - - hasSingleSource(*this, s_hat); - - adjEntry adj; - forall_adj(adj, s_hat) - m_isSourceArc[adj->theEdge()] = true; - - FaceSinkGraph fsg(m_Gamma, s_hat); - List dummyList; - FaceArray< List > sinkSwitches(m_Gamma, dummyList); - fsg.sinkSwitches(sinkSwitches); - m_sinkSwitchOf.init(*this, 0); - - face f; - forall_faces(f, m_Gamma) { - adjEntry adj_top; - switches = sinkSwitches[f]; - if (switches.empty() || f == m_Gamma.externalFace()) - continue; - else - adj_top = switches.popFrontRet(); // first switch in the list is a top sink switch - - while (!switches.empty()) { - adjEntry adj = switches.popFrontRet(); - Tuple2 pair(adj, adj_top); - l.pushBack(pair); - } - } - // construct sink arcs - // for the ext. face - extFaceHandle = getAdjEntry(m_Gamma, s_hat, m_Gamma.externalFace()); - node t = this->newNode(); - switches = sinkSwitches[m_Gamma.externalFace()]; - - OGDF_ASSERT(!switches.empty()); - - while (!switches.empty()) { - adjEntry adj = switches.popFrontRet(); - edge e_new; - if (t->degree() == 0) { - e_new = m_Gamma.splitFace(adj, t); - } - else { - adjEntry adjTgt = getAdjEntry(m_Gamma, t, m_Gamma.rightFace(adj)); - e_new = m_Gamma.splitFace(adj, adjTgt); - } - m_isSinkArc[e_new] = true; - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); - } - - /* - * set ext. face handle - * we add a additional node t_hat and an addtional edge e=(t, t_hat) - * e will never been crossed. we use e as the ext. face handle - */ - t_hat = this->newNode(); - adjEntry adjSource = getAdjEntry(m_Gamma, t, m_Gamma.externalFace()); - extFaceHandle = m_Gamma.splitFace(adjSource, t_hat)->adjTarget(); - m_isSinkArc[extFaceHandle->theEdge()] = true; // not really a sink arc !! TODO?? - - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); - - //for int. faces - while (!l.empty()) { - Tuple2 pair = l.popFrontRet(); - - - edge e_new; - if (pair.x2()->theNode()->degree() == 0 ) { - e_new = m_Gamma.splitFace(pair.x1(), pair.x2()->theNode()); - } - else { - adjEntry adjTgt = getAdjEntry(m_Gamma, pair.x2()->theNode(), m_Gamma.rightFace(pair.x1())); - e_new = m_Gamma.splitFace(pair.x1(), adjTgt); - } - m_isSinkArc[e_new] = true; - } - - isAugmented = true; - - OGDF_ASSERT(isSimple(*this)); - - computeSinkSwitches(); -} - - -void UpwardPlanRep::removeSinkArcs(SList &crossedEdges) { - - if (crossedEdges.size() == 2) - return; - - - SListIterator itPred = crossedEdges.begin(), itLast = crossedEdges.rbegin(), it; - for(it = itPred.succ(); it != itLast; ++it) { - adjEntry adj = *it; - if (m_isSinkArc[adj->theEdge()]) { - m_Gamma.joinFaces(adj->theEdge()); - crossedEdges.delSucc(itPred); - it = itPred; - continue; - } - itPred = it; - } - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); -} - - -void UpwardPlanRep::insertEdgePathEmbedded(edge eOrig, SList crossedEdges, EdgeArray &costOrig) -{ - removeSinkArcs(crossedEdges); - - //case the copy v of eOrig->source() is a sink switch - //we muss remove the sink arcs incident to v, since after inserting eOrig, v is not a sink witch - node v = crossedEdges.front()->theNode(); - List outEdges; - if (v->outdeg() == 1) - this->outEdges(v, outEdges); // we delete this edges later - - m_eCopy[eOrig].clear(); - - adjEntry adjSrc, adjTgt; - SListConstIterator it = crossedEdges.begin(); - SListConstIterator itLast = crossedEdges.rbegin(); - - // iterate over all adjacency entries in crossedEdges except for first - // and last - adjSrc = *it; - List dirtyList; // left and right face of the element of this list are modified - for(++it; it != itLast; ++it) - { - adjEntry adj = *it; - - bool isASourceArc = false, isASinkArc = false; - if (m_isSinkArc[adj->theEdge()]) - isASinkArc = true; - if (m_isSourceArc[adj->theEdge()]) - isASourceArc = true; - - int c = 0; - if (original(adj->theEdge()) != 0) - c = costOrig[original(adj->theEdge())]; - - // split edge - node u = m_Gamma.split(adj->theEdge())->source(); - if (!m_isSinkArc[adj->theEdge()] && !m_isSourceArc[adj->theEdge()]) - crossings = crossings + c; // crossing sink/source arcs cost nothing - - // determine target adjacency entry and source adjacency entry - // in the next iteration step - adjTgt = u->firstAdj(); - adjEntry adjSrcNext = adjTgt->succ(); - - if (adjTgt != adj->twin()) - swap(adjTgt,adjSrcNext); - - - edge e_split = adjTgt->theEdge(); // the new split edge - if (e_split->source() != u) - e_split = adjSrcNext->theEdge(); - - if (isASinkArc) - m_isSinkArc[e_split] = true; - if (isASourceArc) - m_isSourceArc[e_split] = true; - - // insert a new edge into the face - edge eNew = m_Gamma.splitFace(adjSrc,adjTgt); - m_eIterator[eNew] = GraphCopy::m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = eOrig; - dirtyList.pushBack(eNew->adjSource()); - - adjSrc = adjSrcNext; - } - - // insert last edge - edge eNew = m_Gamma.splitFace(adjSrc,*it); - m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); - m_eOrig[eNew] = eOrig; - dirtyList.pushBack(eNew->adjSource()); - - // remove the sink arc incident to v - if(!outEdges.empty()) { - edge e = outEdges.popFrontRet(); - if (m_isSinkArc[e]) - m_Gamma.joinFaces(e); - } - - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); - - //computeSinkSwitches(); - FaceSinkGraph fsg(m_Gamma, s_hat); - List dummyList; - FaceArray< List > sinkSwitches(m_Gamma, dummyList); - fsg.sinkSwitches(sinkSwitches); - - //construct sinkArc for the dirty faces - List< Tuple2 > l; - forall_listiterators(adjEntry, it, dirtyList) { - face fLeft = m_Gamma.leftFace(*it); - face fRight = m_Gamma.rightFace(*it); - List switches = sinkSwitches[fLeft]; - - OGDF_ASSERT(!switches.empty()); - - constructSinkArcs(fLeft, switches.front()->theNode()); - - OGDF_ASSERT(!switches.empty()); - - switches = sinkSwitches[fRight]; - constructSinkArcs(fRight, switches.front()->theNode()); - } - - m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); - computeSinkSwitches(); -} - - - -void UpwardPlanRep::constructSinkArcs(face f, node t) -{ - List srcList; - adjEntry adjTgt; - - if (f != m_Gamma.externalFace()) { - adjEntry adj; - forall_face_adj(adj, f) { - node v = adj->theNode(); - if (v == adj->theEdge()->target() && adj->faceCyclePred()->theEdge()->target() == v) { - if (v != t) - srcList.pushBack(adj); - else - adjTgt = adj; // top-sink-switch of f - } - } - // contruct the sink arcs - while(!srcList.empty()) { - adjEntry adjSrc = srcList.popFrontRet(); - edge eNew; - if (t->degree() == 0) - eNew = m_Gamma.splitFace(adjSrc, t); - else { - adjEntry adjTgt = getAdjEntry(m_Gamma, t, m_Gamma.rightFace(adjSrc)); - eNew = m_Gamma.splitFace(adjSrc, adjTgt); - } - m_isSinkArc[eNew] = true; - } - } - else { - adjEntry adj; - forall_face_adj(adj, f) { - node v = adj->theNode(); - - OGDF_ASSERT(s_hat != 0); - - if (v->outdeg() == 0 && v != t_hat) - srcList.pushBack(adj); - } - - // contruct the sink arcs - while(!srcList.empty()) { - adjEntry adjSrc = srcList.popFrontRet(); - edge eNew; - if (adjSrc->theNode() == adjSrc->theEdge()->source()) // on the right face part of the ext. face - adjTgt = extFaceHandle; - else - adjTgt = extFaceHandle->cyclicPred(); // on the left face part - - eNew = m_Gamma.splitFace(adjSrc, adjTgt); - m_isSinkArc[eNew] = true; - } - - } -} - - -void UpwardPlanRep::computeSinkSwitches() -{ - OGDF_ASSERT(m_Gamma.externalFace() != 0); - - if (s_hat == 0) - hasSingleSource(*this, s_hat); - FaceSinkGraph fsg(m_Gamma, s_hat); - List dummyList; - FaceArray< List > sinkSwitches(m_Gamma, dummyList); - fsg.sinkSwitches(sinkSwitches); - m_sinkSwitchOf.init(*this, 0); - - face f; - forall_faces(f, m_Gamma) { - List switches = sinkSwitches[f]; - ListIterator it = switches.begin(); - for (it = it.succ(); it.valid(); it++) { - m_sinkSwitchOf[(*it)->theNode()] = (*it); - } - } -} - - -void UpwardPlanRep::initMe() -{ - m_Gamma.init(*this); - isAugmented = false; - - FaceSinkGraph fsg(m_Gamma, s_hat); - SList extFaces; - fsg.possibleExternalFaces(extFaces); - - OGDF_ASSERT(!extFaces.empty()); - - face f_ext = 0; - forall_slistiterators(face, it, extFaces) { - if (f_ext == 0) - f_ext = *it; - else { - if (f_ext->size() < (*it)->size()) - f_ext = *it; - } - } - m_Gamma.setExternalFace(f_ext); - adjEntry adj; - forall_adj(adj, s_hat) { - if (m_Gamma.rightFace(adj) == m_Gamma.externalFace()) { - extFaceHandle = adj; - break; - } - } - - computeSinkSwitches(); -} - - -} diff --git a/ext/OGDF/src/upward/UpwardPlanarModule.cpp b/ext/OGDF/src/upward/UpwardPlanarModule.cpp deleted file mode 100644 index d08d7a2b2..000000000 --- a/ext/OGDF/src/upward/UpwardPlanarModule.cpp +++ /dev/null @@ -1,1405 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class UpwardPlanarModule... - * - * ...which represents the upward-planarity testing and embedding - * algorithm for single-source digraphs. - * Reference: "Optimal upward planarity testing of single-source - * digraphs" P. Bertolazzi, G. Di Battista, C. Mannino, and - * R. Tamassia, SIAM J.Comput., 27(1) Feb. 1998, pp. 132-169 - * - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include - - -namespace ogdf { - - -//--------------------------------------------------------- -// SkeletonInfo -//--------------------------------------------------------- -class UpwardPlanarModule::SkeletonInfo -{ -public: - SkeletonInfo() { } - SkeletonInfo(const Skeleton &S) : - m_degInfo(S.getGraph()), m_containsSource(S.getGraph(),false) - { } - - void init(const Skeleton &S) { - m_degInfo.init(S.getGraph()); - m_containsSource.init(S.getGraph(),false); - } - - EdgeArray m_degInfo; - EdgeArray m_containsSource; - ConstCombinatorialEmbedding m_E; - FaceSinkGraph m_F; - SList m_externalFaces; -}; - - - -//--------------------------------------------------------- -// ConstraintRooting -// maintains constraints set during upward-planarity test -// on rooting of SPQR-tree -//--------------------------------------------------------- -class UpwardPlanarModule::ConstraintRooting -{ -public: - ConstraintRooting(const SPQRTree &T); - - // constrains a Q-node vQ associated with real edge e to be directed - // leaving vQ - void constrainRealEdge(edge e); - - // constrains a tree edge e in original SPQR-tree T to be directed - // leaving src; returns false iff e was already constrained to be directed - // in opposite direction - bool constrainTreeEdge(edge e, node src); - - // if a roting satisfying all constraints exits, return a real edge at - // which the SPQR-tree can be rooted, otherwise 0 is returned - edge findRooting(); - - void outputConstraints(ostream &os); - - // avoid automatic creation of assignment operator - ConstraintRooting &operator=(const ConstraintRooting &); - -private: - bool checkEdge(edge e, node parent, EdgeArray &checked); - - Graph m_tree; // tree with Q-nodes - const SPQRTree &m_T; // original SPQR-tree - - // edge in m_tree corresponding to real edge - EdgeArray m_realToConstraint; - // node in m_tree corresponding to node in original SPQR-tree T - NodeArray m_internalNode; - // edge in m_tree corresponding to edge in original SPQR-tree T - EdgeArray m_treeToConstraint; - // true <=> edge in m_tree has been constrained - EdgeArray m_isConstrained; -}; - - -// constructor -// builds copy of SPQR-tree with Q-nodes -UpwardPlanarModule::ConstraintRooting::ConstraintRooting(const SPQRTree &T) : - m_T(T), m_isConstrained(m_tree,false) -{ - const Graph > = T.tree(); - - m_internalNode.init(GT); - - node v; - forall_nodes(v,GT) - m_internalNode[v] = m_tree.newNode(); - - m_treeToConstraint.init(GT); - - edge e; - forall_edges(e,GT) { - m_treeToConstraint[e] = m_tree.newEdge( - m_internalNode[e->source()],m_internalNode[e->target()]); - } - - // create Q-nodes and adjacent edges - const Graph &G = T.originalGraph(); - m_realToConstraint.init(G); - - forall_edges(e,G) { - node qNode = m_tree.newNode(); - node internal = m_internalNode[T.skeletonOfReal(e).treeNode()]; - // An edge adjacent with a Q-node qNode is always directed leaving - // qNode because this is the only constraint used for those edges. - // If we have to constrain such an edge, we simply mark it constrained - // because it is already directed correctly. - m_realToConstraint[e] = m_tree.newEdge(qNode,internal); - } -} - - -// output for debugging -void UpwardPlanarModule::ConstraintRooting::outputConstraints(ostream &os) -{ - const Graph &G = m_T.originalGraph(); - const Graph > = m_T.tree(); - - os << "constrained edges in tree:\n"; - os << "real edges:"; - - edge e; - forall_edges(e,G) { - if (m_isConstrained[m_realToConstraint[e]]) - os << " " << e; - } - - os << "\ntree edges:"; - forall_edges(e,GT) { - if (m_isConstrained[m_treeToConstraint[e]]) { - if(m_internalNode[e->source()] == m_treeToConstraint[e]->source()) - os << " " << e->source() << "->" << e->target(); - else - os << " " << e->target() << "->" << e->source(); - } - } - os << endl; -} - - - -// constrains a real edge to be directed leaving its Q-node -// (such a Q-node cannot be selected as root node) -void UpwardPlanarModule::ConstraintRooting::constrainRealEdge(edge e) -{ - m_isConstrained[m_realToConstraint[e]] = true; -} - - -// constrains a tree edge to be directed leaving src -// if it was already constrained to be directed in opposite direction -// false is returned and no rooting of the tree is possible -bool UpwardPlanarModule::ConstraintRooting::constrainTreeEdge( - edge e, - node src) -{ - OGDF_ASSERT(src == e->source() || src == e->target()); - - edge eTree = m_treeToConstraint[e]; - node srcTree = m_internalNode[src]; - - // tree edge in wrong direction ? - if (srcTree != eTree->source()) - { - // if it was already constriant we have a contradiction - if (m_isConstrained[eTree] == true) - return false; - - m_tree.reverseEdge(eTree); - } - - m_isConstrained[eTree] = true; - return true; -} - - -// find a rooting of the tree satisfying all constraints -// if such a rooting exists, a root edge is returned (an edge in the -// original graph), otherwise 0 is returned -edge UpwardPlanarModule::ConstraintRooting::findRooting() -{ - EdgeArray checked(m_tree,false); - - // we check each constrained edge - // such a constraint constrains the complete subtree rooted at - // e->source(), hence procedure checkEdge() recursively checks - // all (not-checked) edges in this subtree - edge e; - forall_edges(e,m_tree) { - if (m_isConstrained[e]) { - if (checkEdge(e,e->target(),checked) == false) - return 0; - } - } - - // if all constraints are checked, we can find a rooting iff there is - // a Q-node whose (only) adjacent edge was not constrained - const Graph &G = m_T.originalGraph(); - forall_edges(e,G) { - edge eQ = m_realToConstraint[e]; - - if(checked[eQ] == false) - return e; - } - - return 0; -} - - -bool UpwardPlanarModule::ConstraintRooting::checkEdge( - edge e, - node parent, - EdgeArray &checked) -{ - if (checked[e]) - return (e->target() == parent); - - if (e->target() != parent) { - if (m_isConstrained[e]) - return false; - else - m_tree.reverseEdge(e); - } - - checked[e] = true; - node child = e->source(); - - edge eAdj; - forall_adj_edges(eAdj,child) { - if (eAdj != e) { - if (checkEdge(eAdj,child,checked) == false) - return false; - } - } - - return true; -} - - - -//--------------------------------------------------------- -// UpwardPlanarModule -//--------------------------------------------------------- - -//--------------------------------------------------------- -// embedded digraphs -//--------------------------------------------------------- - -// -// tests if an embeddeding of a planar biconnected single-source graph is -// upward and, if it is, returns the list of possible external faces -// Remark: the external face which is set in E is ignored! -bool UpwardPlanarModule::testEmbeddedBiconnected( - const Graph &G, // embedded input graph - const ConstCombinatorialEmbedding &E, // embedding of G - SList &externalFaces) // returns list of possible external faces -{ - OGDF_ASSERT(G.representsCombEmbedding()); - //OGDF_ASSERT(isBiconnected(G)); - - if(isAcyclic(G) == false) - return false; - - - // the single source in G - node s = getSingleSource(G); - OGDF_ASSERT(s != 0); - - FaceSinkGraph F(E,s); - - // find possible external faces (the faces in T containing s) - externalFaces.clear(); - F.possibleExternalFaces(externalFaces); - - return !externalFaces.empty(); -} - - -bool UpwardPlanarModule::testAndAugmentEmbedded( - Graph &G, // embedded input graph - SList &augmentedNodes, - SList &augmentedEdges) -{ - OGDF_ASSERT(G.representsCombEmbedding()); - - if(isAcyclic(G) == false) - return false; - - // the single source in G - node s = getSingleSource(G); - OGDF_ASSERT(s != 0); - - ConstCombinatorialEmbedding E(G); - FaceSinkGraph F(E,s); - - // find possible external faces (the faces in T containing s) - SList externalFaces; - F.possibleExternalFaces(externalFaces); - - if (externalFaces.empty()) - return false; - - else { - F.stAugmentation(F.faceNodeOf(externalFaces.front()),G,augmentedNodes,augmentedEdges); - return true; - } - -} - - -bool UpwardPlanarModule::testAndAugmentEmbedded( - Graph &G, // embedded input graph - node &superSink, - SList &augmentedEdges) -{ - OGDF_ASSERT(G.representsCombEmbedding()); - - if(isAcyclic(G) == false) - return false; - - // the single source in G - node s = getSingleSource(G); - OGDF_ASSERT(s != 0); - - ConstCombinatorialEmbedding E(G); - FaceSinkGraph F(E,s); - - - // find possible external faces (the faces in T containing s) - SList externalFaces; - F.possibleExternalFaces(externalFaces); - - if (externalFaces.empty()) - return false; - - else { - F.stAugmentation(F.faceNodeOf(externalFaces.front()),G,superSink,augmentedEdges); - return true; - } - -} - - -// finds the single source in G; if it does not exist, returns 0 -node UpwardPlanarModule::getSingleSource(const Graph &G) -{ - node singleSource = 0; - node v; - forall_nodes(v,G) { - if (v->indeg() == 0) { - if (singleSource == 0) - singleSource = v; - else // we have more than one source! - return 0; - } - } - - return singleSource; -} - - - -//--------------------------------------------------------- -// general case -//--------------------------------------------------------- - -// tests if a single-source digraph G is upward-planar -// computes sorted adjacency lists of an upward-planar embedding if -// embed is true -bool UpwardPlanarModule::doUpwardPlanarityTest( - Graph &G, - bool embed, - NodeArray > &adjacentEdges) -{ - // test whether G is acyclic - if (isAcyclic(G) == false) - return false; - - // build expansion graph of G - ExpansionGraph exp(G); - - // determine single source; if not present (or several sources) test fails - node sG = getSingleSource(G); - if (sG == 0) - return false; - - // If embed is true we compute also the list of adjacency entries for each - // node of G in an upward planar embedding. - // Function testBiconnectedComponent() iterates over all biconnected - // components of exp starting with the components adjacent to the single - // source in exp. - return testBiconnectedComponent(exp,sG,-1,embed,adjacentEdges); -} - - -// embeds single-source digraph G upward-planar -// also computes a planar st-augmentation of G and returns the list of -// augmented nodes and edges if augment is true -void UpwardPlanarModule::doUpwardPlanarityEmbed( - Graph &G, - NodeArray > &adjacentEdges, - bool augment, - SList &augmentedNodes, - SList &augmentedEdges) -{ - node vG; - forall_nodes(vG,G) { - G.sort(vG, adjacentEdges[vG]); - } - - // the following tests check if the assigned embedding is upward planar - OGDF_ASSERT(G.consistencyCheck()); - OGDF_ASSERT(G.representsCombEmbedding()); - -#ifdef OGDF_DEBUG - if(!augment) { - CombinatorialEmbedding E(G); - SList externalFaces; - OGDF_ASSERT(testEmbeddedBiconnected(G,E,externalFaces)); - } -#endif - - if (augment) - { -#ifdef OGDF_DEBUG - bool isUpwardPlanar = -#endif - testAndAugmentEmbedded(G,augmentedNodes,augmentedEdges); - OGDF_ASSERT(isUpwardPlanar); - } -} - - -// embeds single-source digraph G upward-planar -// also computes a planar st-augmentation of G and returns the list of -// augmented nodes and edges if augment is true -void UpwardPlanarModule::doUpwardPlanarityEmbed( - Graph &G, - NodeArray > &adjacentEdges, - bool augment, - node &superSink, - SList &augmentedEdges) -{ - node vG; - forall_nodes(vG,G) { - G.sort(vG, adjacentEdges[vG]); - } - - // the following tests check if the assigned embedding is upward planar - OGDF_ASSERT(G.consistencyCheck()); - OGDF_ASSERT(G.representsCombEmbedding()); - -#ifdef OGDF_DEBUG - if(!augment) { - CombinatorialEmbedding E(G); - SList externalFaces; - OGDF_ASSERT(testEmbeddedBiconnected(G,E,externalFaces)); - } -#endif - - if (augment) - { -#ifdef OGDF_DEBUG - bool isUpwardPlanar = -#endif - testAndAugmentEmbedded(G,superSink,augmentedEdges); - OGDF_ASSERT(isUpwardPlanar); - } -} - - -// performs the actual test (and computation of sorted adjacency lists) for -// each biconnected component -// Within this procedure all biconnected components in which sG is (the -// original vertex) of the single-source are handled, for all other vertices -// in the biconnected component the procedure is called recursively. -// This kind of traversal is crucial for the embedding algorithm -bool UpwardPlanarModule::testBiconnectedComponent( - ExpansionGraph &exp, - node sG, - int parentBlock, - bool embed, - NodeArray > &adjacentEdges) -{ - SListConstIterator itBlock; - for(itBlock = exp.adjacentComponents(sG).begin(); - itBlock.valid(); ++itBlock) - { - int i = *itBlock; - if (i == parentBlock) continue; - - exp.init(i); - - // cannot construct SPQR-tree of graph with a single edge so treat - // it as special case here - if (exp.numberOfNodes() == 2) { - edge eST = exp.original(exp.firstEdge()); - if(embed) { - node src = eST->source(); - node tgt = eST->target(); - - edge e; - forall_edges(e,exp) { - edge eG = exp.original(e); - adjacentEdges[src].pushBack(eG->adjSource()); - adjacentEdges[tgt].pushFront(eG->adjTarget()); - } - } - - bool testOk = - testBiconnectedComponent(exp,eST->target(),i,embed,adjacentEdges); - if (!testOk) - return false; - - continue; - } - - // test whether expansion graph is planar - if (isPlanar(exp) == false) - return false; - - // construct SPQR-tree T of exp with embedded skeleton graphs - StaticPlanarSPQRTree T(exp); - const Graph &tree = T.tree(); - - // skeleton info maintains precomputed information, i.e., degrees of - // nodes in expansion graph of virtual edges, if expansion graph - // constains the single source - NodeArray skInfo(tree); - node vT; - forall_nodes(vT,tree) - skInfo[vT].init(T.skeleton(vT)); - - // the single source in exp - node s = exp.copy(sG); - OGDF_ASSERT(exp.original(s) == sG); - - // precompute information maintained in skInfo - // for each virtual edge e of a skeleton, determine its in- and - // outdegree in the pertinent digraph of e; also determine if the - // pertinent digraph of e contains the source - computeDegreesInPertinent(T,s,skInfo,T.rootNode()); - - OGDF_ASSERT_IF(dlConsistencyChecks, checkDegrees(T,s,skInfo)); - - // For each R-node vT: - // compute its sT-skeleton, test whether the sT-skeleton is upward- - // planar - // mark the virtual edges of skeleton(vT) whose endpoints are on the - // external face in some upward-drawing of the sT-skeleton of vT - // for each unmarked edge e of skeleton(vT), constrain the tree - // edge associated with e to be directed towards vT - // if the source is not in skeleton(vT), let wT be the node neighbour - // of vT whose pertinet digraph contains the source, and constrain - // the tree edge (vT.wT) to be directed towards wT - // - // Determine whether T can be rooted at a Q-node in such a way that - // orienting edges from children to parents satisfies the constraints - // above. Procedure directSkeletons() returns true iff such a rooting - // exists - edge eRoot = directSkeletons(T,skInfo); - - - if (eRoot == 0) - return false; - - OGDF_ASSERT(exp.consistencyCheck()); - - if(embed) - { - T.rootTreeAt(eRoot); - - embedSkeleton(exp,T,skInfo,T.rootNode(),true); - - T.embed(exp); - OGDF_ASSERT(exp.consistencyCheck()); - - OGDF_ASSERT(exp.representsCombEmbedding()); - CombinatorialEmbedding E(exp); - - FaceSinkGraph F(E,s); - - // find possible external faces (the faces in T containing s) - //externalFaces.clear(); - SList externalFaces; - F.possibleExternalFaces(externalFaces); - - OGDF_ASSERT(!externalFaces.empty()); - - face extFace = externalFaces.front(); - - NodeArray assignedFace(exp,0); - assignSinks(F,extFace,assignedFace); - - adjEntry adj1 = 0; - forall_adj(adj1,s) { - if(E.leftFace(adj1) == extFace) - break; - } - - OGDF_ASSERT(adj1 != 0); - - // handle (single) source - adjacentEdges[sG].pushBack( - exp.original(adj1->theEdge())->adjSource()); - - adjEntry adj; - for(adj = adj1->cyclicSucc(); adj != adj1; adj = adj->cyclicSucc()) { - adjacentEdges[sG].pushBack( - exp.original(adj->theEdge())->adjSource()); - } - - // handle internal vertices - edge e; - forall_edges(e,exp) - { - if(exp.original(e)) continue; - - node vG = exp.original(e->source()); - adj1 = e->adjSource(); - for(adj = adj1->cyclicSucc(); adj != adj1; - adj = adj->cyclicSucc()) - { - adjacentEdges[vG].pushBack( - exp.original(adj->theEdge())->adjTarget()); - } - - adj1 = e->adjTarget(); - for(adj = adj1->cyclicSucc(); adj != adj1; - adj = adj->cyclicSucc()) - { - adjacentEdges[vG].pushBack( - exp.original(adj->theEdge())->adjSource()); - } - } // iterate over internal vertices (associated expansion edge) - - // handle sinks - node v; - forall_nodes(v,exp) - { - if (v->outdeg() > 0) continue; - node vG = exp.original(v); - - adj1 = 0; - forall_adj(adj1,v) { - if(E.leftFace(adj1) == assignedFace[v]) - break; - } - - OGDF_ASSERT(adj1 != 0); - - adjacentEdges[vG].pushBack( - exp.original(adj1->theEdge())->adjTarget()); - - for(adj = adj1->cyclicSucc(); adj != adj1; adj = adj->cyclicSucc()) { - adjacentEdges[vG].pushBack( - exp.original(adj->theEdge())->adjTarget()); - } - } // iterate over sinks - } // embed - - - // for each cut-vertex, process all components different from i - SListPure origNodes; - node v; - forall_nodes(v,exp) { - node vG = exp.original(v); - - if (vG && vG != sG) - origNodes.pushBack(vG); - } - - SListConstIterator itV; - for(itV = origNodes.begin(); itV.valid(); ++itV) { - bool testOk = - testBiconnectedComponent(exp,*itV,i,embed,adjacentEdges); - if (!testOk) - return false; - } - - } - - return true; -} - - -// checks if precomputed in-/outdegrees in pertinet graphs are correctly -// (for debugging only) -bool UpwardPlanarModule::checkDegrees( - SPQRTree &T, - node s, - NodeArray &skInfo) -{ - const Graph &tree = T.tree(); - - node vT; - forall_nodes(vT,tree) - { - T.rootTreeAt(vT); - - const Skeleton &S = T.skeleton(vT); - const Graph &M = S.getGraph(); - - edge e; - forall_edges(e,M) { - node wT = S.twinTreeNode(e); - if (wT == 0) continue; - - PertinentGraph P; - T.pertinentGraph(wT,P); - - Graph &Gp = P.getGraph(); - - if (P.referenceEdge()) - Gp.delEdge(P.referenceEdge()); - - node x = 0, y = 0, v; - forall_nodes(v,Gp) { - if (P.original(v) == S.original(e->source())) - x = v; - if (P.original(v) == S.original(e->target())) - y = v; - } - - OGDF_ASSERT(x != 0 && y != 0); - - const DegreeInfo °Info = skInfo[vT].m_degInfo[e]; - if(x->indeg() != degInfo.m_indegSrc) - return false; - if(x->outdeg() != degInfo.m_outdegSrc) - return false; - if(y->indeg() != degInfo.m_indegTgt) - return false; - if(y->outdeg() != degInfo.m_outdegTgt) - return false; - - bool contSource = false; - forall_nodes(v,Gp) { - if (v != x && v != y && P.original(v) == s) - contSource = true; - } - - if (skInfo[vT].m_containsSource[e] != contSource) - return false; - } - } - - return true; -} - - -// precompute information: in-/outdegrees in pertinent graph, contains -// pertinent graph the source? -void UpwardPlanarModule::computeDegreesInPertinent( - const SPQRTree &T, - node s, - NodeArray &skInfo, - node vT) -{ - const Skeleton &S = T.skeleton(vT); - const Graph &M = S.getGraph(); - EdgeArray °Info = skInfo[vT].m_degInfo; - EdgeArray &containsSource = skInfo[vT].m_containsSource; - - // recursively compute in- and outdegrees at virtual edges except for - // the reference edge of S; additionally compute if source is contained - // in pertinent (and no endpoint of reference edge) - edge eT; - forall_adj_edges(eT,vT) { - node wT = eT->target(); - if (wT != vT) - computeDegreesInPertinent(T,s,skInfo,wT); - } - - edge eRef = S.referenceEdge(); - node src = eRef->source(); - node tgt = eRef->target(); - - bool contSource = false; - node v; - forall_nodes(v,M) { - if (v != src && v != tgt && S.original(v) == s) - contSource = true; - } - - // the in- and outdegree at real edges is obvious ... - // m_containsSource is set to false by default - edge e; - forall_edges(e,M) { - if (S.isVirtual(e) == false) { - degInfo[e].m_indegSrc = 0; - degInfo[e].m_outdegSrc = 1; - degInfo[e].m_indegTgt = 1; - degInfo[e].m_outdegTgt = 0; - } else if (e != eRef) { - contSource |= containsSource[e]; - } - } - - - if (vT == T.rootNode()) - return; // no virtual reference edge - - - // compute in- and outdegree of poles of reference edge in pertinent graph - // of reference edge - - int indegSrc = 0; - int outdegSrc = 0; - {forall_adj_edges(e,src) { - if (e == eRef) continue; - if (e->source() == src) { - indegSrc += degInfo[e].m_indegSrc; - outdegSrc += degInfo[e].m_outdegSrc; - } else { - indegSrc += degInfo[e].m_indegTgt; - outdegSrc += degInfo[e].m_outdegTgt; - } - }} - - int indegTgt = 0; - int outdegTgt = 0; - {forall_adj_edges(e,tgt) { - if (e == eRef) continue; - if (e->source() == tgt) { - indegTgt += degInfo[e].m_indegSrc; - outdegTgt += degInfo[e].m_outdegSrc; - } else { - indegTgt += degInfo[e].m_indegTgt; - outdegTgt += degInfo[e].m_outdegTgt; - } - }} - - // set degrees at reference edge - node srcOrig = S.original(src); - degInfo[eRef].m_indegSrc = srcOrig->indeg () - indegSrc; - degInfo[eRef].m_outdegSrc = srcOrig->outdeg() - outdegSrc; - - node tgtOrig = S.original(tgt); - degInfo[eRef].m_indegTgt = tgtOrig->indeg() - indegTgt; - degInfo[eRef].m_outdegTgt = tgtOrig->outdeg() - outdegTgt; - - containsSource[eRef] = (contSource == false && - s != S.original(src) && s != S.original(tgt)); - - // set degres at twin edge of reference edge - node wT = S.twinTreeNode(eRef); - DegreeInfo °InfoTwin = skInfo[wT].m_degInfo[S.twinEdge(eRef)]; - degInfoTwin.m_indegSrc = indegSrc; - degInfoTwin.m_outdegSrc = outdegSrc; - degInfoTwin.m_indegTgt = indegTgt; - degInfoTwin.m_outdegTgt = outdegTgt; - - skInfo[wT].m_containsSource[S.twinEdge(eRef)] = contSource; -} - - -// by default, corresponding virtual edges should be oriented in the -// same directions, i.e., the original nodes of source/target are equal -// this procedure serves to assert that this really holds! -bool UpwardPlanarModule::virtualEdgesDirectedEqually(const SPQRTree &T) -{ - node v; - forall_nodes(v,T.tree()) - { - const Skeleton &S = T.skeleton(v); - const Graph &M = S.getGraph(); - - edge e; - forall_edges(e,M) { - edge eTwin = S.twinEdge(e); - - if (eTwin == 0) continue; - - const Skeleton &STwin = T.skeleton(S.twinTreeNode(e)); - - if (S.original(e->source()) != STwin.original(eTwin->source())) - return false; - - if (S.original(e->target()) != STwin.original(eTwin->target())) - return false; - } - } - - return true; -} - - -// compute sT-skeletons -// test for upward-planarity, build constraints for rooting, and find a -// rooting of the tree satisfying all constraints -// returns true iff such a rooting exists -edge UpwardPlanarModule::directSkeletons( - SPQRTree &T, - NodeArray &skInfo) -{ - const Graph &tree = T.tree(); - ConstraintRooting rooting(T); - - // we assume that corresponding virtual edges are directed equally before, - // i.e., the original nodes of the sources are equal and the original nodes - // of the targets are equal - OGDF_ASSERT(virtualEdgesDirectedEqually(T)); - - node vT; - forall_nodes(vT,tree) - { - const StaticSkeleton &S = *dynamic_cast(&T.skeleton(vT)); - const Graph &M = S.getGraph(); - - edge e; - forall_edges(e,M) { - edge eTwin = S.twinEdge(e); - if (eTwin == 0) continue; - - const DegreeInfo °Info = skInfo[vT].m_degInfo[e]; - bool contSource = skInfo[vT].m_containsSource[e]; - - node u = e->source(); - node v = e->target(); - // K = pertinent subgraph of e - // K^0 = K - {u,v} - - const DegreeInfo °InfoTwin = - skInfo[S.twinTreeNode(e)].m_degInfo[eTwin]; - - bool uTwinIsSource = (degInfoTwin.m_indegSrc == 0); - bool vTwinIsSource = (degInfoTwin.m_indegTgt == 0); - - // Rule 1 - // u and v are sources of K - if(degInfo.m_indegSrc == 0 && degInfo.m_indegTgt == 0) { - // replace e by a peak - T.replaceSkEdgeByPeak(vT,e); - - // Rule 2 - // u is a source of K and v is a sink of K - } else if (degInfo.m_indegSrc == 0 && degInfo.m_outdegTgt == 0) { - // s not in K^0 ? - if (!contSource) { - // a directed edge (u,v) - T.directSkEdge(vT,e,u); - } else { - // a peak - T.replaceSkEdgeByPeak(vT,e); - } - - // Rule 2' - // v is a source of K and u is a sink of K - } else if (degInfo.m_indegTgt == 0 && degInfo.m_outdegSrc == 0) { - // s not in K^0 ? - if (!contSource) { - // a directed edge (v,u) - T.directSkEdge(vT,e,v); - } else { - // a peak - T.replaceSkEdgeByPeak(vT,e); - } - - - // Rule 3 - // u is a source of K and v is an internal vertex of K - } else if (degInfo.m_indegSrc == 0 && - degInfo.m_indegTgt > 0 && degInfo.m_outdegTgt > 0) { - - // v is a source of G-K and s not in K^0 - if (vTwinIsSource && contSource == false) { - // a directed edge (u,v) - T.directSkEdge(vT,e,u); - } else { - // a peak - T.replaceSkEdgeByPeak(vT,e); - } - - // Rule 3' - // v is a source of K and u is an internal vertex of K - } else if (degInfo.m_indegTgt == 0 && - degInfo.m_indegSrc > 0 && degInfo.m_outdegSrc > 0) { - - // u is a source of G-K and s not in K^0 - if (uTwinIsSource && contSource == false) { - // a directed edge (v,u) - T.directSkEdge(vT,e,v); - } else { - // a peak - T.replaceSkEdgeByPeak(vT,e); - } - - // Rule 4 - // u and v ar not source of K - } else { - // u is a source of G-K - if (uTwinIsSource) { - // a directed edge (u,v) - T.directSkEdge(vT,e,u); - } else { - // a directed edge (v,u) - T.directSkEdge(vT,e,v); - } - } - } - - - // at this point, the sT-skeleton of vT is computed - - // if the source is not in skeleton(vT), let eWithSource be the virtual - // edge in skeleton(vT) whose expansion graph contains the source - edge eWithSource = 0; - forall_edges(e,M) { - if (skInfo[vT].m_containsSource[e]) { - eWithSource = e; - break; - } - } - - // constrain the tree edge associated with eWithSource to be directed - // leaving vT - if (eWithSource) { - if (rooting.constrainTreeEdge(S.treeEdge(eWithSource),vT) == false) - return 0; - } - - - // test whether the sT-skeletonof vT is upward planar and determine - // the possible external faces - if (!isAcyclic(M)) - return 0; - - // for S- and P-nodes, we know already that they are upward planar - if (T.typeOf(vT) != SPQRTree::RNode) - continue; - - //FaceSinkGraph &F = skInfo[vT].m_F; - //ConstCombinatorialEmbedding &E = skInfo[vT].m_E; - SList &externalFaces = skInfo[vT].m_externalFaces; - - if(initFaceSinkGraph(M,skInfo[vT]) == false) - return 0; - - - // mark the edges of the skeleton of vT whose endpoints are on the - // external face of some upward drawing of the sT-skeleton of vT - EdgeArray marked(M,false); - - SListConstIterator it; - for(it = externalFaces.begin(); it.valid(); ++it) { - adjEntry adj; - forall_face_adj(adj,*it) { - marked[adj] = true; - } - } - - // for each unmarked edge e of the skeleton of vT, constrain the tree - // edge associated with e to be directed towards vT - forall_edges(e,M) { - if (marked[e]) continue; - - edge eT = S.treeEdge(e); - edge eR = S.realEdge(e); - if (eR) - rooting.constrainRealEdge(eR); - else if (eT) { - if (!rooting.constrainTreeEdge(eT,S.twinTreeNode(e))) - return 0; - } - } - } - - - // determine whether T can be rooted at a Q-node in such a way that - // orienting edges from children to parents satisfies the constraints - // above - //rooting.outputConstraints(cout); - edge eRoot = rooting.findRooting(); - - //cout << "\nroot edge: " << eRoot << endl; - - return eRoot; -} - - -// initializes embedding and face-sink graph in skeleton info for -// embedded skeleton graph -// determines the possible external faces and returns true if skeleton -// graph is upward planar -bool UpwardPlanarModule::initFaceSinkGraph( - const Graph &M, - SkeletonInfo &skInfo) -{ - ConstCombinatorialEmbedding &E = skInfo.m_E; - FaceSinkGraph &F = skInfo.m_F; - SList &externalFaces = skInfo.m_externalFaces; - - E.init(M); - node s = getSingleSource(M); - OGDF_ASSERT(s != 0); - - F.init(E,s); - - // find possible external faces (the faces in T containing s) - F.possibleExternalFaces(externalFaces); - - return !externalFaces.empty(); -} - - -// embeds skeleton(vT) and mirrors it if necessary such that the external -// face is to the left of the reference edge iff extFaceIsLeft = true -void UpwardPlanarModule::embedSkeleton( - Graph &G, - StaticPlanarSPQRTree &T, - NodeArray &skInfo, - node vT, - bool extFaceIsLeft) -{ - StaticSkeleton &S = *dynamic_cast(&T.skeleton(vT)); - Graph &M = S.getGraph(); - - edge eRef = S.referenceEdge(); - - // We still have to embed skeletons of P-nodes - if (T.typeOf(vT) == SPQRTree::PNode) { - - node lowerPole = eRef->source(); - - SListPure lowerAdjs, upperAdjs; - - adjEntry adjRef = eRef->adjSource(); - adjEntry adjRefTwin = adjRef->twin(); - - adjEntry adj; - forall_adj(adj, lowerPole) { - // ignore reference edge - if (adj == adjRef) continue; - - adjEntry adjTwin = adj->twin(); - if (S.original(adjTwin->theNode()) == 0) { // peak - lowerAdjs.pushFront(adj); - upperAdjs.pushBack (adjTwin->cyclicSucc()->twin()); - - } else { // non-peak - lowerAdjs.pushBack (adj); - upperAdjs.pushFront(adjTwin); - } - } - - // adjacency entries in lowerAdjs are now sorted: peaks, non-peaks - // (without reference edge) - - // is reference edge a peak - bool isRefPeak = (S.original(eRef->target()) == 0); - adjEntry adjRefUpper = (isRefPeak) ? - (adjRefTwin->cyclicSucc()->twin()) : - adjRefTwin; - - if (isRefPeak) { - // lowerAdjs: ref. peak, other peaks, non-peaks - lowerAdjs.pushFront(adjRef); - upperAdjs.pushBack (adjRefUpper); - } else { - // lowerAdjs: peaks, non-peaks, ref. non-peak - lowerAdjs.pushBack (adjRef); - upperAdjs.pushFront(adjRefUpper); - } - - - M.sort(lowerPole, lowerAdjs); - M.sort(adjRefUpper->theNode(), upperAdjs); - } - - - OGDF_ASSERT(M.representsCombEmbedding()); - - // we still have to compute the face-sink graph for S and P nodes - if(T.typeOf(vT) != SPQRTree::RNode) { -#ifdef OGDF_DEBUG - bool testOk = -#endif - initFaceSinkGraph(M,skInfo[vT]); - OGDF_ASSERT(testOk); - } - - // variables stored in skeleton info - ConstCombinatorialEmbedding &E = skInfo[vT].m_E; - FaceSinkGraph &F = skInfo[vT].m_F; - SList &externalFaces = skInfo[vT].m_externalFaces; - - - // determine a possible external face extFace adjacent to eRef - face fLeft = E.leftFace (eRef->adjSource()); - face fRight = E.rightFace(eRef->adjSource()); - face extFace = 0; - - SListConstIterator it; - for(it = externalFaces.begin(); it.valid(); ++it) { - face f = *it; - if (f == fLeft || f == fRight) - extFace = f; - } - - OGDF_ASSERT(extFace != 0); - - // possibly we have to mirror the embedding of S - bool mirrorEmbedding = (extFaceIsLeft != (extFace == fLeft)); - - // assign sinks to faces (a sink t is assigned to the face above t in - // an upward planar drawing) - NodeArray assignedFace(M,0); - assignSinks(F,extFace,assignedFace); - - - // Traverse SPQR-tree by depth-first search. - // This kind of traversal is required for correctly embedding the - // skeletons (see paper). - edge e; - forall_edges(e,M) - { - edge eT = S.treeEdge(e); - if (eT == 0) continue; - - node wT = eT->target(); - if (wT == vT) continue; - - bool eExtFaceLeft = true; - node p = e->target(); - if(S.original(p) == 0) { - const Skeleton &S2 = T.skeleton(wT); - node vOrig = S2.original(S2.referenceEdge()->source()); - adjEntry adj = e->adjSource(); - - if (S.original(e->source()) != vOrig) - adj = adj->twin()->cyclicSucc()->twin(); - - if(assignedFace[p] == E.rightFace(adj)) - eExtFaceLeft = true; - else { - OGDF_ASSERT(assignedFace[p] == E.leftFace(adj)); - eExtFaceLeft = false; - } - if (mirrorEmbedding) - eExtFaceLeft = !eExtFaceLeft; - } - - // recursive call - embedSkeleton(G,T,skInfo,wT,eExtFaceLeft); - - } // traverse SPQR-tree - - - if(mirrorEmbedding) - T.reverse(vT); - - OGDF_ASSERT_IF(dlConsistencyChecks,M.consistencyCheck()); - - - // We have to unsplit all peaks in skeleton S again, since the embedding - // procedure of StaticPlanarSPQRTree does not support such modified skeletons - // (only reversing skeleton edges is allowed). - node v, vSucc; - for(v = M.firstNode(); v; v = vSucc) - { - vSucc = v->succ(); - - if (S.original(v) == 0) { - OGDF_ASSERT(v->indeg() == 2 && v->outdeg() == 0); - - edge e1 = v->firstAdj()->theEdge(); - edge e2 = v->lastAdj ()->theEdge(); - - if(S.realEdge(e1) != 0 || S.twinEdge(e1) != 0) { - M.reverseEdge(e2); - } else { - OGDF_ASSERT(S.realEdge(e2) != 0 || S.twinEdge(e2) != 0); - M.reverseEdge(e1); - } - - M.unsplit(v); - } - } -} - - -// assigns each sink to a face such that there exists an upward planar drawing -// with exteriour fac extFace in which the assigned face of each sink t is -// above t -void UpwardPlanarModule::assignSinks( - FaceSinkGraph &F, - face extFace, - NodeArray &assignedFace) -{ - // find the representative h of face extFace in face-sink graph F - node h = 0; - node v; - forall_nodes(v,F) { - if (F.originalFace(v) == extFace) { - h = v; break; - } - } - - // find all roots of trees in F different from (the unique tree T) - // rooted at h - SListPure roots; - forall_nodes(v,F) { - node vOrig = F.originalNode(v); - if (vOrig != 0 && vOrig->indeg() > 0 && vOrig->outdeg() > 0) - roots.pushBack(v); - } - - // recursively assign faces to sinks - dfsAssignSinks(F,h,0,assignedFace); - - SListConstIterator itRoots; - for(itRoots = roots.begin(); itRoots.valid(); ++itRoots) - dfsAssignSinks(F,*itRoots,0,assignedFace); -} - - -node UpwardPlanarModule::dfsAssignSinks( - FaceSinkGraph &F, // face-sink graph - node v, // current node - node parent, // its parent - NodeArray &assignedFace) -{ - bool isFace = (F.originalFace(v) != 0); - node vf = 0; - - // we perform a dfs-traversal (underlying graph is a tree) - adjEntry adj; - forall_adj(adj,v) - { - node w = adj->twinNode(); - - if (w == parent) continue; - - if (isFace) { - assignedFace[F.originalNode(w)] = F.originalFace(v); - } - - dfsAssignSinks(F,w,v,assignedFace); - } - - return vf; -} - - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/upward/UpwardPlanarSubgraphModule.cpp b/ext/OGDF/src/upward/UpwardPlanarSubgraphModule.cpp deleted file mode 100644 index a91f7eed5..000000000 --- a/ext/OGDF/src/upward/UpwardPlanarSubgraphModule.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of class UpwardPlanarSubgraphModule - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include - - -namespace ogdf { - - -void UpwardPlanarSubgraphModule::callAndDelete( - GraphCopy &GC, - List &delOrigEdges) -{ - List delEdges; - - call(GC, delEdges); - - ListConstIterator it; - for(it = delEdges.begin(); it.valid(); ++it) { - edge eCopy = *it; - - delOrigEdges.pushBack(GC.original(eCopy)); - GC.delCopy(eCopy); - } -} - - -} // end namespace ogdf diff --git a/ext/OGDF/src/upward/UpwardPlanarSubgraphSimple.cpp b/ext/OGDF/src/upward/UpwardPlanarSubgraphSimple.cpp deleted file mode 100644 index e368934a0..000000000 --- a/ext/OGDF/src/upward/UpwardPlanarSubgraphSimple.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * $Revision: 2599 $ - * - * last checkin: - * $Author: chimani $ - * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implements class UpwardPlanarSubgraphSimple which computes - * an upward planar subgraph of a single-source acyclic digraph - * - * \author Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - - -#include -#include -#include -#include - - -namespace ogdf { - - -void UpwardPlanarSubgraphSimple::call(const Graph &G, List &delEdges) -{ - delEdges.clear(); - - // We construct an auxiliary graph H which represents the current upward - // planar subgraph. - Graph H; - NodeArray mapToH(G); - - node v; - forall_nodes(v,G) - mapToH[v] = H.newNode(); - - - // We currently support only single-source acyclic digraphs ... - node s; - hasSingleSource(G,s); - - OGDF_ASSERT(s != 0); - OGDF_ASSERT(isAcyclic(G)); - - // We start with a spanning tree of G rooted at the single source. - NodeArray visitedNode(G,false); - SListPure treeEdges; - dfsBuildSpanningTree(s,treeEdges,visitedNode); - - - // Mark all edges in the spanning tree so they can be skipped in the - // loop below and add (copies of) them to H. - EdgeArray visitedEdge(G,false); - SListConstIterator it; - for(it = treeEdges.begin(); it.valid(); ++it) { - edge eG = *it; - visitedEdge[eG] = true; - H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); - } - - - // Add subsequently the remaining edges to H and test if the resulting - // graph is still upward planar. If not, remove the edge again from H - // and add it to delEdges. - UpwardPlanarModule upm; - - edge eG; - forall_edges(eG,G) - { - if(visitedEdge[eG] == true) - continue; - - edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); - - if (upm.upwardPlanarityTest(H) == false) { - H.delEdge(eH); - delEdges.pushBack(eG); - } - } - -} - - -void UpwardPlanarSubgraphSimple::dfsBuildSpanningTree( - node v, - SListPure &treeEdges, - NodeArray &visited) -{ - visited[v] = true; - - edge e; - forall_adj_edges(e,v) - { - node w = e->target(); - if(w == v) continue; - - if(!visited[w]) { - treeEdges.pushBack(e); - dfsBuildSpanningTree(w,treeEdges,visited); - } - } -} - - - -void UpwardPlanarSubgraphSimple::call(GraphCopy &GC, List &delEdges) -{ - const Graph &G = GC.original(); - delEdges.clear(); - - // We construct an auxiliary graph H which represents the current upward - // planar subgraph. - Graph H; - NodeArray mapToH(G,0); - NodeArray mapToG(H,0); - - node v; - forall_nodes(v,G) - mapToG[ mapToH[v] = H.newNode() ] = v; - - - // We currently support only single-source acyclic digraphs ... - node s; - hasSingleSource(G,s); - - OGDF_ASSERT(s != 0); - OGDF_ASSERT(isAcyclic(G)); - - // We start with a spanning tree of G rooted at the single source. - NodeArray visitedNode(G,false); - SListPure treeEdges; - dfsBuildSpanningTree(s,treeEdges,visitedNode); - - - // Mark all edges in the spanning tree so they can be skipped in the - // loop below and add (copies of) them to H. - EdgeArray visitedEdge(G,false); - SListConstIterator it; - for(it = treeEdges.begin(); it.valid(); ++it) { - edge eG = *it; - visitedEdge[eG] = true; - H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); - } - - - // Add subsequently the remaining edges to H and test if the resulting - // graph is still upward planar. If not, remove the edge again from H - // and add it to delEdges. - UpwardPlanarModule upm; - - SList > augmented; - GraphCopySimple graphAcyclicTest(G); - - edge eG; - forall_edges(eG,G) - { - // already treated ? - if(visitedEdge[eG] == true) - continue; - - // insert edge into H - edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); - - node superSink; - SList augmentedEdges; - if (upm.upwardPlanarAugment(H,superSink,augmentedEdges) == false) { - // if H is no longer upward planar, remove eG from subgraph - H.delEdge(eH); - delEdges.pushBack(eG); - - } else { - // add augmented edges as node-pair to tmpAugmented and remove - // all augmented edges from H again - SList > tmpAugmented; - SListConstIterator it; - for(it = augmentedEdges.begin(); it.valid(); ++it) { - node v = mapToG[(*it)->source()]; - node w = mapToG[(*it)->target()]; - - if (v && w) - tmpAugmented.pushBack(Tuple2(v,w)); - - H.delEdge(*it); - } - - if (mapToG[superSink] == 0) - H.delNode(superSink); - - //**************************************************************** - // The following is a simple workaround to assure the following - // property of the upward planar subgraph: - // The st-augmented upward planar subgraph plus the edges not - // in the subgraph must be acyclic. (This is a special property - // of the embedding, not the augmentation.) - // The upward-planar embedding function gives us ANY upward-planar - // embedding. We check if the property above holds with this - // embedding. If it doesn't, we have actually no idea if another - // embedding would do. - // The better solution would be to incorporate the acyclicity - // property into the upward-planarity test, but this is compicated. - //**************************************************************** - - // test if original graph plus augmented edges is still acyclic - if(checkAcyclic(graphAcyclicTest,tmpAugmented) == true) { - augmented = tmpAugmented; - - } else { - // if not, remove eG from subgraph - H.delEdge(eH); - delEdges.pushBack(eG); - } - } - - } - - // remove edges not in the subgraph from GC - ListConstIterator itE; - for(itE = delEdges.begin(); itE.valid(); ++itE) - GC.delEdge(GC.copy(*itE)); - - // add augmented edges to GC - SListConstIterator > itP; - for(itP = augmented.begin(); itP.valid(); ++itP) { - node v = (*itP).x1(); - node w = (*itP).x2(); - - GC.newEdge(GC.copy(v),GC.copy(w)); - } - - // add super sink to GC - node sGC = 0; - SList sinks; - forall_nodes(v,GC) { - if(v->indeg() == 0) - sGC = v; - if(v->outdeg() == 0) - sinks.pushBack(v); - } - - node superSinkGC = GC.newNode(); - SListConstIterator itV; - for(itV = sinks.begin(); itV.valid(); ++itV) - GC.newEdge(*itV,superSinkGC); - - // add st-edge to GC, so that we now have a planar st-digraph - GC.newEdge(sGC,superSinkGC); - - OGDF_ASSERT(isAcyclic(GC)); - OGDF_ASSERT(isPlanar(GC)); -} - - -// test if graphAcyclicTest plus edges in tmpAugmented is acyclic -// removes added edges again -bool UpwardPlanarSubgraphSimple::checkAcyclic( - GraphCopySimple &graphAcyclicTest, - SList > &tmpAugmented) -{ - SListPure added; - - SListConstIterator > it; - for(it = tmpAugmented.begin(); it.valid(); ++it) - added.pushBack(graphAcyclicTest.newEdge( - graphAcyclicTest.copy((*it).x1()), - graphAcyclicTest.copy((*it).x2()))); - - bool acyclic = isAcyclic(graphAcyclicTest); - - SListConstIterator itE; - for(itE = added.begin(); itE.valid(); ++itE) - graphAcyclicTest.delEdge(*itE); - - return acyclic; -} - - -} // end namespace ogdf - diff --git a/ext/OGDF/src/upward/VisibilityLayout.cpp b/ext/OGDF/src/upward/VisibilityLayout.cpp deleted file mode 100644 index 609b81622..000000000 --- a/ext/OGDF/src/upward/VisibilityLayout.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* - * $Revision: 2559 $ - * - * last checkin: - * $Author: gutwenger $ - * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $ - ***************************************************************/ - -/** \file - * \brief Implementation of visibility layout algorithm. - * - * \author Hoi-Ming Wong and Carsten Gutwenger - * - * \par License: - * This file is part of the Open Graph Drawing Framework (OGDF). - * - * \par - * Copyright (C)
    - * See README.txt in the root directory of the OGDF installation for details. - * - * \par - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 or 3 as published by the Free Software Foundation; - * see the file LICENSE.txt included in the packaging of this file - * for details. - * - * \par - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * \par - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * \see http://www.gnu.org/copyleft/gpl.html - ***************************************************************/ - -#include -#include -#include -#include -#include - -namespace ogdf { - - -void VisibilityLayout::call(GraphAttributes &GA) -{ - if (GA.constGraph().numberOfNodes() <= 1) - return; - - //call upward planarizer - UpwardPlanRep UPR; - UPR.createEmpty(GA.constGraph()); - m_upPlanarizer.get().call(UPR); - layout(GA, UPR); -} - - -void VisibilityLayout::layout(GraphAttributes &GA, const UpwardPlanRep &UPROrig) -{ - UpwardPlanRep UPR = UPROrig; - - //clear some data - edge e; - forall_edges(e, GA.constGraph()) { - GA.bends(e).clear(); - } - - int minGridDist = 1; - node v; - forall_nodes(v, GA.constGraph()) { - if (minGridDist < max(GA.height(v), GA.width(v))) - minGridDist = (int) max(GA.height(v), GA.width(v)); - } - minGridDist = max(minGridDist*2+1, m_grid_dist); - - CombinatorialEmbedding &gamma = UPR.getEmbedding(); - //add edge (s,t) - adjEntry adjSrc = 0; - forall_adj(adjSrc, UPR.getSuperSource()) { - if (gamma.rightFace(adjSrc) == gamma.externalFace()) - break; - } - - OGDF_ASSERT(adjSrc != 0); - - edge e_st = UPR.newEdge(adjSrc, UPR.getSuperSink()); // on the right - gamma.computeFaces(); - gamma.setExternalFace(gamma.rightFace(e_st->adjSource())); - - constructVisibilityRepresentation(UPR); - - // the preliminary postion - NodeArray xPos(UPR); - NodeArray yPos(UPR); - - // node Position - forall_nodes(v, UPR) { - NodeSegment vVis = nodeToVis[v]; - int x = (int) (vVis.x_l + vVis.x_r)/2 ; // median positioning - xPos[v] = x; - yPos[v] = vVis.y; - - if (UPR.original(v) != 0) { - node vOrig = UPR.original(v); - //final position - GA.x(vOrig) = x * minGridDist; - GA.y(vOrig) = vVis.y * minGridDist; - } - } - - //compute bendpoints - forall_edges(e, GA.constGraph()) { - List chain = UPR.chain(e); - forall_listiterators(edge, it, chain) { - edge eUPR = *it; - EdgeSegment eVis = edgeToVis[eUPR]; - if (chain.size() == 1) { - if ((yPos[eUPR->target()] - yPos[eUPR->source()]) > 1) { - DPoint p1(eVis.x*minGridDist, (yPos[eUPR->source()]+1)*minGridDist); - DPoint p2(eVis.x*minGridDist, (yPos[eUPR->target()]-1)*minGridDist); - GA.bends(e).pushBack(p1); - if (yPos[eUPR->source()]+1 != yPos[eUPR->target()]-1) - GA.bends(e).pushBack(p2); - } - } - else { - //short edge - if ((yPos[eUPR->target()] - yPos[eUPR->source()]) == 1) { - if (UPR.original(eUPR->target()) == 0) { - node tgtUPR = eUPR->target(); - DPoint p(xPos[tgtUPR]*minGridDist, yPos[tgtUPR]*minGridDist); - GA.bends(e).pushBack(p); - } - } - //long edge - else { - DPoint p1(eVis.x*minGridDist, (yPos[eUPR->source()]+1)*minGridDist); - DPoint p2(eVis.x*minGridDist, (yPos[eUPR->target()]-1)*minGridDist); - GA.bends(e).pushBack(p1); - if (yPos[eUPR->source()]+1 != yPos[eUPR->target()]-1) - GA.bends(e).pushBack(p2); - if (UPR.original(eUPR->target()) == 0) { - node tgtUPR = eUPR->target(); - DPoint p(xPos[tgtUPR]*minGridDist, yPos[tgtUPR]*minGridDist); - GA.bends(e).pushBack(p); - } - } - } - } - - DPolyline &poly = GA.bends(e); - DPoint pSrc(GA.x(e->source()), GA.y(e->source())); - DPoint pTgt(GA.x(e->target()), GA.y(e->target())); - poly.normalize(pSrc, pTgt); - }//forall_edges -} - - -void VisibilityLayout::constructDualGraph(UpwardPlanRep &UPR) -{ - CombinatorialEmbedding &gamma = UPR.getEmbedding(); - - faceToNode.init(gamma, 0); - leftFace_node.init(UPR, 0); - rightFace_node.init(UPR, 0); - leftFace_edge.init(UPR, 0); - rightFace_edge.init(UPR, 0); - - //construct a node for each face f - face f; - forall_faces(f, gamma) { - faceToNode[f] = D.newNode(); - - if (f == gamma.externalFace()) - s_D = faceToNode[f] ; - - //compute face switches - node s, t; - adjEntry adj; - forall_face_adj(adj, f) { - adjEntry adjNext = adj->faceCycleSucc(); - if (adjNext->theEdge()->source() == adj->theEdge()->source()) - s = adjNext->theEdge()->source(); - if (adjNext->theEdge()->target() == adj->theEdge()->target()) - t = adjNext->theEdge()->target(); - } - - //compute left and right face - bool passSource = false; - if (f == gamma.externalFace()) { - adj = UPR.getSuperSink()->firstAdj(); - if (gamma.rightFace(adj) != gamma.externalFace()) - adj = adj->cyclicSucc(); - } - else - adj = UPR.getAdjEntry(gamma, t, f); - - adjEntry adjBegin = adj; - do { - node v = adj->theEdge()->source(); - if (!passSource) { - if (v != s) - leftFace_node[v] = f; - leftFace_edge[adj->theEdge()] = f; - } - else { - if (v != s) - rightFace_node[v] = f; - rightFace_edge[adj->theEdge()] = f; - } - if (adj->theEdge()->source() == s) - passSource = true; - adj = adj->faceCycleSucc(); - } while(adj != adjBegin); - } - t_D = D.newNode(); // the second (right) node associated with the external face - - //construct dual edges - edge e; - forall_edges(e, UPR) { - face f_r = rightFace_edge[e]; - face f_l = leftFace_edge[e]; - node u = faceToNode[f_l]; - node v = faceToNode[f_r]; - if (f_r == gamma.externalFace() || f_r == f_l) - D.newEdge(u, t_D); - else - D.newEdge(u,v); - } - - OGDF_ASSERT(isConnected(D)); -} - - -void VisibilityLayout::constructVisibilityRepresentation(UpwardPlanRep &UPR) -{ - constructDualGraph(UPR); - //makeSimple(D); - //if (t_D->degree() <= 1) - // D.newEdge(s_D, t_D); // make biconnected - - - //OGDF_ASSERT(isSimple(UPR)); - //OGDF_ASSERT(isBiconnected(UPR)); - //OGDF_ASSERT(isSimple(D)); - //OGDF_ASSERT(isBiconnected(D)); - - //compute top. numbering - NodeArray topNumberUPR(UPR); - NodeArray topNumberD(D); - - topologicalNumbering(UPR, topNumberUPR); - topologicalNumbering(D, topNumberD); - - nodeToVis.init(UPR); - edgeToVis.init(UPR); - - node v; - forall_nodes(v, UPR) { - NodeSegment vVis; - - //cout << "node : " << v << " stNum: " << topNumberUPR[v] << endl; - - if (v == UPR.getSuperSource() || v == UPR.getSuperSink()) { - vVis.y = topNumberUPR[v]; - vVis.x_l = topNumberD[s_D]; - vVis.x_r = topNumberD[t_D]-1; - nodeToVis[v] =vVis; - continue; - } - - vVis.y = topNumberUPR[v]; - face f_v = leftFace_node[v]; - node vD = faceToNode[f_v]; - vVis.x_l = topNumberD[vD]; - f_v = rightFace_node[v]; - vD = faceToNode[f_v]; - vVis.x_r = topNumberD[vD]-1; - nodeToVis[v] =vVis; - } - - edge e; - forall_edges(e, UPR) { - EdgeSegment eVis; - face f_v = leftFace_edge[e]; - node vD = faceToNode[f_v]; - eVis.x = topNumberD[vD]; - eVis.y_b = topNumberUPR[e->source()]; - eVis.y_t = topNumberUPR[e->target()]; - edgeToVis[e] = eVis; - } -} - -}// namespace -- 2.11.4.GIT