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 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 GameObject AddChildContainer(UiNode node, Transform parent, int n, float initialPhi = 0) { ////////////////////////////////// // // // y // // ∧ // // | . r // // | ˙ . // // | ˙ . node // // |__˛ ‚´ . // // | θ \‚´ . // // | ‚´ l . // // |‚´ . // // parent ˚-. ------.--> x // // / φ ˙ . . // // /————´ ˙ . // // ⩗ // // - z // // // ////////////////////////////////// var r = TreeGeometry.CalcSunflowerRadius(n); var phi = TreeGeometry.CalcPhi(n, initialPhi); var theta = TreeGeometry.CalcTheta(manipulator.DefaultEdgeHeight, r); var l = TreeGeometry.CalcEdgeLength(manipulator.DefaultEdgeHeight, theta); var nodePosition = TreeGeometry.CalcNodePosition(l, theta, phi); var branchObject = manipulator.AddEmptyBranchObject(parent); var edgeObject = manipulator.AddEdgeObject(branchObject.transform, TreeGeometry.SizeToScale(l, manipulator.DefaultEdgeHeight, manipulator.DefaultEdgeScale.y), theta, phi); var nodeObject = manipulator.AddEmptyNodeObject(node, branchObject.transform, nodePosition, edgeObject); return(nodeObject); }
private static LinkedListNode <Circle> GetIntersectingCircle(LinkedList <Circle> frontChain, Vector2 position, float radius) { return(frontChain.Find(frontChain.FirstOrDefault( c => TreeGeometry.Intersects(c.Position.Value, position, c.Radius, radius)))); }