Форум программистов, компьютерный форум, киберфорум
Assembler: математика, вычисления
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
0 / 0 / 0
Регистрация: 25.02.2017
Сообщений: 11

Рисование спиралей и окружностей (некорректная отрисовка окружностей)

30.10.2018, 22:55. Показов 4107. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Возникла проблема, разобраться в которой не получается

Задача:нарисовать две спирали (по часовой и против) цвет
которых чередуется от 1 до 255, в точках пересечения которых рисует окружность
заданного радиуса и цвета.

Проблема: окружности в точках пересечения рисуются не до конца, не могу понять, в чем причина

Код:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
.model small
.stack 100h
.data
delta dd 0.001 ;расстояние между точками
divK dd 1.5 ;расстояние между дугами
xr dw 0
yr dw 0 
color db 0
 
circleRadius dd 10.0
circleAlpha dd 0.0 ;изменяющаяся переменная
tmp dd 0 ;temp
circleXR dw 0 ;координаты выводимой точки
circleYR dw 0
 
xtemp dw ?
ytemp dw ?
.code
.486
drawCircle:
l2:
 fld circleAlpha        ;x=round(circleRadius*cos(circleAlpha))
 fcos                   ;y=round(circleRadius*sin(circleAlpha))
 fld circleRadius            
 fmul              
 frndint           
 fild xtemp         
 fadd              
 fistp word ptr circleXR 
 
 fld circleAlpha     
 fsin              
 fld circleRadius            
 fmul              
 frndint           
 fstp tmp          
 fild ytemp         
 fsub tmp          
 fistp word ptr circleYR 
 
 pusha
 mov ah,0ch
 mov al,0ah  ;set color == green
 mov bh,0h
 mov cx,circleXR
 mov dx,circleYR
 int 10h
 popa 
 
 fld delta ;вычисляем новое значение circleAlpha
 fld circleAlpha
 fadd
 fstp circleAlpha
loop l2;цикл по cx
ret
 
start:  
mov ax,@data
mov ds,ax
 
mov cx,20200 ;количество итераций цикла
mov ax,13h   ;320x200 @ 256 colors
int 10h
 
;рисование дуг
 
    finit ;инициализация сопроцессора 
    fldz  ;загрузка 0.0
    mov ah,0Ch; функция 10h прерывания - установить точку
    xor bx,bx
l1: fld st  ;константы под синус/косинус
    fld st
    fsincos ;вычисление синуса/косинуса          
    fmul divK
    fmul st,st(2)
    fistp word ptr xr ;заносим X в переменную для вывода на экран 
    fmul divK
    fmul
    fistp word ptr yr ;заносим Y в переменную для вывода на экран 
    push cx
    mov cx,xr
    mov dx,yr
    add dx,100; половина высоты экрана
    add cx,160; половина ширины экрана
    
    mov al,color; цвет спирали
    inc color
        
    mov ytemp,dx
    mov xtemp,cx
    
    int 10h           ;выводим точку заданным цветом 
    
    sub dx,yr
    sub dx,yr
    int 10h           ;выводим точку заданным цветом 
    
    cmp ytemp,100
    je draw
    jmp doNotDraw
    
    draw:
    call drawCircle    ;отрисовка круга
    
    doNotDraw:
    pop cx
    fadd delta; вычисляем новое значение alpha
    loop l1 ;цикл по cx
 
    
;окончание работы    
    mov ah,0 ;ожидание нажатия клавиши 
    int 16h
    mov ax,3 ;перевод обратно в TextMode
    int 10h
    mov ah,4Ch ;стандартный выход
    int 21h
end start
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.10.2018, 22:55
Ответы с готовыми решениями:

Движение двух окружностей
круг, с частным и остатком внутри, с начала находится в центре..по клавише 1-круг с частным движется влево, а круг с остатком вправо, по...

Даны координаты центров n окружностей и их радиусы. Определить число пересекающихся окружностей
Допуск к экзамену в субботу а не решено еще 5 заданий по С++ 1.Даны координаты центров n окружностей и их радиусы. Определить число...

Найти геометрическое место центров окружностей, касающихся двух данных окружностей
Найти геометрическое место точек, из которых эллипс 4x^2+5y^2=20 виден под прямым углом.

14
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4495 / 1669
Регистрация: 01.02.2015
Сообщений: 13,906
Записей в блоге: 12
30.10.2018, 23:38
Ошибка где-то в процедуре drawCircle - она не рисует окружность. Там какая-то ошибка.
0
0 / 0 / 0
Регистрация: 25.02.2017
Сообщений: 11
31.10.2018, 09:53  [ТС]
ФедосеевПавел,
Это понятно
Там дело в цикле, не могу в толк взять, какое значение является триггером для окончания цикла
Первые окружности отрисовываются корректно, но чем дальше от центра, тем больше недорисовываются эти окружности
0
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
31.10.2018, 10:23
sryv,
F.A.Q.https://www.cyberforum.ru/cgi-bin/latex.cgi?\rightarrow Вывод спирали на экран в DOS
mov cx,0C470h ;количество итераций цикла у меня
mov cx,20200 ;количество итераций цикла у тебя
0C470h=50288, а всё остальное сперто с минимальными изменениями, разумеется без ссылки на автора
2
0 / 0 / 0
Регистрация: 25.02.2017
Сообщений: 11
31.10.2018, 10:46  [ТС]
Mikl___,
Виноват, что не указал ссылку
Код не мой, я просто хочу в нем разобраться
Проблема же не в этом: mov cx,0C470h
Это цикл для вывода спирали, а вывод спирали работает хорошо, некорректно выводятся сами окружности, т.е. изъян в процедуре drawCircle, и там явно проблема с количеством итераций цикла, собственно что я и не могу разобрать
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4495 / 1669
Регистрация: 01.02.2015
Сообщений: 13,906
Записей в блоге: 12
31.10.2018, 12:32
Сделайте новую процедуру вывода окружности на основе
подобие алгоритма Брезенхэма
вычисления с FPU (модификация исходника из книги Зубкова)
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4495 / 1669
Регистрация: 01.02.2015
Сообщений: 13,906
Записей в блоге: 12
01.11.2018, 22:47
Лучший ответ Сообщение было отмечено sryv как решение

Решение

Окружность - методом Мичнера.
Судя по всему это первоисточник http://ermak.cs.nstu.ru/kg_riv... tth_sEc0.3
а здесь уже приводится более компактно http://algolist.manual.ru/grap... circle.php

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*--------------------------------------------------- V_MIcirc
 * Генерирует 1/8 окружности по алгоритму Мичнера
 */
 
void V_MIcirc (xc, yc, r, pixel)
int  xc, yc, r, pixel;
{  int  x, y, d;
   x= 0;  y= r;  d= 3 - 2*r;
   while (x < y) {
      Pixel_circle (xc, yc, x, y, pixel);
      if (d < 0) d= d + 4*x + 6; else {
         d= d + 4*(x-y) + 10;  --y;
      }
      ++x;
   }
   if (x == y) Pixel_circle (xc, yc, x, y, pixel);
}  /* V_MIcirc */
Я не реализовал построение при (x==y). Но это самостоятельно сделаете.

Мне не понравился код построения спирали из FAQ - много обращений к памяти, да и условие завершения какое-то невнятное, ни к чему не привязанное. Переделал - всё то же самое, но значения переменных берутся из стека FPU, а не из памяти.

У меня ощущение, что вы не все окружности проставляете. При расчётах вычисляете 2 точки, а на пересечение проверяете лишь одну из них. Хотя на рисунке всё нормально. С этим самостоятельно разберётесь.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
LOCALS
 
.model small, Pascal
 
.stack 200h
 
.data
        delta   dd      0.01    ;приращение угла при построении спирали
        divK    dd      3.5     ;расстояние между дугами
        xr      dw      0
        yr      dw      0
        xtemp   dw ?
        ytemp   dw ?
        color   db      0       ;цвет точки спирали и окружности
 
        K       dw      4       ;количество оборотов спирали на экране
 
        Radius  dw      5       ;радиус окружности
.code
.486
;Вспомогательная процедура алгоритма рисования окружности.
;Рисует 8 точек окружности.
PutPixels8      proc    Xc:WORD, Yc:WORD, X:WORD, Y:WORD, PixelColor:WORD
        push    ax
        push    bx
        push    cx
        push    dx
 
        mov     ax,     [PixelColor]
        mov     ah,     0Ch
        mov     bh,     0
        ;putpixel(x0 + x, y0 + y);
        mov     cx,     [Xc]
        add     cx,     [X]
        mov     dx,     [Yc]
        add     dx,     [Y]
        int     10h
        ;putpixel(x0 - x, y0 + y);
        mov     cx,     [Xc]
        sub     cx,     [X]
        ;mov    dx,     [Yc]
        ;add    dx,     [Y]
        int     10h
        ;putpixel(x0 - x, y0 - y);
        ;mov    cx,     [Xc]
        ;sub    cx,     [X]
        mov     dx,     [Yc]
        sub     dx,     [Y]
        int     10h
        ;putpixel(x0 + x, y0 - y);
        mov     cx,     [Xc]
        add     cx,     [X]
        ;mov    dx,     [Yc]
        ;sub    dx,     [Y]
        int     10h
 
        ;putpixel(x0 + y, y0 + x);
        mov     cx,     [Xc]
        add     cx,     [Y]
        mov     dx,     [Yc]
        add     dx,     [X]
        int     10h
        ;putpixel(x0 - y, y0 + x);
        mov     cx,     [Xc]
        sub     cx,     [Y]
        ;mov    dx,     [Yc]
        ;add    dx,     [X]
        int     10h
        ;putpixel(x0 - y, y0 - x);
        ;mov    cx,     [Xc]
        ;sub    cx,     [Y]
        mov     dx,     [Yc]
        sub     dx,     [X]
        int     10h
        ;putpixel(x0 + y, y0 - x);
        mov     cx,     [Xc]
        add     cx,     [Y]
        mov     dx,     [Yc]
        sub     dx,     [X]
        int     10h
 
        pop     dx
        pop     cx
        pop     bx
        pop     ax
 
        ret
PutPixels8      endp
 
;Рисование окружности методом Мичнера для 1/8 окружности
;на входе:
; __Xc, __Yc - координаты центра окружности
; __R        - радиус окружности
; __Color    - цвет окружности
Cyrcle          proc    __Xc:WORD, __Yc:WORD, __R:WORD, __Color:WORD
 
        push    ax
        push    bx              ;error
        push    cx              ;x
        push    dx              ;y
 
        mov     cx,     0       ;       x=0
        mov     dx,     [__R]   ;       y=R
        mov     bx,     3       ;       error=3-2*y
        sub     bx,     dx
        sub     bx,     dx
        ;Вычисление координат точек и вывод рисунка
@@do:
        ;вывод 8-ми точек окружности (в разных четвертях)
        push    [__Xc]
        push    [__Yc]
        push    cx
        push    dx
        push    [__Color]
        call    PutPixels8      ;       putpixel(...)
 
@@if:
        or      bx,     bx      ;       if (error<0)
        jge     @@else          ;       {
        add     bx,     cx      ;               error += x*4+6
        add     bx,     cx
        add     bx,     cx
        add     bx,     cx
        add     bx,     6       ;
        jmp     @@next          ;       }
@@else:                         ;       else
        or      bx,     bx      ;       {
        mov     ax,     cx      ;               error += 4(x-y)+10
        sub     ax,     dx
        add     ax,     ax
        add     ax,     ax
        add     bx,     ax
        add     bx,     10
        dec     dx              ;               y--;
                                ;       }
@@next:
        inc     cx              ;       x++;
@@while:
        cmp     cx,     dx      ;       while (x<=y)
        jle     @@do
 
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
Cyrcle          endp
 
start:
        mov     ax,     @data
        mov     ds,     ax
 
        mov     ax,     13h     ;320x200 @ 256 colors
        int     10h
 
;рисование дуг
 
        finit ;инициализация сопроцессора
        fldpi
        fadd    st(0),  st(0)
        fimul   [K]             ;конечный угол рисования спиралей
        fld     [delta]         ;
        fld     [divK]          ;
        fldz                    ;загрузка 0.0
        xor     bx,     bx      ;номер видеостраницы при выводе точки
 
l1:
        fld     st(0)
        fsincos                 ;st(0) cos, st(1) sin
 
        fmul    st(0),  st(3)   ;x=st(0)=A*L*cos(A)
        fmul    st(0),  st(2)
        fistp   word ptr [xr]   ;заносим X в переменную для вывода на экран
 
        fmul    st(0),  st(1)   ;y=st(0)=A*L*sin(A)
        fmul    st(0),  st(2)
        fistp   word ptr [yr]   ;заносим Y в переменную для вывода на экран
 
        fadd    st(0),  st(2)   ; вычисляем новое значение alpha
 
        mov     cx,     xr
        mov     dx,     yr
        add     dx,     100; половина высоты экрана
        add     cx,     160; половина ширины экрана
 
        mov     al,     color   ; цвет спирали
        cmp     al,     1
        adc     al,     0
        mov     color,  al
        inc     color
 
        mov     ytemp,  dx
        mov     xtemp,  cx
 
        mov     ah,     0Ch     ; функция 10h прерывания - установить точку
        int     10h             ;выводим точку заданным цветом
 
        sub     dx,     yr
        sub     dx,     yr
        int     10h             ;выводим точку заданным цветом
 
        cmp     ytemp,  100
        jne     doNotDraw
 
        ;рисование окружности
        push    word ptr xtemp  ;Xcenter
        push    word ptr ytemp  ;Ycenter
        push    word ptr Radius
        push    word ptr Color
        call    Cyrcle
 
    doNotDraw:
        fcom    st(3)   ;проверить значение угла, на конечное
        fstsw   ax
        sahf
 
        jb      l1
 
;окончание работы
    mov ah,0 ;ожидание нажатия клавиши
    int 16h
    mov ax,3 ;перевод обратно в TextMode
    int 10h
    mov ah,4Ch ;стандартный выход
    int 21h
end start
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
05.11.2018, 20:06
Вот очень простая прога для рисования окружности.
Инициализируем угол значением A = 0 (радиан) и делаем цикл из 2*Pi*R итераций, увеличивая каждый раз угол на 1/R радиан. В цикле рисуем точку в координатах X=Cos(A)*R, R=Sin(A)*R.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Radius  =       50
Color   =       14
CenterX =       160
CenterY =       100
 
org     100h
 
        mov     ax,13h
        int     10h             ; графический режим
 
        mov     ax,0A000h
        mov     es,ax           ; видеосегмент
 
        finit
 
        mov     cx,(Radius*314+25)/50 ; кол-во точек = Round(Radius*6.28)
        fldz                    ; st = 0 = a (угол)
    .next:
        fld     st              ; st = a, a
        fsincos                 ; st = cos, sin, a
        fimul   [iRadius]       ; st = r*cos, sin, a
        fistp   [Temp]          ; st = sin, a
        mov     bx,[Temp]       ; x
        fimul   [iRadius]       ; st = r*sin, a
        fistp   [Temp]          ; st = a
        mov     di,[Temp]       ; y
        imul    di,320
        mov     byte [es:di+bx + CenterX+CenterY*320],Color ; рисуем точку цветом Color с центром в CenterX, CenterY
        fadd    [DeltaA]        ; a += DeltaA
        loop    .next
 
        xor     ah,ah
        int     16h             ; ждём нажатия
 
        mov     ax,3
        int     10h             ; возврат в текстовый режим
 
        int     20h             ; выход
 
iRadius dw      Radius          ; радиус (целое число)
DeltaA  dd      0.02            ; приращение угла в радианах = 1/Radius (!!! НЕОБХОДИМО УКАЗАТЬ ВРУЧНУЮ !!!)
Temp    dw      ?
Добавлено через 33 секунды
Для эллипса:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
RadiusX =       100
RadiusY =       50
Color   =       14
CenterX =       160
CenterY =       100
 
; Radius = Max(RadiusX, RadiusY)
Radius = RadiusX
if RadiusY > RadiusX
  Radius = RadiusY
end if
 
org     100h
 
        mov     ax,13h
        int     10h             ; графический режим
 
        mov     ax,0A000h
        mov     es,ax           ; видеосегмент
 
        finit
 
        mov     cx,(Radius*314+25)/50 ; кол-во точек = Round(Radius*6.28)
        fldz                    ; st = 0 = a (угол)
    .next:
        fld     st              ; st = a, a
        fsincos                 ; st = cos, sin, a
        fimul   [iRadX]         ; st = r*cos, sin, a
        fistp   [Temp]          ; st = sin, a
        mov     bx,[Temp]       ; x
        fimul   [iRadY]         ; st = r*sin, a
        fistp   [Temp]          ; st = a
        mov     di,[Temp]       ; y
        imul    di,320
        mov     byte [es:di+bx + CenterX+CenterY*320],Color ; рисуем точку цветом Color с центром в CenterX, CenterY
        fadd    [DeltaA]        ; a += DeltaA
        loop    .next
 
        xor     ah,ah
        int     16h             ; ждём нажатия
 
        mov     ax,3
        int     10h             ; возврат в текстовый режим
 
        int     20h             ; выход
 
iRadX   dw      RadiusX         ; радиус (целое число)
iRadY   dw      RadiusY         ; радиус (целое число)
DeltaA  dd      0.01    ; приращение угла в радианах = 1/Max(RadiusX,RadiusY) (!!! НЕОБХОДИМО УКАЗАТЬ ВРУЧНУЮ !!!)
Temp    dw      ?
4
 Аватар для Kukuxumushu
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
06.11.2018, 13:27
Лучший ответ Сообщение было отмечено Mikl___ как решение

Решение

Jin X, а вот и мой "каноничный" вариант (FASM):
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
org 100h
mov ax,13h
int 10h
 
push 200        ; X0
push 100        ; Y0
push 50         ; R
push 7          ; Цвет
call DrawCircle ; Вызов отрисовки
 
xor ah,ah
int 16h
ret
 
 
; Процедура отрисовки
; bp+10 = X0
; bp+8 = Y0
; bp+6 = R
; bp+4 = цвет
DrawCircle:
push bp
mov bp,sp
sub sp,2         ; Локальная переменная под координату точки
 
fld1             ; Вычисление приращения угла
fadd st,st       ; da=pi/(4R)
fadd st,st
fimul word[bp+6]
fldpi
fdivrp
fldz             ; Начальный угол = 0
 
mov cx,[bp+6]
shl cx,3         ; Кол-во точек = 8R
xor bh,bh        ; Инициализация int 10h
mov ax,[bp+4]
mov ah,0ch
@@:push cx          ; Цикл отрисовки точек
   fld st           ; Предотвращение затирания a
   fsincos
   fimul word[bp+6] ; X = R*cos(a)+X0
   fistp word[bp-2]
   mov cx,[bp-2]
   add cx,[bp+10]
   fimul word[bp+6] ; Y = R*sin(a)+Y0
   fistp word[bp-2]
   mov dx,[bp-2]
   add dx,[bp+8]
   int 10h          ; Отрисовка точки
   fadd st,st1      ; a+=da
   pop cx
   loop @b
 
mov sp,bp
pop bp
ret 8
3
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
07.11.2018, 13:07
В общем, я капец как заморочился и сделал универсальную процедуру, которая рисует окружности, эллипсы, дуги и спирали (иногда получаются даже сплайны и разные забавные фигуры). См. скриншот.

В архиве содержится несколько исходников, в т.ч. универсальный: с настройкой режима вывода (через BIOS или прямой доступ к видеопамяти) и оптимизации (по размеру или скорости). Плюс демонстрационные примеры.

В отдельных папках – варианты с минимальным кол-вом условных директив (более понятные).

p.s. На данный момент имеется небольшой баг: если разница начального и конечного радиуса очень большая (несколько десятков витков), конечный угол может быть заметно сдвинут. Это происходит из-за потери точности при постепенном приращении угла. Но это решаемо (надеюсь, у меня дойдут руки исправить это)

Здесь приведу только вариант отрисовки через BIOS с оптимизацией по размеру кода (файл bios\spiral_bios.inc):
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
;--------------------------------------------------------------------------;
; Spiral Draw include file [fasm], v1.00 (c) 2018 by Jin X (jin_x☼list.ru) ;
; Вариант отрисовки через BIOS с оптимизацией по размеру кода              ;
;--------------------------------------------------------------------------;
; Макросы и процедура рисования окружности, эллипса, дуги и спирали!       ;
; При вызове макросов/процедуры стек FPU должен быть пуст!                 ;
; Работают в любом графическом режиме!                                     ;
; Неиспользуемые участки в код не включаются!                              ;
;--------------------------------------------------------------------------;
 
; НАСТРОЙКИ (могут быть изменены после включения файла в программу)
SPIRAL_RAREFY_COEF      equ     1.0             ; коэфициент разряженности по умолчанию, вещественное число(!); при необходимости выводить линии разряженными увеличьте это значение;
                                                ; для регулировки этого коэффициента в рантайме можно изменять значение переменной SpiralRarefy (dword, вещественная!)
 
; НАРИСОВАТЬ ОКРУЖНОСТЬ
; Параметры: X0, Y0, Color, R
; где:
; * X0, Y0 - координаты центра
; * R - радиус (знаковое число)
; * Color - цвет в младшем байте, номер видеостраницы (обычно 0) в старшем байте
macro   DrawCircle!     X0, Y0, R, Color
{
                push    X0
                push    Y0
                push    R
                push    R
                push    R
                push    R
                push    0
                push    360
                push    Color
                call    DrawSpiral
} ; DrawCircle!
 
; НАРИСОВАТЬ ЭЛЛИПС
; Параметры: X0, Y0, Color, RX, RY
; где:
; * X0, Y0 - координаты центра
; * RX, RY - радиус по горизонтали и вертикали (знаковое число)
; * Color - цвет в младшем байте, номер видеостраницы (обычно 0) в старшем байте
macro   DrawEllipse!    X0, Y0, RX, RY, Color
{
                push    X0
                push    Y0
                push    RX
                push    RY
                push    RX
                push    RY
                push    0
                push    360
                push    Color
                call    DrawSpiral
} ; DrawEllipse!
 
; НАРИСОВАТЬ ДУГУ
; Параметры: X0, Y0, Color, RX, RY, StartA, FinalA
; где:
; * X0, Y0 - координаты центра
; * RX, RY - радиус по горизонтали и вертикали (знаковое число)
; * StartA, FinalA - начальный и конечный углы в градусах (знаковое число);
;     последняя точка финального угла не включается в отрисовку;
;     желательно не делать разницу больше, чем 360 градусов
; * Color - цвет в младшем байте, номер видеостраницы (обычно 0) в старшем байте
macro   DrawArc!        X0, Y0, RX, RY, StartA, FinalA, Color
{
                push    X0
                push    Y0
                push    RX
                push    RY
                push    RX
                push    RY
                push    StartA
                push    FinalA
                push    Color
                call    DrawSpiral
} ; DrawArc!
 
; НАРИСОВАТЬ СПИРАЛЬ
; Параметры: X0, Y0, Color, StartRX, StartRY, StartA, FinalA, FinalRX, FinalRY
; где:
; * X0, Y0 - координаты центра
; * StartRX, StartRY - начальный радиус по горизонтали и вертикали (знаковое число)
; * FinalRX, FinalRY - финальный радиус по горизонтали и вертикали
; * StartA, FinalA - начальный и конечный углы в градусах (знаковое число);
;     последняя точка финального угла не включается в отрисовку;
;     если нужно сделать несколько витков, делайте разницу 360 * кол-во витков
; * Color - цвет в младшем байте, номер видеостраницы (обычно 0) в старшем байте
macro   DrawSpiral!     X0, Y0, StartRX, StartRY, FinalRX, FinalRY, StartA, FinalA, Color
{
                push    X0
                push    Y0
                push    StartRX
                push    StartRY
                push    FinalRX
                push    FinalRY
                push    StartA
                push    FinalA
                push    Color
                call    DrawSpiral
} ; DrawSpiral!
 
;-----------------------------------------------------------------------------------------------------------------------
 
; МАКРОС ДЛЯ ВСТАВКИ ОСНОВНОГО КОДА РИСОВАНИЯ
; Обязательно используйте этот макрос (и только 1 раз) в том месте программы, куда нужно вставить код отрисовки фигур
macro   Insert_Spiral_Code
{
 
; ОТРИСОВКА СПИРАЛИ
; Параметры: X0, Y0, Color, StartRX, StartRY, FinalRX, FinalRY, StartA, FinalA (по соглашению Pascal)
; Описание параметров см. чуть выше
if used DrawSpiral
DrawSpiral:
_Spiral@X0      equ     word [bp+20]
_Spiral@Y0      equ     word [bp+18]
_Spiral@StartRX equ     word [bp+16]
_Spiral@StartRY equ     word [bp+14]
_Spiral@FinalRX equ     word [bp+12]
_Spiral@FinalRY equ     word [bp+10]
_Spiral@StartA  equ     word [bp+8]
_Spiral@FinalA  equ     word [bp+6]
_Spiral@Color   equ     word [bp+4]
;-----------------------------------
_Spiral@MaxR    equ     word [bp-2]             ; локальная переменная maxR
_Spiral@DeltaA  equ     word [bp-4]             ; локальная переменная deltaA (не используется после _Spiral@TempDW)
_Spiral@Temp    equ     word [bp-6]             ; локальная переменная для обмена значений регистров FPU и CPU (word)
_Spiral@TempDW  equ     dword [bp-6]            ; локальная переменная для обмена значений регистров FPU и CPU (dword)
_Spiral@Pi180   equ     dword [bp-10]           ; Pi/180
;-----------------------------------
 
                enter   6,0                     ; кадр стека с 3-мя словами под локальные переменные
                push    dword 0.017453292519943 ; значение для расчётов (Pi/180)
 
                ; Предподготовка
                mov     bx,_Spiral@FinalA
                sub     bx,_Spiral@StartA       ; bx = разница углов [deltaA]
                mov     _Spiral@DeltaA,bx       ; deltaA
 
                push    _Spiral@FinalRY
                push    _Spiral@FinalRX
                push    _Spiral@StartRY
                push    _Spiral@StartRX
                mov     cx,4                    ; кол-во радиусов
                xor     ax,ax
        .max:   pop     dx
        @@:     neg     dx
                jl      @B                      ; приводим к абсолютному значению
                cmp     ax,dx
                jae     @F
                xchg    ax,dx                   ; ax = максимальный по модулю радиус [maxR]
        @@:     loop    .max
                mov     _Spiral@MaxR,ax         ; maxR
 
                ; Предварительные расчёты
                fld     _Spiral@Pi180           ; st = Pi/180
                fimul   _Spiral@DeltaA          ; st = deltaA*(Pi/180)
                fimul   _Spiral@MaxR            ; st = maxR*deltaA*(Pi/180)
if used SpiralRarefy | SPIRAL_RAREFY_COEF <> 1.0
                fdiv    [SpiralRarefy]          ; st = maxR*deltaA*(Pi/180)/SpiralRarefy (применяем коэффициент разряженности)
end if
                fabs                            ; st = |maxR*deltaA*(Pi/180)/SpiralRarefy| [кол-во точек: Count]
 
                fist    _Spiral@TempDW          ; st = Count
                mov     esi,_Spiral@TempDW      ; esi = кол-во точек (Count)
;               test    esi,esi
;               jz      .exit                   ; выходим из процедуры, если углы равны (рисовать нечего)
 
                fld     st                      ; st = Count, Count
                mov     ax,_Spiral@FinalRY
                sub     ax,_Spiral@StartRY      ; ax = разница радиусов по вертикали
                mov     _Spiral@Temp,ax
                fidivr  _Spiral@Temp            ; st = deltaRY/Count [приращение радиуса по вертикли: incRY], Count
                fxch                            ; st = Count, incRY
                mov     ax,_Spiral@FinalRX
                sub     ax,_Spiral@StartRX      ; ax = разница радиусов по горизонтали
                mov     _Spiral@Temp,ax
                fidivr  _Spiral@Temp            ; st = deltaRX/Count [приращение радиуса по горизонтали: incRX], incRY
 
if used SpiralRarefy | SPIRAL_RAREFY_COEF <> 1.0
                fld     [SpiralRarefy]          ; st = SpiralRarefy (коэффициент разряженности), incRX, incRY, incRX, incRY
else
                fld1                            ; st = 1, incRX, incRY, incRX, incRY
end if ; used SpiralRarefy | SPIRAL_RAREFY_COEF <> 1.0
                fidiv   _Spiral@MaxR            ; st = SpiralRarefy/maxR [приращение угла: incA], incRX, incRY, incRX, incRY
                test    bx,bx                   ; проверяем deltaA
                jns     @F
                fchs                            ; меняем знак incA (направление приращения угла), если deltaA < 0
        @@:
                ; Финальная подготовка
                fild    _Spiral@StartRY         ; st = StartRY, incA, incRX, incRY
                fild    _Spiral@StartRX         ; st = StartRX, StartRY, incA, incRX, incRY
                fild    _Spiral@StartA          ; st = StartA, StartRX, StartRY, incA, incRX, incRY
                fmul    _Spiral@Pi180           ; st = StartA*Pi/180 (переводим в радианы), StartRX, StartRY, incA, incRX, incRY
                mov     ax,_Spiral@Color
 
                mov     bh,ah                   ; номер видеостраницы
                mov     ah,0x0C                 ; функция отрисовки точки
 
        .next:  ; Основной цикл: расчёты координат, отрисовка
                fld     st                      ; st = A, A, RX, RY, incA, incRX, incRY
                fsincos                         ; st = cos(A), sin(A), A, RX, RY, incA, incRX, incRY
                fmul    st,st3                  ; st = RX*cos(A), sin(A), A, RX, RY, incA, incRX, incRY
                fistp   _Spiral@Temp            ; st = sin(A), A, RX, RY, incRX, incRY, incA
                mov     cx,_Spiral@Temp         ; cx = координата X
                add     cx,_Spiral@X0           ; cx = X + X0
 
                fmul    st,st3                  ; st = RY*sin(A), A, RX, RY, incA, incRX, incRY
                fistp   _Spiral@Temp            ; st = A, RX, RY, incA, incRX, incRY
                mov     dx,_Spiral@Temp         ; dx = координата Y
                add     dx,_Spiral@Y0           ; dx = Y + Y0
                int     0x10                    ; отрисовка точки
 
                ; Приращение угла и радиусов
                fadd    st,st3                  ; st = A+incA, RX, RY, incA, incRX, incRY
                fxch                            ; st = RX, A+incA, RY, incA, incRX, incRY
                fadd    st0,st4                 ; st = RX+incRX, A+incA, RY, incA, incRX, incRY
                fxch    st2                     ; st = RY, A+incA, RX+incRX, incA, incRX, incRY
                fadd    st0,st5                 ; st = RY+incRY, A+incA, RX+incRX, incA, incRX, incRY
                fxch    st2                     ; st = RX+incRX, A+incA, RY+incRY, incA, incRX, incRY
                fxch                            ; st = A+incA, RX+incRX, RY+incRY, incA, incRX, incRY
 
                dec     esi
                jnle    .next                   ; повторяем цикл
 
        .exit:  ; Завершение
                fninit                          ; очищаем стек FPU
                leave
                ret     18
 
end if ; used DrawSpiral
 
if used SpiralRarefy
SpiralRarefy    dd      SPIRAL_RAREFY_COEF      ; коэффициент разряженности линий
end if
 
} ; Insert_Spiral_Code
Ну и демо (spiral104.fasm):
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
org     100h
 
include 'spiral_bios.inc'               ; подключение файла с процедурой рисования спирали
 
SCREEN_WIDTH    =       1024
SCREEN_HEIGHT   =       768
SCREEN_MID_X    =       SCREEN_WIDTH/2
SCREEN_MID_Y    =       SCREEN_HEIGHT/2
SCREEN_QMID_X   =       SCREEN_MID_X/2
SCREEN_QMID_Y   =       SCREEN_MID_Y/2
SCREEN_RX       =       SCREEN_WIDTH/6
SCREEN_RY       =       SCREEN_HEIGHT/6
 
                ; Видеорежим
                mov     ax,0x4F02       ; установка VESA-режима
                mov     bx,0x0105       ; 1024x768, 16 цветов
                int     0x10            ; графический режим
                cmp     ax,0x004F
                jne     .exit           ; выход в случае ошибки
 
                ; Выводим фигуры
                ; X0,Y0, RX, Color
                DrawCircle!     SCREEN_QMID_X,SCREEN_QMID_Y, SCREEN_RY, 9       ; отрисовка круга
 
                ; X0,Y0, RX,RY, FinalRX,FinalRY, Color
                DrawEllipse!    SCREEN_QMID_X*3,SCREEN_QMID_Y, SCREEN_RX,SCREEN_RY, 10  ; отрисовка эллипса
 
                ; X0,Y0, RX,RY, StartA,FinalA, StartA,FinalA, Color
                DrawArc!        SCREEN_QMID_X,SCREEN_QMID_Y*3, SCREEN_RX,SCREEN_RY, -180, 90, 11        ; отрисовка дуги
                DrawArc!        SCREEN_QMID_X,SCREEN_QMID_Y*3, SCREEN_RX*3/4,SCREEN_RY*3/4, 225, 45, 7  ; отрисовка другой дуги
 
                ; X0,Y0, StartRX,StartRY, FinalRX,FinalRY, StartA,FinalA, Color
                DrawSpiral!     SCREEN_QMID_X*3,SCREEN_QMID_Y*3, SCREEN_RX,SCREEN_RY, 0,0, 45,(360*2+180+45), 15        ; отрисовка спирали (2.5 витка)
 
                DrawSpiral!     SCREEN_QMID_X,SCREEN_QMID_Y, SCREEN_RX*2/3,SCREEN_RY*2/3, -SCREEN_RX*2/3,-SCREEN_RY*2/3, 90,(360*3-90), 14      ; отрисовка суперспирали
                DrawSpiral!     SCREEN_QMID_X*3,SCREEN_QMID_Y, -SCREEN_RX/2,-SCREEN_RY/3, SCREEN_RY/2,SCREEN_RX/2, 30,(360*3+60), 12            ; отрисовка сплайна :)
                DrawSpiral!     SCREEN_MID_X,SCREEN_MID_Y, -SCREEN_RX,-SCREEN_RY/2, SCREEN_RX,SCREEN_RY, 120,(360*5+60), 13                     ; отрисовка ещё одного сплайна :)
                mov     [SpiralRarefy], 5.0     ; увеличиваем разряженность
                DrawSpiral!     SCREEN_QMID_X,SCREEN_QMID_Y*3, SCREEN_RX/2,SCREEN_RY/2, -SCREEN_RX/2,SCREEN_RY/2, 0,(360*2), 6  ; отрисовка необычной фигуры
 
                ; Завершение
                xor     ah,ah
                int     0x16            ; ждём нажатия
        .exit:
                mov     ax,3
                int     0x10            ; возврат в текстовый режим
 
                ret                     ; выход
 
Insert_Spiral_Code                      ; место размещения кода вывода спирали
Миниатюры
Рисование спиралей и окружностей (некорректная отрисовка окружностей)  
Вложения
Тип файла: zip spiral_1.00.zip (40.9 Кб, 9 просмотров)
3
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
07.11.2018, 13:09
По-хорошему, инструкции:
Assembler
165
166
;               test    esi,esi
;               jz      .exit
лучше раскомментировать (они закомментированы из-за оптимизации по размеру)
1
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4495 / 1669
Регистрация: 01.02.2015
Сообщений: 13,906
Записей в блоге: 12
07.11.2018, 13:32
Jin X, я пробовал алгоритмы Брезенхема и Мичнера из-за анимации - перемещении двух окружностей и текста. Вариант с применением FPU будет так же мерцать или качество анимации возрастёт?

Вычисление выражение и прорисовка ответа в овале

Моя собственная реализация алгоритма Мичнера неоптимальна - можно ускорить за счёт сокращения ветвлений.
0
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
07.11.2018, 14:05
ФедосеевПавел, а какая связь между алгоритмом и мерцанием? Тут же не в алгоритме дело, а в том, как организован вывод и буферизация.

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

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

Если же очищать видеопамять и перерисовывать элементы, соответственно мерцание будет (что вполне логично). Мы не можем "заморозить" видеопамять (по крайней мере, я не знаю и не слышал о таком), чтобы выводимое в неё содержимое не отображалось на экране на время перерисовки.

А по вашей ссылке код почти на 700 строк, причём без графики, поэтому я не очень понял, зачем эта ссылка.

Добавлено через 6 минут
Другое дело, что если мы работаем через функции BIOS с попиксельной отрисовкой (ah=0Ch/int 10h). Как вариант, можно выводить на разные видеостраницы и переключать их с одной на другую (если данный видеорежим поддерживает несколько страниц).
2
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4495 / 1669
Регистрация: 01.02.2015
Сообщений: 13,906
Записей в блоге: 12
07.11.2018, 15:22
Это у ТС из той темы 700+ строк. Я ему показал окружности по Midpoint circle algorithm и текст 400 строк.
По сравнению с другой темой с этим же заданием, где я показывал другому ТС вычисления с FPU - отрисовка быстрее, но всё равно мерцает.

Поэтому у меня появился бзик на тему ускорения прорисовки окружностей.

В текущёй теме нужно отрисовать с десяток окружностей. Проверка Midpoint_circle_algorithm показала, что на малых радиусах получаются квадраты - пришлось подыскать замену.

На примере той темы с анимацией просто хотел привлечь внимание, что построение при помощи FPU - значительно медленнее.

Наверное, переработаю реализации и добавлю в FAQ.
0
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
07.11.2018, 16:01
Если рисуем через BIOS, то важно свести к минимуму кол-во точек. У меня на ровных кругах дублирования должно быть немного, но есть. На спиралях будет много наложений на ту же точку (лишний то есть).
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.11.2018, 16:01
Помогаю со студенческими работами здесь

Найти геометрическое место центров окружностей, касающихся двух данных окружностей
Найти геометрическое место центров окружностей, касающихся двух данных окружностей (x+1)^2-y^2=4 (x-1)^2-y^2=36 В ответе должно...

Вычислить длины двух окружностей и площадь кольца, образованного из этих окружностей
Очень нужна ваша помощь. Вычислите длины двух окружностей с радиусами R и r, а также площадь кольца, образованного из этих окружностей с...

По координатам центров окружностей и их радиусам найти пару пересекающихся окружностей.
Окружности Входной файл input.txt, Выводной файл output.txt. Ограничение по времени, сек 2 Ограничение по памяти,...

В массиве из N чисел - радиусов окружностей, выделить те, для которых площади окружностей S >= 100
В массиве из N чисел( N и числа вводятся с клавиатуры и представляют собой r окружностей) выделить те,для которых площадь S&gt;=100 и...

Найти геометрическое место центров окружностей, проходящих через точку А и касающихся окружностей
Найти геометрическое место центров окружностей, проходящих через точку А (-1;4) и касающихся окружностей {x}^{2}+{y}^{2}+18x+8y-3=0 ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru