netlib.narod.ru | < Назад | Оглавление | Далее > |
Запрограммировать синусоиду довольно просто, поскольку ее значения y являются простой функцией x. Однако вообще программирование кривых сложнее. Например, уравнение единичной окружности (т.е. окружности с радиусом 1), с центром в начале координат обычно дают как:
x2 + y2 = 1
В более общем виде окружность с радиусом r может быть представлена как:
x2 + y2 = r2
Но если попытаться представить это уравнение в виде зависимости y от x, то вот что получится:
y = ±√ r2 – x2
Здесь возникает целый ряд проблем. Во-первых, каждому значению x соответствуют пара значений y. Во-вторых, некоторые значения x недопустимы: x должен быть в интервале от –r до +r. И в-третьих, проблема практического толка возникает собственно при рисовании окружности на основе этого уравнения. Полученная функция нелинейна: при значениях x, близких к 0, изменения x дают относительно небольшие изменения y. Когда же x приближается к r или –r, изменения x дают гораздо большие изменения y.
Более общий подход к рисованию кривых применяет параметрические уравнения, в которых обе координаты каждой точки, x и y, вычисляются на основе значения третьей переменной, часто называемой t Интуитивно t можно воспринимать как время или какой-то абстрактный показатель, нужный для исчерпывающего определения кривой. При программировании графики в Windows Forms можно считать, что переменная t изменяется от 0 до числа на единицу меньшего, чем количество структур PointF в массиве.
Параметрические уравнения, определяющие единичную окружность, таковы:
x(t) = cos(t)
y(t) = sin(t)
Для t, изменяющегося от 0 до 2π радиан, эти уравнения задают окружность с центром в точке с координатами (0, 0) и радиусом 1.
Сходным образом может быть задан и эллипс:
x(t) = RX cos(t)
y(t) = RY sin(t)
Оси эллипса параллельны горизонтальной и вертикальной осям координат. Длина горизонтальной оси эллипса равна 2 × RX, вертикальной — 2 × RY. Эллипс также центрирован относительно начала координат. Чтобы переместить центр эллипса в точку с координатами (CX, CY), формулы должны принять такой вид:
x(t) = CX + RX cos(t)
y(t) = CY + RY sin(t)
А вот программа для рисования эллипса, вписанного в экран:
PolyEllipse.cs
//-------------------------------------------- // PolyEllipse.cs (C) 2001 by Charles Petzold //-------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class PolyEllipse: PrintableForm { public new static void Main() { Application.Run(new PolyEllipse()); } public PolyEllipse() { Text = "Ellipse with DrawLines"; } protected override void DoPage(Graphics grfx, Color clr, int cx, int cy) { int iNum = 2 * (cx + cy); PointF[] aptf = new PointF[iNum]; for (int i = 0; i < iNum; i++) { double dAng = i * 2 * Math.PI / (iNum - 1); aptf[i].X = (cx - 1) / 2f * (1 + (float)Math.Cos(dAng)); aptf[i].Y = (cy - 1) / 2f * (1 + (float)Math.Sin(dAng)); } grfx.DrawLines(new Pen(clr), aptf); } }
Поскольку центр эллипса находится на пересечении прямых, делящих экран надвое по ширине и высоте, а ширина и высота эллипса равны ширине и высоте области экрана, я смог несколько упростить формулы. Я аппроксимировал число точек массива как число точек, достаточное для изображения прямоугольника, периметр которого равен периметру экрана.
Далее вы увидите, что в классе Graphics есть метод DrawEllipse. Возникает вопрос: зачем было рисовать эллипс «вручную»? Назовем это просто упражнением для подготовки к изучению следующей программы, рисующей фигуру, простого метода для изображения которой точно нет в классе Graphics.
Spiral.cs
//--------------------------------------- // Spiral.cs (C) 2001 by Charles Petzold //--------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class Spiral: PrintableForm { public new static void Main() { Application.Run(new Spiral()); } public Spiral() { Text = "Spiral"; } protected override void DoPage(Graphics grfx, Color clr, int cx, int cy) { const int iNumRevs = 20; int iNumPoints = iNumRevs * 2 * (cx + cy); PointF[] aptf = new PointF[iNumPoints]; float fAngle, fScale; for (int i = 0; i < iNumPoints; i++) { fAngle = (float)(i * 2 * Math.PI /(iNumPoints / iNumRevs)); fScale = 1 - (float)i / iNumPoints; aptf[i].X = (float)(cx / 2 * (1 + fScale * Math.Cos(fAngle))); aptf[i].Y = (float)(cy / 2 * (1 + fScale * Math.Sin(fAngle))); } grfx.DrawLines(new Pen(clr), aptf); } }
А вот как выглядит эта фигура:
netlib.narod.ru | < Назад | Оглавление | Далее > |