さて、私はホンジュラス工科大学 (UTH) でアセンブリ言語を教えており、何らかの理由で線と円を描こうとしていましたが、ブレゼンハムのものとは異なるアルゴリズムを見つけようとしました。円を同心円で塗りつぶすとき、または長方形を斜線で塗りつぶすときに、元のブレゼンハムの穴を解決します。
注 1: このアルゴリズムは Supercover Algorithm のものと同じではありませんが、同じ目的でそのアルゴリズムを使用できます。
注 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