Справочник программиста на персональном компьютере фирмы IBM. Вывод на терминал - Рисование линий на экране. Часть 2
ОГЛАВЛЕНИЕ
Оператор DRAW может включать строковые переменные, которые
состоят из набора допустимых кодов. Это свойство позволяет прог-
рамме повторно использовать части фигур в различных рисунках. В
операторе DRAW имя строки должно быть помещено за буквой X и за
ним должны следовать точка с запятой. Например:
100 S$ = "U12R15U45L32"
110 DRAW "XS$;"
В одном операторе DRAW может содержаться несколько строк, переме-
жаемых другими кодами. Отметим, что любые числа, используемые с
кодами в операторах DRAW могут сами быть переменными. Таким обра-
зом с помощью одного оператора DRAW могут выводиться фигуры,
отличающиеся по форме, цвету, масштабу и ориентации. Надо помес-
тить знак равенства между буквенным кодом и именем переменной, а
за именем поместить точку с запятой. Например, чтобы установить
код цвета, определяемый переменной, напишите DRAW "C=PCOLOR;".
Компилятор Бейсика требует, чтобы ссылка на эти переменные осу-
ществлялась с помощью функции VARPTR$. В этом случае такой опера-
тор будет иметь вид DRAW "X" + VARPTR$(S$) или DRAW "C=" +
VARPTR$(PCOLOR). Сложные рисунки могут быть сохранены в массиве и
затем возвращены на экран в любой момент. Обсуждение этого вопро-
са см. в [4.4.6].
Низкий уровень.
Нижеприведенная процедура использует алгоритм Брезенхэма для
вывода прямой линии, соединяющей любые две точки. Она использует
функцию BIOS установки точек и ее можно убыстрить если заменить
эту функцию на встроенную процедуру, использующую прямое отобра-
жение в память. Как и все быстрые алгоритмы данная процедура
избегает операций умножения и деления. Линия рассматривается как
набор сегментов двух типов: тех которые расположены диагонально и
тех, которые расположены горизонтально или вертикально. Для линий
с наклоном больше 1 прямые сегменты вертикальны, в противном
случае они горизонтальны; первая задача алгоритма состоит в вы-
числении наклона. Затем вычисляется выравнивающий фактор, который
следит чтобы некоторое число прямых сегментов имело большую дли-
ну, чем остальные. И, наконец, сложный цикл поочередно выводит
диагональные и прямые сегменты. BX поочередно принимает то поло-
жительные, то отрицательные значения, отмечая какой тип сегмента
выводится. Ниже готовятся данные для вывода диагонали из одного
угла экрана в противоположный:
;---в сегменте данных
START_X DW 0
END_X DW 319
START_Y DW 0
END_Y DW 199
COLOR DB 2
DIAGONAL_Y_INCREMENT DW ?
DIAGONAL_X_INCREMENT DW ?
SHORT_DISTANCE DW ?
STRAIGHT_X_INCREMENT DW ?
STRAIGHT_Y_INCREMENT DW ?
STRAIGHT_COUNT DW ?
DIAGONAL_COUNT DW ?
;---установка режима дисплея
MOV AH,0 ;функция установки режима
MOV AL,4 ;цветной 320*200
INT 10H ;установка режима
;---установка начальных инкрементов для каждой позиции точки
MOV CX,1 ;инкремент для оси x
MOV DX,1 ;инкремент для оси y
;---вычисление вертикальной дистанции
MOV DI,END_Y ;вычитаем координату начальной
SUB DI,START_Y ;точки из координаты конечной
JGE KEEP_Y ;вперед если наклон < 0
NEG DX ;иначе инкремент равен -1
NEG DI ;а дистанция должна быть > 0
KEEP_Y: MOV DIAGONAL_Y_INCREMENT,DX
;---вычисление горизонтальной дистанции
MOV SI,END_X ;вычитаем координату начальной
SUB SI,START_X ;точки из координаты конечной
JGE KEEP_X ;вперед если наклон < 0
NEG CX ;иначе инкремент равен -1
NEG SI ;а дистанция должна быть > 0
KEEP_X: MOV DIAGONAL_Y_INCREMENT,CX
;---определяем горизонтальны или вертикальны прямые сегменты
CMP SI,DI ;горизонтальные длиннее?
JGE HORZ_SEG ;если да, то вперед
MOV CX,0 ;иначе для прямых x не меняется
XCHG SI,DI ;помещаем большее в CX
JMP SAVE_VALUES;сохраняем значения
HORZ_SEG: MOV DX,0 ;теперь для прямых не меняется y
SAVE_VALUES: MOV SHORT_DISTANCE,DI ;меньшее расстояние
MOV STRAIGHT_X_INCREMENT,CX ;один из них 0,
MOV STRAIGHT_Y_INCREMENT,DX ;а другой - 1.
;---вычисляем выравнивающий фактор
MOV AX,SHORT_DISTANCE ;меньшее расстояние в AX
SHL AX,1 ;удваиваем его
MOV STRAIGHT_COUNT,AX ;запоминаем его
SUB AX,SI ;2*меньшее - большее
MOV BX,AX ;запоминаем как счетчик цикла
SUB AX,SI ;2*меньшее - 2*большее
MOV DIAGONAL_COUNT,AX ;запоминаем
;---подготовка к выводу линии
MOV CX,START_X ;начальная координата x
MOV CX,START_Y ;начальная координата y
INC SI ;прибавляем 1 для конца
MOV AL,COLOR ;берем код цвета
;---теперь выводим линию
MAINLOOP: DEC SI ;счетчик для большего расстояния
JZ LINE_FINISHED ;выход после последней точки
MOV AH,12 ;функция вывода точки
INT 10H ;выводим точку
CMP BX,0 ;если BX < 0, то прямой сегмент
JGE DIAGONAL_LINE ;иначе диагональный сегмент
;---выводим прямые сегменты
ADD CX,STRAIGHT_X_INCREMENT ;определяем инкре-
ADD DX,STRAIGHT_Y_INCREMENT ;менты по осям
ADD BX,STRAIGHT_COUNT ;фактор выравнивания
JMP SHORT MAINLOOP ;на следующую точку
;---выводим диагональные сегменты
DIAGONAL_LINE: ADD CX,DIAGONAL_X_INCREMENT ;определяем инкре-
ADD DX,DIAGONAL_Y_INCREMENT ;менты по осям
ADD BX,DIAGONAL_COUNT ;фактор выравнивания
JMP SHORT MAINLOOP ;на следующую точку
LINE_FINISHED: