public void Circlify(List <TreemapData> data) { //IL faut commencer par les 2 plus gros cercles, le milieu du cercle final étant le centre du segment reliant les extrémités de ces cercles. double a1 = GetInnerCircleArea() * data[0].Size / Size; double a2 = GetInnerCircleArea() * data[1].Size / Size; double r1 = Math.Sqrt(a1 / Math.PI); double r2 = Math.Sqrt(a2 / Math.PI); var items = new Dictionary <TreemapItem, List <TreemapItem> >(); Geometric.Point center = GetCenter(); TreemapItem item1 = AddItem(data[0], center.AddX(-r2), r1); TreemapItem item2 = AddItem(data[1], center.AddX(r1), r2); items.Add(item1, new List <TreemapItem> { item2 }); items.Add(item2, new List <TreemapItem> { item1 }); for (int d = 2; d < data.Count; d++) { double a = GetInnerCircleArea() * data[d].Size / Size; double r = Math.Sqrt(a / Math.PI); var results = new List <Tuple <TreemapItem, TreemapItem, Geometric.Point, double> >(); foreach (var kvp in items) { TreemapItem i1 = kvp.Key; foreach (TreemapItem i2 in kvp.Value) { Triangle t = Triangle.FromTwoPointsAndTwoLengths(i1.GetCenter(), i2.GetCenter(), i1.GetRadius() + r, i2.GetRadius() + r); double distance = center.Distance(t.Point3); if (Items.All(item => item.GetCenter().Distance(t.Point3) - (item.GetRadius() + r) >= -0.0001)) { results.Add(Tuple.Create(i1, i2, t.Point3, distance)); } } } var result = results.OrderBy(t => t.Item4).First(); TreemapItem newItem = AddItem(data[d], result.Item3, r); items[result.Item1].Add(newItem); items[result.Item2].Add(newItem); items.Add(newItem, new List <TreemapItem> { result.Item1, result.Item2 }); } //Identify the item farther from the center and expand the chart so that this item becomes adjacent to external circle var max = Items .Select(i => new { Item = i, Distance = i.GetCenter().Distance(center) + i.GetRadius() }) .OrderByDescending(o => o.Distance) .First(); Homothety homothety = new Homothety(center, GetRadius() / max.Distance); foreach (var item in Items) { item.Rectangle = homothety.Transform(item.Rectangle); item.InnerRectangle = homothety.Transform(item.InnerRectangle); item.Empty = homothety.Transform(item.Empty); } //Homothety from contact point Vector vector = new Segment(center, max.Item.GetCenter()).ToVector(); Geometric.Point contact = max.Item.GetCenter() .AddX(max.Item.GetRadius() / vector.Length * vector.X) .AddY(max.Item.GetRadius() / vector.Length * vector.Y); NewtonSolver solver = new NewtonSolver((c) => { Homothety h = new Homothety(contact, c); double min = Items .Except(new List <TreemapItem> { max.Item }) .Select(i => h.Transform(i.InnerRectangle)) .Select(r => new { Center = new Geometric.Point(r.Left + r.Width / 2, r.Top + r.Height / 2), Radius = r.Width / 2 }) .Min(r => GetRadius() - (r.Center.Distance(center) + r.Radius)); return(min); }) .Solve(1); homothety = new Homothety(contact, solver.Solution); foreach (var item in Items) { item.Rectangle = homothety.Transform(item.Rectangle); item.InnerRectangle = homothety.Transform(item.InnerRectangle); item.Empty = homothety.Transform(item.Empty); } }