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); }
private List <GameObject> AddBranchObjects(UiInnerNode node, Transform parent, float scale) { var branches = new List <GameObject>(); var count = node.Children.Count; for (var i = 0; i < count; i++) { // Add a new branch and subsequent edge and node branches.Add(AddBranchObject(node.Children[i], parent, count, i, scale)); } return(branches); }
private void DistributeSunflower(UiInnerNode innerNode, Transform parent) { var rndAngle = TreeGeometry.GetRandomAngle(); for (var i = 0; i < innerNode.Children.Count; i++) { var child = innerNode.Children[i]; var nodeObject = AddChildContainer(child, parent, i, rndAngle); GenerateBranches(child, nodeObject.transform); } innerNode.Circle.Radius = innerNode.Children.Count == 1 ? TreeGeometry.NodeDistanceFactor : TreeGeometry.CalcSunflowerRadius(innerNode.Children.Count - 1); }
/// <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); }
private void GenerateUnsdistributedBranches(UiInnerNode innerNode, Transform parent) { var nodeHeight = innerNode.GetHeight(); var centralEdgeHeight = manipulator.DefaultEdgeHeight * GetYScalingFactor(nodeHeight); var edgeThickness = manipulator.DefaultEdgeScale.x * GetXScalingFactor(nodeHeight); foreach (var child in innerNode.Children) { var branchObject = manipulator.AddEmptyBranchObject(parent); // Edge length doesn't matter at this point. It is set properly at subscription of node position. var edgeObject = manipulator.AddEdgeObject(branchObject.transform, 1, 0, 0, edgeThickness); var nodeObject = manipulator.AddEmptyNodeObject(child, branchObject.transform, Vector3.up * centralEdgeHeight, edgeObject); // Rotate and stretch edge according to corresponding node. manipulator.SubscribeNodePosition(child.Circle, nodeObject, edgeObject, centralEdgeHeight); GenerateBranches(child, nodeObject.transform); } }
private static bool HasOnlyLeaves(UiInnerNode node) { return(node.Children.TrueForAll(n => n is UiLeaf)); }
private void DistributeCirclePacking(UiInnerNode innerNode, Transform parent) { GenerateUnsdistributedBranches(innerNode, parent); CirclePacking(innerNode); }