Рисуем график функции

В этой статье мы рассмотрим несколько способов нарисовать график какой-нибудь функции. Рисовать график мы будем на канве компонента image.

Рисование по пикселам

Рисовать на канве можно разными способами. Первый вариант - рисовать по пикселям. Для этого используется свойство канвы pixels. Это свойство представляет собой двумерный массив, который отвечает за цвета канвы. Например canvas.pixels[10,20] - соответствует цвету пикселя с координатами (10,20). С массивом пикселей можно обращаться, как с любым свойством: изменять цвет, задавая пикселю новое значение, или определять его цвет, по хранящемуся в нем значению. На примере ниже мы зададим черный цвет пикселю с координатами (10,20):

canvas.pixels[10,20]:=clblack;

Теперь мы попробуем нарисовать график функции f(x), если известен диапазон ее изменений ymax и ymin, и диапазон изменения аргумента xmax и xmin. Для этого мы напишем пользовательскую функцию, которая будет вычислять значение функции f в точке x, а также будет возвращать максимум и минимум функции и ее аргумента.

function tform1.f(x:real; var xmax,xmin,ymax,ymin:real):real;
begin
f:=sin(x);
xmax:=4*pi;
xmin:=0;
ymax:=1;
ymin:=-1;
end;

Не забудьте также указать заголовок этой функциии в разделе public:

public
{ public declarations }
function f(x:real; var xmax,xmin,ymax,ymin:real):real;

Здесь для ясности мы просто указали диапазон изменения функции sin(x) и ее аргумента, ниже эта функция будет описана целиком. Параметры xmax, xmin, ymax, ymin - описаны со словом var потому что они являются входными-выходными, т.е. через них функция будет возвращать значения вычислений этих данных в основную программу. Поэтому надо объявить xmax, xmin, ymax, ymin как глобальные переменные в разделе implementation:

implementation
var xmax,xmin,ymax,ymin:real;

Теперь поставим на форму кнопку и в ее обработчике события onclick напишем следующий код:

procedure tform1.button1click(sender: tobject);
var x,y:real;
px,py:longint;
begin
for px:=0 to image1.width do
begin
x:=xmin+px*(xmax-xmin)/image1.width;
y:=f(x,xmax,xmin,ymax,ymin);
py:=trunc(image1.height-(y-ymin)*image1.height/(ymax-ymin));
image1.canvas.pixels[px,py]:=clblack;
end;
end;

В этом коде вводятся переменные x и y, являющиеся значениями аргумента и функции, а также переменные px и py, являющиеся координатами пикселей, соответствующих x и y. Сама процедура состоит из цикла по всем значениям горизонтальной координаты пикселей px компонента image1. Сначала выбранное значение px пересчитывается в соответствующее значение x. Затем производится вызов функции f(x) и определяется ее значение y. Это значение пересчитывается в вертикальную координату пикселя py

Рисование с помощью пера pen

У канвы имеется свойство pen - перо. Это объект в свою очередь имеющий ряд свойств. Одно из них свойство color - цвет, которым наносится рисунок. Второе свойство width - ширина линии, задается в пикселах (по умолчанию 1).

Свойство style определяет вид линии и может принимать следующие значения:

pssolid Сплошная линия
psdash Штриховая линия
psdot Пунктирная линия
psdashdot Штрих пунктирная линия
psdashdotdot Линия, чередующая штрих и два пунктира
psclear Отсутствие линии
psinsideframe Сплошная линия, но при width > 1 допускающая цвета, отличные от палитры windows

Все стили со штрихами и пунктирами доступны только при толщине линий равной 1. Иначе эти линии рисуются как сплошные.

У канвы имеется свойство penpos, типа tpoint. Это свойство определяет в координатах канвы текущую позицию пера. Перемещение пера без прорисовки осуществляется методом moveto(x,y). После вызова этого метода канвы точка с координатами (x,y) становится исходной, от которой методом lineto(x,y) можно провести линию, в любую точку с координатами (x,y).

Давайте теперь попробуем нарисовать график синуса пером. Для этого добавим перед циклом оператор:

image1.canvas.moveto(0,image1.height div 2);

А перед заключительным end цикла добавьте следующий оператор:

image1.canvas.lineto(px,py);

Таким образом у Вас должен получиться такой код:

procedure tform1.button1click(sender: tobject);
var x,y:real;
px,py:longint;
begin
image1.canvas.moveto(0,image1.height div 2);
for px:=0 to image1.width do
begin
x:=xmin+px*(xmax-xmin)/image1.width;
y:=f(x,xmax,xmin,ymax,ymin);
py:=trunc(image1.height-(y-ymin)*image1.height/(ymax-ymin));
image1.canvas.pixels[px,py]:=clblack;
image1.canvas.lineto(px,py);
end;
end;

Как Вы уже успели заметить, если запустили программу, качество рисования графика пером, намного лучше, чем рисования по пикселям.

Как обещал сейчас напишу пример программы которая находит максимум и минимум функции. Я маленько изменил структуру процедур и функций, чтобы было яснее. Вот готовый код программы:

...
type
tform1 = class(tform)
button1: tbutton;
image1: timage;
procedure button1click(sender: tobject);
private
{ private declarations }
public
function f(x:real):real;
procedure extrem1(xmax,xmin:real; var ymin:real);
procedure extrem2(xmax,xmin:real; var ymax:real);
{ public declarations }
end;

var
form1: tform1;

implementation
const e=1e-4;//точность одна тысячная
var xmax,xmin,ymax,ymin:real;
{$r *.dfm}
function tform1.f(x:real):real;
begin
f:=sin(x);
end;

//поиск минимума функции
procedure tform1.extrem1(xmax,xmin:real; var ymin:real);
var x,h:real; j,n:integer;
begin
n:=10;
repeat
x:=xmin;
n:=n*2;
h:=(xmax-xmin)/n;
ymin:=f(xmin);
for j:=1 to n do begin
if f(x)then ymin:=f(x);
x:=x+h;
end;
until abs(f(ymin)-f(ymin+h))
end;

//поиск максимума функции
procedure tform1.extrem2(xmax,xmin:real; var ymax:real);
var x,h:real; j,n:integer;
begin
n:=10;
repeat
x:=xmin;
n:=n*2;
h:=(xmax-xmin)/n;
ymax:=f(xmin);
for j:=1 to n do begin
if f(x)>=ymax then ymax:=f(x);
x:=x+h;
end;
until abs(f(ymax)-f(ymax+h))
end;


procedure tform1.button1click(sender: tobject);
var x,y:real;
px,py:longint;
begin
//здесь необходимо указать диапазон изменения x
xmax:=8*pi;
xmin:=0;

//вычисляем экстремумы функции
extrem1(xmax,xmin,ymin);
extrem2(xmax,xmin,ymax);

//рисуем график функции
image1.canvas.moveto(0,image1.height div 2);
for px:=0 to image1.width do
begin
x:=xmin+px*(xmax-xmin)/image1.width;
y:=f(x);
py:=trunc(image1.height-(y-ymin)*image1.height/(ymax-ymin));
image1.canvas.pixels[px,py]:=clblack;
image1.canvas.lineto(px,py);
end;
end;
end.

Источник www.delphid.dax.ru



Опубликовал admin
5 Дек, Среда 2007г.



Программирование для чайников.