欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

圆弧的扫描转换算法

程序员文章站 2022-03-22 16:03:51
...

圆弧的扫描转换算法

  • 处理对象:圆心在原点、半径为R的圆
  • 圆的八对称性:
    圆弧的扫描转换算法

一、 直接算法

两种直接离散方法:

  • 利用隐函数方程:x2+y2=R2x^2 + y^2 = R^2
    (xi,yi=R2xi2)>(xi,yi,r)(x_i, y_i = \sqrt{R^2 - x_i^2}) \frac{取整}{}>(x_i, y_{i,r})
  • 利用参数方程:{x=Rcosθy=Rsinθ\begin{cases}x = R\cos{\theta} \\ y = R\sin{\theta} \end{cases}

这两种方法都不可取,因为分别用到了开根运算、三角函数运算、浮点运算、取整等,计算量大,效率不高,不均匀。

二、角度DDA算法

由圆的参数方程:
{x=Rcosθy=Rsinθ \begin{cases} x = R\cos{\theta} \\ y = R\sin{\theta} \end{cases}
取微分:
{dx=Rsinθdθdy=Rcosθdθ{dx=ydθdy=xdθ\begin{cases} dx = -R\sin{\theta}d\theta \\ dy = R\cos{\theta}d\theta \end{cases} \Rightarrow \begin{cases} dx = -yd\theta \\ dy = xd\theta \end{cases}
圆弧的扫描转换算法

三、中点算法

利用圆的对称性,只须讨论18\frac{1}{8}圆。考虑第一象限内x[0,R2]x \in[0, \frac{R}{\sqrt{2}}]的圆弧:
圆弧的扫描转换算法
P(xp,yp)P(x_p,y_p)为当前点亮像素,那么下一个点亮的像素可能是P1(xp+1,yp)P_1(x_p+1, y_p)P2(xp+1,yp1)P_2(x_p + 1, y_p - 1)

  • MMP1P2P_1、P_2间的中点,M=(xp+1,yp+0.5)M = (x_p + 1, y_p + 0.5)
  • 有如下结论:
    • F(M)<0MF(M) < 0 \rightarrow M在圆内\rightarrowP1P_1

    • F(M)0MF(M) \ge 0\rightarrow M在圆外\rightarrowP2P_2

    • 为此,可采用如下判别式:
      d=F(M)=F(xp+1,yp0.5)  =(xp+1)2+(yp0.5)2R2d = F(M) = F(x_p + 1, y_p - 0.5) \\ \ \ = (x_p + 1)^2 + (y_p - 0.5)^2 - R^2

      • (1) d<0d<0,则P1P_1为下一个像素,那么再下一个像素的判别式为:d1=F(xp+2,yp0.5)=(xp+2)2+(yp0.5)2R2=d+2xp+3d_1 = F(x_p + 2, y_p - 0.5) \\ \qquad \qquad= (x_p+2)^2+(y_p-0.5)^2-R^2 \\ = d+ 2x_p + 3
        dd的增量为2xp+32x_p + 3
        圆弧的扫描转换算法
      • (2)d0d \ge 0,则P2P_2为下一个像素,那么在下一个像素的判别式为:d1=F(xp+2,yp1.5)=(xp+2)2+(yp1.5)2R2=d+2(xpyp)+5d_1 = F(x_p + 2, y_p - 1.5) \\ \qquad \qquad= (x_p+2)^2+(y_p-1.5)^2-R^2 \\ = d+ 2(x_p - y_p) + 5
        dd的增量为2(xpyp)+52(x_p - y_p) + 5
        圆弧的扫描转换算法

      d的初值:d0=F(1,R0.5)=1+(R0.5)2R2=1.25Rd_0 = F(1, R - 0.5) = 1 + (R - 0.5)^2 - R^2 = 1.25 - R

void MidpointCircle(int r, int color) {
	int x, y;
	float d;
	x = 0; y = r; d = 1.25 - r;
	drawpixel(x, y, color);
	while (x < y) {
		if ( d < 0 ) { 
			d += 2 * x + 3; 
			x++;
		} else {
			d += 2 * (x - y) + 5;
			x++;
			y--;
		}
		drawpixel(x, y, color);
	}
}

四、正负法

即求得PiP_i点后选择下一个像素点Pi+1P_{i+1}的规则为:

  • F(xi,yi)0F(x_i, y_i) \leq 0,取xi+1=xi+1, yi+1=yix_{i+1} = x_i + 1,\ y_{i+1} = y_i
    F(xi+1,yi+1)=(xi+1)2+(yi+1)2R2   =(xi+1)2+yi2R2   =F(xi,yi)+2xi+1F(x_{i+1}, y_{i+1}) = (x_{i+1})^2 + (y_{i+1})^2 - R^2 \\ \qquad \qquad \quad \ \ \ = (x_i+1)^2 + y_i^2 - R^2 \\ \qquad \qquad \quad \ \ \ =F(x_i,y_i)+2x_i + 1
  • F(xi,yi)>0F(x_i, y_i) > 0,取xi+1=xi, yi+1=yi1x_{i+1} = x_i,\ y_{i+1} = y_i - 1
    F(xi+1,yi+1)=(xi+1)2+(yi+1)2R2   =xi2+(yi1)2R2   =F(xi,yi)2yi+1F(x_{i+1}, y_{i+1}) = (x_{i+1})^2 + (y_{i+1})^2 - R^2 \\ \qquad \qquad \quad \ \ \ = x_i^2 + (y_i - 1)^2 - R^2 \\ \qquad \qquad \quad \ \ \ =F(x_i,y_i)-2y_i + 1
    圆弧的扫描转换算法

椭圆的扫描转换

圆弧的扫描转换算法

  • 标准椭圆方程:x2a2+y2b2=1\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1
  • 隐函数的形式:F(x,y)=(bx)2+(ay)2(ab)2=0F(x,y) = (bx)^2 + (ay)^2 - (ab)^2 = 0

椭圆的对称性

  • 椭圆的对称性,只考虑第一象限跟随椭圆弧的生成,分上下两部分,以切线斜率为-1的点§作为分界点。
    圆弧的扫描转换算法
  • 椭圆上任一点(x,y)(x,y)处的法向量为:(Fx,Fy)=(2b2x,2a2y)(\frac{\partial{F}}{\partial{x}},\frac{\partial{F}}{\partial{y}}) = (2b^2x,2a^2y)
    P点处的两个分量相等,即:2b2x=2a2y2b^2x = 2a^2y

中点算法

确定一个像素后,接着在两个候选像素的中点计算一个判别式的值,由判别式的符号确定更近的点。

  • 椭圆弧的上部分,各点斜率在[1,0][-1, 0]之间
    (xp,yp)(x_p,y_p)已确定,则下一待选像素的中点MM(xp+1,yp0.5)(x_p + 1, y_p - 0.5)
    d1=F(xp+1,yp0.5)=b2(xp+1)2+a2(yp0.5)2a2b2d_1 = F(x_p+1, y_p-0.5) = b^2(x_p+1)^2 + a^2(y_p - 0.5)^2 - a^2b^2
    圆弧的扫描转换算法
  • 再讨论椭圆弧的下部分,各点斜率kk满足:1k[1,0]\frac{1}{k}\in[-1,0]
    圆弧的扫描转换算法
MidPointEllipe(int a, int b, int color) {
	int x, y;
	float d1, d2;
	x = 0,; y = b;
	d1 = b * b + a * a * (-b + 0.25); // 初始判别式
	putpixel(x, y, color);
	while (b * b * (x + 1) < a * a * (y - 0.5)) { // 椭圆的上部
		if (d1 < 0) {
			d1 += b * b * (2 * x + 3);
			x++;
		} else {
			d1 += (b * b * (2 * x + 3) + a * a * (-2 * y + 2));
			x++;
			y--;
		}
		putpixel(x, y, color);
	} // 上部分
	d2 = sqr(b * (x + 0.5)) + sqr(a * (y - 1)) - sqr(a * b);
	while (y > 0) {
		if (d2 < 0) {
			d2 += b * b * (2 * x + 2) + a * a * (-2 * y + 3);
			x++;
			y--;
		} else {
			d2 += a * a * (-2 * y + 3);
			y--;
		}
		putpixel(x, y, color);
	}
}