Основы программирования (947332), страница 48
Текст из файла (страница 48)
Рассмотрим еще одинпример.Пример 8.6. Разработать программу построения круговой диаграммыпо заданным значениям не более 12, которые должны выводиться рядом с соответствующим сектором диаграммы.Круговая диаграмма рисуется как совокупность закрашенных секторовкруга. Угол сектора пропорционален доле соответствующего значения в об282<^. Управление техническими средствами и взаимодействие с MS DOSщей сумме значений. Надпись должна выводиться напротив биссектрисы у гла сектора соответственно слева или справа диаграммы.Ниже приведена программа.Program difgramma;Uses Graph;Constkmax=12; {максимальное количество значений функции}r=J50;{радиус диаграммы}п=5;{ширина поля вывода}т=2;{размер дробной части числа}Туреmas=array[J..kmax+JJ of integer;masl=array[L.kmax] of real;Varfmasl;{массив значений функции}alfa:mas;{массив значений углов диаграммы}driver,err,{тип и режим работы адаптера}К{фактическое количество значений функции}bet, {величина угла, образованного радиусом и биссектрисой сектора диаграммы}у,х,{координаты точки, являющейся центром дуги сектора}х1,у1,{координаты начальной точки вывода надписи}хп,уп,{координаты центра диаграммы}i: integer;st:string[5]; {строка для хранения выводимой надписи}s:real;{сумма значений функции}beginWriteLnCВведите количество точек (от 1 до\ктах:3,') ');ReadLn(k);{вводим значения функций и определяем их сумму}for i:=l to к dobeginWriteLnCBeedume\i:3, '-e значение функции');ReadLn(f[i]);while f[i]<0 dobeginWriteLnCНедопустимое значение, повторите ввод');WriteLnCBeedume\i:3, '-e значение функции);ReadLn(f[i]);end;283Часть 1.
Основы алгоритмизации и процедурное программированиеs:-s+f[i]:end;if s=0 thenbeginWriteLn('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 dobeginifi<>k+l thenalfa[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-^10elsexJ:=X'8*n']0;if((bet>=0)and(bet<=J80))thenyl—y-lSelseyli^y^l;Sir(f[i'l]:n:m,st);{преобразуем значение в строку}OutTextXY(xl,yl,st);{выведем надпись}end;ReadLn;CloseGraph;EndРезультатом работы программы является изображение круговой диаграммы, приведенное на рис.
8.8.2848. Управление техническими средствами и взаимодействие с MS DOS56.0079.0035.0024.0023.0044.0066.0038.0079.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. Разработать программу, которая демонстрирует на экранедвижение прямоугольника: прямоугольник улетает от нас к некоторой точкегоризонта, одновременно вращаясь вокруг своей оси.Обобщенный алгоритм последовательного показа кадров данной задачивыглядит следующим образом.Начало:Установить точку отсчета координат (условное время).Рассчитать координаты квадрата.Цикл-пока не истекло время или не нажата любая клавишаУстановить цвет рисования.Изобразить квадрат.Приостановить выполнение программы на время просмотра кадра.2868.
Управление техническими средствами и взаимодействие с MS DOSТочкагоризонтаПовернутоеизображениеИсходное положениеРезультатмасштабированияРис. 8.10. Разложение движенияУстановить в качестве цвета рисования цвет фона.Изобразить квадрат цветом фона - стереть.Изменить точку отсчета (условное время).Пересчитать координаты квадрата.все-циклКонец.В а р и а н т ! . Координаты вершин квадрата будем хранить в специальных массивах х, у, а квадрат рисовать линиями, проводя их из одной вершины в другую.
Изображение квадрата будет осуществлять специальная процедура Square.Пересчет координат вершин реализуем через разложение «движения»прямоугольника на элементарные составляющие (рис. 8.10): эффект удаления от зрителя получим, используя масштабирование относительно точки горизонта, эффект вращения - за счет поворота вокруг геометрического центра.Вначале определим координаты вершин и центра квадрата после масштабирования, а затем координаты вершин после поворота вокруг центраквадрата.
Ниже приведена соответствующая программа:Program ex;Uses Crt,Graph;Constr=]00;Typemas =array[I.. 4] of integer;VarX, y, xl, yl:mas;gd,gm,xn,yn,xc,yc, ij, kl: integer;t,k:reaJ;287Часть L Основы алгоритмизации и процедурное программирование{изображение квадрата по координатам его вершин}Procedure Square(х,у:mas);BeginLine(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);Beginxl: =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);BeginxJ :=round(x*k-^(]-k) *xc);yl: =round(y*k+(l'k) *yc);End;{основная программа}Begingd: =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 dobeginSetColor(2); {установим цвет рисования}Square(x,y); {нарисуем квадрат}t:=t-^0.001; {увеличим угол поворота}2888.
Управление техническими средствами и взаимодействие с 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; {размер половины стороны квадрата}VarX, у, dx, dy, dxl, dyJ, xn, yn, xc, yc, xnl, ynl.real;gd,gmJJ: integer;tyk:real; {угол поворота и масштаб}{изображение квадрата}Procedure Squarel(x,ydx,dy:integer);BeginLine(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;{основная программа}Begingd:=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 dobeginSetColor(2); {выводим кадр}Squarel(round(xn)у round(yn), round(dx), round(dy));{масштабирование}xnl: = xn *k+(]'k) *xc;yn 1: =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); {приостановка}2908, Управление техническими средствами и взаимодействие с MS DOSSetColor(O); {стираем кадр}Squarel(round(xn), round(yn), round(dx), round(dy));dx:=dxl; {заменяем параметры квадрата}dy: =dylxn:=xnJyn:=ynlend;CloseGraph;end.Прямая запись в видеобуфер.
При программировании на экране движения объектов критичным является время перезаписи изображения: именно из-за большого времени перезаписи движение получается прерывистым.Для уменьшения этого времени при программировании в MS DOS часто используют прямую запись информации в видеобуфер.Как указывалось в параграфе 8.4, формат информации в видеобуфере зависит от используемого графического режима. При использовании младшихрежимов VGA, на которые рассчитан Borland Pascal, видеобуфер содержит 4бита на каждую точку, причем биты расположены в параллельных битовыхплоскостях и доступ к ним напрямую существенно затруднен (программирование таких операций обычно выполняется на ассемблере). Однако существует режим VGA (режим 19: 200*320 точек 256 цветов из палитры 262 144цвета), при котором каждой точке соответствует байт (8 бит) в видеобуфере.Именно этот режим и используется, если возникает необходимость программировать сложное движение с использованием прямой записи в видеобуфер.Пример 8.8.