Ejemplo n.º 1
0
        private Bitmap DrawGraph(Dictionary <int, List <int> > data, int startNodeId)
        {
            List <int> parentIds = new List <int>();
            Dictionary <int, WedgeNode> nodes = new Dictionary <int, WedgeNode>();

            Geometry.CoordinatePlane = Geometry.CoordinatePlanes.Screen;

            Shapes.Point center = new Shapes.Point(1000, 1000);
            nodes[startNodeId] = new WedgeNode()
            {
                Id            = startNodeId,
                Center        = center,
                Wedge         = new Shapes.Wedge(new Shapes.Circle(center, nodeWidth / 2), 0, 360),
                ChildrenWedge = new Shapes.WedgeUnbound(center, 0, 360)
            };
            parentIds.Add(startNodeId);

            int parentIdsIndex = 0;

            while (parentIdsIndex < parentIds.Count)
            {
//				if(parentIdsIndex > 9)
//					break;
                int parentId = parentIds[parentIdsIndex];
                if (!data.ContainsKey(parentId))
                {
                    parentIdsIndex++;
                    continue;
                }
                WedgeNode parentNode = nodes[parentId];

                //if a sibling does not have any unplaced children, this node can take up the sibling's childrenwedge space
                if (parentNode.SiblingClockwise != null && CountChildrenNotPlaced(parentNode.SiblingClockwise.Id, data, nodes) == 0)
                {
                    parentNode.ChildrenWedgeDegrees += parentNode.SiblingClockwise.ChildrenWedgeDegrees;
                }
                if (parentNode.SiblingCounterClockwise != null && CountChildrenNotPlaced(parentNode.SiblingCounterClockwise.Id, data, nodes) == 0)
                {
                    parentNode.ChildrenWedgeDegrees += parentNode.SiblingCounterClockwise.ChildrenWedgeDegrees;
                }

                ChildCalculations calculations;
                int childCount = CountChildrenNotPlaced(parentId, data, nodes);
                if (childCount == 0)
                {
                    parentIdsIndex++;
                    continue;
                }
                if (childCount > 2 && parentNode.ParentNode != null)
                {
                    //move node out from old parent to make room for new children
                    calculations = new ChildCalculations(childCount + 1, 360, nodeWidth);
                    Shapes.Point newCenter = Geometry.PointPastLine(parentNode.ParentNode.Center, parentNode.Center, calculations.Radius * 1.2);
                    parentNode.Center = newCenter;
                    Shapes.Circle newCircle = new Shapes.Circle(newCenter, 1);
                    double        connectionToParentAtDegrees = newCircle.DegreesAtPoint(parentNode.ParentNode.Center);
                    parentNode.ChildrenWedge = new Shapes.WedgeUnbound(newCenter, connectionToParentAtDegrees + calculations.AngleUnit, 360 - calculations.AngleUnit);
                }
                else
                {
                    calculations = new ChildCalculations(childCount, parentNode.ChildrenWedge.Span, nodeWidth);
                }
                while (DoesCollide(parentId, nodes, parentNode.Center, calculations.Radius + (nodeWidth / 2)))
                {
                    //move node out from old parent to make room for new children
                    Shapes.Point newCenter = Geometry.PointPastLine(parentNode.ParentNode.Center, parentNode.Center, nodeWidth * 1.2);
                    parentNode.Center = newCenter;
                    parentNode.ChildrenWedgeCenter = newCenter;
                }
                double       childAngle              = parentNode.ChildrenWedge.Start;
                Shapes.Point childCenter             = parentNode.ChildrenWedge.Center;
                WedgeNode    siblingCounterClockwise = null;
                foreach (int childId in data[parentId])
                {
                    if (nodes.ContainsKey(childId))
                    {
                        continue;
                    }

                    //todo: if the sibling nodes next to you have no children, you can take up a wider space with your children

                    Shapes.Point childPoint = new Shapes.Point(childCenter.X + (Math.Cos(Shapes.Circle.DegreesToRadians(childAngle)) * calculations.Radius), childCenter.Y + (Math.Sin(Shapes.Circle.DegreesToRadians(childAngle)) * calculations.Radius));
                    nodes[childId] = new WedgeNode()
                    {
                        Id                      = childId,
                        Center                  = childPoint,
                        Wedge                   = new Shapes.Wedge(new Shapes.Circle(parentNode.Center, calculations.Radius + (nodeWidth / 2)), childAngle - (0.5 * calculations.AngleUnit), childAngle + (0.5 * calculations.AngleUnit)),
                        ParentNode              = parentNode,
                        ChildrenWedge           = new Shapes.WedgeUnbound(childCenter, Shapes.RangeCircular.Centered(childAngle, calculations.ChildAngleSpan, 360)),
                        SiblingCounterClockwise = siblingCounterClockwise
                    };
                    if (siblingCounterClockwise != null)
                    {
                        siblingCounterClockwise.SiblingClockwise = nodes[childId];
                    }
                    siblingCounterClockwise = nodes[childId];
                    parentIds.Add(childId);

                    childAngle += calculations.AngleUnit;
                }

                parentIdsIndex++;
            }

            //todo: check for lines very closely overlapping each other (see graph 1952, up to parentId 7)

            //adjust graph location as close to origin as possible
            int margin = 20;
            int minX   = (int)(nodes.Select(pair => pair.Value.Center.X).Min() - (nodeWidth / 2) - margin);
            int minY   = (int)(nodes.Select(pair => pair.Value.Center.Y).Min() - (nodeWidth / 2) - margin);

            Shapes.Point minPoint = new Shapes.Point(minX, minY);
            foreach (WedgeNode node in nodes.Values)
            {
                node.Center -= minPoint;
            }
            int maxX = (int)(nodes.Select(pair => pair.Value.Center.X).Max() + (nodeWidth / 2) + margin);
            int maxY = (int)(nodes.Select(pair => pair.Value.Center.Y).Max() + (nodeWidth / 2) + margin);

            Bitmap bitmap = new Bitmap(maxX, maxY);

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.SmoothingMode = SmoothingMode.AntiAlias;
                graphics.Clear(Color.White);

                //draw results
                //lines
                Pen pen      = new Pen(Color.Black, 1);
                Pen thickPen = new Pen(Color.Black, 4);
                foreach (int fromId in data.Keys)
                {
                    if (!nodes.ContainsKey(fromId))
                    {
                        continue;
                    }
                    foreach (int toId in data[fromId].Distinct())
                    {
                        if (!nodes.ContainsKey(toId))
                        {
                            continue;
                        }
                        graphics.DrawLine(pen,
                                          new System.Drawing.Point((int)nodes[fromId].Center.X, (int)nodes[fromId].Center.Y),
                                          new System.Drawing.Point((int)nodes[toId].Center.X, (int)nodes[toId].Center.Y)
                                          );

                        //Point pointAlongLine = PointAlongLine(nodeLocations[toId], nodeLocations[fromId], nodeWidth * 0.75F);
                        //graphics.DrawLine(thickPen, pointAlongLine, nodeLocations[toId]);
                    }
                }
                //nodes
                foreach (int id in nodes.Keys)
                {
                    DrawNode(graphics, nodes[id].Center, ShortLabel(id));
                }
                //debugging: wedges

                /*
                 * Pen redPen = new Pen(Color.Red, 1);
                 * foreach(int id in nodes.Keys)
                 * {
                 *      nodes[id].Wedge.Paint(graphics, redPen, 1);
                 * }
                 */
            }
            return(bitmap);
        }
Ejemplo n.º 2
0
 private bool DoesCollide(WedgeNode otherNode, Shapes.Point center, double radius)
 {
     return(otherNode.Wedge.Overlaps(new Shapes.Circle(center, radius)));
 }