private static LinkedList <Circle> InitFrontchain(UiInnerNode node) { var frontChain = new LinkedList <Circle>(); if (node.Children.Count == 0) { return(frontChain); } var c1 = node.Children[0].Circle; frontChain.AddLast(c1); if (node.Children.Count == 1) { return(frontChain); } var c2 = node.Children[1].Circle; c2.Position.Value = TreeGeometry.CalcTangentCircleCenter(c1.Position.Value, c1.Radius, c2.Radius, TreeGeometry.GetRandomAngle()); frontChain.AddLast(c2); return(frontChain); }
/// <summary> /// From Wang's circle packing algorithm, see "Visualization of large hierarchical data by circle packing" /// </summary> /// <param name="innerNode"></param> internal LinkedList <Circle> CirclePacking(UiInnerNode innerNode) { var frontChain = InitFrontchain(innerNode); for (var i = 2; i < innerNode.Children.Count; i++) { // circle with minimal distance to origin var tangentCircle1 = GetClosestFromOrigin(frontChain); // circle after tangent circle 1 var tangentCircle2 = tangentCircle1.Next(); // circle of current inner node, claculate potential position var currentCircleRad = innerNode.Children[i].Circle.Radius; var currentCirclePos = TreeGeometry.CalcTangentCircleCenter(tangentCircle1.Value.Position.Value, tangentCircle2.Value.Position.Value, tangentCircle1.Value.Radius, tangentCircle2.Value.Radius, currentCircleRad); // circle that intersects current circle var intersectingCircle = GetIntersectingCircle(frontChain, currentCirclePos, currentCircleRad); // No intersection, place current circle if (intersectingCircle == null) { innerNode.Children[i].Circle.Position.Value = currentCirclePos; frontChain.AddBefore(tangentCircle2, innerNode.Children[i].Circle); continue; } // Delete old circles from front chain if (intersectingCircle.IsAfter(tangentCircle2)) { tangentCircle1.DeleteAfterUntil(intersectingCircle); } else { intersectingCircle.DeleteAfterUntil(tangentCircle2); } // Proceed with current circle again, position is calculated according to updated front chain i--; } innerNode.Circle.Radius = GetEnclosingRadius(frontChain); return(frontChain); }