目录
圆的几何特性分析
圆是中心对称图形,具有以下几何特性:
1>对于一个圆心在原点的圆形对象,圆上一个点,我们可以根据x=y、x=0、y=0三条对轴,将其不断对称产生圆上8个点,如下图利用(xi, yi)可产生圆上标注的8个点.
2>同样的,对于一个圆的1/8圆弧来讲,可以根据x=y、x=0、y=0三条对轴,将其不断对称产生整圆,如下图利用一象限y轴与y=x直线之间的8分之圆可以对称得到整圆.
3>利用八分之圆对称得到整圆的方法本质上是利用八分之圆上所有点对称得到整圆的过程。
MidPoint画圆算法
原理:
MidPoint画圆算法的思想与中点画直线算法的思想大致一致,在前一已知点位置的基础上,选择下一绘制点可能像素位置中靠近圆像素进行绘制的一种算法。
我们考虑第一象限y轴与直线y=x之间的八分之圆的顺时针绘制方式。对于这一部分的点来讲,假设在某点(xpos, ypos)确定的情况下,那么我们绘制的下一个像素点位置应当在(xpos+1, ypos)与(xpos+1, ypos-1)之间做选择。决策方式取决于这两点中点(xpos+1, ypos-0.5)与圆的位置关系,具体来讲,就是点(xpos+1, ypos-0.5)在圆的外面时,点(xpos+1, ypos-1)据圆上点更近,选择该点;点(xpos+1, ypos-0.5)在圆的内部时,点(xpos+1, ypos)据圆上点更近,选择该点。利用圆半径,我们可以获知圆方程为x*x+y*y-R*R=0,令d=F(x, y)=x*x+y*y-R*R,则当F(xi, yi)>0时,点(xi, yi)在圆的外面;当F(xi, yi)<0时,点(xi, yi)在圆的外面;当F(xi, yi)=0时,点(xi, yi)在圆上。根据以上分析,我们可以由点(0,radius)出发,依次选择这个八分圆内的绘制点,并将这些点以及对称产生的另外七个点进行绘制,完成整圆的绘制。
对于上述过程来讲,每次进行乘法计算时间效率不高,考虑递推过程中d的递推方式简化计算。有以下结论成立:
1>首先,对于d的初值我们易得为1.25-R。由于我们所涉及的都是整数运算,1.25-R在正负性上与1-R等价,为简化计算,可认为d0=1-R。
2>假设我们现在确定绘制了(xpos, ypos)点,并对d进行一定变化后(此时d=F(xpos+1, ypos+0.5)),d<0,那么下一个点选择(xpos+1, ypos),并且我们要计算的下一个中点位置为:
得到d的变化deta1=(xpos<<1)+3。
3>假设我们现在确定绘制了(xpos, ypos)点,并对d进行一定变化后,d>=0,那么下一个点选择(xpos+1, ypos-1),并且我们要计算的下一个中点位置为:
得到d的变化deta2=((xpos-ypos)<<1)+5。
综合以上结论,我们可以得到d的递推方式。
代码实现:
void MidPointCircle(const pair<int, int>& center, int radius, unsigned long color) { int xbase = 0, ybase = radius; //首先进行四分圆界限上点的绘制,原因:在下面的绘制算法中,这四个点会被忽略。 dc.SetPixel(center.first, center.second + radius, color); dc.SetPixel(center.first, center.second - radius, color); dc.SetPixel(center.first + radius, center.second, color); dc.SetPixel(center.first - radius, center.second, color); int d = 1 - radius; while (ybase >= xbase) { if (d < 0) { xbase++; d = d + (xbase << 1) + 3; } else { xbase++, ybase--; d = d + ((xbase - ybase) << 1) + 5; } dc.SetPixel(center.first + xbase, center.second + ybase, color); dc.SetPixel(center.first - xbase, center.second + ybase, color); dc.SetPixel(center.first + xbase, center.second - ybase, color); dc.SetPixel(center.first - xbase, center.second - ybase, color); dc.SetPixel(center.first + ybase, center.second + xbase, color); dc.SetPixel(center.first - ybase, center.second + xbase, color); dc.SetPixel(center.first + ybase, center.second - xbase, color); dc.SetPixel(center.first - ybase, center.second - xbase, color); } }
Bresenham画圆算法
原理:
Bresenham画圆算法中我们对第一象限的四分之圆进行考虑(同样是顺时针方向进行绘制)。那么对于一个我们已经确定的点(xpos, ypos)来讲,下一个被绘制的像素点可能是(xpos+1, ypos)、(xpos+1, ypos-1)或(xpos, ypos-1)中的一个,实际圆弧存在5种情况,如下图(xi, yi)以及点H、D、V点所示:
对于下一绘制点的决策同样取决于哪个点与圆的距离最近。令d=F(x, y)=x*x+y*y-R*R,则当F(xi, yi)>0时,点(xi, yi)在圆的外面;当F(xi, yi)<0时,点(xi, yi)在圆的外面;当F(xi, yi)=0时,点(xi, yi)在圆上。我们可以首先判断D点与圆的位置关系。假设D点在圆上(即F(xpos+1, ypos-1)=0),那么我们可以直接绘制D点,然后考察后面的点;假设D点在圆内部(即F(xpos+1, ypos-1)<0),那么我们需要进一步在H、D点之间决策哪个点更加接近圆,然后进行该点的绘制。假设D点在圆外部(即F(xpos+1, ypos-1)>0),那么我们需要进一步在D、V点之间决策哪个点更加接近圆,然后进行该点的绘制。在H、D之间的决策可以通过|F(H)|-|F(D)|值的正负性进行判断,该值为正说明D点距圆更近,故而对D点进行绘制,否则证明H点距圆更近,对H点进行绘制。在V、D之间的决策同理。
对于上述过程,同样存在每一点的决策过程涉及多次乘法运算,时间效率低的问题,故考虑决策以及d的递推过程。存在以下结论:
1>对于d的初值,易得为F(1, R-1)=2*(1-R)=(1-R)<<1。
2>假设我们现在确定绘制了(xpos, ypos)点,当前d为F(xpos+1, ypos-1),当d<0时,我们需要在(xpos+1, ypos)与(xpos+1, ypos-1)之间进行选择,选择依据为|F(xpos+1, ypos)|-|F(xpos+1, ypos-1)|的正负。对于这个表达式我们可以化简为:
judgeHD>0时下一个点选择为(xpos+1, ypos-1),否则下一个点选择为(xpos+1, ypos)。
3>假设我们现在确定绘制了(xpos, ypos)点,当前d为F(xpos+1, ypos-1),当d>0时,我们需要在(xpos, ypos-1)与(xpos+1, ypos-1)之间进行选择,选择依据为|F(xpos+1, ypos-1)|-|F(xpos, ypos-1)|的正负。对于这个表达式我们可以化简为:
judgeDV>0时下一个点选择为(xpos, ypos-1),否则下一个点选择为(xpos+1, ypos-1)。
4>假设我们现在确定绘制了(xpos, ypos)点,当前d为F(xpos+1, ypos-1),当d=0时,下一个点选择为(xpos+1, ypos-1)。
5>当下一个点选择为(xpos+1, ypos-1)时,我们下一次需要计算F(xpos+2, ypos-2),有:
故d的变化量deat1为((xpos-ypos+3)<<1)。
6>当下一个点选择为(xpos+1, ypos)时,我们下一次需要计算F(xpos+2, ypos-1),有:
故d的变化量deat2为(xpos<<1)+3。
7>当下一个点选择为(xpos, ypos-1)时,我们下一次需要计算F(xpos+1, ypos-2),有:
故d的变化量deat3为-(ypos<<1)+3。
综合以上结论,我们可以得到决策以及d的递推过程。
代码实现:
void BresenhamCircle(const pair<int, int>& center, int radius, unsigned long color) { int xbase = 0, ybase = radius, pos=0; int d = (1 - radius) << 1; while (ybase >= 0) { if (d > 0) { if (((d - xbase) << 1) - 1 <= 0) d = d + ((xbase - ybase + 3) << 1), xbase++, ybase--; else d = d - (ybase << 1) + 3, ybase--; } else if (d < 0) { if (((d + ybase) << 1) - 1 <= 0) d = d + (xbase << 1) + 3, xbase++; else d = d + ((xbase - ybase + 3) << 1), xbase++, ybase--; } else d = d + ((xbase - ybase + 3) << 1), xbase++, ybase--; dc.SetPixel(center.first + xbase, center.second + ybase, color); dc.SetPixel(center.first - xbase, center.second + ybase, color); dc.SetPixel(center.first + xbase, center.second - ybase, color); dc.SetPixel(center.first - xbase, center.second - ybase, color); } }
今天的文章
计算机图形学--2种圆绘制算法原理及代码实现分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/97749.html