赞
踩
确定最佳逼近于直线的一组象素,且按扫描线顺序,对这些象素进行写操作
三个常用算法:
知道了两个端点 P 0 ( x 0 , y 0 ) , P 1 ( x 1 , y 1 ) P_0(x_0,y_0),P_1(x_1,y_1) P0(x0,y0),P1(x1,y1),则可以求出直线段的斜率 k k k,根据公式 y = k x + b y=kx+b y=kx+b来计算响应y点的坐标,取像素点 ( x , ( round ( y ) ) ) (x,(\text{round}(y))) (x,(round(y))) 为当前点的坐标
评价:方法直观,效率低
在一个迭代算法中,每一步的x,y值使用前一步的值加上一个增量来获得
计算 y i + 1 = y i + k Δ x y_{i+1}=y_i+k\Delta x yi+1=yi+kΔx,当 Δ x = 1 \Delta x =1 Δx=1时, y i + 1 = y i + k y_{i+1}=y_i+k yi+1=yi+k
即:当x每递增1,y递增k(即直线斜率)
- 由此注意上述分析的算法仅适用于|k| ≤1的情形。在这种情况下,x每增加1,y最多增加1
- 当 |k| >1时,必须把x,y位置互换
void DDALine(int x0,int y0,int x1,int y1,int color)
{
int x;
float dx, dy, y, k;
dx= x1-x0, dy=y1-y0;
k=dy/dx, y=y0;
for (x=x0; x<=x1, x++)
{ drawpixel (x, int(y+0.5), color);
y=y+k;
}
}
注意这里额外加了0.5,就可以省掉round运算了
设当前像素点为 ( x p , y p ) (x_p,y_p) (xp,yp),下一个像素点为右侧 P 1 P_1 P1或右上角 P 2 P_2 P2两个点中的一个,设 M = ( x p + 1 , y p + 0.5 ) M=(x_p+1,y_p+0.5) M=(xp+1,yp+0.5)为 P 1 , P 2 P_1,P_2 P1,P2的中点,Q为理想直线与 x = x p + 1 x=x_p+1 x=xp+1垂线的交点。将Q与M的y坐标值进行比较
构造判别式:
d
=
F
(
M
)
=
F
(
x
p
+
1
,
y
p
+
0.5
)
=
a
(
x
p
+
1
)
+
b
(
y
p
+
0.5
)
+
c
其中
a
=
y
0
−
y
1
,
b
=
x
1
−
x
0
,
c
=
x
0
y
1
−
x
1
y
0
a=y_0-y_1,b=x_1-x_0,c=x_0y_1-x_1y_0
a=y0−y1,b=x1−x0,c=x0y1−x1y0
d是 x p , y p x_p,y_p xp,yp的线性函数,因此可以采取增量计算,提高运算效率
若当前像素处于 d ≥ 0 d\ge0 d≥0的情况,则去右侧像素 P 1 ( x p + 1 , y p ) P_1(x_p+1,y_p) P1(xp+1,yp),要判断下一个像素位置,应计算
d 1 = F ( x p + 2 , y p + 0.5 ) = a ( x p + 2 ) + b ( y p + 0.5 ) = d + a d_1=F(x_p+2, y_p+0.5)=a(x_p+2)+b(y_p+0.5)=d+a d1=F(xp+2,yp+0.5)=a(xp+2)+b(yp+0.5)=d+a;增量为a
若 d < 0 d\lt0 d<0时,则要取右上方像素 P 2 ( x o + 1 , y p + 1 ) P_2(x_o+1,y_p+1) P2(xo+1,yp+1),要判断下一个像素,应计算
$d_2= F(x_p+2, y_p+1.5)=a(x_p+2)+b(y_p+1.5)+c=d+a+b ; 增 量 为 ;增量为 ;增量为a+b$
具体算法:
画线从 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)开始,d的初值
d 0 = F ( x 0 + 1 , y 0 + 0.5 ) = F ( x 0 , y 0 ) + a + 0.5 b = a + 0.5 b d_0=F(x_0+1, y_0+0.5)=F(x_0, y_0)+a+0.5b =a+0.5b d0=F(x0+1,y0+0.5)=F(x0,y0)+a+0.5b=a+0.5b
a = y 0 − y 1 , b = x 1 − x 0 a=y_0-y_1,b=x_1-x_0 a=y0−y1,b=x1−x0
可以使用2d代替d来摆脱小数,提高运算效率
令 d 0 = 2 a + b , d 1 = 2 a , d 2 = 2 a + 2 b d_0=2a+b, d_1=2a, d_2=2a+2b d0=2a+b,d1=2a,d2=2a+2b,我们有如下算法
void Midpoint Line (int x0,int y0,int x1, int y1,int color) { int a, b, d1, d2, d, x, y; a=y0-y1, b=x1-x0, d=2*a+b; d1=2*a, d2=2* (a+b); x=x0, y=y0; drawpixel(x, y, color); while (x<x1){ if (d<0){ // d<0,应该加增量a+b,这里是d2 x++, y++, d+=d2; }else { // d>=0 应该加增量a,这里是d1 x++, d+=d1; } drawpixel (x, y, color); } }
先计算 d 0 , d 1 , d 2 d_0,d_1,d_2 d0,d1,d2,然后写成左下角的形式
设直线方程为 y i + 1 = y i + k ( x i + 1 − x i ) = y i + k y_{i+1}=y_i+k(x_{i+1}-x_i)=y_i+k yi+1=yi+k(xi+1−xi)=yi+k,其中 k = d y / d x k=dy/dx k=dy/dx,因为直线的起始点在像素中心,所以误差项d的初值d0=0
X的下标每增加1,d的值相应递增直线的斜率k,即d=d+k。一旦 d ≥ 0.5 d\ge0.5 d≥0.5,就把他减去1
为了方便计算,令 e = d − 0.5 e=d-0.5 e=d−0.5,e的初值为-0.5,增量为k(这样比较时候直接与0比较即可)
void Bresenhamline (int x0,int y0,int x1, int y1,int color)
{ int x, y, dx, dy;
float k, e;
dx = x1-x0, dy = y1- y0, k=dy/dx;
e=-0.5, x=x0, y=y0;
for (i=0; idx; i++){
drawpixel (x, y, color);
x=x+1,e=e+k;
if (e>=0){
y++, e=e-1;
}
}
}
首先计算出斜率k,然后写成左下角的形式
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。