椭圆与圆不同,不能八分只能四分。中点椭圆算法将分成两部分应用于第一象限。在斜率绝对值小于1的区域内在x方向取单位步长,在斜率绝对值大于1的区域内在y方向取单位步长。
取
,可定义椭圆函数为
即决策参数。从
开始,在
方向取单位步长直到区域1和区域2的界限处,然后转还为
方向的单位步长,再覆盖第一象限中剩余的曲线段。不过,每一步都要检测曲线斜率值。
斜率方程:
在区域1和区域2的交界区,
,且
因此,移除区域1的条件是
和中点画圆算法一样,通过该中点对决策函数求值来确定沿椭圆轨迹的下一个位置:
在下一个取样位置
,区域1的决策参数可求值为
或
其中,
根据
的符号取值为
或
。如果
,递增增量为
;如果
,递增增量为
。
在区域2中,在负方向以单位步长取样。
在下一个位置
对椭圆函数求值:
或
其中,
的设置根据
的符号可取值为
或
。
算法过程:
1.输入
、
和椭圆中心
,并得到椭圆上的第一个点:
2.计算区域1中决策参数的初始值:
3.在区域1中的每个
位置,从
开始,假如
,沿中心在
的椭圆的下一个点为
,并且
否则,沿椭圆的下一个点为
,并且
其中
并且直到
。4.使用区域1中计算的最后点
来计算区域2中参数的初始值:
5.在区域2的每个
位置处,从
开始,假如
,沿中心为
的椭圆的下一个点为
,并且
否则,沿椭圆的下一个点
,并且
使用与区域1中相同的
和
增量进行计算,直到
。
6.确定其他三个象限中的对称点。
7.将计算出的每个像素位置
移动到中心在
的椭圆轨迹上,并按坐标值绘制点:
1 inline int Round(const float a) { return static_cast<int>(a + 0.5); }
2
3 void setPixel(GLint xCoord, GLint yCoord)
4 {
5 glBegin(GL_POINTS);
6 glVertex2i(xCoord, yCoord);
7 glEnd();
8 }
9
10 void ellipsePlotPoints(int xCenter, int yCenter, int x, int y)
11 {
12 setPixel(xCenter + x, yCenter + y);
13 setPixel(xCenter - x, yCenter + y);
14 setPixel(xCenter + x, yCenter - y);
15 setPixel(xCenter - x, yCenter - y);
16 }
17
18 void ellipseMidpoint(int xCenter, int yCenter, int Rx, int Ry)
19 {
20 int Rx2 = Rx * Rx;
21 int Ry2 = Ry * Ry;
22 int twoRx2 = 2 * Rx2;
23 int twoRy2 = 2 * Ry2;
24 int p;
25 int x = 0;
26 int y = Ry;
27 int px = 0;
28 int py = twoRx2 * y;
29 // Plot the initial point in each quadrant
30 ellipsePlotPoints(xCenter, yCenter, x, y);
31 /* Region 1 */
32 p = Round(Ry2 - (Rx2 * Ry) + (0.25 * Rx2));
33 while (px < py) {
34 x++;
35 px += twoRy2;
36 if (p < 0) {
37 p += Ry2 + px;
38 }
39 else {
40 y--;
41 py -= twoRx2;
42 p += Ry2 + px - py;
43 }
44 ellipsePlotPoints(xCenter, yCenter, x, y);
45 }
46 /* Region 2 */
47 p = Round(Ry2 * (x + 0.5) * (x + 0.5) + Rx2 * (y - 1) * (y - 1) - Rx2 * Ry2);
48 while (y > 0) {
49 y--;
50 py -= twoRx2;
51 if (p > 0) {
52 p += Rx2 - py;
53 }
54 else {
55 x++;
56 px += twoRx2;
57 p += Rx2 - py + px;
58 }
59 ellipsePlotPoints(xCenter, yCenter, x, y);
60 }
61 }