Example #1
0
        private void LayoutLinkedShapes(Graph graph, out Microsoft.Msagl.Core.Layout.GeometryGraph geometry)
        {
            var geomGraph      = new Microsoft.Msagl.Core.Layout.GeometryGraph();
            var layoutSettings = new Microsoft.Msagl.Layout.Layered.SugiyamaLayoutSettings();

            Microsoft.Msagl.Core.Layout.Node EnsureNode(Node node)
            {
                var res = geomGraph.Nodes.FirstOrDefault(n => n.UserData == node);

                if (res == null)
                {
                    var geomNode = new Microsoft.Msagl.Core.Layout.Node(
                        Microsoft.Msagl.Core.Geometry.Curves.CurveFactory.CreateRectangle(
                            ShapeSize,
                            ShapeSize,
                            new Microsoft.Msagl.Core.Geometry.Point()
                            ),
                        node
                        );

                    geomGraph.Nodes.Add(geomNode);

                    return(geomNode);
                }

                return(res);
            }

            foreach (var l in graph.Links)
            {
                var n1 = EnsureNode(l.Node1);
                var n2 = EnsureNode(l.Node2);
                var e  = new Microsoft.Msagl.Core.Layout.Edge(n1, n2);
                geomGraph.Edges.Add(e);
            }

            LayoutHelpers.CalculateLayout(geomGraph, layoutSettings, null);

            foreach (var kv in nodesAndShapes)
            {
                var pos = geomGraph.Nodes.FirstOrDefault(n => n.UserData == kv.Key)?.Center;
                if (pos.HasValue)
                {
                    kv.Value.X = (int)pos.Value.X + ShapeSize;
                    kv.Value.Y = Diagram.Height - (int)pos.Value.Y + ShapeSize / 2;
                }
            }

            geometry = geomGraph;
        }
Example #2
0
 /// <summary>
 /// Creates an auxilliary geometry graph, which contains all the nodes of a flattened nested graph. Produces a map from the original graph nodes to the auxilliary graph nodes.
 /// </summary>
 /// <param name="gg">The auxilliary graph to be filled.</param>
 /// <param name="graph">The original graph.</param>
 /// <param name="offset">Offset to be applied to all nodes.</param>
 /// <param name="connectedNodes">Map from original graph nodes to auxilliary graph nodes.</param>
 private static void FillAuxGraph(GeometryGraph gg, DGraph graph, GeometryPoint offset, Dictionary <DNode, GeometryNode> connectedNodes)
 {
     foreach (DNode n in graph.Nodes())
     {
         GeometryNode clone = new GeometryNode(n.GeometryNode.BoundaryCurve.Clone());
         clone.BoundaryCurve.Translate(offset);
         gg.Nodes.Add(clone);
         connectedNodes[n] = clone;
         DNestedGraphLabel ngLabel = n.Label as DNestedGraphLabel;
         if (ngLabel != null)
         {
             GeometryPoint labelPosition = new GeometryPoint(Canvas.GetLeft(ngLabel), Canvas.GetTop(ngLabel));
             foreach (DGraph dg in ngLabel.Graphs)
             {
                 Point         p                = ngLabel.GetDGraphOffset(dg);
                 GeometryPoint offsetToLabel    = new GeometryPoint(p.X, p.Y);
                 GeometryPoint graphOffset      = labelPosition + offsetToLabel;
                 GeometryPoint normalizedOffset = graphOffset - dg.Graph.BoundingBox.LeftBottom;
                 FillAuxGraph(gg, dg, offset + normalizedOffset, connectedNodes);
             }
         }
     }
 }
Example #3
0
        private MSAGL.Core.Layout.GeometryGraph CreateMsaglGraph(DirectedGraphLayout layout_diagram)
        {
            var mg_graph = new MSAGL.Core.Layout.GeometryGraph();

            // Create the nodes in MSAGL
            foreach (var layout_shape in layout_diagram.Shapes)
            {
                var nodesize       = this.ToMGCoordinates(layout_shape.Size ?? this.LayoutOptions.DefaultShapeSize);
                var node_user_data = new NodeUserData(layout_shape.ID, layout_shape);
                var center         = new MSAGL.Core.Geometry.Point();
                var rectangle      = MSAGL.Core.Geometry.Curves.CurveFactory.CreateRectangle(nodesize.Width, nodesize.Height, center);
                var mg_node        = new MSAGL.Core.Layout.Node(rectangle, node_user_data);
                mg_graph.Nodes.Add(mg_node);
            }

            this.validate_connectors(layout_diagram);

            var mg_coordinates = this.ToMGCoordinates(this.DefaultBezierConnectorLabelBoxSize);

            var map_id_to_ud = new Dictionary <string, MSAGL.Core.Layout.Node>();

            foreach (var n in mg_graph.Nodes)
            {
                var ud = (NodeUserData)n.UserData;
                if (ud != null)
                {
                    map_id_to_ud[ud.ID] = n;
                }
            }

            // Create the MG Connectors
            foreach (var layout_connector in layout_diagram.Connectors)
            {
                if (layout_connector.From == null)
                {
                    throw new ArgumentException("Connector's From node is null");
                }

                if (layout_connector.To == null)
                {
                    throw new ArgumentException("Connector's To node is null");
                }

                var from_node = map_id_to_ud[layout_connector.From.ID];
                var to_node   = map_id_to_ud[layout_connector.To.ID];

                var new_edge = new MSAGL.Core.Layout.Edge(from_node, to_node);
                // TODO: MSAGL
                //new_edge.ArrowheadAtTarget = false;
                new_edge.UserData = new NodeUserData(layout_connector.ID, layout_connector);
                mg_graph.Edges.Add(new_edge);

                new_edge.Label = new MSAGL.Core.Layout.Label(mg_coordinates.Width, mg_coordinates.Height, new_edge);
            }

            var geom_graph_components = MSAGL.Core.Layout.GraphConnectedComponents.CreateComponents(mg_graph.Nodes, mg_graph.Edges);
            var settings = new MSAGL.Layout.Layered.SugiyamaLayoutSettings();

            foreach (var subgraph in geom_graph_components)
            {
                var layout = new Microsoft.Msagl.Layout.Layered.LayeredLayout(subgraph, settings);
                subgraph.Margins = settings.NodeSeparation / 2;
                layout.Run();
            }

            // Pack the graphs using Golden Aspect Ratio
            MSAGL.Layout.MDS.MdsGraphLayout.PackGraphs(geom_graph_components, settings);

            //Update the graphs bounding box
            mg_graph.UpdateBoundingBox();

            this._mg_bb = new VA.Drawing.Rectangle(
                mg_graph.BoundingBox.Left,
                mg_graph.BoundingBox.Bottom,
                mg_graph.BoundingBox.Right,
                mg_graph.BoundingBox.Top);

            this._layout_bb = new VA.Drawing.Rectangle(0, 0, this._mg_bb.Width, this._mg_bb.Height)
                              .Multiply(this.ScaleToDocument, this.ScaleToDocument);

            return(mg_graph);
        }
        private MSAGL.Core.Layout.GeometryGraph _create_msagl_graph(DirectedGraphLayout dglayout)
        {
            var msagl_graph = new MSAGL.Core.Layout.GeometryGraph();

            // Create the nodes in MSAGL
            foreach (var layout_shape in dglayout.Nodes)
            {
                var nodesize       = this._to_mg_coordinates(layout_shape.Size ?? this.LayoutOptions.DefaultShapeSize);
                var node_user_data = new ElementUserData(layout_shape.ID, layout_shape);
                var center         = new MSAGL.Core.Geometry.Point();
                var rectangle      = MSAGL.Core.Geometry.Curves.CurveFactory.CreateRectangle(nodesize.Width, nodesize.Height, center);
                var mg_node        = new MSAGL.Core.Layout.Node(rectangle, node_user_data);
                msagl_graph.Nodes.Add(mg_node);
            }

            this.validate_connectors(dglayout);

            var mg_coordinates = this._to_mg_coordinates(this.DefaultBezierConnectorLabelBoxSize);

            var map_id_to_ud = new Dictionary <string, MSAGL.Core.Layout.Node>();

            foreach (var n in msagl_graph.Nodes)
            {
                var ud = (ElementUserData)n.UserData;
                if (ud != null)
                {
                    map_id_to_ud[ud.ID] = n;
                }
            }

            // Create the MG Connectors
            foreach (var layout_connector in dglayout.Edges)
            {
                if (layout_connector.From == null)
                {
                    throw new ArgumentException("Connector's From node is null");
                }

                if (layout_connector.To == null)
                {
                    throw new ArgumentException("Connector's To node is null");
                }

                var from_node = map_id_to_ud[layout_connector.From.ID];
                var to_node   = map_id_to_ud[layout_connector.To.ID];

                var new_edge = new MSAGL.Core.Layout.Edge(from_node, to_node);
                // TODO: MSAGL
                //new_edge.ArrowheadAtTarget = false;
                new_edge.UserData = new ElementUserData(layout_connector.ID, layout_connector);
                msagl_graph.Edges.Add(new_edge);

                new_edge.Label = new MSAGL.Core.Layout.Label(mg_coordinates.Width, mg_coordinates.Height, new_edge);
            }

            var msagl_graphs           = MSAGL.Core.Layout.GraphConnectedComponents.CreateComponents(msagl_graph.Nodes, msagl_graph.Edges);
            var msagl_sugiyamasettings = new MSAGL.Layout.Layered.SugiyamaLayoutSettings();

            if (this.LayoutOptions.Direction == MsaglDirection.TopToBottom)
            {
                // do nothing
            }
            else if (this.LayoutOptions.Direction == MsaglDirection.BottomToTop)
            {
                msagl_sugiyamasettings.Transformation = MSAGL.Core.Geometry.Curves.PlaneTransformation.Rotation(Math.PI);
            }
            else if (this.LayoutOptions.Direction == MsaglDirection.LeftToRight)
            {
                msagl_sugiyamasettings.Transformation = MSAGL.Core.Geometry.Curves.PlaneTransformation.Rotation(Math.PI / 2);
            }
            else if (this.LayoutOptions.Direction == MsaglDirection.RightToLeft)
            {
                msagl_sugiyamasettings.Transformation = MSAGL.Core.Geometry.Curves.PlaneTransformation.Rotation(-Math.PI / 2);
            }
            else
            {
                throw new System.ArgumentOutOfRangeException();
            }

            foreach (var subgraph in msagl_graphs)
            {
                var layout = new Microsoft.Msagl.Layout.Layered.LayeredLayout(subgraph, msagl_sugiyamasettings);

                subgraph.Margins = msagl_sugiyamasettings.NodeSeparation / 2;

                layout.Run();
            }

            // Pack the graphs using Golden Aspect Ratio
            MSAGL.Layout.MDS.MdsGraphLayout.PackGraphs(msagl_graphs, msagl_sugiyamasettings);

            //Update the graphs bounding box
            msagl_graph.UpdateBoundingBox();

            this._msagl_bb = new VA.Geometry.Rectangle(
                msagl_graph.BoundingBox.Left,
                msagl_graph.BoundingBox.Bottom,
                msagl_graph.BoundingBox.Right,
                msagl_graph.BoundingBox.Top);

            this._visio_bb = new VA.Geometry.Rectangle(0, 0, this._msagl_bb.Width, this._msagl_bb.Height)
                             .Multiply(this._scale_to_document, this._scale_to_document);

            return(msagl_graph);
        }