CDC :: Ellipse无法正确绘制圆圈

时间:2013-10-31 10:24:40

标签: c++ mfc

在我的一个项目(VC ++ 2010,MFC)中,我想使用CDC :: Ellipse绘制一个圆。我设置了两个点:第一个是圆的中心,第二个是我希望它在圆周上的点。

我传递给CDC :: Ellipse(int x1,int y1,int x2,int y2)左上角和右下角的坐标。

简单地说:使用Pitagora定理我计算两点之间的距离(半径),然后我从中心的坐标中减去该值以获得左上角并添加以获得右下角。

当我绘制cirlce和点,并且我放大时,我看到第二个不在预期的圆周上,除非你把它设置在0°,45°,90°并且它是微小的内部关于坐标的绝对系统,等等。

然后我尝试使用CDC :: Polyline绘制相同的圆,我给这个方法得到的点是围绕中心旋转另一个点,距离等于半径。在这种情况下,每个我设置的点都在圆周上。

这两个圆的重叠表明它们在0°,45°,90°等情况下完全重叠,但间隙在22.5°,67.5°等处最大。

有没有人注意到类似的行为?

感谢所有能帮助我的人!

代码段

这是我如何计算给定2点的半径:

centerPX = vvFPoint( 1380, 845 );
secondPointPX = vvFPoint( 654,654 );
double radiusPX = (sqrt( (secondPointPX.x - centerPX.x) * (secondPointPX.x - centerPX.x) + (secondPointPX.y - centerPX.y) * (secondPointPX.y - centerPX.y) ));

vvFPoint 是从CPoint派生的自定义类型)

这是我用CDC :: Ellipse绘制“圆圈”的方式:

int up = (int)(((double)(m_p1.y-(double)originY - m_radius) / zoom) + 0.5) + offY;
int left = (int)(((double)(m_p1.x-(double)originX - m_radius) / zoom) + 0.5) + offX;
int down = (int)(((double)(m_p1.y-(double)originY + m_radius) / zoom) + 0.5) + offY;
int right = (int)(((double)(m_p1.x-(double)originX + m_radius) / zoom) + 0.5) + offX;
pDC->Ellipse( left, up, right, down);

m_p1 是圆的中心, originX / Y 是图像的原点, m_radius 是圆的半径,缩放是比例因子, offX / Y 是我SW的客户区内的偏移量

这是我使用自定义折线类“手动”(以及非常简单的方法)绘制圆的方法:

1)创建点数组:

point.x = centerPX.x + radiusPX;
point.y = centerPX.y;
for ( i=0; i < 3600; i++ )
{
    pt1.RotateDeg ( centerPX, (double)0.1 );
    poly->AddPoint( pt1 );
}

RotateDeg 是一种自定义方法,使用第一个参数作为枢轴旋转点,第二个参数作为角度值以度为单位, AddPoint 是一种自定义方法来创建点数组, poly 是我的自定义折线对象。)

2)画出来:

当我调用Draw(CDC * pDC)时,我使用前一个数组绘制折线:

pDC->MoveTo(p);

我希望这可以帮助你重现我奇怪的观察结果!

代码段2

void vvPoint<Tipo>::RotateDeg(const vvPoint<Tipo> &center, double angle)
{
vvPoint<Tipo> ptB;

angle *= -(M_PI / 180);

*this -= center;
ptB.x = ((this->x * cos(angle)) - (this->y * sin(angle)));
ptB.y = ((this->x * sin(angle)) + (this->y * cos(angle)));
*this = ptB + center;
}

但是为了让你更好地理解我的观察,我想添加一些图像,这样你就可以看到我的整个问题从哪里开始......问题是:我无法添加图像,因为我需要有10个声望。我在dropbox上传了一个.zip文件,如果你愿意我可以发给你这个文件的URL。如果这是绕过这个问题的正确(和安全......)方式,请告诉我。

谢谢!

1 个答案:

答案 0 :(得分:1)

这可能是一种可能的解释。关于CDC::Ellipse MSDN says(我强调):

  

椭圆的中心是边界矩形的中心   由 x1 y1 x2 y2 lpRect 指定。绘制椭圆   当前的笔,其内部充满了当前的笔刷。

     

此功能绘制的数字最多可扩展为,但不包括,   右下坐标。这意味着高度   figure是 y2 - y1 ,图的宽度是 x2 - x1

您描述如何计算边界矩形的方式并不完全清楚(某些源代码会有所帮助)但是,鉴于上面引用的第二段,您可能需要在 x2 中添加1和 y2 值,以确保您有一个具有所需半径的圆圈。

值得注意的是,您的两种绘图方法之间可能存在轻微的舍入差异,其中您有一个奇数大小的边界框(即中心点在逻辑上落在半像素上)。

更新

使用你的代码片段(谢谢),假设没有缩放和零偏移等,我得到一个750.704像素的半径和椭圆的以下参数:

pDC->Ellipse(629, 94, 2131, 1596);

根据MSDN,这意味着椭圆将以下列尺寸的图形绘制:

width  = (2131 - 629) = 1502
height = (1596 -  94) = 1502

据我所见,这个应该产生一个圆而不是一个椭圆。

接下来要做的是找出你如何绘制多边形 - 为此我们需要看到RotateDeg的实现 - 你能发布那些代码吗?我怀疑这里有一些简单的舍入错误,当你缩放时可能会放大。

更新2

只看这段代码:

for ( i=0; i < 3600; i++ )
{
    pt1.RotateDeg ( centerPX, (double)0.1 );
    poly->AddPoint( pt1 );
}

每次以递增方式旋转多边形点0.1度。这可能会累积一些错误,所以可能值得这样做:

for ( i=0; i < 3600; i++ )
{
    vvFPoint ptNew = pt1;
    ptNew.RotateDeg ( centerPX, (double)i * 0.1 );
    poly->AddPoint( ptNew );
}

这可能意味着您必须更改RotateDeg功能以处理正确的象限。

另外一点,您提到放大图像时会看到问题。如果这意味着您正在使用zoom变量,则值得在此行中查看...:

pDC->Ellipse( left, up, right, down);

...参数仍然形成方形,所以(right - left) == (down - up)

更新3

我刚刚以当前形式运行你的RotateDeg函数,以查看错误如何累积(通过将前一个结果输入到下一次迭代)。在每一步,我计算了新点和中心之间的距离,并将其与所需的半径进行了比较。

下面的图表显示了结果,在计算得分时,您可以看到4像素的误差。

errors

我认为这至少解释了部分差异(即你的多边形绘图有缺陷)和 - 取决于zoom - 你可以在椭圆参数中引入不对称性,你可以通过比较宽度来调试我上面描述的高度。

相关问题