/// <summary>
        /// Draws the X Axis labels, returns the height required to fit all the labels.
        /// </summary>
        /// <param name="dc"></param>
        /// <param name="scaleY"></param>
        /// <param name="labels"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        private double DrawXAxisLabels(DrawingContext dc, double scaleX, IEnumerable <GridLabel> labels, double offset)
        {
            // A list of areas on the label area on which we've already rendered text.
            // If we go to render text on a area that's already used, then go to the next
            // area and move out one width
            List <List <Range <double> > > usedDrawingAreas = new List <List <Range <double> > >();

            usedDrawingAreas.Add(new List <Range <double> >());

            List <double> maxHeights = new List <double>();

            maxHeights.Add(0);

            // First of all work out all of the render positions on the y axis

            List <LabelAndPos> labelAndPos = new List <LabelAndPos>();

            foreach (var gridLabel in labels)
            {
                double xValue = gridLabel.IsFloating ? (MinPoint.X + MaxPoint.X) * 0.5 : gridLabel.Location;
                if (!RangeX.Contains(xValue))
                {
                    continue;
                }
                double        xPos          = (-xValue + MinPoint.X) * scaleX + this.ActualWidth;
                int           labelIndex    = 0;
                FormattedText formattedText = GetText(gridLabel.Text, gridLabel.Brush);

                UnrestrictedSize labelArea;
                if (gridLabel.Orientation == Orientation.Vertical)
                {
                    labelArea = new UnrestrictedSize(formattedText.Height, formattedText.Width);
                }
                else
                {
                    labelArea = new UnrestrictedSize(formattedText.Width, formattedText.Height);
                }

                Point textPoint = new Point(xPos - labelArea.Width * 0.5 - 1, offset);
                textPoint.X = Math.Min(textPoint.X, this.ActualWidth - Math.Max(0, labelArea.Width * 0.5));
                // Uncomment this line to stop any labels going below the bottom chart line
                //textPoint.X = Math.Max(textPoint.X, 0);
                Range <double> range = new Range <double>(textPoint.X, textPoint.X + labelArea.Width);

                bool intersects;
                do
                {
                    intersects = false;
                    foreach (var usedRange in usedDrawingAreas[labelIndex])
                    {
                        if (range.Intersects(usedRange))
                        {
                            intersects = true;
                            labelIndex++;
                            if (usedDrawingAreas.Count <= labelIndex)
                            {
                                usedDrawingAreas.Add(new List <Range <double> >());
                                maxHeights.Add(0);
                            }
                            break;
                        }
                    }
                } while(intersects);

                usedDrawingAreas[labelIndex].Add(range);
                maxHeights[labelIndex] = Math.Max(maxHeights[labelIndex], labelArea.Height);
                labelAndPos.Add(new LabelAndPos(formattedText, textPoint, labelIndex, gridLabel.Orientation));
            }

            List <double> labelOffsets = new List <double>();

            labelOffsets.Add(0);
            double labelOffset = -2;

            foreach (double height in maxHeights)
            {
                labelOffset += 2 + height;
                labelOffsets.Add(labelOffset);
            }

            foreach (var gridLabel in labelAndPos)
            {
                FormattedText formattedText = gridLabel.Text;
                Point         textPoint     = gridLabel.Location;
                textPoint.X -= labelOffsets[gridLabel.Layer];
                if (gridLabel.Orientation == Orientation.Vertical)
                {
                    RotateTransform rotateTransform = new RotateTransform(-90);
                    dc.PushTransform(rotateTransform);
                    textPoint = rotateTransform.Inverse.Transform(textPoint);
                    dc.DrawText(formattedText, textPoint);
                    dc.Pop();
                }
                else
                {
                    dc.DrawText(formattedText, textPoint);
                }
            }

            double totalMaxHeight = -2;

            foreach (var maxHeight in maxHeights)
            {
                totalMaxHeight += maxHeight + 2;
            }
            return(totalMaxHeight);
        }
    /// <summary>
    /// Draws the X Axis labels, returns the height required to fit all the labels.
    /// </summary>
    /// <param name="dc"></param>
    /// <param name="scaleY"></param>
    /// <param name="labels"></param>
    /// <param name="offset"></param>
    /// <returns></returns>
    private double DrawXAxisLabels(DrawingContext dc, double scaleX, IEnumerable<GridLabel> labels, double offset) {

      // A list of areas on the label area on which we've already rendered text.
      // If we go to render text on a area that's already used, then go to the next
      // area and move out one width
      List<List<Range<double>>> usedDrawingAreas = new List<List<Range<double>>>();
      usedDrawingAreas.Add(new List<Range<double>>());

      List<double> maxHeights = new List<double>();
      maxHeights.Add(0);

      // First of all work out all of the render positions on the y axis

      List<LabelAndPos> labelAndPos = new List<LabelAndPos>();

      foreach(var gridLabel in labels) {
        double xValue = gridLabel.IsFloating ? (MinPoint.X + MaxPoint.X) * 0.5 : gridLabel.Location;
        if(!RangeX.Contains(xValue)) {
          continue;
        }
        double xPos = (-xValue + MinPoint.X) * scaleX + this.ActualWidth;
        int labelIndex = 0;
        FormattedText formattedText = GetText(gridLabel.Text, gridLabel.Brush);

        UnrestrictedSize labelArea;
        if(gridLabel.Orientation == Orientation.Vertical) {
          labelArea = new UnrestrictedSize(formattedText.Height, formattedText.Width);
        } else {
          labelArea = new UnrestrictedSize(formattedText.Width, formattedText.Height);
        }

        Point textPoint = new Point(xPos - labelArea.Width * 0.5 - 1 , offset);
        textPoint.X = Math.Min(textPoint.X, this.ActualWidth - Math.Max(0, labelArea.Width * 0.5));
        // Uncomment this line to stop any labels going below the bottom chart line
        //textPoint.X = Math.Max(textPoint.X, 0);
        Range<double> range = new Range<double>(textPoint.X, textPoint.X + labelArea.Width);

        bool intersects;
        do {
          intersects = false;
          foreach(var usedRange in usedDrawingAreas[labelIndex]) {
            if(range.Intersects(usedRange)) {
              intersects = true;
              labelIndex++;
              if(usedDrawingAreas.Count <= labelIndex) {
                usedDrawingAreas.Add(new List<Range<double>>());
                maxHeights.Add(0);
              }
              break;
            }
          }
        } while(intersects);

        usedDrawingAreas[labelIndex].Add(range);
        maxHeights[labelIndex] = Math.Max(maxHeights[labelIndex], labelArea.Height);
        labelAndPos.Add(new LabelAndPos(formattedText, textPoint, labelIndex, gridLabel.Orientation));
      }

      List<double> labelOffsets = new List<double>();
      labelOffsets.Add(0);
      double labelOffset = -2;
      foreach(double height in maxHeights) {
        labelOffset += 2 + height;
        labelOffsets.Add(labelOffset);
      }

      foreach(var gridLabel in labelAndPos) {
        FormattedText formattedText = gridLabel.Text;
        Point textPoint = gridLabel.Location;
        textPoint.X -= labelOffsets[gridLabel.Layer];
        if(gridLabel.Orientation == Orientation.Vertical) {
          RotateTransform rotateTransform = new RotateTransform(-90);
          dc.PushTransform(rotateTransform);
          textPoint = rotateTransform.Inverse.Transform(textPoint);
          dc.DrawText(formattedText, textPoint);
          dc.Pop();
        } else {
          dc.DrawText(formattedText, textPoint);
        }
      }

      double totalMaxHeight = -2;
      foreach(var maxHeight in maxHeights) {
        totalMaxHeight += maxHeight + 2;
      }
      return totalMaxHeight;
    }