/// <summary>
        /// Calculates the graph layout
        /// </summary>
        /// <exception cref="CancelException">Thrown when the layout is canceled.</exception>
#else
        /// <summary>
        /// Calculates the graph layout
        /// </summary>
        /// <exception cref="System.OperationCanceledException">Thrown when the layout is canceled.</exception>
#endif
        public static void CalculateLayout(GeometryGraph geometryGraph, LayoutAlgorithmSettings settings, CancelToken cancelToken) {
            Console.WriteLine("starting CalculateLayout");
            if (settings is RankingLayoutSettings) {
                var rankingLayoutSettings = settings as RankingLayoutSettings;
                var rankingLayout = new RankingLayout(rankingLayoutSettings, geometryGraph);
                rankingLayout.Run(cancelToken);
                RouteAndLabelEdges(geometryGraph, settings, geometryGraph.Edges);
            }
            else if (settings is MdsLayoutSettings) {
                var mdsLayoutSettings = settings as MdsLayoutSettings;
                var mdsLayout = new MdsGraphLayout(mdsLayoutSettings, geometryGraph);
                mdsLayout.Run(cancelToken);
                if (settings.EdgeRoutingSettings.EdgeRoutingMode != EdgeRoutingMode.None)
                    RouteAndLabelEdges(geometryGraph, settings, geometryGraph.Edges);
            }
            else if (settings is FastIncrementalLayoutSettings) {
                var incrementalSettings = settings as FastIncrementalLayoutSettings;
                incrementalSettings.AvoidOverlaps = true;
                var initialLayout = new InitialLayout(geometryGraph, incrementalSettings);
                initialLayout.Run(cancelToken);
                if (settings.EdgeRoutingSettings.EdgeRoutingMode != EdgeRoutingMode.None)
                    RouteAndLabelEdges(geometryGraph, settings, geometryGraph.Edges);
                //incrementalSettings.IncrementalRun(geometryGraph);
            }
            else {
                var sugiyamaLayoutSettings = settings as SugiyamaLayoutSettings;
                if (sugiyamaLayoutSettings != null)
                    ProcessSugiamaLayout(geometryGraph, sugiyamaLayoutSettings, cancelToken);
                else {
                    Debug.Assert(settings is LgLayoutSettings);
                    LayoutLargeGraphWithLayers(geometryGraph, settings, cancelToken);
                }
            }
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="streamPar">the stream to write the graph into</param>
 /// <param name="graphP">the graph</param>
 /// <param name="settings">The settings to be written.</param>
 public GeometryGraphWriter(Stream streamPar, GeometryGraph graphP, LayoutAlgorithmSettings settings) {
     stream = streamPar;
     Graph = graphP;
     Settings = settings;
     var xmlWriterSettings = new XmlWriterSettings {Indent = true};
     XmlWriter = XmlWriter.Create(stream, xmlWriterSettings);
     EdgeEnumeration = graphP.Edges;
 }
        internal static void FixBoundingBox(GeometryGraph component, LayoutAlgorithmSettings settings)
        {
            // Pad the graph with margins so the packing will be spaced out.
            component.Margins = settings.ClusterMargin;
            component.UpdateBoundingBox();

            // Zero the graph
            component.Translate(-component.BoundingBox.LeftBottom);
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="pushingNodes">the nodes are already at the correct positions</param>
 /// <param name="graph"></param>
 /// <param name="layoutSettings"></param>
 public IncrementalDragger(IEnumerable<GeomNode> pushingNodes, GeometryGraph graph, LayoutAlgorithmSettings layoutSettings) {
     this.graph = graph;
     this.nodeSeparation = layoutSettings.NodeSeparation;
     this.layoutSettings = layoutSettings;
     pushingNodesArray = pushingNodes as GeomNode[] ?? pushingNodes.ToArray();
     Debug.Assert(pushingNodesArray.All(n => DefaultClusterParent(n) == null) ||
                   (new Set<GeomNode>(pushingNodesArray.Select(n => n.ClusterParents.First()))).Count == 1,
                             "dragged nodes have to belong to the same cluster");
     InitBumperPushers();
 }
        internal static void RouteEdges(GeometryGraph component, LayoutAlgorithmSettings settings, CancelToken cancelToken)
        {
            EdgeRoutingMode mode = settings.EdgeRoutingSettings.EdgeRoutingMode;

            // Use straight line routing on very large graphs otherwise it is too slow 
            if (component.Nodes.Count >= 2000)
            {
                mode = EdgeRoutingMode.StraightLine;
            }

            switch (mode)
            {
                case EdgeRoutingMode.Spline:
                    var splineRouter = new SplineRouter(
                        component,
                        settings.EdgeRoutingSettings.Padding,
                        settings.NodeSeparation, settings.EdgeRoutingSettings.ConeAngle, null);
                    splineRouter.Run(cancelToken);
                    break;
                case EdgeRoutingMode.SplineBundling:
                    splineRouter = new SplineRouter(
                        component,
                        settings.EdgeRoutingSettings.Padding,
                        settings.NodeSeparation / 20, settings.EdgeRoutingSettings.ConeAngle,
                      new BundlingSettings());
                    splineRouter.Run(cancelToken);
                    break;
                case EdgeRoutingMode.Rectilinear:
                    double edgePadding = settings.EdgeRoutingSettings.Padding;
                    double cornerRadius = settings.EdgeRoutingSettings.CornerRadius;
                    var rectilinearEdgeRouter = new RectilinearEdgeRouter(component, edgePadding, cornerRadius,
                                                                          true);
                    rectilinearEdgeRouter.Run(cancelToken);
                    break;
                case EdgeRoutingMode.StraightLine:
                    var router = new StraightLineEdges(component.Edges,
                                                       settings.EdgeRoutingSettings.Padding);
                    router.Run(cancelToken);
                    break;
            }
        }
        static void ProcessGraphAttrs(Graph graph, GeometryGraph msaglGraph, LayoutAlgorithmSettings settings) {
            msaglGraph.Margins = graph.Attr.Margin;
            var ss = settings as SugiyamaLayoutSettings;
            if (ss != null) {
                switch (graph.Attr.LayerDirection) {
                    case LayerDirection.None:
                    case LayerDirection.TB:
                        break;
                    case LayerDirection.LR:
                        ss.Transformation = PlaneTransformation.Rotation(Math.PI/2);
                        break;
                    case LayerDirection.RL:
                        ss.Transformation = PlaneTransformation.Rotation(-Math.PI/2);
                        break;
                    case LayerDirection.BT:
                        ss.Transformation = PlaneTransformation.Rotation(Math.PI);
                        break;
                    default:
                        throw new InvalidOperationException(); //"unexpected layout direction");
                }

                TransferConstraints(ss, graph);
            }
        }
        public static void Write(GeometryGraph graph, LayoutAlgorithmSettings settings, string fileName) {
            if (fileName == null) return;
            
            if (!fileName.EndsWith(FileExtension, StringComparison.InvariantCultureIgnoreCase))
                fileName += FileExtension;

            using (Stream stream = File.Open(fileName, FileMode.Create)) {
                var graphWriter = new GeometryGraphWriter(stream, graph, settings);
                graphWriter.Write();
            }
        }
 internal void LayoutComponent(LayoutAlgorithmSettings settings, GeometryGraph component) {
     var fdSettings = settings as FastIncrementalLayoutSettings;
     var mdsSettings = settings as MdsLayoutSettings;
     var layeredSettings = settings as SugiyamaLayoutSettings;
     if (fdSettings != null) {
         ForceDirectedLayout(fdSettings, component);
     }
     else if (mdsSettings != null) {
         MDSLayout(mdsSettings, component);
     }
     else if (layeredSettings != null) {
         LayeredLayout(layeredSettings, component);
     }
     else {
         throw new NotImplementedException("Unknown type of layout settings!");
     }
     //LayoutAlgorithmSettings.ShowGraph(component);
 }
 /// <summary>
 /// Recursively lay out the clusters of the given graph using the given settings.
 /// </summary>
 /// <param name="graph">The graph being operated on.</param>
 /// <param name="defaultSettings">Settings to use if none is provided for a particular cluster or its ancestors.</param>
 public InitialLayoutByCluster(GeometryGraph graph, LayoutAlgorithmSettings defaultSettings)
     : this(graph, anyCluster => defaultSettings) {}
 static public void ComputeNodeLabelsOfLargeGraphWithLayers(GeometryGraph geometryGraph, LayoutAlgorithmSettings settings, List<double> noldeLabelRatios, CancelToken cancelToken) {
     var largeGraphLayoutSettings = (LgLayoutSettings)settings;
     var largeGraphLayout = largeGraphLayoutSettings.Interactor;
     largeGraphLayout.InitNodeLabelWidthToHeightRatios(noldeLabelRatios);
     largeGraphLayout.LabelingOfOneRun();
 }
 /// <summary>
 /// calculates all data necessery for large graph browsing
 /// </summary>
 /// <param name="geometryGraph"></param>
 /// <param name="settings"></param>
 /// <param name="cancelToken"></param>
 static public void LayoutLargeGraphWithLayers(GeometryGraph geometryGraph, LayoutAlgorithmSettings settings, CancelToken cancelToken) {
     var largeGraphLayoutSettings = (LgLayoutSettings) settings;
     var largeGraphLayout = new LgInteractor(geometryGraph, largeGraphLayoutSettings, cancelToken);
     largeGraphLayoutSettings.Interactor = largeGraphLayout;
     largeGraphLayout.Run();
 }
        void BindTheGraphs(Graph drawingGraph, GeometryGraph geomGraph, LayoutAlgorithmSettings settings) {
            drawingGraph.GeometryGraph = geomGraph;

            foreach (Node dn in drawingGraph.NodeMap.Values) {
                var geomNode = dn.GeometryNode = geometryGraphReader.FindNodeById(dn.Id);
                geomNode.UserData = dn;
            }

            foreach (var subgraph in drawingGraph.RootSubgraph.AllSubgraphsDepthFirst()) {
                var geomNode = subgraph.GeometryNode = geometryGraphReader.FindClusterById(subgraph.Id);
                if (geomNode != null)
                    geomNode.UserData = subgraph;
            }
            //  geom edges have to appear in the same order as drawing edges
            for(int i = 0;i < EdgeList.Count;i++) {
                var drawingEdge = EdgeList[i];
                var geomEdge = geometryGraphReader.EdgeList[i];
                drawingEdge.GeometryEdge = geomEdge;
                geomEdge.UserData = drawingEdge;
                if(drawingEdge.Label != null) {
                    drawingEdge.Label.GeometryLabel = geomEdge.Label;
                    geomEdge.Label.UserData = drawingEdge.Label;
                }
            }
                
            drawingGraph.LayoutAlgorithmSettings = settings;
        }
 /// <summary>
 /// </summary>
 /// <param name="geometryGraph"></param>
 /// <param name="layoutSettings"></param>
 /// <param name="edgesToRoute"></param>
 public static void RouteAndLabelEdges(GeometryGraph geometryGraph, LayoutAlgorithmSettings layoutSettings, IEnumerable<Edge> edgesToRoute) {
     //todo: what about parent edges!!!!
     var filteredEdgesToRoute =
         edgesToRoute.Where(e => ! e.UnderCollapsedCluster()).ToArray();
     var ers = layoutSettings.EdgeRoutingSettings;
     if (ers.EdgeRoutingMode == EdgeRoutingMode.Rectilinear ||
         ers.EdgeRoutingMode == EdgeRoutingMode.RectilinearToCenter) {
         RectilinearInteractiveEditor.CreatePortsAndRouteEdges(
             layoutSettings.NodeSeparation/3,
             layoutSettings.NodeSeparation/3,
             geometryGraph.Nodes,
             edgesToRoute,
             ers.EdgeRoutingMode,
             true,
             ers.UseObstacleRectangles,
             ers.BendPenalty);
     } else if (ers.EdgeRoutingMode == EdgeRoutingMode.Spline || ers.EdgeRoutingMode==EdgeRoutingMode.SugiyamaSplines) {
         new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle, null)
         {
             ContinueOnOverlaps = true, KeepOriginalSpline = ers.KeepOriginalSpline
         }.Run();
     } else if (ers.EdgeRoutingMode == EdgeRoutingMode.SplineBundling) {
         var edgeBundlingSettings = ers.BundlingSettings ?? new BundlingSettings();
         var bundleRouter = new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle,
                                             edgeBundlingSettings) {
                                                 KeepOriginalSpline = ers.KeepOriginalSpline
                                             };
         bundleRouter.Run();
         if (bundleRouter.OverlapsDetected)
         {
             new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle, null)
             {
                 ContinueOnOverlaps = true,
                 KeepOriginalSpline = ers.KeepOriginalSpline
             }.Run();
         }                
     } else if (ers.EdgeRoutingMode == EdgeRoutingMode.StraightLine) {
         var router = new StraightLineEdges(filteredEdgesToRoute, ers.Padding);
         router.Run();
     }
     var elb = new EdgeLabelPlacement(geometryGraph.Nodes, filteredEdgesToRoute);
     elb.Run();
     geometryGraph.UpdateBoundingBox();
 }
Пример #14
0
        static GeometryGraph GetTestGraphWithClusters(out LayoutAlgorithmSettings settings) {            
            GeometryGraph graph =
                GeometryGraphReader.CreateFromFile(
                    "C:\\dev\\GraphLayout\\MSAGLTests\\Resources\\MSAGLGeometryGraphs\\abstract.msagl.geom",
                    //"E:\\dev\\MSAGL\\GraphLayout\\MSAGLTests\\Resources\\MSAGLGeometryGraphs\\abstract.msagl.geom",
                    out settings);
            foreach (var edge in graph.Edges) {
                edge.Curve = null;
                edge.EdgeGeometry.TargetArrowhead = null;
            }
            graph.UpdateBoundingBox();
            var root = graph.RootCluster;
            var a = new Cluster {UserData = "a"};
            foreach (string id in new[] {"17", "39", "13", "19", "28", "12"})
                a.AddChild(graph.FindNodeByUserData(id));

            var b = new Cluster {UserData = "b"};
            b.AddChild(a);
            b.AddChild(graph.FindNodeByUserData("18"));
            root.AddChild(b);

            var c = new Cluster {UserData = "c"};
            foreach (string id in new[] {"30", "5", "6", "7", "8"})
                c.AddChild(graph.FindNodeByUserData(id));
            root.AddChild(c);

            var clusterNodes = new Set<Node>(root.AllClustersDepthFirst().SelectMany(cl => cl.Nodes));
            foreach (var node in graph.Nodes.Where(n => clusterNodes.Contains(n) == false))
                root.AddChild(node);

            FixClusterBoundariesWithNoRectBoundaries(root, 5);
            var fastIncrementalLayoutSettings = new FastIncrementalLayoutSettings();


            var d=new Dictionary<Cluster, LayoutAlgorithmSettings>();
            d[root] = new FastIncrementalLayoutSettings { AvoidOverlaps = true };

            var initialLayout = new InitialLayoutByCluster(graph, fastIncrementalLayoutSettings);
            initialLayout.Run();
            graph.UpdateBoundingBox();
            //FixClusterBoundariesWithNoRectBoundaries(root, 5);
            return graph;
        }
        void ReadGraph() {
            MoveToContent();
            _graph.Margins = GetDoubleAttributeOrDefault(GeometryToken.Margins, 10);
            if (XmlReader.Name.ToLower() != GeometryToken.Graph.ToString().ToLower())
                Error("expecting element \"graph\"");
            bool done = false;
            do {
                switch (GetElementTag()) {
                    case GeometryToken.Nodes:
                        ReadNodes();
                        break;
                    case GeometryToken.Edges:
                        ReadEdges();
                        break;
                    case GeometryToken.Clusters:
                        ReadClusters();
                        break;
                    case GeometryToken.LayoutAlgorithmSettings:
                        Settings = ReadLayoutAlgorithmSettings(XmlReader); //todo . not tested
                        break;
                    case GeometryToken.LgLevels:
                        ReadLgLevels();
                        break;
                    case GeometryToken.LgSkeletonLevels:
                        ReadLgSkeletonLevels();
                        break;
                    case GeometryToken.End:
                    case GeometryToken.Graph:
                        if (XmlReader.NodeType == XmlNodeType.EndElement) {
                            done = true;
                            ReadEndElement();
                            break;
                        }
                        XmlRead();
                        break;
                    default: //ignore this element
                        XmlReader.Skip();
                        break;

                        //                        XmlReader.Skip();
                        //                        ReadHeader();
                        //                        if (TokenIs(GeometryToken.LayoutAlgorithmSettings))
                        //                            this.Settings = ReadLayoutAlgorithmSettings(XmlReader);
                        //                        ReadNodes();
                        //                        ReadClusters();
                        //                        ReadEdges();
                }
            } while (!done);
            _graph.BoundingBox = _graph.PumpTheBoxToTheGraphWithMargins();
        }
        public static GeometryGraph CreateFromFile(string fileName, out LayoutAlgorithmSettings settings) {
#if DEBUG && TEST_MSAGL
            if (FirstCharacter(fileName) != '<') {
                settings = null;
                return null;
            }
#endif
            using (Stream stream = File.OpenRead(fileName)) {
                var graphReader = new GeometryGraphReader(stream);
                GeometryGraph graph = graphReader.Read();
                settings = graphReader.Settings;
                return graph;
            }
        }
 /// <summary>
 /// Pack the given graph components to the specified aspect ratio
 /// </summary>
 /// <param name="components">set of graphs to pack</param>
 /// <param name="settings">settings for packing method and desired aspect ratio</param>
 /// <returns>Bounding box of the packed components</returns>
 public static Rectangle PackGraphs(IEnumerable<GeometryGraph> components, LayoutAlgorithmSettings settings) {
     List<RectangleToPack<GeometryGraph>> rectangles =
         (from c in components select new RectangleToPack<GeometryGraph>(c.BoundingBox, c)).ToList();
     if (rectangles.Count > 1) {
         OptimalPacking<GeometryGraph> packing = settings.PackingMethod == PackingMethod.Compact
             ? new OptimalRectanglePacking<GeometryGraph>(rectangles, settings.PackingAspectRatio)
             : (OptimalPacking<GeometryGraph>)
                 new OptimalColumnPacking<GeometryGraph>(rectangles, settings.PackingAspectRatio);
         packing.Run();
         foreach (var r in rectangles) {
             GeometryGraph component = r.Data;
             var delta = r.Rectangle.LeftBottom - component.boundingBox.LeftBottom;
             component.Translate(delta);
         }
         return new Rectangle(0, 0, packing.PackedWidth, packing.PackedHeight);
     }
     if (rectangles.Count == 1)
         return rectangles[0].Rectangle;
     return Rectangle.CreateAnEmptyBox();
 }