《Windows32 SDK教程》12章 用AngleArc函数画圆


AngleArc函数是通过角度来画圆弧,注意是正圆的弧,而不是椭圆的弧。当然如果指定的角度为360度,画出来的就是圆了。这是一个非常有用的函数,但这个函数多了一条线段,使许多人达不到自己想要的结果,初学者都改用前面章节介绍过的方法来实现。

一、弧线之外的一条线

下面是AngleArc函数的原型,由结果图可以看出,除了弧线之外多了一条线。这条线段是从画笔位置到开始角度在圆周的位置。注意:画笔位置并不是鼠标位置。程序中开始角度为30度。

BOOL AngleArc(
  HDC hdc,            //HDC
  int X,              //圆心x座标
  int Y,              //圆心y座标
  DWORD dwRadius,     //半径
  FLOAT eStartAngle,  //弧线的开始角度
  FLOAT eSweepAngle   //弧线经过的角度。注意:不是终止角度
);
LONG clsCur;
bool bDrawing = false;   //画图状态为true
POINTS start, end, prev;  //开始点、结束点、前一个移动点

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        //与上例相同,省略
    }
    return 0;
}

//求半径
double cal(POINTS beg, POINTS end)
{
    double x, y;
    DWORD r;    //半径
    x = end.x - beg.x, y = end.y - beg.y;
    r = (DWORD)sqrt(x * x + y * y);

    return r;
}

//用AngleArc函数画弧线
void doDraw(HDC hdc, POINTS beg, POINTS end)
{
    DWORD r;    //半径
    float angle = 30;

    r = (DWORD)cal(beg, end);
    AngleArc(hdc, beg.x, beg.y, r, angle, 270);
    
    return;
} 

void Draw(HDC hdc, POINTS beg, POINTS end)
{
    SetROP2(hdc, R2_NOT);   //设置前景配色方式为象素反转
    doDraw(hdc, beg, end);

    return;
} 

void Draw2(HDC hdc, POINTS beg, POINTS end)
{
    HPEN hPen, hOldPen;
    SetROP2(hdc, R2_COPYPEN);   //设置前景配色方式为画笔颜色

    hPen = CreatePen(PS_SOLID, 5, RGB(0, 100, 255));  //兰色实线画笔
    hOldPen = (HPEN)SelectObject(hdc, hPen);
    SetROP2(hdc, R2_COPYPEN);   //设置前景配色方式

    doDraw(hdc, beg, end);

    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
    
    return;
} 

二、消除多余的这条线段

要消除这个线段很简单,只要在画图前先用MoveToEx()函数将画笔移动到开始角度在圆周上的位置就可以了。那么,圆周上的开始点座标如何确定呢?

圆周上的开始点,根据开始点的角度,相对于圆心的x座标为:“半径×余弦”;相对于圆心的y座标为:“半径×正弦”。然后再加上圆心座标便可以了。注意:sin()函数、cos()函数用的是极座标度数,极座标度数 = 普通度数×PI÷180。


#define RADIAN 3.1415926/180.0

//用AngleArc函数画弧线
void doDraw(HDC hdc, POINTS beg, POINTS end)
{
    DWORD r;    //半径
    float angle = 30;

    r = (DWORD)cal(beg, end);
    MoveToEx(hdc, 
             (int)(beg.x + r * cos(angle * RADIAN)), 
             (int)(beg.y - r * sin(angle * RADIAN)), 
             NULL);
    AngleArc(hdc, beg.x, beg.y, r, angle, 270);
    
    return;
} 

三、用AngleArc函数画弦

在画图前将画笔位置移动到弧线的终止位置,注意终止位置的角度是“开始角度”加上“弧线经过角度”。


void doDraw(HDC hdc, POINTS beg, POINTS end)
{
    DWORD r;    //半径
    float angle = 30;

    r = (DWORD)cal(beg, end);
    MoveToEx(hdc, 
             (int)(beg.x + r * cos((angle + 270) * RADIAN)), 
             (int)(beg.y - r * sin((angle + 270) * RADIAN)), 
             NULL);
    AngleArc(hdc, beg.x, beg.y, r, angle, 270);
    
    return;
} 

四、用AngleArc函数画饼图

在画图前将画笔位置移动到圆心位置,AngleArc函数会自动画一条圆心到弧线的开始点的线段,画完后画笔停在弧线的终止位置,这时只要再画一条直线到圆心便可以了。


void doDraw(HDC hdc, POINTS beg, POINTS end)
{
    DWORD r;    //半径
    float angle = 30;

    r = (DWORD)cal(beg, end);
    MoveToEx(hdc, beg.x, beg.y, NULL);
    AngleArc(hdc, beg.x, beg.y, r, angle, 270);
    LineTo(hdc, beg.x, beg.y);
    
    return;
}