如何用布雷森汉姆算法绘制椭圆扇形?

时间:2018-09-24 18:00:37

标签: math graphics geometry ellipse bresenham

如何使用Bresenham算法和DrawPixel方法绘制位图对象来绘制填充的椭圆扇形?

我已经编写了绘制椭圆的方法,但是该方法使用对称性并且仅通过第一象限。此算法不适用于扇区。当然,我可以写8个循环,但是我认为这并不是解决问题的最优雅的方法。

1 个答案:

答案 0 :(得分:0)

在整数数学上,通常的参数化方法是使用限制线(沿CW或CCW方向)而不是角度。因此,如果您可以将这些角度转换为这样的角度(您只需要ScenarioTestBase一次),则可以为此使用基于整数数学的渲染。正如我在评论中提到的那样,对于椭圆扇形来说,布雷森汉姆不是一个好方法,因为您需要为插值的起点计算内部迭代器和计数器状态,而且它只会为您提供圆周点而不是填充形状。

这里有很多方法可以解决这个问题:

  1. 将椭圆转换为圆形

    只需重新缩放较小的半径轴

  2. 在该圈子的bbox中循环

    简单的2个嵌套的sin,cos循环,覆盖了圆的外方正方形

  3. 检查点是否在圆圈内

    仅在圆以for为中心的情况下检查x^2 + y^2 <= r^2是否为

  4. 检查点是否位于边缘线之间

    因此,它应该是具有一条边的CW和具有另一边的CCW。您可以为此使用叉积(其z坐标极性将告诉您相对于测试边缘线的点是CW还是CCW)

    但是这只能在180度切片中使用,因此您还需要对象限进行一些检查以避免虚假负片。但是,这些只是这些上面的几个ifs。

  5. 如果满足所有条件,则将点收敛到椭圆并渲染

这是一个小的C ++示例:

(0,0)

请注意,两个角度都必须在void elliptic_arc(int x0,int y0,int rx,int ry,int a0,int a1,DWORD c) { // variables int x, y, r, xx,yy,rr, xa,ya,xb,yb, // a0,a1 edge points with radius r mx,my,cx,cy,sx,sy,i,a; // my Pixel access (you can ignore it and use your style of gfx access) int **Pixels=Main->pyx; // Pixels[y][x] int xs=Main->xs; // resolution int ys=Main->ys; // init variables r=rx; if (r<ry) r=ry; rr=r*r; // r=max(rx,ry) mx=(rx<<10)/r; // scale from circle to ellipse (fixed point) my=(ry<<10)/r; xa=+double(r)*cos(double(a0)*M_PI/180.0); ya=+double(r)*sin(double(a0)*M_PI/180.0); xb=+double(r)*cos(double(a1)*M_PI/180.0); yb=+double(r)*sin(double(a1)*M_PI/180.0); // render for (y=-r,yy=y*y,cy=(y*my)>>10,sy=y0+cy;y<=+r;y++,yy=y*y,cy=(y*my)>>10,sy=y0+cy) if ((sy>=0)&&(sy<ys)) for (x=-r,xx=x*x,cx=(x*mx)>>10,sx=x0+cx;x<=+r;x++,xx=x*x,cx=(x*mx)>>10,sx=x0+cx) if ((sx>=0)&&(sx<xs)) if (xx+yy<=rr) // inside circle { if ((cx>=0)&&(cy>=0)) a= 0;// actual quadrant if ((cx< 0)&&(cy>=0)) a= 90; if ((cx>=0)&&(cy< 0)) a=270; if ((cx< 0)&&(cy< 0)) a=180; if ((a >=a0)||((cx*ya)-(cy*xa)<=0)) // x,y is above a0 in clockwise direction if ((a+90<=a1)||((cx*yb)-(cy*xb)>=0)) Pixels[sy][sx]=c; } } 范围内。我的屏幕的y指向下,因此如果<0,360>将为CW方向,与路线相同。如果您使用a0<a1,则范围将被跳过,其余的椭圆将呈现。

此方法使用a1<a0作为真实角度!!!

为了避免在循环内产生分度,我改用10位定点刻度。

您可以简单地将其划分为4个象限,以避免在内部循环中使用4个象限来提高性能。


a0,a1是以x,y为中心的圆形比例的点
(0,0)是以cx,cy为中心的椭圆标度的点
(0,0)是椭圆尺度上的点,已转换为椭圆中心位置

谨防,我的像素访问权限为sx,sy,但是大多数api使用的是Pixels[y][x],因此请不要忘记将其更改为api以避免访问冲突或结果旋转90度。 ..