问题描述:windows下,GDI可以调用Ellipse直接绘制一个水平或垂直方向的椭圆,但是无法按照一定的角度自由旋转。
解决方法:
1. 使用世界坐标系。通过旋转世界坐标系,达到旋转椭圆的目的。需要使用到SetWorldTransform等一系列的函数。
关于这些函数的使用方法参见如下资料:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd145104%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/dd145174(v=vs.85).aspx
简单介绍一下旋转椭圆时,如何计算世界坐标系的转换。
椭圆的中心点(x0,y0),从点(x1,y1)旋转到点(x2,y2),旋转角度为q(单位为弧度)。
x2 = cos(q)*(x1-x0) – sin(q)*(y1-y0) + x0;
y2 = sin(q)*(x1-x0) + cos(q)*(y1-y0) + y0;
当使用世界坐标系时,从点(x,y)变换到点(x', y')时,SetWorldTransform需要一个XFORM的参数,其成员的计算关系为:
y’ = x * eM12 + y * eM22 + eDy;
void EllipseToBezier(CRect& r, CPoint* cCtlPt)
{
// MAGICAL CONSTANT to map ellipse to beziers
// 2/3*(sqrt(2)-1)
const double EToBConst = 0.2761423749154;
CSize offset((int)(r.Width() * EToBConst), (int)(r.Height() * EToBConst));
// Use the following line instead for mapping systems where +ve Y is upwards
// CSize offset((int)(r.Width() * EToBConst), -(int)(r.Height() * EToBConst));
CPoint centre((r.left + r.right) / 2, (r.top + r.bottom) / 2);
cCtlPt[0].x = //------------------------/
cCtlPt[1].x = // /
cCtlPt[11].x = // 2___3___4 /
cCtlPt[12].x = r.left; // 1 5 /
cCtlPt[5].x = // | | /
cCtlPt[6].x = // | | /
cCtlPt[7].x = r.right; // 0,12 6 /
cCtlPt[2].x = // | | /
cCtlPt[10].x = centre.x - offset.cx; // | | /
cCtlPt[4].x = // 11 7 /
cCtlPt[8].x = centre.x + offset.cx; // 10___9___8 /
cCtlPt[3].x = // /
cCtlPt[9].x = centre.x; //------------------------*
cCtlPt[2].y =
cCtlPt[3].y =
cCtlPt[4].y = r.top;
cCtlPt[8].y =
cCtlPt[9].y =
cCtlPt[10].y = r.bottom;
cCtlPt[7].y =
cCtlPt[11].y = centre.y + offset.cy;
cCtlPt[1].y =
cCtlPt[5].y = centre.y - offset.cy;
cCtlPt[0].y =
cCtlPt[12].y =
cCtlPt[6].y = centre.y;
}
// LDPoint is an equivalent type to CPoint but with floating point precision
void Rotate(double radians, const CPoint& c, CPoint* vCtlPt, unsigned Cnt)
{
double sinAng = sin(radians);
double cosAng = cos(radians);
LDPoint constTerm(c.x - c.x * cosAng - c.y * sinAng,
c.y + c.x * sinAng - c.y * cosAng);
for (int i = Cnt-1; i>=0; --i)
{
vCtlPt[i] = (LDPoint(vCtlPt[i].x * cosAng + vCtlPt[i].y * sinAng,
-vCtlPt[i].x * sinAng + vCtlPt[i].y * cosAng) + constTerm).GetCPoint();
}
}
// Create Ellipse
CRect rect; GetClientRect(&rect);
CPoint ellipsePts[13];
EllipseToBezier(ellipseR, ellipsePts);
// Rotate
Rotate(m_Radians, midPoint, ellipsePts, 13);