天秤座的唐风

总会有一个人需要你的分享~!- 唐风 -

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  13 随笔 :: 0 文章 :: 69 评论 :: 0 Trackbacks

昨天晚上动手写了椭圆的光栅化实现,照着计算机图形学书上的伪代码编写了 C++ 的代码,结果运行结果完全出乎我的意料之外。
画出来的椭圆居然像这个样子:


    这实在是不像椭圆了,呵呵。虽然说在网上看到有说 Bresenham 算法有一定的失真?但也不至于成这样啊。于是反复地 check 伪代码与我写的 C++ 代码,感觉算法上我的“翻译”应该是没有问题的。不会是这伪码有问题?所以是翻回前面反复地阅读和理解这个算法的原理,对照原理的公式和伪代码的表达,也没有问题啊,难道公式有问题?只是硬着头皮自己再推导一遍。还是没发现问题所在。头大了,一直折腾到 2 点多,实在是没找出问题在哪,想想第二天还得上班,没办法只好放下。心想第二天在代码中加入一些输出,把计算结果都输出来进行 check。
    第二天中午休息的时候,在网上看到一个代码的实现,拷下来运行,虽然那份代码也有问题,但至少有一半的椭圆弧看起来是相当正常的。另一半没画正确,也是因为斜率为 -1 的判断有问题。再对照看了看我的代码,赫然发现,算法中用于存储决定下一点的选择策略的变量 d,在网上的代码用的是 int 型,而我自己则用的自定义的 INT16。难道是 INT16 太小导致的?于是我改成 INT32,一运行,正常了,虽然有些走样,但椭圆还是比较漂亮的。原来问题出在这里。INT16 的范围太小,而计算结果是 32 位的,截取成 16 位正负号就乱套了,唉,教训啊。OK 后的效果图如下:


    记下来,给自己提个醒!

    附上椭圆的生成代码,Bresenham算法:

 

void Draw2DLine::DrawEllipse(Point const& a_Center, UINT16 a_a, UINT16 a_b)
{
    UINT16 x 
= 0, y = a_b; 
    UINT32 
const taa = a_a*a_a;
    UINT32 
const tbb = a_b*a_b;

    INT32 minYofDeltaX 
= static_cast<INT32>(tbb/sqrt(static_cast<double>(tbb + taa)));

    INT32 p 
= tbb - taa*a_b;  // 就是这个变量!

    
while( minYofDeltaX <= y)
    

        DrawPoint(a_Center.x
+x, a_Center.y+y);
        DrawPoint(a_Center.x
+x, a_Center.y-y);
        DrawPoint(a_Center.x
-x, a_Center.y+y);
        DrawPoint(a_Center.x
-x, a_Center.y-y); 
        
if( p <= 0)
        

            
++x ;
        }
 
        
else
        

            
++x; 
            
--y;
        }
        
        p 
= tbb*(x+1)*(x+1+ taa*(y*- y) - taa*tbb;
    }
 

    p 
= tbb*(x*+ x) + taa*(y*- y) - taa*tbb;
    
while(y > 0)
    

        DrawPoint(a_Center.x
+x, a_Center.y+y);
        DrawPoint(a_Center.x
+x, a_Center.y-y);
        DrawPoint(a_Center.x
-x, a_Center.y+y);
        DrawPoint(a_Center.x
-x, a_Center.y-y); 
        
if(p >= 0)
        

            
--y; 
            p 
= p - 2*taa*- taa; 
        }
 
        
else
        

            
--y; 
            
++x; 
            p 
= p - 2*taa*- taa + 2*tbb*+ 2*tbb; 
        }
 
    }
 
    DrawPoint(a_Center.x
+x, a_Center.y);
    DrawPoint(a_Center.x
-x, a_Center.y);
}
posted on 2009-06-25 21:22 唐风 阅读(740) 评论(1)  编辑 收藏 引用 所属分类: 语言技术

评论

# re: 数据类型错误导致的 bug 与 Bresenham 椭圆生成算法代码 2009-06-25 22:31 唐风
PS:
  附上的代码中,第一个 while 中(切线斜率大于 -1 )的判别子 p 是直接用椭圆方程来计算的,第二个 while 中(切线斜率小于 -1 )中使用的是增量计算。
  原来第一个 while 中也是使用增量法来计算的,但在斜率为 -1 的附近,椭圆的变形比较严重,感觉像是一段很明显的 -1 斜率的直线。可能是计算式的精度有问题?但没有细查。先改成上面的方式,用着先,以后再回来优化。
Mark 下。  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理