public void Build(TimeUnit unit)
        {
            var totalTime = 0.0;
            var totalTick = 0.0;

            Points.Clear();

            double nextBeat = 0.0;
            int measureNumber = 0;
            double quarterCount = 0;

            foreach (var tempo in editor.Messages.Tempos.ToList())
            {
                var scale = 1.0 / ((int)unit).ToDouble();

                var tempoLength = tempo.TimeLength;

                var beatTime = tempo.SecondsPerWholeNote;
                var beatTicks = tempo.TicksPerWholeNote;

                var currentTime = totalTime;
                var currentTick = totalTick;
                var division = 1.0 / scale;

                while (currentTime.Round(4) < totalTime + tempoLength.Round(4))
                {
                    for (int d = 0; d < division.ToInt(); d++)
                    {
                        var divisionTime = beatTime / division;
                        var divisionTicks = beatTicks / division;

                        var isWhole = Math.IEEERemainder(quarterCount.Round(4), 4.0).Round(4) == 0.0;
                        quarterCount += scale * 4;

                        var p = new GridPoint()
                        {
                            Tick = currentTick.Round(),
                            Time = currentTime,
                            TimeUnit = unit,
                            IsWholeNote = isWhole,
                            MeasureNumber = measureNumber,
                        };

                        if (isWhole)
                        {
                            measureNumber++;
                        }

                        Points.Add(p);
                        nextBeat += divisionTime;
                        currentTime += divisionTime;
                        currentTick += divisionTicks;

                        if (currentTime.Round(4) >= tempoLength.Round(4))
                        {
                            var delta = currentTime - tempoLength;
                            break;
                        }
                    }
                }
                totalTime += tempoLength;
                totalTick += tempo.TicksPerSecond * tempoLength;
            }
        }
        public void Build(TimeUnit unit)
        {
            var totalTime = 0.0;
            var totalTick = 0.0;

            Points.Clear();

            double nextBeat      = 0.0;
            int    measureNumber = 0;
            double quarterCount  = 0;

            foreach (var tempo in editor.Messages.Tempos.ToList())
            {
                var scale = 1.0 / ((int)unit).ToDouble();

                var tempoLength = tempo.TimeLength;

                var beatTime  = tempo.SecondsPerWholeNote;
                var beatTicks = tempo.TicksPerWholeNote;

                var currentTime = totalTime;
                var currentTick = totalTick;
                var division    = 1.0 / scale;

                while (currentTime.Round(4) < totalTime + tempoLength.Round(4))
                {
                    for (int d = 0; d < division.ToInt(); d++)
                    {
                        var divisionTime  = beatTime / division;
                        var divisionTicks = beatTicks / division;

                        var isWhole = Math.IEEERemainder(quarterCount.Round(4), 4.0).Round(4) == 0.0;
                        quarterCount += scale * 4;

                        var p = new GridPoint()
                        {
                            Tick          = currentTick.Round(),
                            Time          = currentTime,
                            TimeUnit      = unit,
                            IsWholeNote   = isWhole,
                            MeasureNumber = measureNumber,
                        };

                        if (isWhole)
                        {
                            measureNumber++;
                        }

                        Points.Add(p);
                        nextBeat    += divisionTime;
                        currentTime += divisionTime;
                        currentTick += divisionTicks;

                        if (currentTime.Round(4) >= tempoLength.Round(4))
                        {
                            var delta = currentTime - tempoLength;
                            break;
                        }
                    }
                }
                totalTime += tempoLength;
                totalTick += tempo.TicksPerSecond * tempoLength;
            }
        }
        private TickPair snapRightScreenPoint(TickPair screenPair, GridPoint gridPoint, List<GuitarChord> closeToRight, List<GuitarChord> closeToRight5)
        {
            var gridScreenPoint = Int32.MinValue;
            if (gridPoint != null)
            {
                if (screenPair.Up.IsCloseScreenPoint(gridPoint.ScreenPoint))
                    gridScreenPoint = gridPoint.ScreenPoint;
            }

            if (closeToRight.Any())
            {
                var minDown = closeToRight.Min(x => x.ScreenPointPair.Down);

                if (minDown < screenPair.Up)
                {
                    if (screenPair.Up.IsCloseScreenPoint(minDown))
                        screenPair.Up = minDown;
                }
                else if (gridPoint != null)
                {
                    var gd = gridScreenPoint.DistSq(screenPair.Up);
                    if (gd < minDown.DistSq(screenPair.Up))
                    {
                        if (screenPair.Up.IsCloseScreenPoint(gridScreenPoint))
                            screenPair.Up = gridScreenPoint;
                    }
                    else
                    {
                        if (screenPair.Up.IsCloseScreenPoint(minDown))
                            screenPair.Up = minDown;
                    }
                }
                else
                {
                    if (screenPair.Up.IsCloseScreenPoint(minDown))
                        screenPair.Up = minDown;
                }
            }
            else if (gridPoint != null)
            {
                if (screenPair.Up.IsCloseScreenPoint(gridScreenPoint))
                    screenPair.Up = gridScreenPoint;
            }
            return screenPair;
        }
        private TickPair snapRightTick(TickPair tickPair, GridPoint gridPoint,
            IEnumerable<TickPair> closeToRight,
            IEnumerable<TickPair> closeToRight5, SnapConfig config)
        {
            var gridTick = Int32.MinValue;
            var tickPair5 = Int32.MinValue;
            var tickPair6 = Int32.MinValue;

            if (gridPoint != null && config.SnapGrid)
            {
                if (tickPair.Up.IsCloseTick(gridPoint.Tick))
                    gridTick = gridPoint.Tick;
            }
            if (config.SnapG5 && closeToRight5 != null && closeToRight5.Any())
            {
                var closeDown = closeToRight5.Where(x => x.Down.IsCloseTick(tickPair.Up)).ToList();
                var closeUp = closeToRight5.Where(x => x.Up.IsCloseTick(tickPair.Up)).ToList();

                if (closeDown.Any())
                {
                    var minDown = closeDown.Select(x => new { Dist = (tickPair.Up - x.Down).Abs(), Val = x.Down }).OrderBy(x => x.Dist).FirstOrDefault().Val;

                    if (tickPair.Up.IsCloseTick(minDown))
                    {
                        tickPair5 = minDown;
                    }
                    else if (gridPoint != null && config.SnapGrid && gridTick.IsNotNull())
                    {
                        var gd = gridTick.DistSq(tickPair.Up);
                        if (gd < minDown.DistSq(tickPair.Up))
                        {
                            if (tickPair.Up.IsCloseTick(gridTick))
                                tickPair5 = gridTick;
                        }
                        else
                        {
                            if (tickPair.Up.IsCloseTick(minDown))
                                tickPair5 = minDown;
                        }
                    }

                }
                if (closeUp.Any())
                {
                    var maxUp = closeUp.Select(x => new { Dist = (tickPair.Up - x.Up).Abs(), Val = x.Up }).OrderBy(x => x.Dist).FirstOrDefault().Val;

                    if (tickPair.Up.IsCloseTick(maxUp))
                    {
                        tickPair5 = maxUp;
                    }
                    else if (gridPoint != null && config.SnapGrid && gridTick.IsNotNull())
                    {
                        var gd = gridTick.DistSq(tickPair.Up);
                        if (gd < maxUp.DistSq(tickPair.Up))
                        {
                            if (tickPair.Up.IsCloseTick(gridTick))
                                tickPair5 = gridTick;
                        }
                        else
                        {
                            if (tickPair.Up.IsCloseTick(maxUp))
                                tickPair5 = maxUp;
                        }
                    }

                }

            }
            if (config.SnapG6 && closeToRight != null && closeToRight.Any())
            {
                var closeDown = closeToRight.Where(x => x.Down.IsCloseTick(tickPair.Up)).ToList();
                var closeUp = closeToRight.Where(x => x.Up.IsCloseTick(tickPair.Up)).ToList();

                if (closeDown.Any())
                {
                    var minDown = closeDown.Select(x => new { Dist = (tickPair.Up - x.Down).Abs(), Val = x.Down }).OrderBy(x => x.Dist).FirstOrDefault().Val;

                    if (tickPair.Up.IsCloseTick(minDown))
                    {
                        tickPair6 = minDown;
                    }
                    else if (gridPoint != null && config.SnapGrid && gridTick.IsNotNull())
                    {
                        var gd = gridTick.DistSq(tickPair.Up);
                        if (gd < minDown.DistSq(tickPair.Up))
                        {
                            if (tickPair.Up.IsCloseTick(gridTick))
                                tickPair6 = gridTick;
                        }
                        else
                        {
                            if (tickPair.Up.IsCloseTick(minDown))
                                tickPair6 = minDown;
                        }
                    }

                }
                if (closeUp.Any())
                {
                    var maxUp = closeUp.Select(x => new { Dist = (tickPair.Up - x.Up).Abs(), Val = x.Up }).OrderBy(x => x.Dist).FirstOrDefault().Val;

                    if (tickPair.Up.IsCloseTick(maxUp))
                    {
                        tickPair6 = maxUp;
                    }
                    else if (gridPoint != null && config.SnapGrid && gridTick.IsNotNull())
                    {
                        var gd = gridTick.DistSq(tickPair.Up);
                        if (gd < maxUp.DistSq(tickPair.Up))
                        {
                            if (tickPair.Up.IsCloseTick(gridTick))
                                tickPair6 = gridTick;
                        }
                        else
                        {
                            if (tickPair.Up.IsCloseTick(maxUp))
                                tickPair6 = maxUp;
                        }
                    }

                }
            }
            else if (gridPoint != null && config.SnapGrid && gridTick.IsNotNull())
            {
                if (tickPair.Up.IsCloseTick(gridTick))
                    tickPair.Up = gridTick;
            }
            var ret = new[] { tickPair6, tickPair5, gridTick }.Where(x => x.IsNotNull());
            if (ret.Any())
            {
                tickPair.Up = ret.Select(x => new { Dist = (x - tickPair.Up).Abs(), Val = x }).OrderBy(x => x.Dist).FirstOrDefault().Val;
            }
            if (tickPair.Up.IsNull() == false &&
                tickPair.Up < tickPair.Down)
            {
                tickPair.Up = tickPair.Down;
            }
            return tickPair;
        }
        private TickPair snapLeftScreenPoint(TickPair screenPair, GridPoint gridPoint, List<GuitarChord> closeToLeft, List<GuitarChord> closeToLeft5)
        {
            var gridScreenPoint = Int32.MinValue;
            if (gridPoint != null)
            {
                if (screenPair.Down.IsCloseScreenPoint(gridPoint.ScreenPoint))
                    gridScreenPoint = gridPoint.ScreenPoint;
            }
            if (closeToLeft5.Any())
            {
                var maxLeft = closeToLeft5.Max(x => x.ScreenPointPair.Up);

                if (maxLeft > screenPair.Down)
                {
                    if (screenPair.Down.IsCloseScreenPoint(maxLeft))
                        screenPair.Down = maxLeft;
                }
                else if (gridPoint != null)
                {
                    var gd = gridScreenPoint.DistSq(screenPair.Down);
                    if (gd < maxLeft.DistSq(screenPair.Down))
                    {
                        if (screenPair.Down.IsCloseScreenPoint(gridScreenPoint))
                            screenPair.Down = gridScreenPoint;
                    }
                    else
                    {
                        if (screenPair.Down.IsCloseScreenPoint(maxLeft))
                            screenPair.Down = maxLeft;
                    }
                }
                else
                {
                    if (screenPair.Down.IsCloseScreenPoint(maxLeft))
                        screenPair.Down = maxLeft;
                }
            }
            if (closeToLeft.Any())
            {
                var maxLeft = closeToLeft.Max(x => x.ScreenPointPair.Up);

                if (maxLeft > screenPair.Down)
                {
                    if (screenPair.Down.IsCloseScreenPoint(maxLeft))
                        screenPair.Down = maxLeft;
                }
                else if (gridPoint != null)
                {
                    var gd = gridScreenPoint.DistSq(screenPair.Down);
                    if (gd < maxLeft.DistSq(screenPair.Down))
                    {
                        if (screenPair.Down.IsCloseScreenPoint(gridScreenPoint))
                            screenPair.Down = gridScreenPoint;
                    }
                    else
                    {
                        if (screenPair.Down.IsCloseScreenPoint(maxLeft))
                            screenPair.Down = maxLeft;
                    }
                }
                else
                {
                    if (screenPair.Down.IsCloseScreenPoint(maxLeft))
                        screenPair.Down = maxLeft;
                }
            }
            else if (gridPoint != null)
            {
                if (screenPair.Down.IsCloseScreenPoint(gridScreenPoint))
                    screenPair.Down = gridScreenPoint;
            }
            return screenPair;
        }