直线光栅化法
1、DDA法:
由直线基本微分方程 dydx=k d y d x = k ,k是常数。直线方程也可表示为 ΔyΔx=y2−y1x2−x1=k Δ y Δ x = y 2 − y 1 x 2 − x 1 = k
(1)David.F.Roger描述:
如果已知第i点坐标,可用步长StepX,StepY得到第i+1点的坐标(x+StepX,y+StepY)。
StepX和StepY由直线斜率k决定,例如k<1的时候,StepX = 1,StepY = k,将算得的坐标四舍五入得到光栅点的位置。
(2)James.D.Foley描述:
算法与前者相似,但略有不同:前者直线点并非直线的一个最好的逼近;后者则只给出0~45度坐标系下一个描述,且未分析直线端点不在像素点的情况。
(3)改进后的DDA算法(首点矫正):
void DDALine (
float xs, ys; //起点
float xe, ye; //终点
int value) //赋给线上的象数值
{
int n, ix, iy, idx, idy;
int Flag; //插补方向标记
int Length; //插补长度
float x, y, dx, dy;
dx=xe-xs;
dy=ye-ys;
if (fabs(dy)<fabs(dx)) { //X方向长 , 斜率 <=1
Length=abs(Round(xe)-Round(xs));
Flag=1; //最大的插补长度和方向标记
ix= Round(xs); //初始 X点
idx=isign(dx); //X方向单位增量
y= ys+dy/dx*((float)(ix)-xs); //初始 Y点修正
dy=dy/fabs(dx); //Y方向斜率增量
}
else { // Y方向长 , 斜率 >1
Length=abs(Round(ye)-Round(ys));
Flag=0;
iy= Round(ys); //初始 Y点
idy=isign(dy); //Y方向单位增量
x= xs+dx/dy*((float)(iy)-ys); //初始 X点修正
dx=dx/fabs(dy); //X方向斜率增量
}
if (Flag) { //X方向单位增量
for (n=0; n<= Length; n++) {
//X方向插补过程
WritePixel(ix, Round(y), value);
ix+=idx;
y+=dy;
} //End of for
} //End of if
else { //Y方向斜率增量
for (n=0; n<= Length; n++) {
//Y方向插补过程
WritePixel (Round(x), iy, value);
iy+=idy;
x+=dx;
} //End of for
} //End of else
} //Finish
首点矫正后的效果如下所示:
2、Bresenham算法
参考资料如下:
https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
(1)以 0<k<1 0 < k < 1 时为例,令e = d-0.5,当e>0时,x+=1,y+=1;e<0时,x+=1,y不变。
之后e+=k,并重复执行上述步骤。
//Bresenham's line resterization algorithm for the first octal.
//The line end points are (xs,ys) and (xe,ye) assumed not equal.
// Round is the integer function.
// x,y, ∆ x, ∆ y are the integer, Error is the real.
//initialize variables
x=xs
y=ys
∆x = xe -xs
∆y = ye -ys
//initialize e to compensate for a nonzero intercept
Error =∆ y/∆x-0.5
//begin the main loop
for i=1 to ∆x
WritePixel (x, y, value)
if (Error ≥ 0) then
y=y+1
Error = Error -1
end if
x=x+1
Error = Error +∆ y/∆x
next i
finish
(2)整数Bersenham算法:采用整数运算、避免除法运算。由于上述算法只用到误差项(初值 Error=ΔyΔx−0.5 E r r o r =