Пример #1
0
            public override void ApplyLayout(LayoutGraph graph)
            {
                // determine the single node to keep at the center.
                var  provider   = graph.GetDataProvider("NodeLayouts");
                Node centerNode = null;

                if (provider != null)
                {
                    centerNode = graph.Nodes.FirstOrDefault(n => provider.Get(n) != null);
                }
                if (CoreLayout != null)
                {
                    if (centerNode != null)
                    {
                        // remember old center
                        RectD oldLayout     = (RectD)provider.Get(centerNode);
                        var   fixedLocation = new YPoint(graph.GetX(centerNode) + graph.GetWidth(centerNode), graph.GetY(centerNode));
                        //Set to saved size (this is important for collapsed nodes to ensure correct size)
                        graph.SetSize(centerNode, oldLayout.Width, oldLayout.Height);
                        // run layout
                        CoreLayout.ApplyLayout(graph);
                        // obtain new center
                        var newFixedLocation = new YPoint(graph.GetX(centerNode) + graph.GetWidth(centerNode),
                                                          graph.GetY(centerNode));
                        // and adjust the layout
                        LayoutGraphUtilities.MoveSubgraph(graph, graph.GetNodeCursor(), fixedLocation.X - newFixedLocation.X,
                                                          fixedLocation.Y - newFixedLocation.Y);
                    }
                    else
                    {
                        CoreLayout.ApplyLayout(graph);
                    }
                }
            }
        private void AdjustNodeSize(Node node, LayoutGraph graph)
        {
            double width  = 60;
            double height = 40;

            var leftEdgeSpace  = CalcRequiredSpace(node.InEdges, graph);
            var rightEdgeSpace = CalcRequiredSpace(node.OutEdges, graph);

            if (LayoutOrientation == LayoutOrientation.TopToBottom || LayoutOrientation == LayoutOrientation.BottomToTop)
            {
                // we have to enlarge the width such that the in-/out-edges can be placed side by side without overlaps
                width = Math.Max(width, leftEdgeSpace);
                width = Math.Max(width, rightEdgeSpace);
            }
            else
            {
                // we have to enlarge the height such that the in-/out-edges can be placed side by side without overlaps
                height = Math.Max(height, leftEdgeSpace);
                height = Math.Max(height, rightEdgeSpace);
            }

            // adjust size for edges with strong port constraints
            var edgeThicknessDP = graph.GetDataProvider(HierarchicLayout.EdgeThicknessDpKey);

            if (edgeThicknessDP != null)
            {
                foreach (var edge in node.Edges)
                {
                    var thickness = edgeThicknessDP.GetDouble(edge);

                    var spc = PortConstraint.GetSPC(graph, edge);
                    if (edge.Source == node && spc != null && spc.Strong)
                    {
                        var sourcePoint = graph.GetSourcePointRel(edge);
                        width  = Math.Max(width, Math.Abs(sourcePoint.X) * 2 + thickness);
                        height = Math.Max(height, Math.Abs(sourcePoint.Y) * 2 + thickness);
                    }

                    var tpc = PortConstraint.GetTPC(graph, edge);
                    if (edge.Target == node && tpc != null && tpc.Strong)
                    {
                        var targetPoint = graph.GetTargetPointRel(edge);
                        width  = Math.Max(width, Math.Abs(targetPoint.X) * 2 + thickness);
                        height = Math.Max(height, Math.Abs(targetPoint.Y) * 2 + thickness);
                    }
                }
            }
            graph.SetSize(node, width, height);
        }
Пример #3
0
        /// <summary>
        /// Executes the layout algorithm.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Enlarges the node layout to fully encompass the rotated layout (the rotated layout's bounding box).
        /// If the <see cref="EdgeRoutingMode"/> is set to <see cref="RoutingMode.FixedPort"/>
        /// port constraints are created to keep the ports at their current location.
        /// Existing port constraints are adjusted to the rotation.
        /// </para>
        /// <para>
        /// Then, the <see cref="LayoutStageBase.CoreLayout"/> is executed.
        /// </para>
        /// <para>
        /// After the core layout the original node sizes are restored.
        /// If the <see cref="EdgeRoutingMode"/> is set to <see cref="RoutingMode.ShortestStraightPathToBorder"/>
        /// the last edge segment is extended from the bounding box to the rotated layout.
        /// </para>
        /// </remarks>
        public override void ApplyLayout(LayoutGraph graph)
        {
            if (CoreLayout == null)
            {
                return;
            }

            var boundsProvider = graph.GetDataProvider(RotatedNodeLayoutDpKey);

            if (boundsProvider == null)
            {
                // no provider: this stage adds nothing to the core layout
                CoreLayout.ApplyLayout(graph);
                return;
            }

            bool     addedSourcePortConstraints  = false;
            bool     addedTargetPortContstraints = false;
            IDataMap sourcePortConstraints       = (IDataMap)graph.GetDataProvider(PortConstraintKeys.SourcePortConstraintDpKey);
            IDataMap targetPortConstraints       = (IDataMap)graph.GetDataProvider(PortConstraintKeys.TargetPortConstraintDpKey);

            if (EdgeRoutingMode == RoutingMode.FixedPort)
            {
                // Fixed port: create port constraints to keep the ports at position
                // in this case: create data providers if there are none yet
                if (sourcePortConstraints == null)
                {
                    sourcePortConstraints = graph.CreateEdgeMap();
                    graph.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, sourcePortConstraints);
                    addedSourcePortConstraints = true;
                }
                if (targetPortConstraints == null)
                {
                    targetPortConstraints = graph.CreateEdgeMap();
                    graph.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, targetPortConstraints);
                    addedTargetPortContstraints = true;
                }
            }
            try {
                var originalDimensions = new Dictionary <Node, OldDimensions>();
                foreach (var node in graph.Nodes)
                {
                    var nodeShape      = (RotatedNodeShape)boundsProvider.Get(node);
                    var orientedLayout = nodeShape != null ? nodeShape.OrientedLayout : null;
                    var outline        = nodeShape != null ? nodeShape.Outline : null;
                    if (orientedLayout != null)
                    {
                        // if the current node is rotated: apply fixes
                        // remember old layout and size
                        var oldLayout     = graph.GetLayout(node);
                        var newLayout     = orientedLayout.GetBounds().ToYRectangle();
                        var offset        = new PointD(newLayout.X - oldLayout.X, newLayout.Y - oldLayout.Y);
                        var originalSize  = new SizeD(oldLayout.Width, oldLayout.Height);
                        var oldDimensions = new OldDimensions {
                            offset  = offset,
                            size    = originalSize,
                            outline = outline
                        };
                        if (EdgeRoutingMode == RoutingMode.FixedPort)
                        {
                            // EdgeRoutingMode: FixedPort: keep the ports at their current location

                            // The oriented layout's corners to find the best PortSide
                            var tl = new PointD(orientedLayout.AnchorX + orientedLayout.UpX * orientedLayout.Height, orientedLayout.AnchorY + orientedLayout.UpY * orientedLayout.Height);
                            var tr = new PointD(orientedLayout.AnchorX + orientedLayout.UpX * orientedLayout.Height - orientedLayout.UpY * orientedLayout.Width,
                                                orientedLayout.AnchorY + orientedLayout.UpY * orientedLayout.Height + orientedLayout.UpX * orientedLayout.Width);
                            var bl = new PointD(orientedLayout.AnchorX, orientedLayout.AnchorY);
                            var br = new PointD(orientedLayout.AnchorX - orientedLayout.UpY * orientedLayout.Width, orientedLayout.AnchorY + orientedLayout.UpX * orientedLayout.Width);

                            // for each out edge
                            foreach (var edge in node.OutEdges)
                            {
                                // create a strong port constraint for the side which is closest to the port location (without rotation)
                                var constraint = sourcePortConstraints.Get(edge);
                                if (constraint == null)
                                {
                                    var point = graph.GetSourcePointAbs(edge).ToPointD();
                                    var side  = FindBestSide(point, bl, br, tl, tr);
                                    sourcePortConstraints.Set(edge, PortConstraint.Create(side, true));
                                }
                            }
                            foreach (var edge in node.InEdges)
                            {
                                // create a strong port constraint for the side which is closest to the port location (without rotation)
                                var constraint = targetPortConstraints.Get(edge);
                                if (constraint == null)
                                {
                                    var point = graph.GetTargetPointAbs(edge).ToPointD();
                                    var side  = FindBestSide(point, bl, br, tl, tr);
                                    targetPortConstraints.Set(edge, PortConstraint.Create(side, true));
                                }
                            }
                        }

                        // For source and target port constraints: fix the PortSide according to the rotation
                        var angle = Math.Atan2(orientedLayout.UpY, orientedLayout.UpX);
                        if (sourcePortConstraints != null)
                        {
                            foreach (var edge in node.OutEdges)
                            {
                                FixPortConstraintSide(sourcePortConstraints, edge, angle);
                            }
                        }
                        if (targetPortConstraints != null)
                        {
                            foreach (var edge in node.InEdges)
                            {
                                FixPortConstraintSide(targetPortConstraints, edge, angle);
                            }
                        }

                        // enlarge the node layout
                        var position = new YPoint(newLayout.X, newLayout.Y);
                        oldDimensions.location = position;
                        originalDimensions.Add(node, oldDimensions);
                        graph.SetLocation(node, position);
                        graph.SetSize(node, newLayout);
                    }
                }

                // ===============================================================

                CoreLayout.ApplyLayout(graph);

                // ===============================================================

                var groups = graph.GetDataProvider(GroupingKeys.GroupDpKey);
                foreach (var node in graph.Nodes)
                {
                    if (groups != null && groups.GetBool(node))
                    {
                        // groups don't need to be adjusted to their former size and location because their bounds are entirely
                        // calculated by the layout algorithm and they are not rotated
                        continue;
                    }

                    // for each node which has been corrected: undo the correction
                    var oldDimensions = originalDimensions[node];
                    var offset        = oldDimensions.offset;
                    var originalSize  = oldDimensions.size;
                    var newLayout     = graph.GetLayout(node);

                    // create a general path representing the new roated layout
                    var path      = oldDimensions.outline;
                    var transform = new Matrix2D();
                    transform.Translate(new PointD(newLayout.X - oldDimensions.location.X, newLayout.Y - oldDimensions.location.Y));
                    path.Transform(transform);

                    // restore the original size
                    graph.SetLocation(node, new YPoint(newLayout.X - offset.X, newLayout.Y - offset.Y));
                    graph.SetSize(node, originalSize.ToYDimension());

                    if (EdgeRoutingMode == RoutingMode.NoRouting)
                    {
                        // NoRouting still needs fix for self-loops
                        foreach (var edge in node.Edges)
                        {
                            if (edge.SelfLoop)
                            {
                                FixPorts(graph, edge, path, false);
                                FixPorts(graph, edge, path, true);
                            }
                        }
                        continue;
                    }

                    if (EdgeRoutingMode != RoutingMode.ShortestStraightPathToBorder)
                    {
                        continue;
                    }

                    // enlarge the adjacent segment to the oriented rectangle (represented by the path)
                    // handling in and out edges separately will automatically cause selfloops to be handled correctly
                    foreach (var edge in node.InEdges)
                    {
                        FixPorts(graph, edge, path, false);
                    }
                    foreach (var edge in node.OutEdges)
                    {
                        FixPorts(graph, edge, path, true);
                    }
                }
            } finally {
                // if data provider for the port constraints have been added
                // remove and dispose them
                if (addedSourcePortConstraints)
                {
                    graph.RemoveDataProvider(PortConstraintKeys.SourcePortConstraintDpKey);
                    graph.DisposeEdgeMap((IEdgeMap)sourcePortConstraints);
                }
                if (addedTargetPortContstraints)
                {
                    graph.RemoveDataProvider(PortConstraintKeys.TargetPortConstraintDpKey);
                    graph.DisposeEdgeMap((IEdgeMap)targetPortConstraints);
                }
            }
        }