Ejemplo n.º 1
0
 private void AddNode(List <BubbleNode> currentNodes, BubbleNode interativeNode, BubbleNode lastNode, BubbleNode newNode, Point point)
 {
     newNode.X = point.X;
     newNode.Y = point.Y;
     newNode.TangentBubbles.Add(lastNode);
     newNode.TangentBubbles.Add(interativeNode);
     currentNodes.Add(newNode);
 }
Ejemplo n.º 2
0
        private BubbleNode CreateBubbleNode(BubbleData data, double maxWeight, double minWeight, double bubbleMaxRadius, double anticipateMinRadius, double margin, int index)
        {
            //var bubbleRadius = maxWeight == minWeight ? bubbleMaxRadius : (data.Weight - minWeight) * ((bubbleMaxRadius - chart.BubbleAnticipateMinRadius) / (maxWeight - minWeight)) + chart.BubbleAnticipateMinRadius;
            var bubbleRadius = maxWeight == minWeight ? bubbleMaxRadius : (data.Weight - minWeight) * ((bubbleMaxRadius - anticipateMinRadius) / (maxWeight - minWeight)) + anticipateMinRadius;

            bubbleRadius += margin;

            var newNode = new BubbleNode();

            newNode.Index  = index;
            newNode.Radius = bubbleRadius;
            newNode.Name   = data.Name;
            newNode.Shape  = new Bubble()
            {
                Diameter = newNode.Radius * 2
            };

            if (data.Color != null)
            {
                newNode.Shape.Fill = data.Color.CloneCurrentValue();
            }
            else if (chart.BubbleBrushes != null)
            {
                if (chart.BubbleBrushes.Keys.Contains(newNode.Name))
                {
                    newNode.Shape.Fill = chart.BubbleBrushes[newNode.Name].CloneCurrentValue();
                }
            }
            else if (chart.BubbleBrush != null)
            {
                newNode.Shape.Fill = chart.BubbleBrush.CloneCurrentValue();
            }

            newNode.OriginalBrush = newNode.Shape.Fill.CloneCurrentValue();

            if (chart.BubbleLabelTemplate != null)
            {
                newNode.Shape.DataContext     = data;
                newNode.Shape.ContentTemplate = chart.BubbleLabelTemplate;
                newNode.Shape.SetCurrentValue(ContentControl.ContentProperty, data);
            }

            // for highlighting or other actions
            newNode.Shape.Tag                = newNode.Name;
            newNode.Shape.MouseEnter        += NodeMouseEnter;
            newNode.Shape.MouseLeave        += NodeMouseLeave;
            newNode.Shape.MouseLeftButtonUp += NodeMouseLeftButtonUp;

            return(newNode);
        }
Ejemplo n.º 3
0
        private bool CheckCollision(Point point, BubbleNode node, double newBubbleRadius, double bubbleGap)
        {
            var collisionAlpha           = 0.1;
            var differFromPointXAndNodeX = point.X - node.X;
            var differFromPointYAndNodeY = point.Y - node.Y;
            var distanceBetweenCentersFromNodeToPoint     = Math.Sqrt(differFromPointXAndNodeX * differFromPointXAndNodeX + Math.Pow(differFromPointYAndNodeY, 2));
            var distanceBetweenCentersFromNodeToNewBubble = node.Radius + newBubbleRadius + bubbleGap;

            if (distanceBetweenCentersFromNodeToNewBubble - distanceBetweenCentersFromNodeToPoint > collisionAlpha)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
Ejemplo n.º 4
0
        private void LayoutBubbleNode(BubbleNode newNode, List <BubbleNode> currentNodes, Point canvasCenter, double bubbleGap)
        {
            // create first bubble
            if (currentNodes.Count == 0)
            {
                newNode.X = canvasCenter.X;
                newNode.Y = canvasCenter.Y;
                currentNodes.Add(newNode);

                return;
            }

            // create second bubble
            if (currentNodes.Count == 1)
            {
                // set second bubble initial angle to 45
                var rad = Math.PI / 180 * 45;

                var distanceBetweenCenters = currentNodes[0].Radius + newNode.Radius + bubbleGap;
                newNode.X = canvasCenter.X + Math.Sin(rad) * (distanceBetweenCenters + 100);
                newNode.Y = canvasCenter.Y + Math.Cos(rad) * (distanceBetweenCenters - 100);

                newNode.TangentBubbles.Add(currentNodes[0]);
                currentNodes.Add(newNode);

                return;
            }

            var initialAngle = 70;
            var lastIndex    = currentNodes.Last().Index;

            // find second tangent bubble
            for (var round = 0; round < currentNodes.Count; round++)
            {
                var bubbleStack      = currentNodes.FindAll(n => n.Index <= lastIndex - round);
                var candidateBubbles = new List <BubbleNode>();

                if (bubbleStack.Count >= 2)
                {
                    for (var index = bubbleStack.Count - 2; index >= bubbleStack.Last().TangentBubbles.Last().Index; index--)
                    {
                        candidateBubbles.Insert(0, bubbleStack[index]);
                    }
                }

                var IsNodeAdded = false;

                for (var index = 0; index < candidateBubbles.Count; index++)
                {
                    #region prepare for checking collisions

                    var interativeNode = candidateBubbles[index];
                    var lastNode       = bubbleStack.Last();
                    var distanceBetweenCentersFromLastNodeToNewBubble       = lastNode.Radius + newNode.Radius + bubbleGap;
                    var distanceBetweenCentersFromInterativeNodeToNewBubble = interativeNode.Radius + newNode.Radius + bubbleGap;
                    var interativeNodeXRelativeToLastNode = interativeNode.X - lastNode.X;
                    var interativeNodeYRelativeToLastNode = interativeNode.Y - lastNode.Y;
                    var squareOfX  = Math.Pow(interativeNodeXRelativeToLastNode, 2);
                    var squareOfY  = Math.Pow(interativeNodeYRelativeToLastNode, 2);
                    var squareOfD1 = Math.Pow(distanceBetweenCentersFromLastNodeToNewBubble, 2);
                    var sumFromSquareOfXAndSquareOfY      = squareOfX + squareOfY;
                    var differFromSquareOfD1AndSquareOfD2 = squareOfD1 - Math.Pow(distanceBetweenCentersFromInterativeNodeToNewBubble, 2);
                    var sumFromSumFromSquareOfXAndSquareOfYAndDifferFromSquareOfD1AndSquareOfD2 = sumFromSquareOfXAndSquareOfY + differFromSquareOfD1AndSquareOfD2;

                    // find the third ecllipse
                    var a                           = 4 * sumFromSquareOfXAndSquareOfY;
                    var b                           = -4 * interativeNodeYRelativeToLastNode * sumFromSumFromSquareOfXAndSquareOfYAndDifferFromSquareOfD1AndSquareOfD2;
                    var c                           = Math.Pow(sumFromSumFromSquareOfXAndSquareOfYAndDifferFromSquareOfD1AndSquareOfD2, 2) - 4 * squareOfX * squareOfD1;
                    var squareOfB                   = Math.Pow(b, 2);
                    var aMultiplycMultiply4         = 4 * a * c;
                    var solutionOfQuadraticEquation = squareOfB - aMultiplycMultiply4;
                    var aMultiply2                  = 2 * a;
                    var xMultiply2                  = 2 * interativeNodeXRelativeToLastNode;
                    var yMultiply2                  = 2 * interativeNodeYRelativeToLastNode;

                    #endregion

                    // quadratic equation has solution
                    if (solutionOfQuadraticEquation >= 0)
                    {
                        var y1     = (-b + Math.Sqrt(solutionOfQuadraticEquation)) / aMultiply2;
                        var x1     = (sumFromSumFromSquareOfXAndSquareOfYAndDifferFromSquareOfD1AndSquareOfD2 - yMultiply2 * y1) / xMultiply2;
                        var y2     = (-b - Math.Sqrt(solutionOfQuadraticEquation)) / aMultiply2;
                        var x2     = (sumFromSumFromSquareOfXAndSquareOfYAndDifferFromSquareOfD1AndSquareOfD2 - yMultiply2 * y2) / xMultiply2;
                        var point1 = new Point(x1 + lastNode.X, y1 + lastNode.Y);
                        var point2 = new Point(x2 + lastNode.X, y2 + lastNode.Y);
                        var collisionWithPoint1 = false;
                        var collisionWithPoint2 = false;

                        // check collisions
                        for (var checkCollitionIndex = currentNodes.Count - 1; checkCollitionIndex >= 0; checkCollitionIndex--)
                        {
                            var node = currentNodes[checkCollitionIndex];

                            if (!collisionWithPoint1)
                            {
                                collisionWithPoint1 = CheckCollision(point1, node, newNode.Radius, bubbleGap);
                            }

                            if (!collisionWithPoint2)
                            {
                                collisionWithPoint2 = CheckCollision(point2, node, newNode.Radius, bubbleGap);
                            }
                        }

                        // no collisions
                        if (!collisionWithPoint1 && !collisionWithPoint2)
                        {
                            var point = new Point(interativeNode.X, interativeNode.Y);
                            var angleFromIntertiveNodeToPoint1 = CalculateAngle(point1, point);
                            var newBubbleAngle = CalculateAngle(new Point(lastNode.X, lastNode.Y), point);

                            // > 50 means it's clockwise
                            if (CheckAngleInRightHand(newBubbleAngle, Math.PI, angleFromIntertiveNodeToPoint1, initialAngle > 50))
                            {
                                AddNode(currentNodes, interativeNode, lastNode, newNode, point1);
                                IsNodeAdded = true;

                                break;
                            }
                            else
                            {
                                AddNode(currentNodes, interativeNode, lastNode, newNode, point2);
                                IsNodeAdded = true;

                                break;
                            }
                        }
                        else if (!collisionWithPoint1)
                        {
                            AddNode(currentNodes, interativeNode, lastNode, newNode, point1);
                            IsNodeAdded = true;

                            break;
                        }
                        else if (!collisionWithPoint2)
                        {
                            AddNode(currentNodes, interativeNode, lastNode, newNode, point2);
                            IsNodeAdded = true;

                            break;
                        }
                    }
                }

                if (IsNodeAdded)
                {
                    break;
                }
            }
        }