示例#1
0
        /// <summary>
        /// Fix the ports for <see cref="RoutingMode.ShortestStraightPathToBorder"/>
        /// by enlarging the adjacent segment to the rotated layout.
        /// </summary>
        /// <param name="graph">The layout graph to work on.</param>
        /// <param name="edge">The edge to fix.</param>
        /// <param name="path">A <see cref="GeneralPath"/> which represents the rotated layout.</param>
        /// <param name="atSource">Whether to fix the source or target port of the edge.</param>
        private static void FixPorts(LayoutGraph graph, Edge edge, GeneralPath path, bool atSource)
        {
            var el         = graph.GetLayout(edge);
            var pointCount = el.PointCount();
            // find the opposite point of the port at the adjacent segment
            PointD firstBend = atSource
        ? (pointCount > 0 ? el.GetPoint(0) : graph.GetTargetPointAbs(edge)).ToPointD()
        : (pointCount > 0 ? el.GetPoint(pointCount - 1) : graph.GetSourcePointAbs(edge)).ToPointD();
            // The port itself
            PointD port = (atSource ? graph.GetSourcePointAbs(edge) : graph.GetTargetPointAbs(edge)).ToPointD();
            // The adjacent segment as vector pointing from the opposite point to the port
            var direction = port - firstBend;
            // find the intersection (there is always one)
            var    intersection = path.FindRayIntersection(firstBend.ToPointD(), direction);
            PointD point        = port;

            if (intersection < Double.PositiveInfinity)
            {
                // found an intersection: extend the adjacent segment
                point = firstBend + (direction * intersection);
            }
            else
            {
                // no intersection: connect to the original port's nearest point
                var    cursor      = path.CreateCursor();
                double minDistance = Double.PositiveInfinity;
                while (cursor.MoveNext())
                {
                    var distance = port.DistanceTo(cursor.CurrentEndPoint);
                    if (distance < minDistance)
                    {
                        minDistance = distance;
                        point       = cursor.CurrentEndPoint;
                    }
                }
            }
            // set the port position
            if (atSource)
            {
                graph.SetSourcePointAbs(edge, point.ToYPoint());
            }
            else
            {
                graph.SetTargetPointAbs(edge, point.ToYPoint());
            }
        }
示例#2
0
        protected void PaintEdge(Graphics g, LayoutGraph graph, Edge e)
        {
            IEdgeLayout el = graph.GetLayout(e);
            YPoint      sp = graph.GetSourcePointAbs(e);
            YPoint      tp = graph.GetTargetPointAbs(e);

            PointF[] points = new PointF[el.PointCount() + 2];
            points[0] = new PointF((float)sp.X, (float)sp.Y);
            points[el.PointCount() + 1] = new PointF((float)tp.X, (float)tp.Y);
            for (int i = 0; i < el.PointCount(); i++)
            {
                YPoint p = el.GetPoint(i);
                points[i + 1] = new PointF((float)p.X, (float)p.Y);
            }
            g.DrawLines(edgePen, points);
        }
        /// <summary>
        /// Called by the various edge creation callbacks to create an edge in the resulting graph view
        /// that corresponds to the provided <paramref name="layoutEdge"/>.
        /// </summary>
        /// <remarks>
        /// If a model edge is provided, the edge will be created between the copies of the corresponding
        /// source/target ports.
        /// </remarks>
        ///<param name="pageLayoutGraph">The layout graph representing the current page.</param>
        ///<param name="pageView">The <see cref="IGraph"/> that is built to show the multi-page layout in a graph canvas.</param>
        ///<param name="layoutEdge">The edge of the layout graph that should be copied.</param>
        ///<param name="modelEdge">The edge of the original input graph that corresponds to the <paramref name="layoutEdge"/> (may be <see langword="null"/>).</param>
        ///<param name="edgeDefaults"></param>
        ///<returns>The created edge</returns>
        /// <seealso cref="CreateConnectorEdge"/>
        /// <seealso cref="CreateNormalEdge"/>
        /// <seealso cref="CreateProxyEdge"/>
        /// <seealso cref="CreateProxyReferenceEdge"/>
        protected IEdge CreateEdgeCore(LayoutGraph pageLayoutGraph, IGraph pageView, Edge layoutEdge, IEdge modelEdge, IEdgeDefaults edgeDefaults)
        {
            IEdge viewEdge;

            if (modelEdge != null)
            {
                // if the edge has a model edge: create the copied edge between
                // the copies of its source and target ports
                IPort      modelSourcePort = modelEdge.SourcePort;
                IPort      modelTargetPort = modelEdge.TargetPort;
                IPort      viewSourcePort  = GetViewPort(modelSourcePort);
                IPort      viewTargetPort  = GetViewPort(modelTargetPort);
                IEdgeStyle style           = (IEdgeStyle)(edgeDefaults.Style != NullEdgeStyle ?
                                                          edgeDefaults.GetStyleInstance() :
                                                          modelEdge.Style.Clone());
                viewEdge = pageView.CreateEdge(viewSourcePort, viewTargetPort, style, modelEdge.Tag);
            }
            else
            {
                // otherwise create it between the copies of its source and target nodes
                INode viewSource = GetViewNode(layoutEdge.Source);
                INode viewTarget = GetViewNode(layoutEdge.Target);
                viewEdge = pageView.CreateEdge(viewSource, viewTarget);
            }

            // adjust the port location
            YPoint newSourcePortLocation = pageLayoutGraph.GetSourcePointAbs(layoutEdge);
            YPoint newTargetPortLocation = pageLayoutGraph.GetTargetPointAbs(layoutEdge);

            pageView.SetPortLocation(viewEdge.SourcePort, newSourcePortLocation.ToPointD());
            pageView.SetPortLocation(viewEdge.TargetPort, newTargetPortLocation.ToPointD());

            // and copy the bends
            IEdgeLayout edgeLayout = pageLayoutGraph.GetLayout(layoutEdge);

            for (int i = 0; i < edgeLayout.PointCount(); i++)
            {
                YPoint bendLocation = edgeLayout.GetPoint(i);
                pageView.AddBend(viewEdge, new PointD(bendLocation.X, bendLocation.Y), i);
            }

            return(viewEdge);
        }
            public GraphCanvas(LayoutGraph graph)
            {
                this.RenderTransform = new TranslateTransform(_padding, _padding);
                var grouping = new GroupingSupport(graph);

                // Add all edges
                foreach (var edge in graph.Edges)
                {
                    IEdgeLayout el = graph.GetLayout(edge);
                    var         l  = new Polyline();
                    l.Stroke = Brushes.Black;
                    l.Points.Add(new Point(graph.GetSourcePointAbs(edge).X, graph.GetSourcePointAbs(edge).Y));
                    for (int i = 0; i < el.PointCount(); i++)
                    {
                        Point p = new Point(el.GetPoint(i).X, el.GetPoint(i).Y);
                        l.Points.Add(p);
                    }
                    l.Points.Add(new Point(graph.GetTargetPointAbs(edge).X, graph.GetTargetPointAbs(edge).Y));
                    this.Children.Add(l);

                    // edge labels
                    var edgeLabelLayout = graph.GetLabelLayout(edge);
                    foreach (var labelLayout in edgeLabelLayout)
                    {
                        var orientedRectangle = labelLayout.LabelModel.GetLabelPlacement(
                            labelLayout.BoundingBox,
                            graph.GetLayout(edge),
                            graph.GetLayout(edge.Source),
                            graph.GetLayout(edge.Target),
                            labelLayout.ModelParameter);
                        this.Children.Add(GetPolygon(orientedRectangle));
                    }
                }

                // add all nodes
                foreach (var node in graph.Nodes)
                {
                    INodeLayout nl    = graph.GetLayout(node);
                    Color       color = grouping.IsGroupNode(node) ? Color.FromArgb(60, 255, 60, 0) : Color.FromArgb(255, 255, 255, 0);


                    var rect = new Rectangle();
                    this.Children.Add(rect);
                    rect.Stroke = new SolidColorBrush()
                    {
                        Color = Colors.Black
                    };
                    rect.Fill = new SolidColorBrush()
                    {
                        Color = color
                    };
                    rect.Width  = nl.Width;
                    rect.Height = nl.Height;
                    Canvas.SetTop(rect, nl.Y);
                    Canvas.SetLeft(rect, nl.X);

                    // display the node index
                    var text = new TextBlock()
                    {
                        Text = String.Empty + node.Index,
                        HorizontalAlignment = HorizontalAlignment.Center,
                        VerticalAlignment   = VerticalAlignment.Center
                    };

                    this.Children.Add(text);
                    text.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
                    Canvas.SetTop(text, nl.Y + nl.Height / 2 - text.DesiredSize.Height / 2);
                    Canvas.SetLeft(text, nl.X + nl.Width / 2 - text.DesiredSize.Width / 2);
                }
            }
示例#5
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);
                }
            }
        }