/// <summary>
        /// Adjusts the edge end points so they don't end outside the shape of the node they are attached to.
        /// </summary>
        private static void AdjustPortLocation(LayoutGraph graph, Edge e, YPointPath path, bool atSource)
        {
            Node   node     = atSource ? e.Source : e.Target;
            YPoint pointRel = atSource ? graph.GetSourcePointRel(e) : graph.GetTargetPointRel(e);
            // get offset from the node center to the end of the shape at the node side the edge connects to
            LineSegment segment = path.GetLineSegment(atSource ? 0 : path.Length() - 2);
            double      offset  = Math.Min(graph.GetWidth(node), graph.GetHeight(node)) / 2;
            double      offsetX = segment.DeltaX > 0 ^ atSource ? -offset : offset;
            double      offsetY = segment.DeltaY > 0 ^ atSource ? -offset : offset;
            // if the edge end point is at the center of this side, we use the calculated offset to put the end point on
            // the node bounds, otherwise we prolong the last segment to the center line of the node so it doesn't end
            // outside the node's shape
            YPoint newPortLocation = segment.IsHorizontal
        ? new YPoint(pointRel.Y != 0 ? 0 : offsetX, pointRel.Y)
        : new YPoint(pointRel.X, pointRel.X != 0 ? 0 : offsetY);

            if (atSource)
            {
                graph.SetSourcePointRel(e, newPortLocation);
            }
            else
            {
                graph.SetTargetPointRel(e, newPortLocation);
            }
        }
        public void ApplyLayout(LayoutGraph graph)
        {
            var rows = graph.GetNodeArray();

            // sort the rows by their vertical coordinate
            Array.Sort(rows, (node1, node2) => (int)(graph.GetCenterY(node1) - graph.GetCenterY(node2)));

            // layout the nodes in a column
            double currentY = 0;

            foreach (var node in rows)
            {
                graph.SetLocation(node, 0, currentY);
                currentY += graph.GetHeight(node) + Distance;
            }

            // there should be no edges between the 'row' nodes but if there are some, all their bends shall be removed
            foreach (var edge in graph.Edges)
            {
                graph.SetPoints(edge, new YList());
            }
        }
            public override object Get(Object dataHolder)
            {
                Node node = dataHolder as Node;

                if (node != null)
                {
                    // copy descriptor to keep all settings for this node
                    NodeLayoutDescriptor descriptor = new NodeLayoutDescriptor();
                    descriptor.LayerAlignment     = nld.LayerAlignment;
                    descriptor.MinimumDistance    = nld.MinimumDistance;
                    descriptor.MinimumLayerHeight = nld.MinimumLayerHeight;
                    descriptor.NodeLabelMode      = nld.NodeLabelMode;
                    // anchor nodes on grid according to their alignment within the layer
                    descriptor.GridReference  = new YPoint(0.0, (nld.LayerAlignment - 0.5) * graph.GetHeight(node));
                    descriptor.PortAssignment = gridPortAssignment;
                    return(descriptor);
                }
                return(null);
            }