我现在用的中点画圆算法,也被称为布氏,画出同心圆。 每个圆圈的半径,未来的之差始终为1,所以最终的结果应该是一个完整的圆形区域。
然而,一些像素被留为空,如图所示连接的图像中
我使用JavaScript来绘制一个HTML5画布上,操纵canvas.getContext( “2D”)。getImageData(...)。数据阵列。
圆圈是可选地白色和红色,并且空像素都是黑色。 您可能需要放大才能明白我的意思正确。
我想添加一些代码的算法,以便绘制相应的弧线时,这些像素填充。 人们似乎对任何这些像素属于一个弧,而不是下一个没有理由,所以它们沿与具有均匀半径圆弧或有一个奇怪的半径(我弧线充满我不在乎希望我说明白了)。
像素似乎遵循的模式,但我毫无头绪那会是什么。 谁能帮我找到它吗?
function drawCircles(radius, x, y){
var f = 1 - radius;
var ddF_x = 1;
var ddF_y = -2 * radius;
var x = 0;
var y = radius;
//Colors
var red = 255;
var green = radius%2==0?255:0;
var blue = radius%2==0?255:0;
paintPixel(x, y + radius, red, green, blue);
paintPixel(x, y - radius, red, green, blue);
paintPixel(x + radius, y, red, green, blue);
paintPixel(x - radius, y, red, green, blue);
while(x < y){
// ddF_x == 2 * x + 1;
// ddF_y == -2 * y;
// f == x*x + y*y - radius*radius + 2*x - y + 1;
if(f >= 0)
{
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
paintPixel(x + x, y + y, red, green, blue);
paintPixel(x - x, y + y, red, green, blue);
paintPixel(x + x, y - y, red, green, blue);
paintPixel(x - x, y - y, red, green, blue);
paintPixel(x + y, y + x, red, green, blue);
paintPixel(x - y, y + x, red, green, blue);
paintPixel(x + y, y - x, red, green, blue);
paintPixel(x - y, y - x, red, green, blue);
}
}
function paintPixel(x, y, red, green, blue){
imageData.data[grid[y][x]] = red;
imageData.data[grid[y][x]+1] = green;
imageData.data[grid[y][x]+2] = blue;
imageData.data[grid[y][x]+3] = 255; //Alpha
}
布氏旨在通过正像素区域绘制使用一个像素的线。 在45度,这将绘制一个像素接着另一个(+ 1,+ 1)到它。 这给出的1 /√2的两个像素的中心之间的平均厚度。 一个像素粗线的精确打印的厚度为1.中的黑点是由于Bresenham算法线的厚度和真厚度之间的差异。
如果延长像素绘制包括真线的中心跨越所有像素,它不应该有任何间隙,其厚度将永远不会小于一个。 这样做的一种方式是采用布氏两次内外半径,并根据两者之间的差异绘制象素。
如果你设计布氏风格的圆形抽屉计算边界轮廓而不是像素,可以生成圈子里窝完美。 从概念上讲,边界轮廓,而不是像素中心像素边缘的列表。 这与布氏风格的操作非常适合:递增的x坐标时注册一个水平边缘,并增加y坐标时,垂直边缘。
一个是:对于每一个圆圈,计算两个轮廓outer_radius
了,再(outer_radius - pen_diameter)
绘制两个轮廓之间的像素:有位聪明的,你应该能够在相同的循环运行这两个大纲发电机,并在网上做的像素图。
当然,这个边界技术描画圆将目光从直接生成圈子不同。 然而,IIRC,边界技术可能比直接法更稳健,反正...
这看起来像一个肯定走样的问题。 由于丢失的像素似乎更密集的以45°角,我怀疑是问题的根源有距离的计算做。 沿对角线,穿过一个像素的距离是当沿着轴线测量的大于约41%。 这可能会导致像素中心从任一圆进一步可以。 没有看到你的代码,就很难说了。
一个修复可能是简单的固体填充一个圆圈颜色的圆圈,然后就画出另一个圆的颜色。
<canvas width="500" height="500" style="background:#000;">
</canvas>
var canvas = $("canvas")[0];
var cen = $("canvas").width()/2;
var len = cen, i = len;
var ctx = canvas.getContext("2d");
var red = "#f00";
var white = "#fff";
for (; i > 0; i--){
ctx.beginPath();
ctx.arc(cen, cen, i, 0, 2 * Math.PI, false);
ctx.fillStyle = i % 2 ? red : white;
ctx.fill();
}
http://jsfiddle.net/RmHC3/
没有黑点。 :)
哦,我教在洪都拉斯(UTH)的理工大学汇编语言,由于某种原因,我想画直线和圆,但我试图找到比布氏的一个不同的算法,我发现这些的(对于线和圆圈),其解决了原布氏孔时填写圈同心圆或当您填写矩形斜线。
注1:该算法并不比Supercover算法的相同,但你可以使用一个相同的purpouse。
注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