}
//=== Заполнение AxisData для любой из осей
public void Scale (ref AxisData data)
{
if (points.Length == 0)
return;
data.max = data.bX ? points[0].X : points[0].Y; // Поиск экстремумов
data.min = data.max;
foreach (PointF p in points)
{
float d = data.bX ? p.X : p.Y;
if (d < data.min)
data.min = d;
else if (d > data.max)
data.max = d;
}
//===== Максимальная амплитуда двух экстремумов
double ext = Math.Max (Math.Abs (data.min), Math.Abs(data.max));
//=== Искусственно увеличиваем порядок экстремума на 3 единицы.
//=== Хотим покрыть 7 порядков, не переходя к экспоненцеальной форме
double power = ext;
if (ext > 0)
power = Math.Log10 (ext) + 3;
data.power = (float)Math.Floor (power / 7);
//===== Если не укладываемся в этот диапазон, восстанавливаем порядок
if (data.power != 0)
data.power = (float)Math.Floor (power) - 3;
data.factor = (float)Math.Pow (10, data.power);// Реальный множитель
//===== Диапазон изменения мантиссы
double span = (data.max - data.min) / data.factor;
if (span == 0) // Если он нулевой, искусственно раздвигаем график
span = 0.5f;
data.step = CalcStep (span); // Подбираем стандартный шаг мантиссы
data.dStep = data.step * data.factor; // Реальный шаг
//=== Начальная линия сетки д.б. кратна шагу и быть меньше минимума
data.dStart = data.dStep * (float)Math.Floor (data.min / data.dStep);
data.start = data.dStart / data.factor; // Начальная линия сетки (мантисса)
for (data.end = data.start; // Вычисляем последнюю линию сетки
data.end < data.min / data.factor + span - 1e-15;
data.end += data.step)
;
data.dEnd = data.end * data.factor;
float length = data.bX ? (rb.X - lt.X) : (rb.Y - lt.Y);
data.scale = length / (data.factor * (data.end - data.start));
}
float ToPixelX (float x) // Переход к пиксельным координатам
{
return lt.X + (x - dataX.dStart) * dataX.scale;
}
float ToPixelY (float y)
{
return rb.Y - (y - dataY.dStart) * dataY.scale;
}
public void Draw (Graphics g) // Изображение графика в заданном контексте
{
GraphicsPath path = new GraphicsPath ();
path.AddArc (0, 0, 40, 40, 180, 90);
path.AddLine (20, 0, size.Width-20, 0);
path.AddArc (size.Width-40, 0, 40, 40, 270, 90);
path.AddLine (size.Width, 20, size.Width, size.Height-20);
path.AddArc (size.Width-40, size.Height-40, 40, 40, 0, 90);
path.AddLine (size.Width-20, size.Height, 20, size.Height);
path.AddArc (0, size.Height-40, 40, 40, 90, 90);
path.CloseFigure();
g.FillPath (Brushes.AliceBlue, path);
g.DrawPath (new Pen (Color.DarkBlue, 0), path);
SolidBrush brush = new SolidBrush(Color.FromArgb(255,255,250));
g.FillRectangle (brush, lt.X, lt.Y, rb.X-lt.X, rb.Y-lt.Y);
Scale (ref dataX);
Scale (ref dataY);
string s = String.Format ( // Выводим экстремумы функции
"Min = {0:g4} Max = {1:g4}", dataY.min, dataY.max);
Font font = new Font("Tahoma", 10, FontStyle.Bold);
SizeF sz = g.MeasureString (s, font);
int
w = (int)sz.Width/2 + 8,
ww = w + w,
wm = w - 8;
g.FillRectangle (Brushes.DarkGray, bc.X-w, bc.Y+2, ww, hh);
brush = new SolidBrush (Color.FromArgb(200,220,255));
g.FillRectangle (brush, bc.X-w-4, bc.Y-2, ww, hh);
g.DrawString (s, font, Brushes.Black, bc.X-wm, bc.Y+3);
//====== Готовимся изображать координатную сетку
StringFormat fmt = new StringFormat();
fmt.Alignment = StringAlignment.Center;
//====== Вывод меток осей
g.DrawString (title, new Font("Arial", 14), Brushes.DarkBlue,
bc.X-10, lt.Y-hh, fmt);
g.DrawString (sX, wnd.Font, Brushes.Black, rb.X-h, rb.Y+h2);
Pen pen = new Pen (Color.Black, 0);
Pen gridPen = new Pen (Color.DarkGray, 0);
//====== Вертикальные линии сетки
for (float x = dataX.start; x < dataX.end-dataX.step/2; x += dataX.step)
{
float xi = ToPixelX (x * dataX.factor);
g.DrawLine (gridPen, xi, lt.Y, xi, rb.Y);
s = MakeLabel (true, x);
g.DrawString (s, wnd.Font, Brushes.Black, xi, rb.Y+h2, fmt);
}
//=== Повторяем цикл для горизонтальных линий сетки
for (float y = dataY.start; y < dataY.end-dataY.step/2; y += dataY.step)
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.