コード例 #1
0
        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);
            }
        }