РАБОТА С ГРАФИКОЙ
Машинная (компьютерная) графика - одно из важных направлений в современной прикладной информатике. В отличие от базового Паскаля, современные версии содержат мощные средства разработки графических программ. Рассмотрим часть соответствующих возможностей Турбо-Паскаля, в котором они реализованы с помощью стандартного модуля Graph.
Модуль представляет собой мощную библиотеку графических подпрограмм универсального назначения, рассчитанную на работу с наиболее распространенными графическими адаптерами CGA, EGA, VGA, SVGA IBM-совместимых персональных компьютеров.
Подключение модуля Graph, tpu к программе выполняется директивой
uses graph;
Инициализация графического экрана осуществляется с помощью процедуры Initgraph. Драйвер поддерживает тот или иной режим экрана, табл. 3.1.
Таблица 3.1
Некоторые сведения о драйверах н определяемых ими режимах
Адаптер | Драйвер |
| Режим (Номер, имя) | Разрешимость | Число страниц | ||||
EGA | EGA | OEgalo | 640х200 | 4 | |||||
1 Egahi | 640х350 | 2 | |||||||
VGA | VGA | OVgalo | 640х200 | 4 | |||||
IVgalo | 640х350 | 2 | |||||||
2Vgalo | 640х480 | 1 |
Процедура инициализации в Турбо-Паскале имеет три аргумента:
Initgraph(<драйвep>, <режим>, '<путь к драйверу>').
Она может быть выполнена так:
uses graph;
var gd, gm: integer; {переменные gd и gm определяют драйвер и режим}
begin
gd:=vga; gm:=vgahi;
initgraph(gd,gm.'d:\tp551);
Первые две команды можно заменить одной:
gd:=detect
Целая константа detect=0 в модуле Graph автоматически распознает драйвер и устанавливает режим максимального разрешения для данной машины.
Процедура closegraph освобождает память от драйвера и устанавливает режим работы экрана, который был до инициализации графики.
Для обнаружения ошибок в графике применяются функции graphresult и grapherrormsg (код ошибки).
Последняя выдает строку сообщения о характере ошибки, соответствующей коду. Инициализация графического режима с проверкой ошибок может быть выполнена в программе следующим образом:
uses graph; var gd, gm, errorcod: integer;
begin
gd:=detect; initgraph(gd,gm,");
errorcod'=graphresult;
if errorcod <>grok then
begin
writeln('ошибка графики');
writeln(grapherrormsg(errorcod));
halt
end;
Процедура Halt останавливает выполнение программы и возвращает управление операционной системе.
Для формирования палитры используется система смешения красного, зеленого и синего цветов и изменения яркости луча. Цвет задается номером из списка цветов палитры в интервале 0 .. 15.
Процедуры sе1со1ог(<цвет>) и setbkcolor(<цвет>) устанавливают текущий цвет рисунка и цвет фона. При инициализации графики по умолчанию устанавливается черный фон и белый цвет рисунка.
В табл. 3.2 указаны основные процедуры для модуля Graph, применяющиеся для построения простейших геометрических примитивов.
Координаты точек воспринимаются в «экранной» системе координат, в которой начало - верхний левый угол экрана, ось «х» направлена вниз, ось «у» -направо. Максимальные значения координат определяются разрешимостью экрана (см. табл. 3.1).
Первый аргумент процедуры setlinestyle(a,b,t) а - стиль линии второй параметр b -«образец» - имеет значение 4, если а=4, в остальных случаях b=0; третий параметр t -толщина линии - может иметь значение 1 (нормальная толщина) или 3 (жирная линия).
Таблица 3.2
Основные процедуры модуля Graph
Заголовок процедуры |
Геометрический смысл |
putpixel(x,y,c) |
Построить точку (х,у) цветом с |
setlinestyle(a,b,t) |
Установить стиль, образей и толщину линий |
line(xl,yl,x2,y2) |
Соединить две точки отрезком |
rectangle(xl,yl.x2.y2) |
Построить прямоугольник с заданными концами диагонали и |
сторонами, параллельными осям координат |
|
circle(x,y,r) |
Построить окружность с центром (х,у) и радиусом г |
arc(x,y,a,b,r) |
Построить дугу окружности: a,b - начальный и конечный угол в |
Градусах |
|
ellipse(x,y,a,b,rx,ry) |
Построить эллиптическую дугу: rx, rу - полуоси эллипса |
setfillstyle(t,c) |
Установить стиль закраски и ее цвет |
fillellipse(x,y,rx,ry) |
Построить закрашенный эллипс, используя цвет рисунка |
floodfill(x,y,cg) |
Закрасить фигуру до границы с цветом cg; (x,y) - внутренняя |
точка фигуры |
|
bar(xl,yl,x2,y2) |
Построить столбец, используя тип и цвет закраски |
pieslice(x,y,a,b.r) |
Построить и закрасить сектор круга |
sector(x,y.a,b,rx,ry) |
Построить и закрасить эллиптический сектор |
settextsiyle(f,n,d) |
Установить шрифт, направление вывода и размер символа текста ' |
outtextxy(x,y,st) |
Вывести строку st, начиная с точки (х,у) |
outtext(st) |
Вывести строку, начиная с точки расположения текущего указателя |
Первый аргумент процедуры setfillstyle(t,c) - тип закраски t - принимает значения из интервала 0..12. Наиболее употребителен тип t = 1 - заполнение фигуры текущим цветом.
Для вывода текста на графический экран сначала выполняется процедура settextstyle(f,n,d), устанавливающая шрифт f, направление вывода п и размер символов (параметр d). При f = 0 используется стандартный точечный шрифт, встроенный в систему Турбо-Паскаль. С использованием других шрифтов познакомимся ниже. Направление вывода п принимает значения 0 (горизонтальный вывод) и 1 (вертикальный вывод).
Размер букв определяется параметром d, принимающим значения из интервала 1..10. Если d = 1 и f = 0, то каждый символ занимает квадрат 8*8 точек, при d > 1 сторона квадрата умножается на d.
Далее, с помощью процедуры outtextxy(x,y,st) строка st выводится на экран, начиная с точки (х,у).
Например:
settextstyle(0,0,2); оuttехtху(100,200,'горизонтальная строка');
оuttехtху(100,230,'размер увеличен вдвое');
Примеры графических программ
Пример 1:
программа рисует звездное небо с 400 «звездами», вспыхивающими постепенно, и полную желтую луну.
Програлша 29
program sky;
uses crt,graph;
var k,gd,gm:integer;
begin gd:=detect;
initgraph (gd, gm, ' '); randomize;
for k:=l to 400 do
begin putpixel(random(640),random(480),random(15)+1); delay(10);
end;
setfillstyle(l,14); setcolor(14);
circle(550,80,30) ; floodfill(550,80,14) ;
repeat until keypressed; closegraph
end.
Пример 2. Узор. Используя простейшие геометрические образы строят замечательные графические изображения. Ниже приведена программа изображения муарового узора, полученного пересечением двух семейств расходящихся отрезков прямых. Качество и изображение получаемого узора зависит в основном от трех параметров: kl, k2 - расстояний между отрезками слева и справа ; h - смещения вниз (вверх) всего семейства.
Программа 30
program uzor;
uses crt, graph;
var gd,gm,errCode,i,kl,k2,h; integer;
begin
kl:=8; k2:=3; h:=110; gd:=Detect; InitGraph(gd,gm.'') ;
errCode:=GraphResult ;
if errCode = grOk then begin
setcolor(green); *
for i:=l to (420 div kl) do
begin line(0,i*kl,640,i*k2+h); line(0,i*k2+h,640,i*kl);
end;
repeat until keypressed; CloseGraph;
end else writeln('errCode=',errCode)
end.
Процедуры построения прямоугольных фигур удобно использовать, в частности, при построении схем, диаграмм.
Пример 3:
программа 31 строит столбчатую диаграмму, наглядно отражающую числовую информацию о населении 6 крупных городов мира: Токио, Гамбурга, Москвы, Бангкока, Мехико и Парижа.
Программа 31
program colon;
uses crt,graph;
const m:array[l..6] of real=(11500,2300,9700.5100,12400,8200) ;
name:array[I..6] of
string =('Токио','Гамбург','Москва','Бангкок','Мехико','Париж');.
var gd,gm,k,n,s:integer; st:string[6];
begin
gd:=detect;
initgraph(gd,gm,' ');
setcolor(15);
setlinestyle(0,0,1);
line(60,400,620,400);
line(60,400,60,100) ;
settextstyle(0,0,1);
for k:=l to 12 do begin n:=1000*k; str(n.st);
outtextxy(10,400-20*k-4,st);
line(60,400-k*20,65,400-k*20)
end;
setcolor(14); settextstyle(0,0,2);
outtextxy(120,20, 'Население городов (тысяч)'); settextstyle(0,0,1);
for k:=l to 6 do begin setfillstyle(1,k+2);
bar(100+(k-l)*70,400,100+k*70,round(400-m[k]/1000*20)) ;
outtextxy(100+(k-l)*70+4,450,name[k]) ;
end;
repeat until keypressed;
closegraph
end.
Процедура bar3d(xl,yl,x2,y2,d,top) рисует трехмерный столбец, глубина которого определяется параметром d. Последний параметр процедуры top - логического типа. Если top=true, рисуется верхнее основание столбика, в противном случае оно не изображается, что позволяет рисовать столбики один над другим. Диаграммы с трехмерными столбиками красивы, но их труднее создавать.
Построение графиков функций. Построение графиков функции - неотъемлемая часть большинства программ, предназначенных для обучения математике, физике. Ниже представлен пример программы построения графика функции y=x*x*sin(l/x). на произвольном отрезке [а, b]. Количество точек графика (параметр п) также задается произвольно (точка х=0 исключается, так как в ней функция не определена).
В программе также определяются величины tl=(xl-x0)/(b-a) и t2=(yl-y0)/(2m), которые означают масштабы по осям Х и Y соответственно.
График рассматриваемой функции представлен на двух отрезках [а, b] и [-0.1,0.1]. Чтобы построить график другой функции, достаточно задать ее аналитический вид в описании функции (function f).
Программа 32
program grafik;
uses crt, graph;
var gd,gm, errCode : integer; a,b : real; n : integer;
function f(x:real):real;
begin if x<>0
then f:=x*x*sin(l/x);
end;
procedure grafun(xO,xl,yO,yl,n :word;a,b;real);
var h,m,x, tl,t2 : real; i, u,v,xv,yv : word;
begin
h:=(b-a)/n; (поиск максимума f(x)} m:=abs(f (a));
for i:=l to n do if m<abs(f(a+i*h)) then m:=abs(f(a+i*h)) ;
tl:=(xl-x0)/(b-a);
t2:=(yl-y0)/(2*m); (построение координатных осей)
setfillstyle(l,15); bar(x0-5,y0-5,xl+5,yl+5) ;
xv:=round(x0-a*tl); yv:=round((yO+yl)/2) ;
setcolor(l); line(xv,y0,xv,yl);
line(xO,yv,xl.yv) ;
Moveto(xO,yv-round(f(a) *t2)); (установка курсора в начало графика}
setcolor(3); (построение
графика) for i:=l to n do begin x:=a+i*h; u:=x0+round((x-a)*tl);
v:=yv-round(f(x)*t2); lineto(u,v);
end;
end; (конец
процедуры
} begin
clrscr; write ('введи a,b и
n : '); readln(a,b,n); gd^Detect;
InitGraph (gd,gm, ' ' ) ;
errCode:=GraphResult ;
if errCode = grOk then begin
grafun(100,500,50,300,n,a,b);
grafun(550,620,10,100,200,-0.1,0.1);
repeat until keypressed; CloseGraph;
end else writeln( "ezzCode=' ,errCode)
end.
Для изображения поверхностей, определяемых функцией двух переменных z=f(x,y), можно использовать разные способы. Одним из них является метод построения семейства одномерных графиков функции z=f(x.y) от одной переменной х или у различных фиксированных значениях другой. Это может быть хорошей тренировкой для самостоятельной работы по освоению графики.
Построение движущихся изображений.
Особую ценность в графике представляет организация движения фрагментов рисунка. Наиболее просто это сделать по следующему плану:
• нарисовать фрагмент
в нужном месте экрана;
• стереть фрагмент, рисуя его цветом фона или используя процедуру cleardevice;
• снова нарисовать фрагмент в другом месте экрана.
Такой способ осуществлен в программе billiard, где два шарика радиусом 5 пикселей разных цветов двигаются с одинаковой скоростью внутри зеленого прямоугольника, построенного с помощью процедуры bar.
Процедура blou измеряет смещение центра шарика от сторон прямоугольника по каждой оси и, если это смещение на следующем шаге цикла станет меньше радиуса, изменяет направление движения, моделируя поведение упругого шара при ударе о стенку.
В программе также рассмотрена ситуация соприкосновения шариков во время их движения. Она решается примитивно просто: каждый шарик меняет направление своего движения на противоположное.
Программа 33
program billiard;
uses crt,graph;
var х,y,dx,dy,gd,gm:integer; xl,yl,dxl,dyl:integer;
procedure blow(a,b:integer; var c,d:integer);
begin if (a<107) or (a>523) then c:=-c;
if (b<107) or (b>363) then d:=-d;
end;
begin
gd:=detect; initgraph(gd,gm,''); setcolor(14);
setlinestyle(0,0,1); rectangle(99,99,531,371) ;
setfillstyle(l,3); bar(100,100,530,370) ;
x:=320; y:=240; dx:=2; dy:°2;
xl:=320; yl:=200; dxl:=-2; dyl:=-2;
repeat circle(x,y,5); setcolor(4); circle(xl,yl,5);
blow(x,y,dx,dy); blow(xl,yl,dxl,dyl); delay(10);
if (abs(x-xl)<=10) and (abs(y-yl)<=10) then begin
dx:—dx; dy:=-dy; dxl:=-dxl; dyl:=-dyl; delay(300)
end;
setcolor(3); circle(х,у,5);
x:=x+dx; y:=y+dy;
setcolor(3); circle(xl,yl,5) ;
xl:=xl+dxl; yl:=yl+dyl; setcolor(14)
until keypressed;
closegraph
end.
Еще один способ организации движения на экране, широко применяющийся в компьютерных играх, связан с использованием нескольких экранных страниц. В режиме Vgamed их две, а в режиме Vgalo - четыре. Страницы имеют номера: 0,1,... В любой момент времени одну из страниц можно сделать видимой и посмотреть ее содержимое на экране с помощью процедуры setvisualpage(номep).
Визуальная страница обычно пассивна, т.е. на ней нельзя выполнять графические процедуры. Другую страницу можно объявить активной с помощью процедуры setactivepage(номep). Активная страница невидима для пользователя. На ней можно подготовить другой рисунок. В следующий момент можно поменять роли страниц, т.е. визуальную сделать активной и невидимой и на ней рисовать следующий кадр, а бывшую активную сделать визуальной и показать объект в новом месте экрана.
В программе helicopter с помощью страниц моделируется вращение винтов вертолета. Две процедуры verti и vert2 подготавливают рисунки вертолета с разным положением винтов. Изображения выводятся на разные страницы, которые потом по очереди становятся то видимыми, то активными.
В программе организовано также движение вертолета по эллиптической орбите. Центр орбиты - точка (х0,у0) - располагается в центре экрана, числа а=250 и b=130 -горизонтальная и вертикальная полуоси эллипса. Положение вертолета на орбите 'вычисляется по формулам
u=x0+round(a*cosp), t=y0+round(b*sinp),
где р - чекущии угол, образованный радиус-вектором точки эллипса с осью абсцисс.
Программа 34
program helicopter;
uses crt,graph;
const step=0.01;
var gd,gm,u,t,z,k,xO,yorc,ac,vi:integer; p,a,b:real;
procedure vertl(x,у:integer) ;
begin
cleardevice; setcolor(14);
setlinestyle (0,0,1); setfillstyle(1,3) ;
line(x+12,y,x+36,y);line(x+24,y,x+24,y+8) ;
fillellipse(x+24,y+14,12,7); moveto(x+18,y+20);
lineto(x,y+20); lineto(x,y+14);
line(x+18.y+28,x+30,y+28); line(x+24,y+27,x+24,y+21) ;
end;
procedure vert2(x,у:integer);
begin
cleardevice; setcolor(14);
setlinestyle(0.0,1); setfillstyle(1,3) ;
line(x+22,y,x+26,y); line(x+24,у,x+24,y+8) ;
fillellipse(x+24,y+14,12,7); moveto(x+18,y+20) ;
lineto(x,y+20); lineto(x,y+14) ;
line(x-3,y+14,x+3,y+14); line(x+24,y+27,x+24,y+21) ;
line(x+18,y+28.x+30,y+28);
end;
begin
gd:=vga; gm:=vgamed; initgraph(gd,gm,' ');
x0:=getmaxx div 2; y0:=getmaxy div 2;
z:=l; p:=pi; a:=250; b:=130; ac:=0; vi:=l;
for k:=l to 800 do
begin u:=x0+round(a*cos(р)); t:=y0-round(b*sin(p));
• setactivepage(ac); setvisualpage(vi);
if z=l then vertl(u,t) else vert2(u,t); z:=-z;
delay(50); p:=p+step; c:=ac; ac:=vi; vi:=c:
end; closegraph
end.