public PeriodMatrix( StudyDay day ) { _positions = new Dictionary<Period, int>(); _widthMultipliers = new Dictionary<Period, double>(); int[] periodsPerInterval = new int[HoursInDay * MinutesInHour / CollisionCheckingInterval]; foreach ( var period in day.Periods ) { IterateOverIntervals( period, n => periodsPerInterval[n]++ ); } ColumnCount = periodsPerInterval.Max(); int[] remainingPeriods = (int[]) periodsPerInterval.Clone(); // First order the periods by number of periods that collide, otherwise the algorithm fails. // e.g. // --------- // -------- ----- // if we don't handle the top one first, both it and the first bottom one will be in column 1. var totalCollisionsPerPeriods = day.Periods.ToDictionary( p => p, p => day.Periods.Count( p2 => ( p2.Start >= p.Start && p2.Start < p.End ) // start is inside the period || ( p2.End >= p.Start && p2.End < p.End ) // end is inside the period || ( p2.Start <= p.Start && p2.End >= p.End ) // start and end surround the period ) ); foreach ( var pair in totalCollisionsPerPeriods.OrderByDescending( p => p.Value ) ) { var period = pair.Key; int collisions = 1; int column = 0; IterateOverIntervals( period, n => collisions = Math.Max( collisions, periodsPerInterval[n] ) ); IterateOverIntervals( period, n => { remainingPeriods[n]--; column = Math.Max( column, remainingPeriods[n] ); } ); _positions.Add( period, column ); _widthMultipliers.Add( period, 1.0 / collisions ); } }
private void AddPeriodsToCanvas( Canvas canvas, Size size, StudyDay day ) { var matrix = new PeriodMatrix( day ); double heightPerMinute = size.Height / ( ( _maxHour - _minHour ) * MinutesInHour ); double widthPerColumn = size.Width / matrix.ColumnCount; var startDate = day.Day.AddHours( _minHour ); foreach ( var period in day.Periods ) { var control = new ContentControl { ContentTemplate = PeriodTemplate, Content = period, Style = ContainerStyle, Height = ( period.End - period.Start ).TotalMinutes * heightPerMinute, Width = matrix.GetWidthMultiplier( period ) * size.Width }; Canvas.SetTop( control, ( period.Start - startDate ).TotalMinutes * heightPerMinute ); Canvas.SetLeft( control, widthPerColumn * matrix.GetColumn( period ) ); canvas.Children.Add( control ); } }
private static Tuple<int, int> GetHourBoundaries( StudyDay[] days ) { int min = days.Min( d => d.Periods.Any() ? d.Periods.Min( p => p.Start.Hour ) : EmptyScheduleStart ); int max = days.Max( d => d.Periods.Any() ? d.Periods.Max( p => HourCeiling( p.End.TimeOfDay ) ) : EmptyScheduleEnd ); if ( min + MinimumHoursInDay > HoursInDay ) { min = max - MinimumHoursInDay; } else { max = Math.Max( max, min + MinimumHoursInDay ); } return Tuple.Create( min, max ); }
/// <summary> /// Creates a new PeriodMatrix for the specified day's periods. /// </summary> public PeriodMatrix( StudyDay day ) { _positions = new Dictionary<Period, int>(); _widthMultipliers = new Dictionary<Period, double>(); int[] periodsPerInterval = new int[HoursInDay * MinutesInHour / CollisionCheckingInterval]; foreach ( var period in day.Periods ) { IterateOverIntervals( period, periodsPerInterval, n => periodsPerInterval[n]++ ); } ColumnCount = periodsPerInterval.Max(); int[] remainingPeriods = (int[]) periodsPerInterval.Clone(); foreach ( var period in day.Periods ) { int collisions = 1; int column = 0; IterateOverIntervals( period, periodsPerInterval, n => collisions = Math.Max( collisions, periodsPerInterval[n] ) ); IterateOverIntervals( period, remainingPeriods, n => { remainingPeriods[n]--; column = Math.Max( column, remainingPeriods[n] ); } ); _positions.Add( period, column ); _widthMultipliers.Add( period, 1.0 / collisions ); } }