private void RenderPicture(Graphics g) { var angleOffset = -Math.PI / 2; var anglePerStudent = Math.PI * 2 / _students.Count; var center = new Point(_width / 2, _height / 2); var maxRadius = Math.Min(center.X, center.Y) * _ratio / 100.0f; Func<int, float, float, Point> getPoint = (id, delta, lRadius) => { var radius = maxRadius * lRadius / 100.0f; var angle = angleOffset + anglePerStudent * (id + delta / 100.0f); return center + new Size((int)(radius * Math.Cos(angle)), (int)(radius * Math.Sin(angle))); }; Func<float, Rectangle> getRectangle = lRadius => { var delta = maxRadius*lRadius/100.0f; return new Rectangle((int)(center.X - delta), (int)(center.Y - delta), (int) (2*delta), (int) (2*delta)); }; Func<double, float> toDeg = rad => (float) (rad / Math.PI * 180); // Пороговые линии for (var j = 0; j < _grades.Count; ++j) { g.DrawPie(new Pen(Color.Black, j == (_grades.Count - 1) ? 4 : 2) {DashPattern = new[] {3.0f, 5.0f}}, getRectangle(_grades[j]), 0.0f, 360.0f); } // Основные и дополнительные зависимости for (var i = 0; i < _students.Count; ++i) { var grades = _students[i].Grades; var mainGrades = (_mode == Mode.Pie || _mode == Mode.Pie) ? new[]{0.0f}.Concat(grades[0]).ToList() : Enumerable.Range(0, grades[0].Length + 1).Select(a => a * 100.0f / grades[0].Length).ToList(); // Основная зависимость for (var j = mainGrades.Count - 1; j >= 1; --j) { if (Math.Abs(mainGrades[j]) > Parameters.Tolerance) { var brush = GetBrush(j, grades); g.FillPie(brush, getRectangle(mainGrades[j]), toDeg(angleOffset + anglePerStudent * i), toDeg(anglePerStudent)); g.DrawPie(new Pen(Color.Black, 2), getRectangle(mainGrades[j]), toDeg(angleOffset + anglePerStudent * i), toDeg(anglePerStudent)); } } // Дополнительные зависимости for (var k = 1; k < grades.Length; ++k) { var addGrades = new List<float> {0.0f}; addGrades.AddRange(grades[k]); if (addGrades.All(a => a < Parameters.Tolerance)) continue; for (var j = 0; j < addGrades.Count - 1; ++j) g.DrawLine(_additionalData[(k - 1) % _additionalData.Count], getPoint(i, addGrades[j], mainGrades[j]), getPoint(i, addGrades[j + 1], mainGrades[j + 1])); } } // Разделительные линии между секторами for (var i = 0; i < _students.Count; ++i) { g.DrawLine(new Pen(Color.Black, 2), center, getPoint(i, 0, 110)); } // Разделители между секторами for (var j = 0; j < _part.Count; ++j) { g.DrawLine(new Pen(Color.Black, 6), center, getPoint(_part[j], 0, 110)); } var half = (int)Math.Ceiling(_students.Count / 2.0); // Имена студентов for (var i = 0; i < _students.Count; ++i) { var posRight = i < half; var point = getPoint(i, 50, 0.6f * maxRadius); var message = string.Format("{0} ({1})", _students[i].Name, _students[i].Info); g.DrawString(message, _font, Brushes.Black, point, posRight ? _rightFormat : _leftFormat); } var lOffset = new Point(470, 30); var lOffset2 = center + new Size(lOffset.X, lOffset.Y); const int lSize = 30; if (_mode == Mode.BlackRound || _mode == Mode.ColorRound) { lOffset = new Point(530, 30); lOffset2 = center + new Size(lOffset.X, lOffset.Y); // Дата прохождения теста g.DrawString(_localizations["passingTestDate"], _smallFont, Brushes.Black, lOffset2.X - 30, lOffset2.Y - 215); for (var j = 0; j < _dates.Count; ++j) { var rect = getRectangle(100 / _dates.Count * (j + 1)); rect.Offset(lOffset); var center2 = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); g.DrawPie(new Pen(Color.Black, j == (_dates.Count - 1) ? 4 : 2) { DashPattern = new[] { 3.0f, 5.0f } }, rect, 270, 40); g.DrawString(_dates[j], _smallFont, Brushes.Black, center2 + new Size(-5, (int)(-(j + 1) * maxRadius / _dates.Count)), _leftFormat); if ((_grades.Count - 1) == j) { g.DrawLine(new Pen(Brushes.Black, 4.0f), center2, center2 + new Size((int)(maxRadius * Math.Cos(-Math.PI / 180 * 90)), (int)(maxRadius * Math.Sin(-Math.PI / 180 * 90)))); g.DrawLine(new Pen(Brushes.Black, 4.0f), center2, center2 + new Size((int)(maxRadius * Math.Cos(-Math.PI / 180 * 50)), (int)(maxRadius * Math.Sin(-Math.PI / 180 * 50)))); } } var gradeOffsetY = lOffset2.Y + (int)(1.5 * lSize); var gradeSizeY = lSize * 4; var gradeOffset = 1.0f; // Количество баллов за тест g.DrawString(_localizations["scorePerTest"], _smallFont, Brushes.Black, lOffset2.X - 30, lOffset2.Y + 15); var grades2 = new[] { 0.0f }.Concat(_grades.Take(_grades.Count - 1)).ToArray(); if (_mode == Mode.ColorRound) { for (var i = grades2.Length - 1; i >= 0; --i) { var grade = grades2[i] / 100.0f; var fullRect = getRectangle(grade * 100.0f); fullRect.Offset(lOffset); var pgb = new LinearGradientBrush( new Point { X = 0, Y = gradeOffsetY + (int)(gradeSizeY * (1 - gradeOffset)) }, new Point { X = 0, Y = gradeOffsetY + (int)(gradeSizeY * (1 - grade)) }, new HslColor(_modeParam[0], _modeParam[1], _modeParam[i + 3]), new HslColor(_modeParam[0], _modeParam[1], _modeParam[i + 2]) ); g.FillRectangle(pgb, lOffset2.X, gradeOffsetY + (int)(gradeSizeY * (1 - gradeOffset)), lSize, (int)(gradeSizeY * gradeOffset)); gradeOffset = grade; } } else { gradeOffset = 1.0f; for (var i = 100; i >= 0; i -= 10) { var fullRect = getRectangle(i); fullRect.Offset(lOffset); var pgb = TranslateGradeToHatch(i); g.FillRectangle(pgb, lOffset2.X, gradeOffsetY + (int)(gradeSizeY * (1 - gradeOffset)), lSize, (int)(gradeSizeY * (gradeOffset - i / 100.0f))); gradeOffset = i/100.0f; } } gradeOffset = 1.0f; for (var i = grades2.Length - 1; i >= 0; --i) { var grade = grades2[i] / 100.0f; var fullRect = getRectangle(grade * 100.0f); fullRect.Offset(lOffset); g.DrawString(_grades[i].ToString(), _smallFont, Brushes.Black, lOffset2.X + 2 * lSize, gradeOffsetY + (int)(gradeSizeY * (1 - gradeOffset)), _leftFormat); gradeOffset = grade; } g.DrawRectangle(Pens.Black, lOffset2.X, gradeOffsetY, lSize, gradeSizeY); } else { // Количество баллов за тест g.DrawString(_localizations["scorePerTest"], _smallFont, Brushes.Black, lOffset2.X - 30, lOffset2.Y - 215); for (var j = 0; j < _grades.Count; ++j) { var rect = getRectangle(_grades[j]); rect.Offset(lOffset); var center2 = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); g.DrawPie(new Pen(Color.Black, j == (_grades.Count - 1) ? 4 : 2) { DashPattern = new[] { 3.0f, 5.0f } }, rect, 270, 40); g.DrawString(_grades[j].ToString(), _smallFont, Brushes.Black, center2 + new Size(-5, (int)(-_grades[j] * maxRadius / 100)), _leftFormat); if ((_grades.Count - 1) == j) { g.DrawLine(new Pen(Brushes.Black, 4.0f), center2, center2 + new Size((int)(maxRadius * Math.Cos(-Math.PI / 180 * 90)), (int)(maxRadius * Math.Sin(-Math.PI / 180 * 90)))); g.DrawLine(new Pen(Brushes.Black, 4.0f), center2, center2 + new Size((int)(maxRadius * Math.Cos(-Math.PI / 180 * 50)), (int)(maxRadius * Math.Sin(-Math.PI / 180 * 50)))); } } // Дата прохождения теста g.DrawString(_localizations["passingTestDate"], _smallFont, Brushes.Black, lOffset2.X - 30, lOffset2.Y + 15); for (var j = 0; j < _dates.Count; ++j) { var lYOffset = (int)(lOffset2.Y + (j + 1) * lSize * 1.5); if (_mode == 0) g.FillRectangle(_brushes[j % _brushes.Count], lOffset2.X, lYOffset, lSize, lSize); g.DrawRectangle(new Pen(Brushes.Black, 2.0f), lOffset2.X, lYOffset, lSize, lSize); g.DrawString(_dates[j], _smallFont, Brushes.Black, lOffset2.X + lSize, lYOffset); } } // Легенда дополнительных зависимостей var additionalLegendStartPoint = center + new Size((int)(-2.4 * maxRadius), -30); for (var k = 0; k < _additionalName.Count; ++k) { var nameSize = g.MeasureString(_additionalName[k], _smallFont); g.DrawLine(_additionalData[k], additionalLegendStartPoint, additionalLegendStartPoint + new Size(-(int)nameSize.Width, 0)); additionalLegendStartPoint -= new Size(0, (int)_additionalData[k].Width + 10); g.DrawString(_additionalName[k], _smallFont, Brushes.Black, additionalLegendStartPoint, _leftFormat); additionalLegendStartPoint -= new Size(0, (int)nameSize.Height + 30); } }