一、旋转绘制函数介绍
在SimpleCG中我们没有提供直接绘制偏转的,或者有些同学说斜的椭圆形的函数,所以正常情况下绘制出来的椭圆形都是长短轴与横纵坐标线平行。当需要绘制轴有偏转的椭圆形时就没办法了。不过SimpleCG提供了对坐标系进行旋转的函数,所以不仅可以绘制偏转椭圆形,还可以绘制偏转长方形,甚至直接绘制旋转图片。相关函数如下所示:
//进入传动旋转模式开始,返回转换层次,后续定义的旋转点不跟随转动
int EnterRotateLevel( int nXCenter, int nYCenter, float fRotateAngle );
//返回上一模式
bool LeavePrevLevel();
二、转换模式使用例子
每次需要绘制旋转图形时,需要进入旋转模式层次,EnterRotateLevel,之所以需要旋转层次,是因为我们可以在旋转某个物体时,同时对部件进行局部旋转。这个概念在后续介绍,一般只需要一层旋转模式即可。
int EnterRotateLevel( int nXCenter, int nYCenter, float fRotateAngle );
旋转模式有三个参数,分别是旋转中心点坐标(nXCenter, nYCenter),以及旋转角度fRotateAngle 。
下面尝试绘制一个顺时针偏转30度的椭圆。
EnterRotateLevel( 300,250, C_PI /6 );
ellipse(100,200, 500, 300);
LeavePrevLevel();
绘制结果如图
绘制其他偏转图形也只需要在EnterRotateLevel与LeavePrevLevel之间添加即可,甚至直接旋转图片也如此简单,我们把图片按左上角为中心,顺时针偏转60度后绘制在坐标(150,50)位置
SCG_Image imgPet;
img=image_load( _T("jian.png") );
EnterRotateLevel( 150,50, C_PI /6 );
image_draw( &img, 150,50);
LeavePrevLevel();
image_release(&img);
效果如图
三、旋转函数参数说明
旋转函数参数除了旋转角度外还有旋转中心点,在这里需要特别解释下中心点参数。因为同样的角度不同的中心点旋转后图形差别可能非常巨大。
int EnterRotateLevel( int nXCenter, int nYCenter, float fRotateAngle );
前两个参数是在绘制目标的坐标,表示此后绘制的画面均以此坐标为中心进行顺时针旋转,旋转角度为 fRotateAngle 弧度。我们以实际例子来旋转矩形看看具体的绘制效果。
rectangle(100,100, 300, 200);
EnterRotateLevel( 100,100, C_PI /6 );
setlinecolor(RGB(0x0,0xFF,0x0));
rectangle(100,100, 300, 200);
LeavePrevLevel();
EnterRotateLevel( 200,150, C_PI /6 );
setlinecolor(RGB(0x0,0x0,0xFF));
rectangle(100,100, 300, 200);
LeavePrevLevel();
效果如图
黑色是正常绘制的矩形,绿色是以矩形左上角坐标(100,100)为中心旋转30度的矩形,蓝色是以矩形中心点坐标(200,150)为旋转中心旋转30度的矩形。 可以看到两个偏转角度一样,但是位置明显偏移了。所以在使用旋转函数时一定要对旋转中心做到心中有数。
四、旋转函数实际使用的一个例子--时钟绘制
旋转函数作用非常大,下面我们就以该函数来做一个简单的时钟程序看看。我们可以直接用该函数绘制钟面及指针,非常方便。请直接查看代码
// ClockSimple.cpp : 定义控制台应用程序的入口点。
//
#include "../import/include/CGBoard.h"
#define C_IMAGE_WIDTH 500
#define C_IMAGE_HEIGHT 500
#ifdef _DEBUG
#pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
#else
#ifdef _WIN64
#pragma comment(lib,"../import/lib/x64/MTRelease/SimpleCG_MT64.lib")
#else
#pragma comment(lib,"../import/lib/SimpleCG_MT.lib")
#endif
#endif
//绘制
void RenderClock()
{
int i=0;
float fHour = 0.0f;
float fMin = 0.0f;
float fSec = 0.0f;
float fMiliSec = 0.0f;
SYSTEMTIME tm;
ClearDevice();
//钟面
setlinewidth(3);
_circle(C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2);
for(i=0;i<12;++i)
{
EnterRotateLevel( C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2, i*C_PI /6 );
_line( C_IMAGE_WIDTH/2, 10, C_IMAGE_WIDTH/2, 25);
LeavePrevLevel();
}
setlinewidth(1);
for(i=0;i<60;++i)
{
EnterRotateLevel( C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2, i*C_PI /6/5 );
_solidcircle( C_IMAGE_WIDTH/2, 10, 3);
LeavePrevLevel();
}
outtextXYW( C_IMAGE_WIDTH-60,C_IMAGE_WIDTH/2-20, L"3" );
outtextXYW( C_IMAGE_WIDTH/2-20, C_IMAGE_WIDTH-60,L"6" );
outtextXYW( 30, C_IMAGE_WIDTH/2-20,L"9" );
outtextXYW( C_IMAGE_WIDTH/2-40, 40,L"12" );
//指针
GetLocalTime(&tm);
fMiliSec = tm.wMilliseconds;
fSec = tm.wSecond + fMiliSec/1000;
fMin = tm.wMinute + fSec/60;
fHour = tm.wHour % 12 + fMin/60;
setlinewidth(5);
EnterRotateLevel( C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2, C_PI * fHour / 6 );
line( C_IMAGE_WIDTH/2, C_IMAGE_WIDTH/2-C_IMAGE_WIDTH/2*0.6, C_IMAGE_WIDTH/2, C_IMAGE_WIDTH/2+C_IMAGE_WIDTH*0.05);
LeavePrevLevel();
setlinewidth(3);
EnterRotateLevel( C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2, C_PI * fMin / 30 );
line( C_IMAGE_WIDTH/2, C_IMAGE_WIDTH/2-C_IMAGE_WIDTH/2*0.75, C_IMAGE_WIDTH/2, C_IMAGE_WIDTH/2+C_IMAGE_WIDTH*0.05);
LeavePrevLevel();
setlinewidth( 1);
EnterRotateLevel( C_IMAGE_WIDTH/2,C_IMAGE_WIDTH/2, C_PI * fSec / 30 );
line( C_IMAGE_WIDTH/2, C_IMAGE_WIDTH/2-C_IMAGE_WIDTH/2*0.85, C_IMAGE_WIDTH/2, C_IMAGE_WIDTH/2+C_IMAGE_WIDTH*0.05);
LeavePrevLevel();
ReflushWindow();
}
void Drawing()
{
settextfont(40,40,_T("Calibri"));
while(IsShowingWindow())
{
RenderClock();
Sleep(50);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//初始化
if( !ShowingBoard(C_IMAGE_WIDTH,C_IMAGE_HEIGHT, Drawing))
return 1;
//关闭图库
CloseBoard();
return 0;
}
输出一个普通的时钟,你可以通过给他添加一些装饰或造型,甚至增强它的功能,就可以代替系统时钟了。
五、源代码下载
源码地址
ClockSimple · master · b2b160 / SimpleCG_Demo · GitCode
bin/ClockSimple.zip · master · b2b160 / SimpleCG_Demo · GitCode