控制台“图形学”(2)

来源:互联网 发布:mt4 布林线源码 编辑:程序博客网 时间:2024/06/05 03:49

上一篇谈到了画线算法,非最优,只是相对容易理解,如有苛刻的性能要求请自行了解更多的相关知识。以下算法也是如此,仅提供一种想法。

另外,到后面的话,根据需求,可以另外定义多种数据结构,Line,Rect等等,用于对图形的操纵。还可以给类设置一个状态值(矩阵?),用于实现translate,scale,rotate等函数。这一点稍后我们再另作深究。

有了画线函数,自然会相对对矩形的绘制,只需调用画线函数就可以了。

void MyGL::drawRect(int x0, int y0, int width, int height, unsigned char c /*= '+'*/){drawLine(x0, y0, x0, y0 + height,c);drawLine(x0, y0, x0 + width, y0,c);drawLine(x0 + width, y0, x0 + width, y0 + height,c);drawLine(x0, y0 + height, x0 + width, y0 + height,c);}

圆生成算法作了进一步深入。


先亮出代码,大家先自己分析分析。

//参考了中点画圆算法void MyGL::drawCircle(int x0, int y0, int r, unsigned char c /*= '+'*/){int x = r;int y = 0;for (; y <= x; ++y){while ((x - 0.5)*(x - 0.5) + y*y > r*r){--x;}while ((x + 0.5)*(x + 0.5) + y*y < r*r){++x;}setPixel(x0 + x, y0 + y, c);setPixel(x0 + x, y0 - y, c);setPixel(x0 - x, y0 + y, c);setPixel(x0 - x, y0 - y, c);setPixel(y0 + y, x0 + x, c);setPixel(y0 - y, x0 + x, c);setPixel(y0 + y, x0 - x, c);setPixel(y0 - y, x0 - x, c);}}
这里利用了圆的对称性,其实圆是有无数根对称轴,但这里我们只能用用y=0,x=0,y=x,y=-x这四根,这是由于我们在计算机显示中对图形的离散近似造成的。前面提及的四根对称轴恰好也是像素的对称轴(把每个像素视作小正方形)。如下图。


这样我们就可以只计算出第一象限中0~45°的部分即可根据对称同时绘出八个点。

for循环内的这段代码,

while ((x - 0.5)*(x - 0.5) + y*y > r*r){--x;}while ((x + 0.5)*(x + 0.5) + y*y < r*r){++x;}
其实有了两面夹击的意味。学过高中数学的都知道,x*x+y*y* >/=/< r*r分别表征该点在以原点为圆心r为半径的圆的内部,圆周上,外部。对于特定y值的点,该圆向右移动半格(减号表示圆心右移,半个像素为离散误差的上限)后你还在园外,那么说明该点需要向左移动一个单位了。

关于圆的算法另可参考中点画圆算法。

有人可能会问,用圆的参数方程怎么样。有这种想法的人特别留意:计算机中所有非简单函数都是用泰勒展开进行计算的,所以效率远达不到图形算法的要求。

其实此处还有圆的另一个特性被我们利用,很多人忽略了。留意for循环的条件 y <= x。在椭圆中会有所体现。


椭圆算法对圆的算法进行继承是我们的一个简单想法。这里先将圆与椭圆做一定比较。

圆的标准方程:x^2+ y^2 = r^2;

椭圆的标准方程:x^2/a^2 + y^2/b^2 = r^2;

第一个区别是椭圆的对称轴不包括y = x,y = -x。

类似地对于椭圆,我们应当找出何时分界点来决定是沿着x方向查找还是沿着y方向查找。(线段生成算法中已涉及相应内容,圆的部分因对称的缘故未予考虑。)

这个分界点是什么呢?就是该点的斜率为+-1。

如何求解该分界点呢?设切线为y + x = m,然后与椭圆方程联立后令Δ = 0后求出切点?这是极其低效的方法,仅开根号这一步即会拖慢整个算法,并未有效地利用计算机图形的离散性。我们不需要算出分界点的确切值。

方程x^2/a^2 + y^2/b^2 = r^2对x进行求导得到:

2x / a^2 + y / b^2 * y' = 0;

从而 y' = - b^2 / a^2  *  x / y;

y' > -1 即 b^2 * x < a^2 * y。

椭圆生成算法如下给出:

void MyGL::drawEllipse(int x0, int y0, int a, int b, unsigned char c /*= '+'*/){for (int x = a, y = 0; a*a*y < b*b*x; ++y){while ((x - 0.5)*(x - 0.5)*b*b + y*y*a*a > a*a*b*b){--x;}while ((x + 0.5)*(x + 0.5)*b*b + y*y*a*a < a*a*b*b){++x;}setPixel(x0 + x, y0 + y, c);setPixel(x0 + x, y0 - y, c);setPixel(x0 - x, y0 + y, c);setPixel(x0 - x, y0 - y, c);}for (int x = 0, y = b; a*a*y >= b*b*x; ++x){while ((y - 0.5)*(y - 0.5)*a*a + x*x*b*b > a*a*b*b){--y;}while ((y + 0.5)*(y + 0.5)*a*a + x*x*b*b < a*a*b*b){++y;}setPixel(x0 + x, y0 + y, c);setPixel(x0 + x, y0 - y, c);setPixel(x0 - x, y0 + y, c);setPixel(x0 - x, y0 - y, c);}}


给出目前的 完整源代码 下载地址!


0 0
原创粉丝点击