public static DecimalPoint AddPoint(this DecimalPoint p, DecimalPoint q)
 {
     return(new DecimalPoint(p.X + q.X, p.Y + q.Y));
 }
 public static decimal LineLength(this DecimalPoint p, DecimalPoint q)
 {
     return((decimal)Math.Sqrt(Math.Pow((double)p.X - (double)q.X, 2) + Math.Pow((double)p.Y + (double)q.Y, 2)));
 }
 public static decimal LineHeight(this DecimalPoint p, DecimalPoint q)
 {
     return(Math.Abs(p.Y - q.Y));
 }
        public Rect PlaceControl(UIElement child)
        {
            var finalSize = child.DesiredSize;

            if (finalSize.Width == 0 || finalSize.Height == 0)
            {
                return(new Rect(0, 0, 0, 0));
            }

            this.OptimizePoints();

            var sortedPointsLeftFirst = from p in this.Points
                                        orderby p.Key.X, p.Key.Y ascending
            select p;
            var sortedPointsTopFirst = from p in this.Points
                                       orderby p.Key.Y, p.Key.X ascending
            select p;

            Rect finalRect = new Rect();

            for (int i = 0; i < sortedPointsLeftFirst.Count(); i++)
            {
                var entry = sortedPointsLeftFirst.ElementAt(i);

                var upperPoint = entry.Key;
                var lowerPoint = entry.Value;

                if ((decimal)finalSize.Height <= upperPoint.LineHeight(lowerPoint))
                {
                    // Case 1: The tile is shorter or equal to the current line
                    finalRect = new Rect(upperPoint.ToPoint(), finalSize);

                    // Split line
                    var newUpperPoint1 = new DecimalPoint(upperPoint.X + (decimal)finalSize.Width, upperPoint.Y);
                    var newLowerPoint1 = new DecimalPoint(upperPoint.X + (decimal)finalSize.Width, upperPoint.Y + (decimal)finalSize.Height);

                    this.Points.Remove(upperPoint);

                    this.Points.Add(newUpperPoint1, newLowerPoint1);

                    if ((decimal)finalSize.Height < upperPoint.LineHeight(lowerPoint))
                    {
                        var newUpperPoint2 = new DecimalPoint(lowerPoint.X, upperPoint.Y + (decimal)finalSize.Height);
                        var newLowerPoint2 = lowerPoint;
                        this.Points.Add(newUpperPoint2, newLowerPoint2);
                    }

                    break;
                }
                else
                {
                    // Case 2:The tile is longer than the current line
                    var     lowerNeighbors = new Dictionary <DecimalPoint, DecimalPoint>();
                    decimal sum            = upperPoint.LineHeight(lowerPoint);
                    foreach (var neighbor in from p in sortedPointsTopFirst
                             where p.Key.Y >= lowerPoint.Y
                             select p)
                    {
                        lowerNeighbors.Add(neighbor.Key, neighbor.Value);
                        sum += neighbor.Key.LineHeight(neighbor.Value);
                        if (sum >= (decimal)finalSize.Height)
                        {
                            break;
                        }
                    }

                    if (sum < (decimal)finalSize.Height)
                    {
                        // We would leak outside the view at the bottom
                        continue;
                    }

                    // Now we do have all lower neighbors
                    if (lowerNeighbors.Count > 0)
                    {
                        // Do we have place or not?
                        bool cont = false;
                        foreach (var neighbor in lowerNeighbors)
                        {
                            if (neighbor.Key.X > upperPoint.X)
                            {
                                // We have no space!
                                cont = true;
                                break;
                            }
                        }
                        if (cont)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }

                    // We have space
                    finalRect = new Rect(new Point((double)upperPoint.X, (double)upperPoint.Y), finalSize);

                    var lowestNeighbor = lowerNeighbors.Last();

                    // Remove all lower neighbor points
                    for (int j = 0; j < lowerNeighbors.Count; j++)
                    {
                        this.Points.Remove(lowerNeighbors.ElementAt(j).Key);
                    }

                    this.Points.Remove(upperPoint);

                    // Add the necessary points
                    var newUpperPoint1 = new DecimalPoint(upperPoint.X + (decimal)finalSize.Width, upperPoint.Y);
                    var newLowerPoint1 = new DecimalPoint(upperPoint.X + (decimal)finalSize.Width, upperPoint.Y + (decimal)finalSize.Height);

                    var newUpperPoint2 = new DecimalPoint(lowestNeighbor.Key.X, upperPoint.Y + (decimal)finalSize.Height);
                    var newLowerPoint2 = lowestNeighbor.Value;

                    this.Points.Add(newUpperPoint1, newLowerPoint1);
                    this.Points.Add(newUpperPoint2, newLowerPoint2);

                    return(finalRect);
                }
            }

            if (finalRect == new Rect())
            {
                var right = this.Points.Max(p => p.Key.X);

                var topPoint = (from p in this.Points
                                where p.Key.Y == 0
                                select p).First();

                this.Points.Remove(topPoint.Key);
                this.Points.Add(new DecimalPoint(right, topPoint.Key.Y), new DecimalPoint(right, topPoint.Value.Y));

                this.OptimizePoints();
                return(this.PlaceControl(child));
            }

            return(finalRect);
        }