В этой статье мы рассмотрим несколько способов нарисовать график какой-нибудь
функции. Рисовать график мы будем на канве компонента 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.
|