Добавил:
sergeevpavel0406@mail.ru СОВА Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика в техническом университете / Информатика в техническом университете. Основы программирования

.pdf
Скачиваний:
72
Добавлен:
06.03.2018
Размер:
13.53 Mб
Скачать

8. Управление техническими средствами и взаимодействие с MS DOS

Begin

ClrScr;

WriteСВведите начало и конец интервала:');

ReadLn(xn,xk);

 

 

 

h:=(xk-xn)/(k-l);

 

{определяем шаг по оси х}

х[1]: =хп;

 

 

 

ymin:=le30;

 

 

 

ymax:=-lelO;

 

 

 

for

i:=] to к do

{табулируем функцию и ищем экстремумы}

begin

 

 

 

 

yfiJ:=cos(x[iJ+2)/2;

 

 

if y[i]>ymax

then

ymax:=y[ij;

 

if y[i]<ymin

then

ymin:=y[ij;

 

if iolOO

thenx[i+]J:=x[iJ+h;

end;

 

 

 

mx:=(kxk-kxn)/(xfkj'xf]j);

{определяем масштаб по оси х}

my:=(kyk-kyn)/(ymax-yminj;

{определяем масштаб по оси у}

for

i:=J to к do

 

 

{определяем координаты точек}

 

begin

 

 

 

 

kxfij: =round{(xfiJ'X[lJ) *тх) +кхп;

 

kyfij: =round((ymax-y[iJ) *ту) +куп;

 

end;

 

 

 

gd: =detect;

 

 

 

InitGraph(gd,gm, ");

{инициализируем графический режим}

SetColor(4);

 

{текущий цвет - красный}

OutTextXY(180,20, T=cos(x-^2J/2'); {выводим заголовок}

SetColor(17);

 

{цвет рисования - голубой}

SetBKColor(7);

 

{на сером фоне}

Rectangle(кхп,куп,кхккук);

{рисуем прямоугольник для вывода

SetColor(4);

 

 

графика}

 

 

{текущий цвет ~ красный}

for

i:=l to к-1 do

 

{выводим график}

 

Line (kx[i],ky[i],kx[i+l],ky[i^l]);

dkx:='round((kxk'kxn)/nx);

{определяем шаг сетки по х}

dky:=round((kyk'kyn)/ny);

{определяем шаг сетки по у}

SetColorf] 7);

 

 

{текущий цвет - светло-синий}

for

i:=J to пх do

{рисуем сетку, параллельную оси х}

 

Line(kxn+dkx*r,kyn,kxn-^dkx*i,kyk);

for

i:=] to ny do

 

{рисуем сетку, параллельную оси у}

Line(kxn,kyk-dky*i,kxk,kyk'dky*i);

dx:=(x[kJ'X[]JJ/nx;

{определяем шаг для сетки по х}

dy:=(ymax-ymin)/ny;

{определяем шаг для сетки по у}

SetTextJustify(1,2);

{выравнивание «по центру снизу»}

281

Часть 1. Основы алгоритмизации и процедурное программирование

Y = cos(x+2)/2

0.50

0.31

0.12

-0.07

-0.26

-0.46

2.00

3.00

4.00

5.00

6.00

7.00

Рис. 8.7. Результат работы программы

for i:=J to пх+1 do {выводим значения аргумента} begin

Str((xflJ+dx*(i-])):n:m,st);{преобразуем число в строку} OutTextXY(kxn+dkx*(i'l), kyk+6,st); {вывод значений под лини­

ей сетки}

end;

SetTextJustijy(2J); {выравнивание «слева по центру»} for i:=l to ny+I do {выводим значения функции}

begin

Str((ymin+dy*(i'l)):n:m,stJ;{преобразуем число в строку} OutTextXY(kxn-6,kyk'dky*(i'l),st); {вывод слева от оси у} end;

ReadLn; {ожидаем нажатия ENTER}

Closegraph;

End.

Результатом работы программы является график функции на заданном интервале изменения аргумента, представленный на рис. 8.7.

Помимо графиков для представления результатов также могут использо­ ваться диаграммы и гистограммы различных видов. Рассмотрим еще один пример.

Пример 8.6. Разработать программу построения круговой диаграммы по заданным значениям не более 12, которые должны выводиться рядом с со­ ответствующим сектором диаграммы.

Круговая диаграмма рисуется как совокупность закрашенных секторов круга. Угол сектора пропорционален доле соответствующего значения в об-

282

<^. Управление техническими средствами и взаимодействие с MS DOS

щей сумме значений. Надпись должна выводиться напротив биссектрисы уг ла сектора соответственно слева или справа диаграммы.

Ниже приведена программа.

Program difgramma; Uses Graph;

Const

kmax=12; {максимальное количество значений функции} r=J50; {радиус диаграммы}

п=5; {ширина поля вывода} т=2; {размер дробной части числа}

Туре

mas=array[J..kmax+JJ of integer; masl=array[L.kmax] of real;

Var

 

fmasl;

{массив значений функции}

alfa:mas;

{массив значений углов диаграммы}

driver,err,

{тип и режим работы адаптера}

К{фактическое количество значений функции}

bet, {величина угла, образованного радиусом и биссектрисой сек­ тора диаграммы}

у,х, {координаты точки, являющейся центром дуги сектора} х1,у1, {координаты начальной точки вывода надписи} хп,уп, {координаты центра диаграммы}

i:integer;

st:string[5]; {строка для хранения выводимой надписи} s:real; {сумма значений функции}

begin

WriteLnCВведите количество точек (от 1 до\ктах:3,') '); ReadLn(k);

{вводим значения функций и определяем их сумму}

for i:=l to к do begin

WriteLnCBeedume\i:3, '-e значение функции'); ReadLn(f[i]);

whilef[i]<0 do begin

WriteLnCНедопустимое значение, повторите ввод'); WriteLnCBeedume\i:3, '-e значение функции); ReadLn(f[i]);

end;

283

Часть 1. Основы алгоритмизации и процедурное программирование

s:-s+f[i]: end;

if s=0 then begin

WriteLn('Bce значения нулевые.');

ReadLn;

 

halt(l);

 

{выход no ошибке}

end;

 

 

{инициализируем графический режим}

driver: =detect;

 

InitGraph(driver,err, ");

SetBkColor(15); {белый цвет фона}

SetPalette(lO);

 

SetColor(l);

{черный цвет рисования}

{вычисляем координаты центра диаграммы}

хп: =GetMaxX div 2;

 

уп: =GetMaxY div 2;'

{рассчитываем значения углов секторов диаграммы}

alfa[l]:=0;

 

 

for i:= 2 to k+1 do

 

begin

 

 

ifi<>k+l

then

alfa[ij:=alfa[i'lj+round(ffi']]/s*360)

 

else

alfa[k+l]:^360;

SetFillStyle(i mod 10, i); {установим тип и цвет закраски сектора}

Pieslice(xn,yn,alfafi'lJ,alfafiJ,r); {изобразим сектор}

{вычисляем начальные координаты вывода надписей}

bet:=(alfa[i'lj+alfa[ij)

div 2;

 

 

x:==xn+round(r*cos(bet*pi/I80));

 

у: =yn'round(r*sin(bet*pi/I80));

 

if ((bet> =0)and(bet< ^90))or((bet> =2 70)and(bet< -=360))

thenxl:=x-^10

 

elsexJ:=X'8*n']0;

if((bet>=0)and(bet<=J80))

thenyl—y-lS

Sir(f[i'l]:n:m,st);

 

 

else

yli^y^l;

{преобразуем значение в строку}

OutTextXY(xl,yl,st);

 

{выведем надпись}

end;

 

 

 

 

ReadLn;

CloseGraph; End

Результатом работы программы является изображение круговой диа­ граммы, приведенное на рис. 8.8.

284

8. Управление техническими средствами и взаимодействие с MS DOS

 

56.00

35.00

79.00

 

24.00

23.00

66.00

44.00

38.00

79.00

 

Рис. 8.8. Результат работы программы построения круговой диаграммы

8.7. Практикум. Создание движущихся изображений

Движение на экране создается по принципу мультипликации: на экран с соответствующей задержкой выводят последовательность кадров с неболь­ шими изменениями положения «движущихся» объектов или объектов «фо­ на», если эффект движения достигается изменением фона.

Сам «перемещаемый» объект может быть двумерным (плоским) и трех­ мерным (пространственным), причем движение может осуществляться по двум типам траектории: лежащей в плоскости экрана или выходящей за нее. Из аналитической геометрии известны формулы, по которым можно, зная за­ кон движения, определить изменения положения каждой точки изображения движущегося объекта на экране. Проекции трехмерных объектов при движе­ нии изменяются достаточно сложным образом, и в то же время ничего прин­ ципиально нового в программировании движения трехмерных объектов по сравнению с двумерными не существует, поэтому в настоящем учебнике эти вопросы рассматриваться не будут.

Движение плоских объектов. Любое сложное движение плоских объ­ ектов на экране складывается из базовых: перемещения, масштабирования и поворота. Формулы пересчета координат изображений для базовых видов движения следующие.

285

Часть 1. Основы алгоритмизации и процедурное программирование

(х,,у,)

(Х,У)

( х , у ) ^ . (''''У')

C(x,,yJ С(х,,уЛ

Рис. 8.9. Элементарные изменения изображения:

а - перемещение; б- масштабирование; в - поворот

Перемещение (рис. 8.9, а)

Х| = X + dx,

y i = y + dy,

где X, у - исходные координаты точки; xj, У| - координаты точки после пе­ ремещения; dx, dy - смещения по оси х и у соответственно.

Масштабирование относительно точки С (х^, у^>) (рис. 8.9, б):

Х] =(х-Хс)Мх + Хс, У1 =(у-Ус)Му + Ус,

где Mj^, My - масштабы по х и у соответственно; х^., у^. - координаты точки, относительно которой ведется масштабирование.

Поворот относительно точки С с координатами (х^,, у^,) (рис. 8.9, в):

Х| = (х - х^) cosa + (у - у^,) sin а + х^,, У1 = (у - Ус) cosa - (х - x j sin а + у^ ,

где а - угол поворота.

Пример 8.7. Разработать программу, которая демонстрирует на экране движение прямоугольника: прямоугольник улетает от нас к некоторой точке горизонта, одновременно вращаясь вокруг своей оси.

Обобщенный алгоритм последовательного показа кадров данной задачи выглядит следующим образом.

Начало:

Установить точку отсчета координат (условное время). Рассчитать координаты квадрата.

Цикл-пока не истекло время или не нажата любая клавиша Установить цвет рисования.

Изобразить квадрат.

Приостановить выполнение программы на время просмотра кадра.

286

8. Управление техническими средствами и взаимодействие с MS DOS

Точка Повернутое горизонта изображение

 

Результат

Исходное положение

масштабирования

Рис. 8.10. Разложение движения

Установить в качестве цвета рисования цвет фона. Изобразить квадрат цветом фона - стереть. Изменить точку отсчета (условное время). Пересчитать координаты квадрата.

все-цикл Конец.

В а р и а н т ! . Координаты вершин квадрата будем хранить в специаль­ ных массивах х, у, а квадрат рисовать линиями, проводя их из одной верши­ ны в другую. Изображение квадрата будет осуществлять специальная проце­ дура Square.

Пересчет координат вершин реализуем через разложение «движения» прямоугольника на элементарные составляющие (рис. 8.10): эффект удале­ ния от зрителя получим, используя масштабирование относительно точки го­ ризонта, эффект вращения - за счет поворота вокруг геометрического цент­ ра.

Вначале определим координаты вершин и центра квадрата после мас­ штабирования, а затем координаты вершин после поворота вокруг центра квадрата. Ниже приведена соответствующая программа:

Program ex; Uses Crt,Graph; Const

r=]00;

Type

mas =array[I.. 4] of integer; Var

X, y, xl, yl:mas; gd,gm,xn,yn,xc,yc, ij, kl: integer; t,k:reaJ;

287

Часть L Основы алгоритмизации и процедурное программирование

{изображение квадрата по координатам его вершин}

Procedure Square(х,у:mas); Begin

Line(x[lly[llx[2],y[2]);

Line(x[2],y[2],x[3],y[3]);

Line(x[3],y[3lx[4].y[4]);

Line(x[4M4Ml].y[l]):

End:

{определение координат повернутой точки}

Procedure Pow(xc,yc,x,y:integer;t:real;var xl,yl:integer); Begin

xl: =xc+round((X'Xc) ^cos(t)) -^rounddy-yc) '^sin(t)); yl: =yc+round((y'yc) *cos(t))'round((X'Xc) *sin(t));

End;

{определение координат точки после масштабирования}

Procedure Massch(xc,yc,x,y: integer;k:real;var xJ,y J.'integer); Begin

xJ:=round(x*k-^(]-k) *xc); yl: =round(y*k+(l'k) *yc); End;

{основная программа}

Begin

gd: =detect; InitGraph(gd,gm, 'd:\bp\bgi); SetColor(2);

xn: =GetMaxX div 4; yn: =GetMaxY div 3 *2; xc: =GetMaxX'Xn; yc:=GetMaxY'yn;

{расчет начальных координат вершин квадрата}

xflj: =xn-r;

yflj: =уП'Г;

x[2]: =xn+r;

у[2]: =yn-r;

x[3]: =xn+r;

y[3]: =yn-^r;

x[4]: =xn-r;

у[4J: =yn+r;

k:=0.99;

 

t:=0;

{покадровый вывод на экран} while (t<l) and not KeyPressed do

begin

SetColor(2); {установим цвет рисования} Square(x,y); {нарисуем квадрат} t:=t-^0.001; {увеличим угол поворота}

288

8. Управление техническими средствами и взаимодействие с MS DOS

{масштабирование}

forj:=I to 4 do {определим координаты вершин}

Massch(xc,yc,xljJ,y/jJ,kx] [flyJ /jj): Massch(xc,yc,xn,yn,kxn,yn); {определим координаты центра}

{поворот}

 

forj:=l

to 4 do

{определим координаты вершин}

Pow(xn,yn,x]/jJ.yW7rt,x]/jlylOJ)>'

forj:=I

to 1500 do Delay(lOOO); {или NewDelay см. параграф 8.3}

SetColor(O);

{установим цвет рисования - цвет фона}

Square(x,y);

{стираем квадрат}

x:=xJ;

 

{заменим координаты вершин на новые}

y:=yJ;

end;

CloseGraph; End

Недостатком данного способа является то, что квадрат на экране через несколько кадров уже выглядит не квадратным. Это происходит вследствие накопления ошибки округления при пересчете координат вершин. Избежать этого можно двумя способами:

1) все вычисления выполнять в вещественной арифметике и координаты также хранить как вещественные числа, преобразуя их в целые непосредст­ венно перед использованием в процедуре рисования;

2) пересчитывать координаты не всех вершин, а какой-нибудь одной и центра квадрата, восстанавливая квадрат по одной вершине и положению центра квадрата.

Способы являются взаимодополняющими, поэтому используем оба.

В а р и а н т

2. Для упрощения

 

вычислений вместо массивов, хра­

 

нящих координаты вершин квадра­

A4dxl,dyl)

та, будем использовать смещения

 

этих вершин относительно центра

А (dx,dy)

(рис. 8.И). Соответственно проце­

дура рисования

квадрата Square 1

 

должна использовать именно эти

 

параметры. Также учтем, что при

 

масштабировании изменяются раз­

 

мер диагонали и положение центра,

 

а при повороте ~ смещения вершин

 

относительно центра. Ниже пред-

Рис. 8.11. Два соседних кадра

ставлен текст программы.

при повороте

289

Часть I. Основы алгоритмизации и процедурное программирование

Program ex; Uses Crt,Graph;

Const r:real=100; {размер половины стороны квадрата}

Var

X, у, dx, dy, dxl, dyJ, xn, yn, xc, yc, xnl, ynl.real; gd,gmJJ: integer;

tyk:real; {угол поворота и масштаб}

{изображение квадрата}

Procedure Squarel(x,ydx,dy:integer); Begin

Line(x+dx,y-^dy,X'dy,y+dx);

Line(X'dy,y+dx,X'dx,y'dyJ;

Line(x-dx,y'dy,x+dy,y'dx);

Line(x+dyy-dx,x+dx,y+dyJ; End;

{основная программа}

Begin gd:=detect;

InitGraph(gd,gm, *d:\bp\bgi');

{устанавливаем начальную и конечную точки}

хп: =GetMaxX div 4; yn:--GetMaxYdiv3*2; xc: ^'GetMaxX-xn; yc:=GetMaxY'yn;

{определяем начальные значения}

dy:=0; к: =0,95; t:=0;

{покадровый вывод на экран}

while (t<100) and not KeyPressed do begin

SetColor(2); {выводим кадр}

Squarel(round(xn)у round(yn), round(dx), round(dy));

{масштабирование} xnl: = xn *k+(]'k) *xc; yn1: =yn *k+ (J-k) *>'c; r:= k'^r;

{поворот}

t:=t+l; {увеличиваем угол поворота} dxl:=r'^cos(t);

dyl:= r*sin(t);

forj:=J to 5000 do Delay(lOOO); {приостановка}

290