Вопрос № 178349: Здравствуйте уважаемые эксперты! Побывав в реанимации, озадачился вопросом рисования синусоиды методом ПОВ. Чёрно-белые мониторы с маленькой диагональю, в которых рисовалась и перерисовывалась синусоида, там переносились с места на место и вроде как,...
Вопрос № 178349:
Здравствуйте уважаемые эксперты! Побывав в реанимации, озадачился вопросом рисования синусоиды методом ПОВ. Чёрно-белые мониторы с маленькой диагональю, в которых рисовалась и перерисовывалась синусоида, там переносились с места на место и вроде как, кроме эл.сети никуда не подключались, из чего я сделал вывод (возможно ошибочный), что процессор и память находятся внутри монитора. А если это так, то для рисования синусоиды вряд ли используется int 21h DOS, наверное, с большей вероятностью ПОВ.
1.
У меня при нажатии на F1, появляются синие линии, а вот как их убрать, не могу додуматься. Мне нужно, чтобы при последовательном нажатии F1 вертикальные синие линии то появлялись, то исчезали. 2. Как нарисовать недвигающуюся синусоиду в пять периодов (т.к. экран у меня после нажатия на F1 поделён вертикальными линиями на 10 вертикальных полос) амплитудой в 18 строк после нажатия клавиши, например, F2. Не могу найти символы, соответствующие вершинам амплитуд, есть тол
ько вертикальные скобки ( ), тем более что вершины амплитуд при разных условиях будут иметь разное искривление, хотя линию можно заменить и точками. 3. При повторном нажатии на F2 синусоида начинает двигаться вдоль горизонтальной оси, сама скорость перемещения значения не имеет. 4. При следующем нажатии F2 движение синусоида останавливается, ещё при следующем – опять двигается и т.д.. Заранее спасибо.
Отвечает Лысков Игорь Витальевич, Модератор :
Здравствуйте, Adsorores. Позвольте продемонстрировать решение Вашей задачи в графическом режиме:
Код:
.model tiny, C ; модель памяти и порядок вызова параметров .386 ; нужно для команды fsin .code ; сегмент кода .startup ; точка входа
mov ax, 0013h ; vga
320x200x256 int 10h
mov ax, 0a000h mov es, ax ; es - сегмент видео
MainLoop: ;рисуем вертикальные линии через каждые pi/2 0<=у<=199 call vert, 0, 199 ;ось ординат (0,0)-(0,199) цвета 0ch call line, 0, 0, 0, 199, 0ch ;ось абсцисс (0,100)-(319,100) цвета 0ch call line, 0, 100, 319, 100, 0ch ;синусоида 0<=x<=319, y=sinus(x) цвета 0bh call Graph, 0, 319, offset sinus, 0bh
wait_key: ;цикл проверки ожидания
нажатия на клавишу mov ah, 1 int 16h jnz get_key ;что-то нажато, проверим что cmp f_F2, 0 ;флаг движения по F2 = 0, je wait_key ; на ожидание клавиши ;сдвинем синусоиду! call DELAY ;пауза call Graph, 0, 319, offset sinus, 0 ;вытрем старую (нарисуем цветом 0!) fld fi ;изменим параметр в формуле sin(x+fi) fadd c01 ;на 0.1 fstp fi ;благодаря изменению fi и получаем движение синусоиды jmp MainLoop ;рисуем заново! get_key: mov ah, 0 ;проверяем на
код клавиши int 16h cmp ah, 1 ;по Esc выходим je Exit cmp ah, 3bh ;F1 je key_F1 cmp ah, 3ch ;F2 jne wait_key ;все остальное игнорируем xor f_F2, 1 ;по F2 меняем флаг движения jmp wait_key key_F1: ;по F1 меняем цвет вертикальных линий (синий/черный) xor vcolor, 9 call Graph, 0, 319, offset sinus, 0 ;вытираем jmp MainLoop ;и рисуем по-новому
;выход в DOS Exit: mov ax, 0003h ; назад в текстовый режим int 10h
mov ax, 4c00h ; bye-bye int 21h
;подпрограммы
;рисуем вертикальные линии x=(pi*n)/2, ystart<=y<=yend vert proc ystart:word, yend:word local xx:word, num:word mov num, 1 ;номер линии vert_loop: fldpi ;Пи fidiv c2 ;Пи/2 fimul coef ;масштабируем в экранные размеры fimul num ;coef*num*Пи/2 fistp xx ;x cmp xx, 319 ;дошли ли до края экрана ja vert_ret ;рисуем линию цвета vcolor (синим или черным, т.е. невидимым, цветом) call line,
xx, ystart, xx, yend, vcolor inc num ;на следующую линию jmp vert_loop vert_ret: ret vert endp
;Функция вычисления y по x Sinus proc x:word local y:word ;переменная для получения значения из сопроцессора fild x ;экранный x fidiv coef ;убираем масштабирование fadd fi ;x+fi fsin ;sin(x+fi) ;промасштабируем для вывода на экран ;умножим на coef=20 и получим величины [-20,+20] ;отнимем от 100 и получ
им экранные 80-120, "перевернутые" (0 сверху) fimul coef fistp y ;сохраним в y mov ax, 100 sub ax, y ;ax = 100 - y ret Sinus endp
;рисует график, последовательно соединяя точки отрезками ;параметры: ;xmin - левая экранная координата графика ;xmax - правая экранная координата графика ;pFun - адрес функции, вычисляющей экранную координату по вертикали ;col - цвет линий Graph proc xmin:word, xmax:word, pFun:word, col:word Graph_loop: ;цикл рисования
отрезков mov ax, pFun ;адрес функции call ax, xmin ;считаем y первой точки mov cx, ax ;сохраним в cx
mov ax, xmin ;найдем x соседней справа точки inc ax mov si, ax ;сохраним в sі cmp ax, xmax ;проверим, дошли и до правого края ja Graph_ret
mov ax, pFun ;адрес функции call ax, si ;ax = y второй точки
test cx, cx ;проверим, чтобы не выходить за 0 (за пределы экрана) jge Gr_ax xor cx, cx ;отрицательные
y меняем на 0 Gr_ax: test ax, ax ;аналогично jge Gr_draw xor ax, ax Gr_draw: mov dx, ax ;когда оба 0, то игнорируе
м! or dx, cx jz Graph_next ;рисуем линию (xmin, cx)-(si,ax) цветом col call line, xmin, cx, si, ax, col Graph_next: mov xmin, si ;готовим xmin для следующего шага jmp Graph_loop Graph_ret: ret Graph endp
;рисуем линию (x1,y1)-(x2,y2) цветом color Line proc uses di bx, x1:word, y1:word, x2:word, y2:word, color:byte local i:word, \ ;для работы со сопроцессором delta_x:word, \ ;длина проекции на ось абсцисс delta_y:word, \ ;длина проекции на ось ординат incx:word, \ ;приращение
по X incy:word ;приращение по Y
;определим длину проекции на ось абсцисс и шаг по оси X mov ax, x2 sub ax, x1 ;ax=x2-x1;
;определим шаг по X (+1 если вперед, -1 если назад, 0 если не меняется) mov incx, 0 ;пусть incx=0 test ax, ax ;ax=delta_x jz set_delta_x ;не меняется jg set_x_1 ;вперед? dec incx ;назад, значит incx=-1 neg ax ;найдем ax=abs(delta_x) jmp set_delta_x ;на сохранениеset_x_1: inc incx ;вперед, значит incx=1; set_delta_x: mov delta_x, ax ;delta_x = abs(x2-x1)
;определим длину проекции на ось ординат и шаг по оси Y mov ax, y2 sub ax, y1 ;ax=y2-y1;
;определим шаг по Y (+1 если вперед, -1 если назад, 0 если не меняется) mov incy, 0 ;пусть incy=0 test ax, ax ;ax=delta_y jz set_delta_y ;не меняется jg set_y_1 ;вперед? dec incy ;назад, значит incy=-1 neg ax ;найдем ax==abs(delta_y) jmp set_delta_y ;на сохранение set_y_1: inc incy ;вперед,
значит incy=1; set_delta_y: mov delta_y, ax ;delta_y=abs(y2-y1)
;определим большее из проекций как основное напрвление cmp ax, delta_x ;ax=delta_y jge from_y ;y будет основным cmp delta_x, 0 ;проверим, чтобы не было delta_x=0 (для точки), jz Line_ret ; иначе будет деление на 0 ;delta_x>delta_y && delta_x!=0 ;основное направление - по оси X fild delta_y fidiv delta_x ;st=k=(float)(delt
a_y/delta_x)
;for (int i=0;i<delta_x;i++) xor cx, cx ;cx=i jmp cmp_i_x ;на проверку i<delta_x x_loop: ;тело цикла mov i, cx ;запишем переменную цикла в память (для сопроцессора) fld st ;st=st(1)=k fimul i ;st=k*i fimul incy ;st=incy*k*i call floor ;округлим до целого в большую сторону fistp i ;сохраним в переменной mov ax, i ;относительный номер строки на экране add ax, y1 ;добавим до ординаты начальной точки mov dx, 320 ;получим индекс
начала строки экрана в сегменте экрана imul dx ; для этого умножим на длину в байтах одной стоки mov bx, ax ;сохраним bx=y=(y1+floor(incy*k*i))*320 ;посчитаем X mov ax, incx ;X меняется ровно на шаг приращения, imul cx ; умноженному на индекс точки add ax, x1 ;добавим абциссу начальной точки ax=x=x1+incx*i
add ax, bx ;сложим с индексом начала строки mov di, ax ;будем адресовать через di
mov al, color ;цвет точки
mov es:[di], al ;рисуем!
inc cx ;на следующую точку cmp_i_x: cmp cx, delta_x ;дошли до конца? jl x_loop jmp Line_ret ;на выход
from_y: ;вдоль оси Y fild delta_x fidiv delta_y ;st=k=(float)(delta_x/delta_y)
;for (int i=0;i<delta_y;i++) xor cx, cx ;cx=i jmp cmp_i_y ;на проверку i<delta_y y_loop: ;тело цикла mov ax, incy ;Y меняется ровно на шаг приращения, imul cx ; умноженному на индекс точки add ax, y1 ;добавим абциссу начальной
точки ax=y=y1+incy*i mov dx, 320 ;получим индекс начала строки экрана в сегменте экрана imul dx ; для этого умножим на длину в байтах одной стоки mov bx, ax ;сохраним bx=y=(y1+incy*i)*320 ;посчитаем X mov i, cx ;запишем переменную цикла в память (для сопроцессора) fld st ;st=st(1)=k fimul i ;st=k*i fimul incx ;st=incx*k*i call floor ;округлим до целого в большую сторону fistp i ;сохраним в переменной mov ax
, i ;относительный номер строки на экране add ax, x1 ;ax=x=x1+floor(incx*k*i)
add ax, bx ;сложим с индексом начала строки mov di, ax ;будем адресовать через di
mov al, color ;цвет точки mov es:[di], al ;рисуем!
inc cx ;на следующую точку cmp_i_y: cmp cx, delta_y ;дошли до конца? jl y_loop Line_ret: fistp i ;удалим из сопроцессора k ret Line endp
;округление до целого в большую сторону ;округление по умолчанию, до ближайщего, не устраивает floor proc local CtrlWordOld:word, CtrlWordNew:word fstcw CtrlWordOld ;сохраним управляющее слово fclex ;сбросим
исключения mov CtrlWordNew,0763h ;установим необходимое значение управляющего слова fldcw CtrlWordNew ;загружаем управляющее слово frndint ;округляем st до целого fclex ;сбросим исключения fldcw CtrlWordOld ;восстановим старое управляющее слово ret floor endp
;пауза ~40мс. Под Windows весьма условно, скорее всего будет больше time equ 4 ;число интервалов по 10мс DELAY: pusha ;сохраним все регистры mov ah,2dh ;сбросим &q
uot;локальное" системное время (под nt+ все равно не поменяет) xor cx,cx xor dx,dx int 21h
dl2: mov ah,2ch int 21h ;читаем время ;считаем сотни мс mov al,100 mul dh ;секунды умножаем на 100 -> ax = количество интервалов по 10мс xor dh,dh ;dx - число сотых xchg ax,dx ;поменяем местами mov cl,10 div cl ;ax = количество интервалов по 10мс из сотых add ax,dx ;складываем с количеством из секунд cmp ax,time ;сравним с ожидаемым интервалом jl dl2 ;ждем,
если меньше popa ;восстановим все регистры ret
.data f_F2 dw 0 ;флаг движения по F2 vcolor dw 0 ;цвет вертикальных линий, меняется по F1 coef dw 20 ;коэффициент масштабирования fi dd 0 ;угол сдвига в функции sin(x+fi) c01 dd 0.1 ;шаг для изменения угла сдвига c2 dw 2 ;константа для деления в сопроцессоре на 2 END
----- Удачи!
Ответ отправил: Лысков Игорь Витальевич, Модератор
Ответ отправлен: 13.05.2010, 01:58
Номер ответа: 261355 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Оценка ответа: 5
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 261355
на номер 1151 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.