在我的一个项目(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> ¢er, 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。如果这是绕过这个问题的正确(和安全......)方式,请告诉我。
谢谢!
答案 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像素的误差。
我认为这至少解释了部分差异(即你的多边形绘图有缺陷)和 - 取决于zoom
- 你可以在椭圆参数中引入不对称性,你可以通过比较宽度来调试我上面描述的高度。