Начало
Наверное, все видели программы, которых
довольно много, для построения всяческих графиков. Если Вы хотите написать
что-то подобное на Delphi,
то эта статья для Вас. В самых-самых программах Вам предлагается ввести формулу
строкой, а не выбирать функции из списка. Самым сложным (?) элементом таких
программ является текстовый анализатор. В данной статье я не собираюсь
рассказывать, как пишутся текстовые анализаторы. Я собираюсь рассказать о
некоторых основных принципах построения графиков, и работы с графикой в среде
Delphi без использования
специальных графических платформ, таких как
DirectX или
OpenGL.
Введение
В Delphi для прорисовки
различных элементов управления используется специальный класс
TCanvas. Можно выделить 4 основных
направления, в которых используется этот класс:
- Загрузка и хранение графических
изображений.
- Создание новых и изменение хранимых изображений с помощью
пера, кисти, шрифта.
- Рисование и/или закраска фигур, линий, текстов.
- Комбинирование изображений.
Как Вы уже поняли, мы пойдем по третьему
направлению.
Теперь давайте рассмотрим некоторые свойства и
методы класса TCanvas.
Сразу скажу, что я буду рассматривать далеко не все методы и свойства класса
TCanvas, а лишь те, которые мы будем
использовать потом.
TCanvas
Свойства:
- property Brush: TBrush;
Данное свойство позволяет определить цвет (Brush.Color) и стиль (Brush.Style) заполнения замкнутых фигур и фона.
- property ClipRect: TRect; -
read-only
Данное свойство позволяет получить доступную
область рисования. Вне этой области рисовать невозможно.
Тип
TRect, описанный в модуле
Windows,, имеет следующий синтаксис:
Type
TRect = record
Case integer of
0: (Left, Top, Right, Bottom: Integer);
1: (TopLeft, BottomRight: TPoint);
end;
- property Pen: Pen;
Данное свойство позволяет задать цвет пера,
рисующего фигуры или линии.
Методы:
- procedure FillRect (const Rect:
TRect);
Метод позволяет заполнить цветом прямоугольную
область холста Rect,
используя текущее значение кисти
Brush.
- procedure MoveTo (x, y:
integer);
Метод позволяет переместить перо в точку (X,
Y).
- procedure LineTo (x, y:
integer);
Метод позволяет нарисовать прямую линию,
которая начинается с текущей позиции пера и заканчивается точкой (x,
y). При рисовании используются текущие установки пера Pen.
Ну вот, пожалуй, и все, что нам будет нужно,
для успешного построения графика.
Построение графика. Теория.
Для начала предлагаю немного теории. Мы
собираемся писать процедуру построения графика функции на определенной
поверхности, заданной свойством
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);
c.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;
Вот и все.
|