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

Основы_Pascal

.pdf
Скачиваний:
47
Добавлен:
12.05.2015
Размер:
518.75 Кб
Скачать

Ранее уже упоминался вариант вызова процедуры write (или writeln) без параметров – для перевода курсора на новую строку.

Процедура read (или readln) без параметров может использоваться как «техническая остановка» - до нажатия пользователем любой клавиши. Это имеет смысл, например, когда результат, появившийся на экране в конце выполнения программы, исчезает (стирается) при выходе в систему после окончания работы программы.

Об особенностях чтения из файлов (кроме клавиатуры) и записи в файлы (не на экран), а также об особенностях ввода/вывода в графическом режиме – будем говорить ниже в процессе решения соответствующих задач.

Визуализация результатов расчетов

Особенность решения задач исследования динамики систем, в том, что здесь объект исследования чаще всего представляется его математической моделью в форме дифференциального уравнения или системы дифференциальных уравнений. Решения же дифференциальных уравнений – это не число или какието ограниченные множества чисел, а функции, а в случае дифференциальных уравнений в частных производных – функции уже не от одной, а от нескольких переменных.

Формировать эти функции – решения в виде формул утомительно, нерационально, а часто и вообще невозможно. Остается – решать их численно. Работать с решением в виде таблиц неудобно. Естественно напрашивается представление решения в виде графика (серии графиков), годографов, изображения поверхностей системами изолиний или в виде аксонометрических или иных изображений. Неплохо смотрится и демонстрация «кино» - образ развития процесса во времени и т.п.

Для этого можно (и нужно!) воспользоваться возможностями графического режима Турбо Паскаля.

2.1. Графический режим в Турбо Паскале

Начиная с версии 4.0, в состав Турбо Паскаля включена мощная библиотека графических подпрограмм Graph, остающаяся практически неизменной во всех последующих версиях. Библиотека содержит в общей сложности более 50 процедур и функций, предоставляющих программисту самые разнообразные возможности управления графическим экраном.

Стандартное состояние персонального компьютера после его включения, а также к моменту запуска программы из среды Турбо Паскаля соответствует работе экрана в текстовом режиме, поэтому любая программа , использующая графические средства компьютера, должна определенным образом инициировать графический режим работы дисплейного адаптера. После завершения работы программы компьютер возвращается в текстовый режим.

31

Настройка графических процедур на работу с конкретным адаптером достигается за счет подключения нужного графического драйвера. Драйвер – это специальная программа, осуществляющая управление теми или иными действиями компьютера. Графический драйвер управляет дисплейным адаптером в графическом режиме. Драйвера обычно располагаются на диске в отдельном подкаталоге BGI в виде файлов с расширением BGI (Borland Graphiс Interface).

С характеристиками различных адаптеров рекомендуем читателю ознакомиться по специальной литературе [1,19] – это чисто справочный материал. Инициирование графического режима осуществляется подпрограммой

Procedure InitGraph (var Driver, Mode:Integer; Path : string);

Здесь Driver определяет тип графического драйвера, Mode – режим его работы, Path – имя файла драйвера и, возможно, маршрут его поиска (путь).

Процедура InitGraph загружает найденный драйвер в оперативную память и переводит адаптер в графический режим работы. Тип драйвера должен соответствовать типу графического адаптера. Для указания типа драйвера в модуле Graph предопределены следующие константы:

const Deteсt=0; CGA=1; MCGA=2; EGA=3; EGA64=4;

EGAMono=5;

IBM8514=6;

HercMono=7;

ATT400=8;

VGA=9;

PC3270=10;

Большинство адаптеров могут работать в различных режимах. Для того, чтобы указать адаптеру требуемый режим работы, используется параметр Mode, значением которого в момент обращения к процедуре InitGraph могут быть такие константы:

const

{Адаптер CGA:}

CGAC0=0; {низкое разрешение, палитра 0}

CGAC1=1; {низкое разрешение, палитра 1}

CGAC2=2; {низкое разрешение, палитра 2}

CGAC1=3; {низкое разрешение, палитра 3} CGAHi=4; {высокое разрешение}

{Адаптер MCGA:}

MCGAC0=0; {Эмуляция CGAC0}

MCGAC1=1; {Эмуляция CGAC1}

MCGAC2=2; {Эмуляция CGAC2}

MCGAC3=3; {Эмуляция CGAC3}

MCGAC4=4; {Эмуляция CGAHi}

32

MCGAHi=5; {640 x 480} {Адаптер EGA:}

EGALo=0; {640 x 200, 16 цветов} EGAHi=1; {640 x 350, 16 цветов} EGAMonoHi=3; {640 x 350, 2 цвета} {Адаптер HGC и HGC+:} HercMonoHi=0; {720 x 348} {Адаптер ATT400:}

ATT400C0=0; {Аналог режима CGAC0}

ATT400C1=1; {Аналог режима CGAC1}

ATT400C2=2; {Аналог режима CGAC2}

ATT400C3=3; {Аналог режима CGAC3} ATT400Med=4; {Аналог режима CGAHi} ATT400Hi=5; {640 x 400, 2 цвета} {Адаптер VGA:}

VGALo=0; {640 x 200}

VGAMed=1; {640 x 350} VGAHi=2; {640 x 480} PC3270Hi=3; {Аналог HercMonoHi} {Адаптер IBM8514:}

IBM8514Lo=0; {640 x 480, 256 цветов} IBM8514Hi=1; {1024 x 768, 256 цветов}

Здесь числа в фигурных скобках, объединенные символом х, - это разрешающая способность по горизонтали и по вертикали (количество пикселей в строке и столбце). Пиксель – это элементарная светящаяся точка на экране (pixel – от слов picture – картинка, и element – элемент, т.е. элемент изображения) .

Если тип адаптера данного компьютера неизвестен или если программа рассчитана на работу с любым адаптером (программы, как правило, пишутся не под конкретный компьютер, а под их семейство), то используется обращение к процедуре InitGraph с требованием автоматического определения типа драйвера:

Driver:=Detect; {или :=0} InitGraph(Driver, Mode, Path);

После такого обращения устанавливается графический режим работы экрана с одним из драйверов, путь к которому указан в Path (если драйвера находятся в текущем каталоге, то путь выглядит так „ ‟). При этом для адаптеров, способных работать в нескольких режимах, выбирается режим с наибольшим номером. Адаптер (при Driver=0) выбирается таким образом чтобы он оказался совместимым с установленным в компьютере монитором.

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

Function GraphResult:integer;

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

33

Const

Grok=0; {нет ошибки}

GrInitGraph=-1; {не инициирован графический режим} GrNotDeteсted=-2; {не определен тип драйвера} GrFileNotFind=-3; {не найден графический драйвер} GrInvalidDriver=-4; {неправильный тип драйвера} GrNoLoadMem=-5; {нет памяти для размещения драйвера} GrNoScanMem=-7; {нет памяти для закраски областей} GrNoFloodMem=-6; {нет памяти для просмотра областей} GrFontNotFound=-8; {не найден файл со шрифтом} GrNoFontMem=-9; {нет памяти для размещения шрифта} GrInvalidMode=-10; {неправильный графический режим}

GrError=-11; {общая ошибка}

GrIoError=-12; {общая ошибка ввода - вывода} GrInvalidFont=-13; {неправильный формат шрифта} GrInvalidNum=-14; {неправильный номер шрифта}

Функция

Function GraphErrorMsg(Code:integer):string;

-возвращает текст, объясняющий причину неудачи.

Здесь Code – код ошибки, возвращаемый функцией GraphResult.

Следует отметить, что после обращения к функции GraphResult признак ошибки сбрасывается, поэтому повторное обращение к ней вернет ноль.

Типичная последовательность операторов для инициации графического режима с автоматическим определением типа драйвера и установкой максимального разрешения выглядит так:

var Driver, Mode, Error : integer; begin

Driver:=0;

InitGraph(Driver, Mode, ´ ´); Error:=GraphResult;

if Error <>0 then

begin writeln(GraphErrorMsg(Error));

………………………………….

end

else

…..

Процедура

procedure CloseGraph;

-завершает работу адаптера в графическом режиме и восстанавливает текстовый режим работы экрана.

Процедура

procedure RestoreCrtMode;

-служит для кратковременного возврата в текстовый режим.

34

Процедура

procedure SetGraphMode(Mode:integer);

-устанавливает новый графический режим работы адаптера. Здесь Mode – код устанавливаемого режима.

2.2. Графические примитивы

Изображение на экране в графическом режиме формируется путем засветки требуемым цветом отдельных пикселей. Координаты каждого пикселя задаются в системе координат экрана (окна). Первая (горизонтальная) координата – это номер позиции (пикселя), отсчитываемый от левого края экрана, вторая (вертикальная) – от верхнего края. Координаты – целые числа.

Максимальное значение горизонтальной координаты определяется (в зависимости от задействованных драйвера и режима) функцией

function GetMaxX : word;

то же для вертикальной координаты function GetMaxY : word;

В случае необходимости может устанавливаться графическое окно – прямоугольный участок экрана, в пределах которого осуществляется формирование графического изображения. Установка окна реализуется процедурой

procedure SetViewPort (X1,Y1,X2,Y2:integer; Clip:boolean);

Здесь X1,Y1 – координаты левого верхнего, X2,Y2 – соответственно правого нижнего угла окна (в системе координат экрана). Параметр Clip (отсечка) – выражение типа boolean, равное true, если требуется отсекать изображения, выходящие за пределы устанавливаемого окна. Если же Clip=false, то отсечка не производится (т.е. соответствующая линия рисуется как в пределах окна, так и за его пределами).

Параметр Clip может задаваться в виде одной из нижеприводимых констант

const

ClipOn=true; {включить отсечку} ClipOff=false; {не включать отсечку}

После установки окна начало системы координат переносится в его левый верхний угол. И все процедуры, в которых используются координаты, работают в дальнейшем в системе координат окна. Если окно не задано ( не установлено) – окном по умолчанию считается весь экран.

Процедура SetViewPort не «срабатывает», если размер окна выходит за пределы экрана (при этом – никаких сообщений, остается в силе ранее установленное окно – или в его отсутствии – экран в целом).

Процедура

procedure GetViewSettings (var ViewInfo : ViewPortType);

-возвращает координаты и признак отсечки текущего графического окна. Здесь ViewInfo – переменная типа ViewPortType, которая определяется так

type ViewPortType=record

35

X1,Y1,X2,Y2:integer;{координаты окна} Clip:Boolean {признак отсечки}

end;

Чтобы закрасить пиксель с координатами X,Y цветом C используется процедура

procedure PutPixel (X,Y:integer;C:word);

При необходимости узнать каким цветом (уже) закрашен пиксель с координатами X,Y можно воспользоваться функцией

function GetPixel (X,Y:integer):word;

Обращаем внимание читателя – если точка, фигура или часть фигуры оказывается или полностью или частично за пределами экрана – компьютер не «возражает», он будет прилежно пиксель за пикселем «рисовать» ее там где вы указали.

А теперь стоит сказать несколько слов о так называемом графическом курсоре (CP – current pointer). Он постоянно присутствует на экране, указывая на один из его пикселей, но в отличии от текстового курсора (который указывает на определенное знакоместо) – графический курсор невидим.

Где он находится в данный момент можно узнать с помощью функций function GetX:integer;

function GetY:integer;

Первая из них возвращает горизонтальную, а вторая – вертикальную координаты CP. Поместить CP в нужный пиксель на экране можно процедурой

procedure MoveTo (X,Y:integer);

или процедурой

procedure MoveRel (DX,DY:integer);

-которая смещает CP на DX по горизонтали и DY по вертикали относительно его предыдущего положения (при DX>0 – вправо, DX<0 – влево и соответственно вверх (при DY<0) и вниз (при DY>0) ).

Следует помнить, что СР может «гулять» по экрану, точнее, его могут «гонять» по нему некоторые процедуры. Так, например, в момент инициализации графического режима СР помещается в верхний левый угол окна (с координатами 0,0 в системе координат экрана). О других перемещениях СР будем говорить по мере возникновения необходимости.

Впроцедуре PutPixel цвет закраски указанного пикселя задавался явно. При формировании более сложных геометрических фигур цвет изображения (элементов этих фигур) задается процедурой

procedure SetColor (Color:word);

Функция

function GetColor:word;

-возвращает последнюю установку цвета. Если цвет явно не устанавливался (процедура SetColor не вызывалась), то автоматически по умолчанию устанавливается Color=15 (яркий белый).

Цвет фона по умолчанию считается равным 0 (черный). При необходимости задать другой цвет (Color) фона можно воспользоваться услугами процедуры

procedure SetBKColor (Color:word);

36

Чтобы узнать каким является установленный на данный момент цвет фона - существует функция

function GetВКColor:word;

Фигуры в виде линий или комбинаций линий требуют указания какими линиями их требуется рисовать. Для этого существует процедура

procedure SetLineStyle (LineStyle,Pattern,Thickness:word);

Здесь LineStyle – тип линии. Для определения типа линии установлены константы

const

SolidLn=0; {сплошная}

DottedLn=1; {точечная}

CenterLn=2; {штрихпунктирная} DashedLn=3; {пунктирная}

UserBitLn=4; {тип определяется пользователем}

С типами от 0 до 3 все понятно. С вариантом 4 стоит разобраться.

Если LineStyle принимает значение 0..3, то параметр Pattern задается равным 0. А вот если LineStyle=4, то конкретный образец линии (шаблон) задается параметром Pattern. Как следует из заголовка процедуры SetLineStyle параметр Pattern имеет тип word. Это два последовательно расположенных байта. Схематически участок памяти для параметра Pattern можно представить так

1

й

полубайт

2

й

полубайт

3

й

полубайт

4

й

полубайт

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

й

байт

2

й

байт

 

 

Пользователь формирует требуемый ему образец (трафарет) линии длиной 16 пикселей и каждому пикселю ставит в соответствие 0 или 1 (0 – разрыв в линии, 1

– заполненный участок линии).

Таким образом, каждый байт образца ассоциируется с числом в шестнадцатеричной форме. Соответствие между первыми 16 шестнадцатеричными цифрами и их двоичными эквивалентами показано ниже

0 - 0000

1 - 0001

2 - 0010

3 - 0011

4 - 0100

5 - 0101

6 - 0110

7 - 0111

8 - 1000

9 - 1001 А - 1010 B - 1011

37

C - 1100

D - 1101

E - 1110

F - 1111

Итак, параметр Pattern для трафарета, ассоциированного с двоичным кодом 0000/0101/1100/1000 может быть задан как $05C8. Код для удобства разбивается на участки длиной 4 бита каждый (полубайт), а после шестнадцатеричные коды всех полубайтов объединяются.

Третий параметр процедуры SetLineStyle, а именно Thickness (толщина линии) может принимать одно из двух значений:

const

NormWidth=1; {нормальная толщина} ThickWidth=3; {тройная толщина}

Здесь нормальная толщина – это толщина в один пиксель.

В модуле Graph предусмотрено два возможных режима формирования элементов изображений, состоящих из образцов прямых линий. Процедура

procedure SetWriteMode (WriteMode:integer);

- устанавливает режим вывода для линий. Здесь WriteMode – код режима, который может принимать одно из двух возможных значений: 0 если линия должна выводиться явным (заданным процедурой SetColor) или 1 – если линии должны формироваться в инверсном цвете.

Значение параметра WriteMode можно задавать константами const

CopyPut=0;

XorPut=1;

Эффект инвертирования цвета можно продемонстрировать на примере перекраски в инверсный цвет отдельного пикселя

PutPixel (X,Y, GetMaxColor-GetPixel(X,Y)).

Здесь GetMaxColor – вызов функции function GetMaxColor:word;

Последняя возвращает максимальный цвет (его код - номер), который можно задать в SetColor (при задействованном драйвере и режиме).

С функцией GetPixel мы уже встречались.

Замечательной особенностью инвертирования цвета является то, что повторном выводе (при четной последовательности инвертирований) цвет пикселя останется тем же, что был до начала инвертирования. Тем самым создается возможность сохранения фона, поверх которого временно наносятся те или иные изображения. Это может оказаться кстати при необходимости демонстрации изображений движущихся на непустом фоне объектов. Или, например, «для примерки» какого-то изображения, вписывается ли оно в данный фон. Если нет, то примеряемое изображения убирается его повторным формированием в инверсном цвете (первичное предполагается, естественно, в том же инверсном виде).

Ну, а теперь процедуры, формирующие некоторые элементарные линии и геометрические фигуры.

38

procedure Line (X1,Y1,X2,Y2:integer);

-рисует отрезок прямой, соединяющий точки (пиксели) с координатами (X1,Y1)

и(X2,Y2). Тип линии, при необходимости – ее образец и толщина задаются процедурой SetLineStyle, цвет – процедурой SetColor, способ взаимодействия с фоном – процедурой SetWriteMode,

procedure LineRel (DX,DY:integer);

-рисует отрезок прямой от текущего положения СР к точке, заданной приращением координат DX,DY (см. процедуру MoveRel),

procedure LineTo (X,Y:integer);

-формирует отрезок прямой от текущего положения СР до точки с координатами

(X,Y).

Вниманию читателя – процедуры LineRel и LineTo переводят СР в конец формируемой линии.

procedure Rectangle (X1,Y1,X2,Y2:integer);

-рисует прямоугольник, стороны которого параллельны осям системы координат, с левым верхним углом прямоугольника в точке (X1,Y1) и правым нижним – в (X2,Y2).

Напоминаем, что действие процедуры SetWriteMode распространяется только на процедуры Line, LineTo, LineRel, Rectangle и еще на процедуру DrawPoly,

которая нам представляется непрактичной, почему мы ее здесь не рассматриваем (это наше личное мнение).

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

procedure Circle (X,Y:integer, R:word);

-рисует окружность радиуса R с центром в точке с координатами (X,Y).

Тип линии, толщина, цвет задаются так же как и для прямых линий.

Здесь уместно упомянуть вот о чем. При использовании различных графических драйверов и режимов соотношение между величиной шага развертки изображения по вертикали и по горизонтали может оказаться не равным единице. О фактическом соотношении между упомянутыми шагами можно узнать с помощью процедуры

procedure GetAspectRatio (var Xasp,Yasp:word);

-она возвращает два числа (Xasp,Yasp), отношение которых равно соотношению горизонтального DX и вертикального DY шагов (Dx/Dy=Xasp/Yasp).

При необходимости поменять установившееся значение данного соотношения можно использовать процедуру

procedure SetAspectRatio (Xasp,Yasp:word);

Установка «правильного» соотношения шагов гарантирует, что Circle будет окружностью, а не эллипсом, а Rectangle, у которого /X2-X1/=/Y2-Y1/, будет квадратом.

С учетом сказанного можно уточнить, что параметр R (радиус) в процедуре Circle задается в «горизонтальных» пикселях.

Дугу окружности формирует процедура procedure Arc (X,Y:integer;An,Ak,R:word);

Здесь X,Y – координаты центра;

39

An,Ak – начальный и конечный углы (в градусах) дуги; R – радиус (в горизонтальных пикселях).

Процедура

procedure Ellipse (X,Y:integer;An,Ak,Rx,Ry:word);

- формирует дугу эллипса. Здесь первые четыре параметра те же, что и в Arc; Rx,Ry – горизонтальный и вертикальный радиусы эллипса в

пикселях.

При необходимости нарисовать полный эллипс достаточно задать An=0, Ak=360.

Имеется ряд процедур, в которых используется заполнение областей, ограниченных определѐнным контуром. Упомянем среди них:

procedure Bar (X1,Y1,X2,Y2:integer);

-закрашивает (но не обводит!) прямоугольную область экрана (X1,Y1 – левый верхний, X2,Y2 – правый нижний угол прямоугольника, как в Rectangle и SetViewPort).

procedure Bar3D (X1,Y1,X2,Y2,Depth:integer;Top:boolean);

-вычерчивает трехмерное изображение параллелепипеда и закрашивает его переднюю грань.

Здесь X1,Y1,X2,Y2 как в Bar;

Depth – третье измерение (в горизонтальных пикселях) т.е. глубина;

Top - способ изображения верхней грани (Top=true – верхняя грань рисуется, Top=false – не рисуется).

procedure FillEllipse (X,Y:integer;Rx,Ry:word);

-обводит линией и закрашивает эллипс.

X,Y – координаты центра эллипса,

Rx,Ry – полуоси этого эллипса (в пикселях). procedure Sector (X,Y:integer;An,Ak,Rx,Ry:word);

- вычерчивает и заполняет эллипсный сектор (обозначение - очевидно). procedure FloodFill (X,Y:integer;Border:word);

- заполняет (закрашивает) произвольную фигуру, ограниченную цветом Border (если фигура незамкнута, заполнение «разольется» по всему экрану).

По умолчанию «заливка» осуществляется в виде сплошной закраски белым цветом. Но при необходимости к услугам программиста процедура

procedure SetFillStyle (Fill,Color:word);

и

procedure SetFillPattern (Pattern,FillPatternType,Color:word);

Здесь Fill –тип заполнения; Color – цвет заполнения.

Для указания типа заполнения используются константы: const

EmptyFill=0; {заполнение фоном – узор отсутствует} SolidFill=1; {сплошное заполнение}

LineFill=2; {заполнение --------------} LtSlashFill=3; {заполнение ////////////}

40