3. 4 Сокрытие линий невидимого контура.
При работе с трехмерной векторной графикой часто встает од-
на важная проблема - как изображать невидимые линии трехнерного
объекта? Эта задача имеет непосредственное отношение к системам
автоматизированного проектирования и наибольшее развитие полу-
чила именно в теории этих систем и. надо сказать, для ее реше-
ния привлекают довольно сложный аппарат из той области высшей
математики, которая называется аналитической геометрией. Для
нас с Вами, поскольку мы занимаемся обычной прикладной графи-
кой, эту задачу можно несколько упростить. На данном этапе нас
не интересует, как изобразить невидимые линии - нам просто
нужно их НЕ ИЗОБРАХАТЬ.
Приемов и методов для достижения этой цели немало и мы
рассмотрим один из наиболее простых, поддающийся несложной ал-
горитмизации.
Посмотрите на Рис. 31. На нем изображен некоторый трехмер-
ный ландшафт. Фактически это график функции:
Ъ - SIN (R)/R .
где R = SQR <Х«Х ♦ У«У)
В своих экспериментах Вы можете изменить эту функцию и по-
работать с другими, важно только, чтобы она имела вид Z=f(X.У)
т. е. чтобы была возможность составить однозначный алгоритм для
вычисления координаты Z по заданным координатам X и У Самое
интересное в этом графике - то. что скрытые детали - на самом
деле скрыты. Все точки, которые находятся за гребнем или за
вершинои - не показаны.
алгоритн.
Давайте рассмотрим алгоритм, с помошью которого может быть
достигнут желаемый эффект. Во-первых, надо отметить, что наша
трехмерная поверхность изображается в два приема. На первом
проходе изображаются все линии, параллельные оси X (Рис. 32),
а на втором проходе - линии, параллельные оси У (Рис.33). Имен-
но благодаря такому порядку изображения кривых и оказывается
возможным скрыть невидимые детали.
Линии изображаются с некоторым шагом по X - Xh и по У -
Yh (см. Рис. 34). Конечно, чем мельче шаг, тем детальнее будет
проработано изображение, но слитком мельчить тоже не надо -
существует некоторый оптимум, который можно установить методом
проб и ошибок. Во всяком случае, параметры
Xh=(Xmax-Xmin)/20 и
Yh=(Ymax-Ymin>/20
выглядят достаточно удачными.
рис. 34
Если какая-то часть вычерчиваемой в текущий момент линии
оказывается за ранее проведенной кривои. то она не изображается
и есть достаточно простой прием, который позволяет в программе
принять такое решение.
Если мы выстраиваем изображение в виде семейству кривых,
начиная от ближайшей к наблюдателю и удаляясь от него назад,
(т.е. идем от т. т. Х2 и Y2 к т. т. XI и Yl. как показано иа
Рис.34), то фактически те точки текущей линии, которые оказыва-
ются на экране ниже, чем точки ранее изображенных линий, и яв-
ляются невидимыми и должны быть скрыты.
Чтобы решить этот вопрос программно, мы создаем в опера-
тивной памяти буфер размером 256 байтов, а дальше действуем
следующим образом. Поскольку экран "Спектрума" имеет в ширину
256 пикселов, то мы будем считать, что он образован как бы из
256-ти узких однопикселных вертикальных столбцов, каждому стол-
бцу отведем по одной ячейке памяти в нашем буфере и теперь вся-
кий раз. когда будем печатать на экране точку, будем смотреть,
что же содержится в буфере для данного столбца. Если то значе-
ние. которое есть там - меньше, чем вертикальная координата эк-
рана. в которой мы будем печатать точку, то новая координата
запоминается в данном буфере и точка печатается. Если же храня-
щееся там значение больше, чем текущая вертикальная координата
позиции печати, то точка должна быть скрыта и не печатается, а
значение в буфере не изменяется. '
Итак, алгоритм имеет следующий вид:
1. Задаем максимальные значения координат Х2 и Y2
2. Задаем минимальные значения координат XI и Yl.
3. определяем шаг по осям X и Y - Xh. Vh.
Xh=iXmax-Xmin)/23
Vh-(Ymax-Ymin)/23
Мы специально делили здесь на "некруглое" число 23, а не
на 20. Это поногает избежать прохождения через нулевую точку в
тон случае, если максимальные и минимальные паранетры заданы
симметрично относительно нуля. Все-таки неуютно себя чувству-
ешь. когда програмна должна посчитать SIN(R)/R. когда R равно
нулю. хотя, в принципе, и этот случаи ножно было бы предусмо-
треть; Для тех, кто еше пока не изучал высшую математику, под-
скажен. что SIN(R)/R приближается к единице, когда R стремится
к нулю.
4. Определяем насштаб по осям X и Y.
Для системы координат, показанной на Рис. 31... 33 масштаб
по X и V - одинаков. Он зависит от ширины экрана и от угла
нежду осяни X. y и осью z. Для того, чтобы при любых допустимых
значениях X и У точка унешалась бы на экране, нам необходимо
избрать насштаб:
(Х2-Х1)+СУ2-У1)«255/SQR(3)«2
5. Задаем масштаб для оси Z (его можно менять).
6. Создаем буферный массив из 256 элементов, обнуляем их.
7. Начинаем строить сенейство кривых, "параллельных" оси
X. Организуен цикл по У от Y2 до Y1 с шагом Yh.
8. Внутри этого цикла организуем цикл от Х2 до XI с шагом
по Xh.
9. Внутри этого цикла для текущих значении X и у опреде-
ляем z по заданной Формуле Функции
10. Полученный результат для Z умножаем на масштаб, полу-
чаем координату Z для графика.
И. Выполняем преобразование систем координат. По трехмер-
ным координатам X.V.z находим значения х и у для плоскости эк-
рана.
Формулы для этого преобразования будут зависеть от того,
какую проекцию трехмерной системы координат На плоскость Вы
изберете. Другими словами, они зависят от того, под какими
углами Вы смотрите на трехмерный объект, для случая, показанно-
го на Рис. 31... 33. подойдут формулы:
X.-- SQR (3) » (Y-X) /2 +127
»
У = Z - (У+Х)/2 + 87
12. Мы готовы поставить на экране точку в координатах
х. у. Но сначала проверим, что есть в буфере для данной коор-
динаты х. Если там значение меньше, чем у. то точку х. у на эк-
ране ставим и значение у обновляем в буфере, а если оно больше,
то точка - невидима, мы ее не ставим и значение в буфере не
обновляем.
13. Вычислив экранные координаты точки х. у. мы готовы сое-
динить ее линией с предыдущей точкой х'.У (если наша точка не
первая). Хорошо бы для этого воспользоваться командой БЕИСИКа
DRAW или процедурой изображения отрезков в машинных кодах, но
делать этого, к сожалению, нельзя. Причина в том. что этот от-
резок (или его часть) может быть невидимым. Значит, надо стро-
ить его по точкам и для каждой точки проверять по буферу видима
она или нет. Поэтому опять же надо организовать цикл для изоб-
ражения отрезка по точкам.
14. теперь иадо определиться с параметром этого цикла, он
может изменяться по горизонтали (по х). а может и по вертикали
(по yi. Надо понять, что больше - прирашение dx (равное х-х')
или dr (равное у-у'). To. которое больше, и следует принять в
качестве параметра цикла.
15. определившись с парметром, организуем цикл и внутри
него вычисляем координаты текущих точек, проверяем для них у.
сравнением с буфером и. если точка видима, печатаем ее и
обновляем буфер, а если нет. то не печатаем и не обновляем
бУФер.
Здесь есть маленькая хитрость, которая несколько усложняет
жизнь программисту. Дело в том. что эти соединительные отрезки
можно проводить слева-направо, а можно и справа налево, в прин-
ципе. это все равно, но есть один нюанс! допустим, мы будем их
проводить слева направо. Все будет в порядке, пока нам не при-
дется провести круто падающий отрезок На одиг шаг по х для не-
го происходит несколько шагов по у. и бывает так. что одной ко-
ординате х соответствуют несколько точек у. Если бы мы рисовали
этот отрезок снизу вверх, все было бы в порядке, а при движении
сверху вниз (слева-направо) ранее напечатанная точка может
иблокировать* печать следующих, забив в буфере свою координату.
Поэтому круто падакшие отрезки программа должна строить наобо-
рот - справа-налево. Тогда отрезок становится как бы не "па-
дающим", а "восходящим".
16. соединив две точки на экране, переходим к очередной
точке, отстоящей на Xh. и возвращаемся на шаг 8.
17. Посторив кривую, "параллельную" оси х. переходим к
следующей, отстоящей от нее на шаг Vh. Возврашаенся на шаг 7.
18. Когда все сенейство кривых, "параллельных" оси X по-
строено, половина дела сделана. Теперь надо построить семейство
кривых, параллельных оси V
19. Для этого сначала переинициализируем буфер, обнулив
все его значения, а затем повторим все то же. что мы делали для
семейства кривых, идущих вдоль оси X (шаги 7 - 18). Правда.
при этом внесто шагов по x буден делать шаги по у и наоборот.
Вот практически и весь алгоритн. Его описание выглядит
страшнее, чем текст программы на БЕИСИКе (см. ниже). И это не
случайно - ведь БЕЙСИК гораздо лучше подходит для описания
алгоритмов и программистских идей, чем нормальный человеческий
язык.
Конечно, скорость работы этой программы на БЕИСИКе остав-
ляет желать лучшего, но для иллюстрации самой концепции он не-
плох. Бы можете менять максимальные и минимальные значения X и
У. Вы можете менять насштаб по Z. Более того. Вы можете менять
и саму Функцию, исследуя другие поверхности.
10 LET xmax = Ю: LET ymax = Ю
20 LET xmm =-10: LET ymin = -10
30 LET xh = -(xmax-xmin)/23: LET yh = -(ymax-ymin)/23
40 LET scale = 255/SQR(3) »2/( (xmax-xmim + (ymax-ymm))
50 LET zscale = 40
60 DIM с(256): FOR 1=1 to 256: LET C(1)=0: NEXT l
70 FOR y=ymax TO ymin STEP yh: LET Yl=y*scale
80 FOR x=xmax TO xmin STEP xh: LET xi=x«scale
90 GO SUB 5000
100 IF x=xmax THEN GO SUB 8100: NEXT X
110 LET dy=vt-yold: LET dx=xt-xold
120 IF ABS(dy) >= ABS(dX) THEN GO SUB 6000: GO TO 140
130 GO SUB 7000
140 NEXT X
150 NEXT у
155 FOR 1=1 TO 256: LET c(l)=0: NEXT 1
160 FOR x=xmax TO xmin STEP xh: LET xl=x«scaie
170 FOR y=ymax TO ymin STEP Yh: LET yl=y«scale
180 GO SUB 5000
190 IF y=ymax THEN GO SUB 8100: NEXT У
200 LET dy=Yt-Yold: LET dx=xt-x0ld
210 IF ABS(dy) >= ABS(dX) THEN GO SUB 6000: GO TO 230
220 GO SUB 7000
230 NEXT у
240 NEXT X
250 STOP
4997 REM
4998 REM**»*..........к»*.»*»».......................
4999 REM
5000 LET Г - SGR(X«X + Y»Y): LET Z = SIN(D/r
5010 LET z = z»zscaie
5020 LET Xt-127+SQR(3)»lyl-Xl)/2
5030 LET yt=87+z-(yl+Xl)/2
5040 RETURN
5997 REM
5998 REM*»**»»*»**»*»»*»»»*»»»»».....................
5999 REM
DOOO IF dy<0 THEN GO TO 6100
6010 FOR 1=0 TO dy
6020 GO SUB 6500
6030 NEXT 1
6040 GO SUB 8100: RETURN
6100 FOR l=dy TO 0
6110 GO SUB 6500
6120 NEXT 1
6130 GO SUB 8200: RETURN
6497 REH
6498 REM*.............................................
6499 REH
6500 LET Xt=XOld+dX/dy»l
6510 LET yt=yold+l
6520 GO SUB 8000: RETURN
6997 REH
6998 REM»*»...........................................
6999 REM
7000 IF dX<0 THEN GO TO 7100
7010 FOR 1=0 TO dX
7020 GO SUB 7500
7030 NEXT 1
7040 GO SUB 8100: RETURN
7100 FOR l=dx TO 0
7110 GO SUB 7500
7120 NEXT 1
7130 GO SUB 6200: RETURN
7497 REM
7498 REM «»*.................*.......................
7499 REM
7500 LET Xt=XOld+l
7510 LET Yt=yold+dy/dX*l
7520 GO SUB 8000: RETURN
7997 REM
7998 REM»»»»»»»»»»»»*»*»*»*..»..»..».«.».«.».»..»«»«•
7999 REM
8000 IF yt > C(xt+1) THEN LET Clxt*l)=yt: PLOT Xt,yt
8010 RETURN ,
8097 REM ,
8098 REM»»»*.........................................
8099 REM
8100 LET XOld=Xt: LET YOld=yt: RETURN
8197 REM
8198 REM»»*»**.....»»*.......................*»».»...
8199 REH
8200 LET x0ld=xcld+dx: LET yold=yold+dy: RETURN
СПИСОК ПРОГРАММНЫХ ПЕРЕМЕННЫХ
хшах - наксимально-допустимое значение координаты X (задается
пользователей>.
ушах - то же для координаты У.
xmin - нинимально-допустимое значение координаты X (задается
пользователей),
ymin - то же для координаты У.
xh. yh - шаг между узлани сетки.
scale - масштаб по координатам X и У (зависит от углов в про-
странстве. под которыми наблюдатель смотрит на
трехмерный объект. Рассчитывается исходя из соображении
оптинального использования плоскости экрана,
zscale - масштаб по оси Z (задается пользователем "по вкусу".
но так. чтобы изображение по вертикали не вышло за
пределы экрана». Возножно и автоматическое определе-
ние zscale в програнне.
с 1256)- буферный нассив на 256 эленентов.
XI.У1 - отмасштабированные значения трехнерных координат X и У.
г - матенатическии конплекс. нужный для вычисления Z.
х.у - текущие трехнерные координаты X и У в узлах сетки,
xt,yt - текущие экранные координаты (двумерные),
xold. yold - экранные (двунерные) координаты предыдущего узла,
dx.dy - приращения экранных координат на очередном шаге
(расстояние на экране нежду узлами».
Те же. кто предпочтут использовать для программирования
машинный код, получат прекрасные результаты, но надо учесть,
что программа выполняет большой обьен чисто Математических вы-
числении ото вообще характерно для трехмерной векторной графи-
ки). Здесь _ и масштабирование (чтобы график аккуратно занимал
плоскость экрана» и пересчет из одной системы координат в дру-
гую (из трехнернои системы координат в двумерную систему коор-
динат плоскости экрана) и. конечно же. расчет санои Функции
Z-i (X.У). Процессор Z-80 не может оперировать с действительными
числани. не ножет выполнять натенатических расчетов и здесь
используют программирование в кодах калькулятора. Ниже приведен
принер программы в машинном коде. Подробный комментарий всех
входящих процедур явится хорошим пособием для тех. кону необ-
ходимо' программирование в кодах калькулятора.
Список использованных ячеек памяти калькулятора.
МО |
drawX ■disPF |
"Снешение" конца вычерчиваеного отрезка отно- сительно его начала в направлении оси X. "Смешение" конца отрезка в "прямом" (см. При- мечание» направлении. |
Ml |
drawY disPT
ratio |
"Смешение" конца отрезка в направлении оси Y. "Смешение" в "поперечном" (см. примечание) направлении. Отношение disPF/disPT. |
H2
linex lineF |
Координата X очередной точки линии. Координата очередной точки линии в "пряной" направлении. |
ИЗ |
lineY lineT |
Координата Y очереднбй точки линии, координата очередной точки в "поперечной" на- правлении. |
М4 |
PlOtX PlOtF |
Координата X текущей печатаемой точки. Координата текуией точки линии в "прямом" направлении. |
н5 |
PlOtY PlOtT |
Координата Y текущей печатаемой точки. Координата текущей точки линии в "поперечном" направлении. |
Нб |
XI |
Нинимальное значение X (см. рис. 34 ) |
Н7 |
Yl |
Минимальное значение Y (см. рис. 34 ) |
не |
X2 |
Максимальное значение X (см. рис. 34 ) |
Н9 |
Y2 |
Максимальное значение Y (см. рис. 34 ) |
НА |
XH |
Наг в направлении оси X (см. рис. 34 ). |
НВ |
YH |
маг в направлении оси Y (см. рис. 34 ). |
нс |
Zscale |
Масштаб по оси Z (на эту величину умножается полученное значение координаты Z). |
HD |
XYscale |
Масштаб по осям X.Y (половина той величины, на которую умножаются координаты X и Y). |
НЕ |
X |
Координата X в трехмерном пространстве. |
HF |
Y |
Координата Y в трехмерном пространстве. |
Примечание. Каждая кривая состоит из отрезков прямых, а
каждый отрезок как-то наклонен к экранным осям X и У. Если от-
резок идет как бы "вдоль" оси X экрана, то прямым направлением
считается ось X. а поперечным - ось У в то же время, если он
ориентирован больше вдоль оси У экрана, то соответственно
наоборот: прямое направление - У. а поперечное - X
Вызов подпрограммы.
Здесь реализован вызов подпрограммы и передача в нее
параметров через БЕИСИКовскую Функцию пользователя FN GO. фун-
кция пользователя задается в БЕИСИКе оператором:
DEF FN G(A. B.C. D. К. L.H.N) = USR address
В качестве адреса старта <sddress> здесь должен быть задан
адрес, с которого в памяти разнешается пусковая процедура
START.
Вызов процедуры выполняется вызовом пользовательской
функции, например так.
RANDOHIZE FN G(X1. Х2. Yl. Y2. XH. YH. Zsc. FNaddr), где:
- XI. X2. Yl. Y2. XH. YH - CH. на РИС.31;
- Zsc - принятый насштаб для оси Z;
- FNaddr - адрес, в котором расположена ваша процедура
для расчета координаты Z - HYFUNC (см. ниже).
Буфер.
Мы организуем буфер, начиная с адреса BUFFER и отведем
под него 256 байтов, т. е. по (BUFFER+255) включительно.
Вызываемые процедуры ПЗУ.
STACK.NUH (ЗЗВ4Н = 13236 DEC) - СМ. СТР. 106.
FIND.INT2 (1Е99Н = 7833 DEC) - процедура снимает верхнее
число со стека калькулятора и. " полагая, что это целое число в
диапазоне о...65535. передает его в регистровую пару ВС. Ранее
мы для этой цели всегда пользовались процедурой FP_TO_BC (2DA2H
= 11682 DEC), что почти то же самое. Разница в том. что если
при этом возникало переполнение, то FP_TO.BC соответственно
выставляла Флаг С регистра F. а процедура FIND_IKT2 в этом
случае вызывает процедуру REPORT.B (1E9FH=7839 DEC) для выдачи
сообщения об ошибке "Integer out of ranse".
RST зон - см. СТР. 106.
break_key (1f54h = 8020 dec) - процедура предназначена для
определение Факта нажатия клавиши break. Она выдает выключенный
Флаг с регистра f. если зафиксировано нажатие клавиши break
(или caps shift + space одновременно, что то же саное).
fp_to_A (2dd5h = 11733 dec) - см. стр. 106.107.
plot (22dch = 8924 dec) - см. стр. 107.
Процедуры программы.
MYFUNC - эта процедура выполняет расчет по Вашей Формуле
z-f (____).
START - с этой процедуры начинается работа программы. Ее
начало служит точкой входа. Здесь выполняется приен параметров
из пользовательской Функции FN О и размещение их на вершине
стека калькулятора.
GRID - процедура является головной. Иненно она увязывает в
единое целое работу всех прочих процедур. Ее алгоритм имеет три
логических части.
Первая часть выполняет инициализацию (первичную настрой-
ку). Так. например. Вы знаете, что "Спектрум" в исходном состо-
янии имеет только шесть ячеек памяти для своего калькулятора
(МО.,.М5). но их число ножет быть увеличено до необходимых нам
шестнадцати (МО... MF). Это выполняется именно здесь. Здесь же
заполняются семь ячеек памяти калькулятора (с Мб до МС). Данные
для них берутся со стека калькулятора, куда попали из функции
пользователя FN О. Здесь же рассчитывается масштабный коэффи-
циент XYscale, необходимый для того, чтобы вычерчиваемая трех-
мерная поверхность не вышла за пределы экрана компьютера. Он
заносится в ячейку памяти HD.
Вторая и третья части процедуры во многом похожи - это два
прохода, при которых строится сама трехмерная поверхность. На
первом проходе выстраиваются кривые вдоль оси У. а на втором -
вдоль оси X. Каждый из проходов Фактически представляет из себя
двойной вложенный цикл. Так. на первом прохоне во внешнем цикле
варьируется координата Y для каждой кривой, а во внутреннем
цикле отрабатывается координата X. На втором (поперечном) про-
ходе. соответственно, все происходит наоборот.
Обратите внимание на то, что при входе в эту подпрограмму,
регистровая пара hl должна содержать адрес, начиная с которого
размешается процедура для расчета Формулы, по которой строится
трехмерная поверхность. Этот адрес был сюда поставлен после
работы процедуры START, которая, в свою очередь, приняла его из
пользовательской функции FN О.
CLEAR - эта очень маленькая процедура служит для очистки
нашего 25б-байтного буфера. Очистка производится занулением
всех его ячеек.
PLOT.3D - процедура служит для печати на экране начальных
и конечных точек отрезков (узловых точек) трехмерной поверхнос-
ти. Пространственные координаты X и Y она получает из ячеек
памяти калькулятора ME и HF. а затем вызовом процедуры CONVERT
преобразует их в двумерные экранные координаты.
DRAW_3D - процедура очень похожа на предыдущую. Если та
процедура выпечатывала концы отрезков, из которых состоит по-
верхность, то эта процедура рисует сами отрезки, при этом пере-
счет трехмерных координат в плоские выполняется вызовом проце-
дуры CONVERT, а печать точек, входящих в отрезки - вызовом про-
цедуры DRAW_TO, которая и принимает решение о том. видима ли
текущая точка (надо ли ее изображать).
Кроне того, процедура DRAW_3d выполняет еше одну полезную
функцию, она проверяет, не была ли нажата клавиша BREAK (CAPS
SHIFT + SPACE), это дает Вам возможность прервать построение
трехнерной поверхности в случае необходимости.
CONVERT - очень важная и интересная процедура, она конвер-
тирует (преобразует) трехмерные координаты нашей поверхности в
двумерные координаты экранной плоскости, координаты X и Y трех-
нерной поверхности хранятся в ячейках памяти калькулятора НЕ и
HF. Взяв их оттуда, процедура рассчитает с помошью подготовлен-
ной вами процедуры третью координату Z. а затем пересчитает их
в экранные координаты PlotX и PlotY (хранятся в Н4 и Н5) с по-
мошью специального алгоритма. При выходе из процедуры экранные
координаты plotx и plotY остаются на стеке калькулятора (в этом
порядке).
Надо сказать несколько слов об алгоритме, с помошью кото-
рого трехнерные пространственные координаты пересчитываются в
двухмерные экранные. На Рис. 29 показан трехмерный параллелепи-
пед. Приведенное изображение является изометрической проекцией.
Чтобы пересчитать по координатам (х.у.2) экранные координаты
X. Y мы можем воспользоваться например следующими Формулами:
X = SOR(3)*(у-х)/2
V. = 2 - (У + Х)/2
Расчет по этим Форнулам и заложен в работу процедуры
CONVERT.
DRAW_TO - это разновидность подпрограммы, предназначенной
для рисования отрезков прямых от своих традиционных аналогов
она отличается тем. что при печати каждой точки (из которых со-
стоит отрезок) она обращается к нижеприведенной процедуре
G.PLOT, которая решает надо ли данную точку печатать и печатает
ее только после того, как сверится с буферной таблицей.
Для своей работы процедура DRAW_TO использует текущие эк-
ранные координаты начала отрезка, хранящиеся в ячейках памяти
калькулятора М4 и М5. Конечные точки отрезка она снимает со
стека калькулятора, ранее помешенные туда процедурой CONVERT
где они хранятся в порядке Xend, Yend.
G.PLOT - эта процедура принимает решение о тон, следует
или нет печатать текущую точку и выполняет данную печать, если
необходимо. Координаты позиции печати берутся из ячеек М4 и М5
паняти калькулятора. Решение о тон, печатать или нет. принима-
ется по результатам сравнения полученной вертикальной экранной
координаты с соответствующим для данного столбца содержимым бу-
фера. принцип, по которону это делается, мы описали выше Если
точка не скрыта, то выполняется ее печать.
Процедура HYFUHC.
Код Метка Мнемоника Комментарий ютек калькулятора!
EF MYFUNC RST 28 ; Включение калькулятора.
ЕЕ recall НЕ ;На вершине стека: X.
31 duplicate ; X. X
01 multiply ;Х«Х
EF recall MF ;X«X. Y
31 duplicate ; X»X. Y. Y
04 multiply ;X«X, Y«Y
OF add :X«X + Y*Y
28 sqr ;R. где R=SQR(XA2+Y"2>
31. duplicate ; R, R
30 еч.гего ;R. R=0?
0008 jump.true, ZERO ;Если R = 0. то этот случай надо
;обрабатывать особо; переходим
; на метку ZERO.
31 duplicate ;R.R
IF Sin ;R. SIN(R)
01 exchange ;SIN(R). R
05 divide ;SIN(R)/R
38 endcalc ; Выключение калькулятора.
C9 RET ; Выход.
EF ZERO delete ; Стек пуст.
Al const_one ; 1. Предел SIN(R)/R, когда
;r стренится к нулю, равен 1.
38 endcalc выключение калькулятора.
С9 RETT ; Выход.
Процедура START.
Код Метка Мнемоника Комментарий (стек калькулятора)
2А0В5С START LD HL. (5СВО) ;По адресу 5СВОН находится СИС-
;темная перененная DEFADD. ко-
; торая в монент расчета функ-
: нии пользователя содержит ад-
;рес, с которого начинаются
;параметры этой Функции.
23 s.LOOF inc hl ;Пропустили имя параметра.
23 INC HL ; Пропустили код CHR 1ч. Теперь
.HL указывает на сам параметр.
; записанный в пятибайтной Фор-
; ме.
CDB433 CALL ЗЗВ4 ; Вызов процедуры системного ПЗУ
; STACK.HUH. см. с. 106.
7Е LD A. (HL) (Проверим, что за байт стоит
;после принятого паранетра.
23 ihc HL .Пропустим этот байт.
2Е2С CP 2С ; Не запятая ли это? Код запятой
; равен 2СН.
28F5 JR Z.S.LOOF ;Если это запятая, то значит не
; все параметры еше приняты и мы
;возврашаенся на метку S.loof.
CD991E CALL 1Е99 ."Вызов процедуры ПЗУ FIND.INT2.
;Верхнее число со стека кальку-
; лятора передается в пару ВС, а
;это число, как мы знаем, явля-
;ется адресом для расчета нашей
; Функции z-f(.... ).
60 LD н. в ; Адрес нашей Функции передается
69 LD L. С ;в регистровую пару HL.
СЗ???? JP GRID ; Безусловный переход на голов-
;ную процедуру GRID для продол-
; жения работы.
Процедура GRID.
Код Метка Мнемоника Комментарии (стек калькулятора)
е5 grid push hl .Запомнили на стеке адрес про-
;цедуры вычисления Функции
; z-i (. .. ).
СО???.' CALL CLEAR ; Вызов процедуры CLEAR для
;очистки буферной таблицы.
015000 LD ВС.0050Н ;Число 50Н = 80 DEC - это необ-
;холимое количество ячеек памя-
;ти для размешения 16-ти ячеек
■ памяти калькулятора, посколь-
.ку в каждой ячейке должно хра-
;ниться пятибайтное число.
F7 RST ЗОН ; Резервируется область в опера-
; тивной памяти на 80 ячеек.
ЕВ EX DE. HL ;Теперь HL указывает на начало
;нулевой ячейки паняти кальку-
. лятора.
22685С LD (MEM).HL ;В системную переменную MEM
;i5С66Н = 23656 DEC), указываю-
щую на начало паняти калькуля-
;тора, заносится этот адрес.
0Е41 LD С.41Н ;число <ИН = 65 DEC (13 ячеек
. памяти калькулятора.
09 ADD HL. ВС ;Теперь HL указывает на 14-ую
; ячейку калькулятора (MD).
ЕВ - EX DE.HL ;DE указывает на ячейку MD.
0Е24 LD С.гчн ; 24Н = 36 DEC (7 ПЯТИбаЙТНЫХ
; ячеек + 1 байт).
2А655С LD HL.(STKEND) , Системная перененная STKEND
;(5С65Н=23653 указывает на
;ячейку, следующую -за вершиной
; стека калькулятора).
EDB8 LDDR ;Блочное переметение. Перекета-
; ются 36 байтов, т. е. 7 верхних
;вложений со стека калькулятора
. копируются в нисходяшен поряд-
; ке в ячеики памяти калькулято-
; pa МС... Мб.
<23 INC HL ; При работе конанды LDDR содер-
жимое HL уменьшилось на 36. а
;теперь увеличилось на 1. Т.о.
.теперь HL указывает на начало
;стека калькулятора.
226550 LD (STKEND)•HL ; СОЕместив конец стека с его
;началон. мы Фактически очис-
; тили стек.
El POP HL ; вернули в HL с машинного стека
;адрес процедуры для расчета
. искомом функции z=f(...) и эа-
22925С LD (НЕМВОТ). HL помнили его в системной пере-
менной МЕМВОТ (для использова-
ния в процедуре CONVERT - см.
ниже).
Мы закончили первичную инициализацию ячеек памяти кальку-
лятора и теперь рассчитаем масштабный Фактор XYscaie. для чего
вначале надо будет заслать на стек калькулятора число:
256/SQR(3) ~ 119.7.
В пятибайтной Форме оно может быть представлено, как:
88 13 CD ЗА 2С.
Код Метка Мнемоника Комментарий (стек калькулятора)
EF RST 28 : Включение калькулятора.
34F813CD3A2C stK.data .: Поместили на вершину стека
; калькулятора число 256/SQR(3).
Е8 recall М8 ;На стеке: 256/SQR(3). хг
Еб recall Мб : 256/SQR (3) • Х2. XI.
03 subtract ;256/SQR(3), Х2-Х1.
Е9 recall М9 ;256/SQR(3). Х2-Х1. Y2.
Е7 recall M7 ; 256/SQR(3). X2-X1, Y2, Yl.
03 subtract ;256/SQR(3). X2-X1, Y2-V1.
OF add ;256/SQR(3). (X2-X1)+(Y2-Y1).
05 divide ;256/(SQR(3)M(X2-X1)♦(Y2-Y1))).
CD store HD ;Теперь в ячейке MD содержится
; масштабный Фактор XYscale.
02 delete ;Стек пуст.
Е9 recall М9 ;Y2
CF store HF ; Ячейка HF содержит У-Уг.
02 delete ;стек пуст.
Е8 LOOP_Yl recall H8 ;X2
СЕ store HE ; Ячейка HE содержит X=X2.
02 delete ;Стек пуст.
38 endcalc ;Выключение калькулятора.
CD???? CALL PLOT_3D ;Вызов подпрограммы PLOT_3D
;для печати самой первой точки.
EF RST 28 ;Включение калькулятора.
ЕЕ LOOP-Xl recall НЕ :На стеке: х.
ЕА recall НА :На стеке: х. XH.
03 subtract ;На стеке: X - ХН.
СЕ store НЕ ; запомнили новое, уменьшенное
; значение X.
Еб recall Нб ;На стеке: х. XI.
03 subtract :на стеке: х - XI.
36 lt.zero ; Проверка X - XI < О?
V
0008 jump_true EXIT-1 :переход. если пикл закончен.
38 endcalc ; Выключение калькулятора.
CD???? CALL DRAW-3D ; вызов подпрограммы DRAW.3D для
;изображения очередного отрез-
. ка.
EF RST 28 ; Включение калькулятора.
33F1 Jump LOOP.XI Переход в начало никла.
EF EXIT.1 recall HF ;На стеке: Y (при работе в ко-
;дах калькулятора следует пом-
нить. что переход jump.true
; имеет косвенный эффект - с
;вершины стека снимается то.
;что там было, т.е. x-xi на
;стеке больше нет.
ЕВ recall НВ ;На стеке: Y, YH.
03 subtract ;На стеке: Y - YH.
CF store MF ;Запомнили новое, уменьшенное
. значение У.
Е7 recall М7 .На стеке: У. Yl.
03 subtract ;На стеке: Y - Yl.
36 lt_zero ;Проверка у - Yl < о?
30 not :проверка Y - Yl >= 0?
OODF jump.true LOOP_Yl .Возврат, если цикл не закон-
; чен.
36 endcaic ;Выключение калькулятора.
CD???? CALL CLEAR .очистка буферной таблицы.
EF RST 28 . включение калькулятора.
Е8 recall М8 ;На стеке: Х2.
СЕ store ME ;Ячейка ME содержит Х=Х2.
02 delete ;стек пуст.
Е9 LOOP.X2 recal1 М9 ; Y2
CF ' store MF .Ячейка MF содержит Y=Y2.
02 delete . ;Стек пуст.
38 endcaic :Выключение калькулятора.
CD???? CALL PLOT.3D ; Вызов подпрограммы PLOT.3D
;для печати пеРЕой точки на
.втором проходе.
EF RST 28 . включение калькулятора.
EF LOOP.Y2 recall MF ;На стеке: Y.
ЕВ recall MB ;На стеке: У. УН.
03 subtract ;На стеке: Y - YH.
CF store MF ; Запомнили новое, уменьшенное
: значение У.
Е7 recall М7 :На стеке: У. Yl.
03 subtract ;На стеке: У - Yl.
36 It.zero ;Проверка У - Yl < о?
0008 jump.true EXIT.2 ;Переход, если цикл закончен.
38 endcaic ; выключение калькулятора.
CD???? CALL DRAW.3D ; ВЫЗОВ подпрограммы DRAW.3D ДЛЯ
; изображения очередного отрез-
. ка.
EF RST 28 ;Включение калькулятора.
33F1 jump LOOP.Y2 ;Переход в начало цикла.
ЕЕ ЕХХТ.2 recall ME ;Х
EA recall «А ;Х. хн.
03 subtract ; Х-ХН.
СЕ store ИЕ :Запомнили новое, уменьшенное
; значение X.
Еб recall Мб .X, XI.
03 subtract ; X-Xi.
36 lt.zero ;X<X1?
30 not ;X>=X1?
OODF jump.true L00P.X2 ; Возврат, если цикл не
; закончен.
36 endcalc ;Выключение калькулятора.
21925С LD HL.HEHBOT
22665С LD (MEM).HL ; Восстановление адреса ячеек
;памяти калькулятора.
С9 RET ;Возврат
Процедура CLEAR.
Код Метка Мненоника Комментарии 1стек калькулятора)
21???? CLEAR LD HL,BUFFER ;Адрес начала буфера.
11???? LD DE.BUFFER+1 ;
01FF00 LD ВС.FFH ;FFH = 255 DEC. Подготовка к
;обнулению 255 байтов.
70 LD (HL). В ;Обнулили первый байт буфера.
EDBO LDIR ;Обнулили остальные 255 бай-
; тов.
С9 RET ; Выход из процедуры.
Процедура PLOT.3D.
Код Метка Мнемоника Коннентарии (стек калькулятора)
CD???? PLOT.3D CALL CONVERT ; Вызов процедуры CONVERT для
;расчета экранных координат.
;На стеке: plotX. plotY.
EF RST 28 ; Включение калькулятора.
C5 store M5 ; Переброска plotY в H5
02 delete ;Ha стеке: plotx.
С4 store М4 :переброска plotx в М4.
02 delete ;Стек очишен.
38 endcaic .Выключение калькулятора.
С9 RET ; возврат в вызывающую подпро-
; грамму.
процедура draw.3d.
Код Метка Мнемоника Коннентарий (стек калькулятора)
CD???? DRAW.3D CALL CONVERT ; ВЫЗОВ подпрограммы CONVERT ДЛЯ
;расчета экранных координат.
CD???? CALL DRAW.TO ;ВЫЗОВ подпрограммы DRAW.ТО ДЛЯ
;рисования отрезка.
CD54F1 CALL 1F54H ;По адресу 1F54H (8020 DEC) В
.ПЗУ находится процедура
. BREAK.KEV. Вызов служит для
;проверки нажатия BREAK.
D27B1B JP NC, 1В7ВН ;В этом случае выполняется пе-
;реход в ПЗУ на процедуру
;REPORT.L (1В7ВН = 7035 DEC).
;которая запустит процедуру
; обработки ошибок RST 08 с
;кодом перехвата 14Н. что озна-
; чает "BREAK Into program".
С9 RET ;возврат
Процедура CONVERT.
Код Метка Мнемоника Комментарий (стек калькулятора)
2А925С CONVERT LD HL.(МЕМВСТ) В регистровую пару HL засы-
;лается адрес, с которого начи-
нается процедура для вычисле-
; ния координаты Z. этот адрес
.был установлен в системной пе-
;ременной МЕМВОТ (23696 DEC =
;5С92Н) с помощью процедуры
: GRID. см. выше.
CD2C16 CALL 162С ;В ПЗУ по этому адресу записана
;одна инструкция JP (HL). Таким
;образом, вызов адреса 162С эк-
4
, Бивалентен вызову той пронеду-
;ры. адрес которой установлен в
;HL. этот прием позволяет сде-
лать "нечувствительной" проце-
;дуру CONVERT к тому, где нахо-
;дится расчетная процедура.
EF RST 28 ; Включение калькулятора. На
;вершине стека координата Z
;(установлена пользовательской
; процедурой).
ЕС recall НС ;на стеке: z. Zscale.
04 multiply ;на стеке: Z', где Z'=Z*Zscale.
Еб recall М8 ;на стеке: Z'. Х2.
Е9 recall М9 ;На стеке: Z', Х2, Y2.
OF add ;На стеке: Z'. X2+Y2.
ЕЕ recall НЕ ; На стеке: 2', X2+Y2. X.
EF recall MF ; На стеке: Z', X2+Y2. X, Y.
OF add ; На стеке: Z'. X2+Y2, X+Y.
03 subtruct ;На стеке: Z'. (X2+Y2)-(X+Y)
ED recall MD ;Z*, (X2+Y2)-(X+Y). XYscale
04 myltiply ;Z'. ((X2+Y2)-(X+Y))«XYscale
OF add ;Z'+ ((X2+Y2)-(X+Y))«XYscale
A2 const_haif ;Z'+ ((X2+Y2)-(X+Y))«XYscale.1/2
04 multiply ;Z'+ ((X2+Y2)-(X+Y))»XYscale/2
27 int ;PlotY
Как видите, в результате операций получено значение, соот-
ветствующее экранной координате У (см.с. 133 - Формула (2)).
Естественная разница состоит только в том, что х.у и z были на-
ми домножены на масштабные коэффициенты Zscale и XYscale. но
это сделать было необходимо, чтобы трехмерная поверхность не
вышла за пределы экрана. Таким образом, в результате последней
операции выделения целой части мы фактически получили на верши-
не стека экранную координату PlotY. Теперь разберемся с коорди-
натой Plotx.
Е8 recall М8 ;PlotY. X2
Е7 recall M7 ; PlotY. X2. Yl
03 subtruct ; PlotY. X2 - Yl
EE recall HE ;PlotY, X2 - Yl. X
EF recall HF ; PlotY. X2 - Yl. X. Y.
03 subtruct ;PlotY. X2 - Yl. X - Y
03 subtruct .-PlotY. (X2 - Yl > -IX - Y)
34F15DB3D743 StK.data iPlotY. (X2-Y1)-(X-Y).SQR(3)
;Эта операция помешает на вер-
.шину стека число, равное корню
;квадратному из трех, в пяти-
, байтной форме оно имеет вид:
; 81 5D ВЗ D7 43.
04 multiply :PlotY. ((X2-Y1)-(X-Y))»SQR(3)
ED recall HD ;PlotY. ((X2-Y1)-(X-Y)) »SQR(3).
. XYscale.
04 multiply JPlotY.((X2-Y1)-(X-Y))"SQR(3)«
; XYscale.
A2 const_half ;PlotY.((X2-Y1)-(X-Y))»SQR(3)»
; XYscale. 1/2.
04 multiply ;PlOtY.((X2-Y1)-(X-Y))»SQR(3)»
;XYscale/2.
27 int : PlotY. PlotX.
Сравнив полученное выражение с Формулой (2). с.133. вы
увидите, что на вершине стека практически получена экранная
' координата X = Plotx.
01 exchange Plotx. PlotY
38 endcaic Выключение калькулятора.
C9 RET Возврат в вызывающую процедуру.
Процедура DRAW.TO.
Код Метка Мненоника Комментарий (стек калькулятора)
EF DRAW_TO RST 28 :Включение калькулятора. На
.стеке содержатся (Xend, Yend).
Е5 recall М5 ; (Xend. Yend. PlotY).
C3 store M3 ;Запомнили в M3 PlotY. На сте-
* ; ке: (Xend. Yend. PlotY).
03 subtract ; Вычитание PlotY - Yend =
; = drawY. (Xend. drawY).
El recall Hi ;Запомнили в Hi drawY. На сте-
; ке: (Xend. drawY).
01 exchanee ;Ha стеке: (drawY, Xend).
ЕЧ recall M4 ; idrawY. Xend. PlotX)
02 store M2 ; Запомнили в M2 PlotX. На сте-
; ке: (drawY, Xend. PlotX)
03 subtract ; Вычитание PlotX - Xend =
; = drawX. (drawY. drawX).
CO store MO : Запомнили в MO drawX.
; (drawY. drawX).
07 or ;Напомним, что нулевые значения
;на вершине стека калькулятора
;могут трактоваться как логи-
ческое значение "ЛОЖЬ", а не-
нулевые - как "ИСТИНА". После
;операции "or" на вершине стека
; будет о только если оба значе-
ния были равны нулю одновре-
;менно. Если же хоть одно из
; них не ноль, то результат
;будет "1" ("ИСТИНА").
0004 jump true CONT-l ;Переход, если хоть одно из
; смешений не равно нулю. Значе-
;ние с вершины стека снимается.
38 endcalc ;В противном случае выключение
; калькулятора.
С9 RET .Выход из программы.
El CONT_l recall Ml .Вызов на стек drawY
2A abs .Вычисление абсолютной
; величины abs (drawY).
ЕО recall МО .Вызов drawX. На стеке:
.abstdrawY). drawX.
гл abs .abs(drawY), abs(drawX)
03 subtruct ;abs(drawY)-abs(drawX) - вычис-
;ление разности.
36 lt_2ero Сравнение разности с нулем.
. т. е. как бы проверка что
.больше abs<drawY) или
;abs(drawX). В результате на
стеке логическии о или 1. На-
;зовем это логическое значение,
.например LV (logical value).
31 duplicate копирование вершины стека. В
.результате на стеке- LV,LV.
OOOD jump true C0NT_2 ; Переход, если lv г i. т.е. ес-
> ли abs(drawX) > ABS(drawY) и
; наш отрезок имеет горизонталь-
.ный характер.
ЕО recall МО ; Вызов drawX На стеке:
; LV. drawX.
El recall Ml :Ha стеке: LV drawX. drawY.
CO store MO ; Перебросили drawY в MO
02 delete ;и удалили это значение со
.-стека. На стеке: LV, drawX.
Cl store Ml .Перебросили drawx в Ml
02 delete ;и удалили это значение со
; стека. На стеке: LV.
Смысл приведенных операций по переброске drawx из МО в Ml.
a drawY из Ml в МО. если отрезок имеет вертикальный характер,
состоит в том. чтобы установить в МО то смешение из двух, кото-
рое имеет максимальное значение и тогда можно предсказать зара-
нее сколько точек будет в отрезке. Число этих точек равно боль-
шему из смешений и Фактически в любом случае может быть взято
из МО.
Точно так же мы выполняем и переброску данных между М2 и
МЗ.
Е2 recall М2 ;На стеке: LV, UneX
ЕЗ recall «3 ;На стеке: LV, uneX, UneY
02 store М2 ;На стеке: LV, UneX. lineY
02 delete ;На стеке: LV. lineX
03 store МЗ ; На стеке: LV. UneX
02 delete ; На стеке: LV
После всего этого мы можем считать, что в ячейках МО и Ml
у нас содержатся смешения dispF и disPT. а в ячейках М2 и МЗ -
координаты lineF и lineT (см. Примечание к таблице использован-
ных ячеек калькулятора - с.149).
/
El CONT.2 recall Ml ;На стеке: LV, dlspT
ЕО recall МО ;на стеке: LV, dispT. disPF
05 divide ;Деление. На стеке:
; LV, dlsPT/dlsPF
Cl store Ml ;в ячейке Ml выставили переме-
.ную ratio (см. табл на с. 148).
02 delete ;На стеке: LV.
ЕО recall МО ;На стеке: LV. dispF,
38 endcalc .Выключение калькулятора и
; переход в коды Z-80.
00 NOP ; Пауза.
CDD52D CALL 2DD5 . Вызов программы ПЗУ FP_TO_A.
,Она снимает значение disPF с
,- вершины стека калькулятора и
; помешает его в регистр А.
; Ее значение равно количеству
; точек, которые следует напе-
; чатать.
F5 LOOP PUSH AF ; Запомнили на машинном стеке.
2009 JR NZ. NEG ; В результате работы процедуры
; FP_TO_A выключенный флаг Z ре-
; гистра F говорит о том. что
;число, снятое со стека в акку-
; мулятор - отрицательно, т. е.
;данный отрезок кривои рисуется
; задом наперед. В этом случае
; выполняется переход на метку
; NEG.
EF RST 28 ; Включили калькулятор.
Е2 recall М2 :На стеке: LV, lineF
Al const.one ;На стеке: LV, lxneF. 1.
OF add ;На стеке: LV. lineF ♦ 1.
E3 recall МЗ ;Ha стеке: LV. nneF+l. UneT.
El recall Ml ;LV. lmeF+l. lmeT. ratio.
OF add ' ;LV. lmeF+l. lineT + ratio.
3308 jujdp COHT_3 ; Обход на метку СОНТ.З.
EF NEG RST 28 ; Включили калькулятор.
E2 recall M2 ;Ha стеке: LV. lineF
Al const_one ;Ha стеке: LV. lineF. l.
03 subtruct ; На стеке: LV, lineF - l.
E3 recall МЗ ;Ha стеке: LV. uneF-l. UneT.
El recall Ml :LV, lineF-l. lineT, ratio.
03 subtruct :LV, lineF-l. lineT - ratio.
C3 CONT_3 store МЗ ;M3 и M5 получают координату
C5 store M5 ; печати точки в "поперечном"
; направлении.
02 delete ; На стеке: LV. lineF+l
.или LV. lineF-i.
С2 store М2 . М2 и М4 получают координату
С4 store М4 ;печати точки в "прямом"
.направлении.
02 delete ;На стеке: LV.
31 duplicate ;На стеке: LV. LV.
0007 jump true C0NT_4 ; Переход вперед, если отрезок
, имеет горизонтальный характер.
; в противном случае меняем мес-
; тами содержимое М4 и Н5.
Е4 recall М4 ;На стеке: LV, plotF.
Е5 recall М5 ;На стеке: LV, PlotF. plotT.
С4 store М4 ; перебросили PlotT в М4.
02 delete ;На стеке: LV, PlotF.
05 store M5 Перебросили PlotF в М5.
02 delete ;На стеке: LV.
38 ССЫТ_4 endcalc . Выключение калькулятора.
CD???? CALL G_PL0T ; Вызов процедуры проверки и пе-
;чати точки, координаты которой
; находятся в ячейках М4 и М5.
Cl POP ВС .Ранее мы на стек отправляли
;AF. где регистр А содержал
;количество точек, входящих в
;отрезок. Теперь это число по-
. мешается в регистр В.
05 DEC в ; Уменьшили счетчик на 1
С5 PUSH ВС ; и запомнили его на стеке.
2803 JR Z.EXIT ;Если счетчик исчерпан, то пе-
реход на EXIT для подготовки
; к выходу.
Fi POP AF ; В противном случае рисование
;отрезка надо продолжать. Необ-
;ходимость восстанавливать AF
:вызвана тем, что в регистре F
; Флаг Z содержит информацию о
.направлении отрезка.
18D2 JR LOOP ; Возврат в начало цикла для
.печати последующих точек
. отрезка.
EF EXIT RST 28 ;Включили калькулятор.
02 delete ;Перед выходом очистили его
; стек.
38 endcalc ; выключили калькулятор.
Fi POP AF ;Очистили машинный стек.
С9 RET , Возврат.
Процедура G.PLOT
Код Метка Мнемоника Комментарии (стек калькулятора)
EF G.PLOT RST 28 ;Включение калькулятора.
Е4 recall М4 ;(PlotX)
Е5 recall M5 ;(Plotx.PlotY)
38 endcaic выключение калькулятора.
CDD52D CALL 2DD5 ;Вызов программы ПЗУ FP_TO_A.
■Она снимает значение с вершины
;стека калькулятора и помешает
;его в регистр А процессора.
;теперь там переменная PlotY.
F5 PUSH AF ;запомнили ее на машинном сте-
; ке.
CDD52D CALL 2DD5 ;Вызов программы ПЗУ FP_TO_A.
;В регистре А - Plotx.
3819 JR С, EXIT ;Переход, если координата X
;слишком велика.
2017 JR NZ.EXIT ;Переход, если X - меньше ну-
: ля.
oF LD L. А ; В регистре L - координата X.
26 >? LD н.??Н ;В регистр Н заносим старшим
.байт буферной таблицы.
Fl POP AF ;В аккумуляторе теперь PlotY.
СО RET HZ ;выход, если координата Y
; отрицательна.
3804 JR С. MAXIM :Переход, если координата Y
;с лишком велика I> 2 5 5).
FEBO CP ВОН : ВОН =1761 предел по верти-
,кали»
3802 JR С.PL.0K ;переход, если Y<176 и все в
; порядке.
3EFF MAXIM LD A. FF ;в противном случае в аккунуля-
;торе выставляем "FF". как сиг-
;нал о выходе за пределы экра-
I ; на.
BE PL.OK CP(HL) Сравним с тем. что содержится
; в буфере.
D8 RET С ; Выход, если точка должна быть
;"невидимой" и ее печатать не
; надо.
77 LD (HL).A ;в противном случае запомнили в
;буфере новое значение для
;данной вертикали.
47 LD В. А ;
4D LD С. L ;Теперь ВС содержит экранные
;координаты печатаемой точки.
ЗС INC А ;Проверка на выход за пределы
; экрана.
С4Е522 CALL HZ.22Е5 ; вызов подпрограммы ПЗУ PLOT.
.которая напечатает точку, ес-
;ли она не лежит вне пределов
; экрана.
С9 RET Возврат в вызывающую программу.