这里实现的是多点画多边形,然后把这个多边形进行二维的变换。

首先,多点画多边形,为了方便起见,我直接调用了Opengl的库函数。其次,就是如何进行多边形的二维变换。在这里我有两种方法。第一种是直接根据数学三角等公式推断得到结果。第二种方法是用矩阵相乘的方法。

先讲第一种

平移

假如我要平移a到b的位置:

那么操作就是:把这个多边形的n个顶点从一个位置移动到另外一个位置,然后重新生成平移后的多边形。(顶点知道了,那么就可以直接重新绘制多边形了)

大致代码就是:

Void translate2D(int x,int y){//x,y表示平移x、y的距离

For(int i=0;i<n;i++){

顶点[i].x=顶点[i].x+x;

顶点[i].y=顶点[i].y+y;

}

DrawPolygon();//这里表示重新绘制多边形

}

旋转(可以绕任意中心点旋转)

 

旋转原理:我们可以通过应用标准的三角等式得到旋转后的坐标。

根据上图,利用三角形的数学公式可以直接得出旋转后的公式


伪代码如下:

 

Void rotate2D(int x,int y,double theta){//x,y为旋转的中心,theta为旋转的角度

For(inti=0;i<n;i++){

顶点[i].x=x+(顶点[i].x-x)*cos(theta)-(顶点[i].y-y)*sin(theta);

顶点[i].y=y+(顶点[i].x-x)*sin(theta)+(顶点[i].y-y)*cos(theta);

}

DrawPolygon();//这里表示重新绘制多边形

}

二维缩放(基于一个固定点缩放)

简单缩放可以直接通过将缩放系数sx,sy与对应x,y坐标相乘:x’=x*sx,y’=y*sy

当然,我们需要在一个固定点进行缩放,那么就需要我们选择一个在缩放变换后不改变位置的点,来控制缩放后对象的位置。

得到的公式则是:

其中sx,sy属于缩放系数。0~1表示缩小,>1表示放大

伪代码:

Void scale2D(int x,int y,float sx,float sy){//x,y表示固定坐标,sx,sy为缩放系数

For(inti=0;i<n;i++){

顶点[i].x=顶点[i].x*sx+x*(1-sx);

顶点[i].y=顶点[i].y*sy+y*(1-sy);

}

DrawPolygon();//这里表示重新绘制多边形

}

第二种方法(矩阵相乘):

       二维平移矩阵:

      

       二维旋转矩阵:绕坐标系原点的而为旋转变换方程可以表示成矩阵形式


      

x’,y’表示变换后的坐标。

如果要基于某个基准点旋转,则:

1.平移对象使基准点位置移动到坐标原点

2.绕坐标原点旋转

3.平移对象使基准点回到原始位置

矩阵公式则是:


二维缩放矩阵:(也是基于原点)


如何要基于某个固定点进行缩放,那么就需要二维复合变换矩阵。

基于某个固定点缩放原理:其实就是先平移然后再缩放,最后再返回到原点。

于是有:

上述矩阵就是基于某个固定点的缩放。

必须注意的是:复合矩阵求值的顺序一定不能交换,除非某些情况譬如连续两次旋转或者连续两次平移等等。

为什么需要用复合矩阵相乘?而不直接一次一次的变换得到结果呢?

因为直接进行复合矩阵的计算会减少乘法和加法次数。具体详解就不在此叙述。

 

 

来看最终完整版代码:

#include<gl/glut.h>
#include<iostream>
#include<cmath>
#include<vector>
#pragma comment(linker,"/subsystem:\"Windows\"/entry:\"mainCRTStartup\"")
#define PI 3.14159265358
//q,w,e,r分别为平移,绘制多边形,旋转,缩放
#define TRANSLATE 0
#define DRAWPOLYGON 1
#define ROTATE 2
#define SCALE 3
int tran_x,tran_y;
int _xtmp,_ytmp;//作为缩放变量用
int mode=DRAWPOLYGON;//默认为绘制模式
using namespace std;
const int winwidth=800;
const int winheight=640;
struct position{double x;double y;
};
typedef GLfloat Matrix3x3[3][3];
Matrix3x3 matComposite;//复合矩阵
vector<position> xy;
position tmp;
void DrawPolygon();
void dragmouse(int x,int y);
void mymouse(int button,int state,int x,int y);
void myKeyboard(unsignedchar key,int x,int y);
void myKeyboardUp(unsignedchar key,int x,int y);
//设置为单位矩阵
voidmatrix3x3SetIdentity(Matrix3x3mat){GLint row,col;for(row=0;row<3;row++){for(col=0;col<3;col++)mat[row][col]=(row==col);}
}
void init(){glClearColor(1.0,1.0,1.0,1.0);//设置绘制窗口颜色为白色glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容/*设置为投影类型模式和其他观察参数*/glPointSize(3.0f);glColor3f(1.0,0.0,0.0);//设置颜色为红glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0,winwidth,winheight,0);matrix3x3SetIdentity(matComposite);
}//矩阵相乘
void matrixpreMultiply(Matrix3x3m1,Matrix3x3m2){GLint row,col;Matrix3x3 tmp;for(row=0;row<3;row++){for(col=0;col<3;col++){tmp[row][col]=m1[row][0]*m2[0][col]+m1[row][1]*m2[1][col]+m1[row][2]*m2[2][col];}}for(row=0;row<3;row++){for(col=0;col<3;col++){m2[row][col]=tmp[row][col];}}
}
//平移
void translate2D(GLfloattx,GLfloatty){Matrix3x3 matTransl;matrix3x3SetIdentity(matTransl);//设置为单位矩阵matTransl[0][2]=tx;matTransl[1][2]=ty;matrixpreMultiply(matTransl,matComposite);}
//旋转
void rotate2D(intx,inty,floattheta){theta=theta/180*PI;Matrix3x3 matRot;matrix3x3SetIdentity(matRot);matRot[0][0]=cos(theta);matRot[0][1]=-sin(theta);matRot[0][2]=x*(1-cos(theta))+y*sin(theta);matRot[1][0]=sin(theta);matRot[1][1]=cos(theta);matRot[1][2]=y*(1-cos(theta))-x*sin(theta);matrixpreMultiply(matRot,matComposite);
}//缩放
void scale2D(GLfloatsx,GLfloatsy,intx,inty){Matrix3x3 matScale;matrix3x3SetIdentity(matScale);matScale[0][0]=sx;matScale[0][2]=(1-sx)*x;matScale[1][1]=sy;matScale[1][2]=(1-sy)*y;matrixpreMultiply(matScale,matComposite);
}
//复合矩阵
void transformVerts2D(){GLfloat tmp;for(int i=0;i<xy.size();i++){tmp=matComposite[0][0]*xy[i].x+matComposite[0][1]*xy[i].y+matComposite[0][2];xy[i].y=matComposite[1][0]*xy[i].x+matComposite[1][1]*xy[i].y+matComposite[1][2];xy[i].x=tmp;}DrawPolygon();matrix3x3SetIdentity(matComposite);
}//绘制多边形
void DrawPolygon(){
//  glEnable(GL_POLYGON_STIPPLE);glPolygonMode(GL_BACK,GL_LINE);//设置反面为线性模式glPolygonMode(GL_FRONT,GL_LINE);//设置正面为线性模式glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容glBegin(GL_POLYGON);for(unsignedint i=0;i<xy.size();i++){glVertex2f(xy[i].x,xy[i].y);}glEnd();glFlush();
}//鼠标拖动
void dragmouse(intx,inty){float ssx=1,ssy=1;switch (mode){//q,w,e,rcase TRANSLATE:translate2D(x-tran_x,y-tran_y);transformVerts2D();tran_x=x;tran_y=y;break;case DRAWPOLYGON:      break;case ROTATE:if(x<=_xtmp&&y>=_ytmp)rotate2D(tran_x,tran_y,-8);elserotate2D(tran_x,tran_y,8);transformVerts2D();_xtmp=x;_ytmp=y;break;case SCALE:/*不等比例缩放*/if(x>_xtmp){ssx+=0.01f;}else if(x<_xtmp&&ssx>0){ssx-=0.01f;}if(y<_ytmp){ssy+=0.01f;}else if(y>_ytmp&&ssy>0){ssy-=0.01f;}/*等比例缩放if(x<=_xtmp&&y>=_ytmp){ssx-=0.01f;ssy-=0.01f;}else{ssx+=0.01f;ssy+=0.01f;}*/scale2D(ssx,ssy,tran_x,tran_y);transformVerts2D();_xtmp=x;_ytmp=y;break;default:break;}}//鼠标监听
void mymouse(intbutton,intstate,intx,inty){if(button==GLUT_LEFT_BUTTON &&state==GLUT_DOWN){switch (mode){//q,w,e,rcase TRANSLATE:tran_x=x;tran_y=y;break;case DRAWPOLYGON:      tmp.x=x;tmp.y=y;xy.push_back(tmp);DrawPolygon();break;case ROTATE:tran_x=x;tran_y=y;_xtmp=x;_ytmp=y;break;case SCALE:tran_x=x;tran_y=y;break;default:break;}}}
//键盘监听
void myKeyboard(unsignedcharkey,intx,inty){//清空删除if(key=='a'){glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容glFlush();xy.clear();}}void myKeyboardUp(unsignedcharkey,intx,inty){switch (key){case 'q':mode=TRANSLATE;break;case 'w':mode=DRAWPOLYGON;break;case 'e':mode=ROTATE;break;case 'r':mode=SCALE;break;default:break;}
}
void myDisplay(){glFlush();
}
void mymenu(intid){if(id==0)mode=0;else if(id==1)mode=1;else if(id==2)mode=2;else if(id==3)mode=3;
}int main(intargc,char**argv){glutInit(&argc,argv);//初始化glutInitDisplayMode(GLUT_SINGLE |GLUT_RGB);//设置绘制模式glutInitWindowPosition(500,300);glutInitWindowSize(winwidth,winheight);glutCreateWindow("二维图形的变换");//创建窗口int id=glutCreateMenu(mymenu);glutAddMenuEntry("平移",0);glutAddMenuEntry("绘制多边形",1);glutAddMenuEntry("旋转",2);glutAddMenuEntry("缩放",3);glutAttachMenu(GLUT_RIGHT_BUTTON);init();glutDisplayFunc(myDisplay);glutMouseFunc(mymouse);//鼠标监听回调函数glutMotionFunc(dragmouse);//鼠标拖动glutKeyboardFunc(myKeyboard);//键盘监听glutKeyboardUpFunc(myKeyboardUp);//键盘弹起状态glutMainLoop();
}

上述默认是绘制模式,如果需要平移,按一下键盘Q,然后按住鼠标左键拖动就可以平移,旋转,缩放也是一样的道理。

最终结果自己运行去吧~O(∩_∩)O哈哈~

以上代码我用的是VS2012+OpenGL环境运行。可以正确运行。

二维图形学的变换-平移、旋转、缩放 OpenGL相关推荐

  1. 【计算机图形学】小白谈计算机图形学(四)二维三维图形变换—1

    小白谈计算机图形学(四)二维三维图形变换-1 窗口与视图 二维图形的几何变换 平移变换 比例变换 旋转变换 二维图形变换的矩阵表示 三种变换 齐次坐标变换 原二维线性变换 齐次坐标法 复合变换 例题: ...

  2. 图形学(8)二维三维图形变换

    本模块内容绝大部分是在慕课上看中国农业大学网客时的笔记,因此算作转载,在此鸣谢赵明.李振波两位老师,感谢他们录制该门课程供大家学习! 在使用计算机处理图像时,我们不可避免对图形的位置.大小.形状等进行 ...

  3. 二维坐标系空间变换(详细解读,附MATLAB代码)

    二维坐标系空间变换 参考链接: 代码资源: 假如存在任意两个二维坐标系,如下图所示: 目的:将xoy坐标系经过处理变换到XOY坐标系. 经过分析可知:对于二维平面上的变换需要 x y 方向上两个平移参 ...

  4. 对图像进行二维离散Fourier变换

    用函数fft2对图像进行二维离散Fourier变换.用图像的形式分别显示清晰的频谱幅度和相位.对图像用窗函数加权,观察其Fourier变换,解释加窗前后的变化.对图像作Fourier变换和反变换.将图 ...

  5. 基于Pyhton的二维离散正弦变换(DST)及其反变换(IDST)

    1.二维离散正弦变换(DST)的矩阵形式可以表示为: 其中T为DST变换后的矩阵,I为输入矩阵,C为变换基,C的表示为: 2.二维离散正弦反变换(IDST)可以表示为: DST和DCT一样,能够把数据 ...

  6. c语言二维图像傅立叶变换,C语言数据结构算法之实现快速傅立叶变换.pdf

    C语语言言数数据据结结构构算算法法之之实实现现快快速速傅傅立立叶叶变变换换 C语语言言数数据据结结构构算算法法之之实实现现快快速速傅傅立立叶叶变变换换 本实例将实现二维快速傅立叶变换,同时也将借此实例 ...

  7. Unity 触屏手势控制Camera平移旋转缩放

    Unity 触屏手势控制Camera平移旋转缩放 实现思路 单点触屏,位移增量控制相机平移: 两点触屏,两点位移控制相机前后移动(缩放):两点中一点不位移控制相机绕点旋转: 实现需要的API Touc ...

  8. 编程将一个二维数组元素变换为逆向存放,即按元素在内存中的物理排列位置,第一个元素变成倒数第一个元素,第二个元素变成倒数第二个元素,依此类推。

    编程将一个二维数组元素变换为逆向存放,即按元素在内存中的物理排列位置,第一个元素变成倒数第一个元素,第二个元素变成倒数第二个元素,依此类推.     例如,原始二维数组为,逆向存放后变为.试建立一个类 ...

  9. 二维坐标基本变换(平移、旋转、缩放、镜像、阵列)

    诸如图像.模型等的基本变换,实际上都是点坐标的变换,通过矩阵,可以非常方便的达到这个目的.在下文仅介绍二维坐标变换原理. 首先,定义点类如下: //定义点类,亦可表示向量 class vec2 { p ...

最新文章

  1. mongodb入门的几篇文章
  2. jQuery接收后台返回的数据
  3. QDoc标记命令Markup Commands
  4. SAP Spartacus ConfigModule.withConfig的处理逻辑
  5. eclipse怎样改编码格式_Eclipse中各种编码格式及设置
  6. python多线程之线程锁(Lock)和递归锁(RLock)实例
  7. 解决复制项目后名称不改变的问题:org.eclipse.wst.common.component
  8. 8.网页找不到服务器
  9. 浅谈Redis基本数据类型底层编码(含C源码)
  10. java和ssm开发的医院体检预约系统有论文
  11. 投资案例分析:投资创业公司时,VC 关注什么?
  12. 低压无感BLDC方波控制方案 反电动势和比较器检测位置 带载满载启动
  13. 传感器故障下的滑模观测器的设计方法——Utkin观测器和Walcott-Zak 观测器
  14. Unity3D摄像机跟随人物
  15. 前端之JS篇(四)——三种循环(forwhiledo...while)
  16. 手把手教你怎么把爱奇艺QSV格式转换成MP4格式
  17. 郭明錤:Meta收缩有利于VR竞品发展,苹果XR头显将改变行业规则
  18. pageInfo参数大全
  19. 深入理解工具链-基于Eclipse的嵌入式IDE快速入门
  20. XSS漏洞常见攻击方式

热门文章

  1. java基础语法-day24-25进阶-Arrays工具类String自动装箱自动拆箱
  2. 胖虎算法初练四之——有效的括号
  3. 16位汇编语言学习笔记(1)——基础知识
  4. SAP推广项目经验总结-MM模块
  5. MATLAB学习笔记 人脸检测
  6. 使用matlab2010读取并播放wmv视频
  7. Linux下C语言编程
  8. 2022-2028年全球与中国自动车牌识别行业发展趋势及竞争策略研究
  9. 讲述30岁处男的悲惨经历
  10. Python输出简洁美观的文本化表格