Построение графиков в DelphiНаверное, все видели программы, которых довольно много, для построения всяческих графиков. Если Вы хотите написать что-то подобное на Delphi, то эта статья для Вас. В самых-самых программах Вам предлагается ввести формулу строкой, а не выбирать функции из списка. Самым сложным (?) элементом таких программ является текстовый анализатор. В данной статье я не собираюсь рассказывать, как пишутся текстовые анализаторы. Я собираюсь рассказать о некоторых основных принципах построения графиков, и работы с графикой в среде Delphi без использования специальных графических платформ, таких как DirectX или OpenGL.
Введение
В Delphi для прорисовки различных элементов управления используется специальный класс TCanvas. Можно выделить 4 основных направления, в которых используется этот класс:
1. Загрузка и хранение графических изображений. 2. Создание новых и изменение хранимых изображений с помощью пера, кисти, шрифта. 3. Рисование и/или закраска фигур, линий, текстов. 4. Комбинирование изображений. Как Вы уже поняли, мы пойдем по третьему направлению. Теперь давайте рассмотрим некоторые свойства и методы класса TCanvas. Сразу скажу, что я буду рассматривать далеко не все методы и свойства класса TCanvas, а лишь те, которые мы будем использовать потом.
TCanvas
Свойства: Построение графика. Теория.
Для начала предлагаю немного теории. Мы собираемся писать процедуру построения графика функции на определенной поверхности, заданной свойством Canvas. Я предлагаю поставить оси координат в середине этой области, а график растянуть так, чтобы он растянулся на всю область. Строить мы будем методом lineto. Поэтому нам нужно определиться с шагом изменения величины аргумента. Я предлагаю взять его обратным к масштабу по оси ординат. Так наш график будет выглядеть плавно при любой функции и любом начальном и конечном значении абсциссы. Масштаб по оси абсцисс считается, отношение ширины поверхности к разнице максимального и минимального значения абсциссы. Масштаб по оси ординат считается аналогично: отношение высоты поверхности к разнице между максимальным и минимальным значениями данной функции на данном интервале.
Процедура DrawGraph
Ну вот и все с теорией и я приведу полный код функции, а потом разберем его.
Type TFunc = function (x: real): real; procedure DrawGraph (f: TFunc; a: real; b: real; C: TCanvas); var x, y, h: real; max, min: real; sx, sy: real; xmid, ymid: integer; begin sx := (c.ClipRect.Right)/(b-a); h := 1/sx; xmid := c.ClipRect.Right div 2; ymid := c.ClipRect.Bottom div 2; x := a; max := f( x); min := max; while x<=b do begin y := f( x); if y<min then min := y; if y>max then max := y; x := x + h; end; sy := c.ClipRect.Bottom/ (max-min); c.Brush.Color := clBlack; c.FillRect(Rect(0, 0, c.ClipRect.Right, c.ClipRect.Bottom)); c.Pen.Color := clYellow; c.MoveTo(0, ymid); c.LineTo(c.ClipRect.Right, ymid); c.MoveTo(xmid, 0); c.LineTo(xmid, c.ClipRect.Bottom); x := a; y := f(x); c.Pen.Color := clWhite; c.MoveTo(xmid+round(sx*x), ymid-round(sy*y)); while x<=b do begin y := f(x); c.LineTo(xmid+round(sx*x), ymid-round(sy*y)); x := x + h; end; end; А теперь, если Вы чего-либо не поняли, давайте разберем этот код. Type TFunc = function (x: real): real; Здесь я создал тип-функцию, для того, чтобы передавать в функцию построения графика можно было передавать имя функции в эту процедуру. procedure DrawGraph (f: TFunc; a: real; b: real; C: TCanvas); Заголовок функции. Параметры: f – функция, график, которой будем троить. a – начальное значение переменной “x”. b – конечное значение переменной “x”. C – канва, на которой будем рисовать. sx := (c.ClipRect.Right)/(b-a); h := 1/sx; xmid := c.ClipRect.Right div 2; ymid := c.ClipRect.Bottom div 2; x := a; max := f( x); min := max; while x<=b do begin y := f( x); if y<min then min := y; if y>max then max := y; x := x + h; end; sy := c.ClipRect.Bottom/ (max-min); В этом куске кода мы считаем масштабы по осям координат, и среднее значения высоты и ширины канвы, чтобы отобразить оси координат. c.Brush.Color := clBlack; c.FillRect(Rect(0, 0, c.ClipRect.Right, c.ClipRect.Bottom)); c.Pen.Color := clYellow; c.MoveTo(0, ymid); c.LineTo(c.ClipRect.Right, ymid); c.MoveTo(xmid, 0); c.LineTo(xmid, c.ClipRect.Bottom); Здесь мы заливаем всю канву черным цветом и рисуем желтым цветом оси координат. x := a; y := f(x); c.Pen.Color := clWhite; c.MoveTo(xmid+round(sx*x), ymid-round(sy*y)); while x<=b do begin y := f(x); LineTo(xmid+round(sx*x), ymid-round(sy*y)); x := x + h; end; Ну и, наконец, нарисовали график нужной нам функции. Небольшой пример: Положим на форму одну кнопку и один компонент TImage. Создадим обработчик функции OnClick для кнопки примерно следующего характера, и следующую функцию для расчета функции Function f(x: real): real; Begin Result := sin(x)*cos(x); End; procedure TForm1.Button1Click(Sender: TObject); begin DrawGraph (f, -10, 10, Image1.Canvas); end; |