好吧,我在洪都拉斯科技大学(UTH)教汇编语言,出于某种原因,我试图画线和圆,但我试图找到一种不同于 Bresenham 的算法,我发现这些(用于线和圆)当您用同心圆填充圆形或用斜线填充矩形时,解决原始 Bresenham 中的孔。
注意 1:此算法与 Supercover 算法不同,但您可以将其用于相同目的。
注2:我只使用整数算术和逻辑函数来完成工作。
这是一个屏幕截图(在 Windows XP VirtualBox 中使用 Emu8086 并将程序编译为 .exe 文件)。
该代码应该进行优化,但由于是出于教学目的,所以我只是以学生可以轻松理解的方式进行编程。
data segment
; Las variables que comienzan con _ son variables usadas en los procedimientos
_migaja dw ?
_x dw ?
_y dw ?
_x2 dw ?
_y2 dw ?
_color dw ?
_deltaX dw ?
_deltaY dw ?
_deltaX_abs dw ?
_deltaY_abs dw ?
_error dw ?
_error_x dw ?
_error_y dw ?
_error_xy dw ?
_error_x_abs dw ?
_error_y_abs dw ?
_error_xy_abs dw ?
_cambio_y dw ?
_color_inicial db ?
_color_relleno db ?
_xc dw ?
_yc dw ?
_radio dw ?
; Variables usadas en la parte principal
i dw ?
xcentro dw 160
ycentro dw 100
radio dw 1
color dw 0
ends
stack segment
dw 32767 dup(0)
ends
code segment
start:
mov ax, data
mov ds, ax
mov es, ax
call videoMode
mov color, 10
pre_ciclo:
mov radio, 0
ciclo:
cmp radio, 100
jge salir_ciclo
push xcentro
push ycentro
push radio
push color
call circulo
inc radio
jmp ciclo
salir_ciclo:
mov ah, 1
int 21h
mov ax, 4c00h
int 21h
ends
videoMode PROC
mov ah, 0
mov al, 13h
int 10h
ret
ENDP
setPixel PROC
pop _migaja
pop ax
pop dx
pop cx
push _migaja
mov ah, 0Ch
int 10h
ret
ENDP
circulo PROC
; Este procedimiento dibuja un circulo en (x,y) de radio r
; Hecho por Ing. Yury Euceda© para los alumnos de UTH Agosto 2014
pop _migaja
pop _color
pop _radio
pop _yc
pop _xc
push _migaja
; Defino el error inicial
pre_ciclo_circle:
mov _error, 0
mov _x, 0
mov ax, _radio
mov _y, ax
ciclo_circulo:
push cx
mov cx, _x
add cx, _xc
mov dx, _yc
add dx, _y
mov ax, _color
mov ah, 0Ch
int 10h
push dx
mov dx, _yc
sub dx, _y
int 10h
push cx
mov cx, _xc
sub cx, _x
int 10h
pop cx
pop dx
mov cx, _xc
sub cx, _x
int 10h
pop cx
cmp _y, 0
je salir_ciclo_circulo
; Calculo error si suben ambos
mov ax, _x
shl ax, 1
inc ax
add ax, _error
mov _error_x, ax
mov _error_x_abs, ax
mov _error_xy, ax
mov _error_xy_abs, ax
mov ax, _y
shl ax, 1
neg ax
inc ax
add _error_xy, ax
add _error_xy_abs, ax
add ax, _error
mov _error_y, ax
mov _error_y_abs, ax
; Calculo los valores absolutos de los errores
cmp _error_x_abs, 0
jge continuar1_circulo
neg _error_x_abs
continuar1_circulo:
cmp _error_y_abs, 0
jge continuar2_circulo
neg _error_y_abs
continuar2_circulo:
cmp _error_xy_abs, 0
jge continuar3_circulo
neg _error_xy_abs
continuar3_circulo:
; Ahora voy a decidir que error absoluto es el menor
inc _x
dec _y
mov ax, _error_xy
mov _error, ax
mov ax, _error_xy_abs
compare_a_b_circulo:
cmp ax, _error_y_abs ; compare a con b
jg compare_b_c_circulo ; si a > b compare b con c
cmp ax, _error_xy_abs ; sino compare a con c
jg continuar_loop_circulo ; si es mayor continue loop
inc _y
mov ax, _error_x
mov _error, ax
jmp continuar_loop_circulo
compare_b_c_circulo:
mov ax, _error_y_abs
cmp ax, _error_xy_abs
jg continuar_loop_circulo
dec _x
mov ax, _error_y
mov _error, ax
continuar_loop_circulo:
jmp ciclo_circulo
salir_ciclo_circulo:
ret
ENDP
linea PROC
; Este procedimiento dibuja una linea desde (x1,y1) hasta (x2,y2)
; Hecho por Ing. Yury Euceda© para los alumnos de UTH Agosto 2014
pop _migaja
pop _color
pop _y2
pop _x2
pop _y
pop _x
push _migaja
mov ax, _x
cmp ax, _x2
jle calcular_deltaX
xchg ax, _x2
mov _x, ax
mov ax, _y
xchg ax, _y2
mov _y, ax
calcular_deltaX:
; Calculo deltaX = X2 - X
mov ax, _x2
sub ax, _x
mov _deltaX, ax
mov _deltaX_abs, ax
cmp ax, 0
jge calcular_deltaY
neg _deltaX_abs
calcular_deltaY:
; Calculo deltaY = Y2 - Y
mov ax, _y2
sub ax, _y
mov _deltaY, ax
mov _deltaY_abs, ax
cmp ax, 0
jge calcular_cambio
neg _deltaY_abs
calcular_cambio:
mov _cambio_y, 1
cmp _deltaY, 0
jge pre_ciclo_linea
neg _cambio_y
; Defino el error inicial
pre_ciclo_linea:
mov _error, 0
mov ax, _deltaY_abs
cmp _deltaX_abs, ax
jge asignar_deltaX
mov cx, _deltaY_abs
inc cx
jmp ciclo_linea
asignar_deltaX:
mov cx, _deltaX_abs
inc cx
ciclo_linea:
push cx
push _x
push _y
push _color
call setPixel
pop cx
; Calculo error si suben ambos
mov ax, _error
add ax, _deltaY_abs ; ax = error + deltaY
mov _error_x, ax
mov _error_x_abs, ax
sub ax, _deltaX_abs ; ax = error + deltaY - deltaX
mov _error_xy, ax
mov _error_xy_abs, ax
sub ax, _deltaY_abs ; ax = error - deltaX
mov _error_y, ax
mov _error_y_abs, ax
; Calculo los valores absolutos de los errores
cmp _error_x_abs, 0
jge continuar1
neg _error_x_abs
continuar1:
cmp _error_y_abs, 0
jge continuar2
neg _error_y_abs
continuar2:
cmp _error_xy_abs, 0
jge continuar3
neg _error_xy_abs
continuar3:
comparar_x_con_y:
mov ax , _error_y_abs
cmp _error_x_abs, ax
jge comparar_y_con_xy
mov ax , _error_xy_abs
cmp _error_x_abs, ax
jg cambiar_xy
inc _x
mov ax, _error_x
mov _error, ax
jmp continuar_loop
comparar_y_con_xy:
mov ax , _error_xy_abs
cmp _error_y_abs, ax
jge cambiar_xy
mov ax, _cambio_y
add _y, ax
mov ax, _error_y
mov _error, ax
jmp continuar_loop
cambiar_xy:
inc _x
mov ax, _cambio_y
add _y, ax
mov ax, _error_xy
mov _error, ax
continuar_loop:
loop ciclo_linea
ret
ENDP
rellenar PROC
pop _migaja
pop ax
pop dx
pop cx
push _migaja
mov _color_relleno, aL
mov ah, 0Dh
int 10h
mov _color_inicial, aL
; Llamo la recursiva
push cx
push dx
call rellenar_recursiva
pop dx
pop cx
ret
ENDP
rellenar_recursiva PROC
pop _migaja
; Saco los parametros de la pila
pop dx
pop cx
; Vuelvo a meterlos a la pila :)
push cx
push dx
push _migaja
; valido que el punto este en rango
cmp cx, 0
jl salir_rellenar
cmp cx, 319
jg salir_rellenar
cmp dx, 0
jl salir_rellenar
cmp dx, 199
jg salir_rellenar
; Extraigo el color del pixel en CX,DX
mov ah, 0Dh
int 10h
; Lo comparo con el color inicial
cmp _color_inicial, aL
; Si no es igual salgase
jne salir_rellenar
; Si es igual entonces lo pinto
mov aL, _color_relleno
mov ah, 0Ch
int 10h
; Pinto el norte
dec dx
push cx
push dx
call rellenar_recursiva
pop dx
pop cx
inc dx
; Pinto el este
inc cx
push cx
push dx
call rellenar_recursiva
pop dx
pop cx
dec cx
; Pinto el sur
inc dx
push cx
push dx
call rellenar_recursiva
pop dx
pop cx
dec dx
; Pinto el oeste
dec cx
push cx
push dx
call rellenar_recursiva
pop dx
pop cx
inc cx
salir_rellenar:
ret
ENDP
end start