有理有条地绘制立体图(利用数据结构)
来源:互联网 发布:linux重启ntp服务命令 编辑:程序博客网 时间:2024/05/07 11:03
- 话题引入
- 利用顶点表边表面表储存信息
- 利用邻接矩阵表示
- 利用邻接表表示
话题引入
之前我曾经绘制过立体图形,不过后来发现这东西和数据结构的关系是很密切的,几个点之间是有不同关系,有的之前相互有线相连,有的之间没有线相连接,不能简单通过肉眼绘制,这在点很多的时候会出很大的问题。关于图的数据结构的博文,在网上有很多很好的讲稿
http://blog.csdn.net/xiazdong/article/details/7354411#t14
http://blog.chinaunix.net/uid-26548237-id-3483650.html
其中这两篇文章写的特别好,照例我还是从最简单的正四面体和正方体开始下刀
其实当时已经用到了一些数据结构的想法
一个就是这里
static const GLfloat vertex_list[][3] = { -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f,};static const GLint index_list[][4] = { 0, 1, 2, 3,//bottem 0, 3, 7, 4,//left 2, 3, 7, 6,//front 1, 2, 6, 5,//right 0, 1, 5, 4,//back 4, 5, 6, 7//top };
分别储存点的坐标,和每个面由哪几个点构成
之后绘制的时候只需要调用
for (int i = 0; i < 6; ++i) // 有六个面,循环六次 { glBegin(GL_LINE_LOOP); for (int j = 0; j < 4; ++j) // 每个面有四个顶点,循环四次 glVertex3fv(vertex_list[index_list[i][j]]); glEnd(); }
即可
连最经典的斯坦福兔子,其实都是用这种方法实现的,第一部分储存顶点的信息,第二部分储存面上的点
下面分别用几种图中最常见的数据结构再次绘制这个立方体
利用顶点表、边表、面表储存信息
利用三个表储存信息,分别为顶点表、边表和面表,其中顶点是一个二维数组
下面以正方体为例
想要绘出立体图的大致来非常容易,只需要把所有的边遍历一遍
完整的代码如下
#include<GL/GLUT.H> #include <windows.h> #include <math.h> #include <gl/GL.h> static const GLfloat vertex_list[][3] = { -0.5f, -0.5f, -0.5f,//0 0.5f, -0.5f, -0.5f,//1 0.5f, 0.5f, -0.5f,//2 -0.5f, 0.5f, -0.5f,//3 -0.5f, -0.5f, 0.5f,//4 0.5f, -0.5f, 0.5f,//5 0.5f, 0.5f, 0.5f,//6 -0.5f, 0.5f, 0.5f,//7};static const GLint line_list[][2] = { 0,1,//0 0,3,//1 0,4,//2 1,2,//3 1,5,//4 2,3,//5 2,6,//6 3,7,//7 4,5,//8 4,7,//9 5,6,//10 6,7,//11};static const GLint face_list[][4] = { 0, 3, 5, 1,//bottem 2, 1, 7, 9,//left 5, 6, 11, 7,//front 3, 4, 10, 6,//right 0, 4, 8, 2,//back 8, 9, 11, 10,//top };template <class T>int getArrayLen(T& array){ return (sizeof(array) / sizeof(array[0]));}void myDisplay(void){ glClear(GL_COLOR_BUFFER_BIT); glRotatef(45, 1, 1, 1); glFrontFace(GL_CCW); int L = getArrayLen(line_list); for (int i = 0; i < L; ++i) // 有L个面,循环L次 { glBegin(GL_LINES); {glVertex3fv(vertex_list[line_list[i][0]]);//其中每条边由两点组成 glVertex3fv(vertex_list[line_list[i][1]]); } glEnd(); } glFlush();}int main(int argc, char *argv[]){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("opengl1"); glutDisplayFunc(&myDisplay); glutMainLoop(); return 0;}
其中的
template <class T>int getArrayLen(T& array){ return (sizeof(array) / sizeof(array[0]));}
部分可以计算数组长度
面点的信息虽然看起来没用,但其实很有用,我想想啊。。日后再说吧
好像仅仅通过保存边表也可以推断出面表。。
利用邻接矩阵表示
维持一个二维数组,arr[i][j]表示i到j的边,如果两顶点之间存在边,则为1,否则为0;
维持一个一维数组,存储顶点信息,比如顶点的名字;
如果我们要看vi节点邻接的点,则只需要遍历arr[i]即可;
缺点:邻接矩阵表示法对于稀疏图来说不合理,因为太浪费空间;
我这里基本全是无向图,所以矩阵都是对称阵
#include<GL/GLUT.H> #include <windows.h> #include <math.h> #include <gl/GL.h> template <class T>int getArrayLen(T& array){ return (sizeof(array) / sizeof(array[0]));}static const GLfloat vertex_list[][3] = { -0.5f, -0.5f, -0.5f,//0 0.5f, -0.5f, -0.5f,//1 0.5f, 0.5f, -0.5f,//2 -0.5f, 0.5f, -0.5f,//3 -0.5f, -0.5f, 0.5f,//4 0.5f, -0.5f, 0.5f,//5 0.5f, 0.5f, 0.5f,//6 -0.5f, 0.5f, 0.5f,//7};int N = getArrayLen(vertex_list);static const GLint line_list[8][8] = {0,1,0,1,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,};void myDisplay(void){ glClear(GL_COLOR_BUFFER_BIT); glRotatef(45, 1, 1, 1); glFrontFace(GL_CCW); int L = getArrayLen(line_list); for (int i = 0; i < 8; ++i) // 有8个点,循环8次 { for (int j = i; j < 8;j++) { if (line_list[i][j]==1) { glBegin(GL_LINES); { glVertex3fv(vertex_list[i]);//其中每条边由两点组成 glVertex3fv(vertex_list[j]); } glEnd(); } else continue; } } glFlush();}int main(int argc, char *argv[]){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("opengl1"); glutDisplayFunc(&myDisplay); glutMainLoop(); return 0;}
这是立方体利用邻接矩阵表示
利用邻接表表示
邻接表的处理方法是这样的:
(1)图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
(2)图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
例如,下图就是一个无向图的邻接表的结构。
实现代码如下。。不过看起来是问题有点多。。不过慢慢改进吧。代码这么冗余我也是醉了,我现在是把每个点都开辟了一个空间
#include<GL/GLUT.H> #include <windows.h> #include <math.h> #include <gl/GL.h> static const GLfloat vertex_list[][3] = { -0.5f, -0.5f, -0.5f,//0 0.5f, -0.5f, -0.5f,//1 0.5f, 0.5f, -0.5f,//2 -0.5f, 0.5f, -0.5f,//3 -0.5f, -0.5f, 0.5f,//4 0.5f, -0.5f, 0.5f,//5 0.5f, 0.5f, 0.5f,//6 -0.5f, 0.5f, 0.5f,//7};#define MAXVEX 1000 //最大顶点数typedef int VertexType; //顶点类型应由用户定义typedef int EdgeType; //边上的权值类型应由用户定义typedef struct EdgeNode //边表结点{ int adjvex; //邻接点域,存储该顶点对应的下标 struct EdgeNode *next; //链域,指向下一个邻接点}EdgeNode;typedef struct VertexNode //顶点表结构{ VertexType data; //顶点域,存储顶点信息 EdgeNode *firstedge; //边表头指针}VertexNode, AdjList[MAXVEX];void myDisplay(void){ glClear(GL_COLOR_BUFFER_BIT); AdjList p; for (int i = 0; i < 8; i++) { p[i].data = i; } //关于0点的 EdgeNode* pn00 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn00->adjvex=1; p[0].firstedge = pn00; EdgeNode* pn01 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn01->adjvex=3; p[0].firstedge->next = pn01; EdgeNode* pn02 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn02->adjvex = 4; p[0].firstedge->next->next = pn02; EdgeNode* pn03 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn03 = NULL; p[0].firstedge->next->next->next = pn03; //关于1点的 EdgeNode* pn10 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn10->adjvex = 0; p[1].firstedge = pn10; EdgeNode* pn11 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn11->adjvex = 2; p[1].firstedge->next = pn11; EdgeNode* pn12 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn12->adjvex = 5; p[1].firstedge->next->next = pn12; EdgeNode* pn13 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn13 = NULL; p[1].firstedge->next->next->next = pn13; //关于2点的 EdgeNode* pn20 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn20->adjvex = 1; p[2].firstedge = pn20; EdgeNode* pn21 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn21->adjvex = 3; p[2].firstedge->next = pn21; EdgeNode* pn22 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn22->adjvex = 6; p[2].firstedge->next->next = pn22; EdgeNode* pn23 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn23 = NULL; p[2].firstedge->next->next->next = pn23; //关于3点的 EdgeNode* pn30 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn30->adjvex = 0; p[3].firstedge = pn30; EdgeNode* pn31 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn31->adjvex = 2; p[3].firstedge->next = pn31; EdgeNode* pn32 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn32->adjvex = 7; p[3].firstedge->next->next = pn32; EdgeNode* pn33 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn33 = NULL; p[3].firstedge->next->next->next = pn33; //关于4点的 EdgeNode* pn40 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn40->adjvex = 0; p[4].firstedge = pn40; EdgeNode* pn41 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn41->adjvex = 5; p[4].firstedge->next = pn41; EdgeNode* pn42 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn42->adjvex = 7; p[4].firstedge->next->next = pn42; EdgeNode* pn43 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn43 = NULL; p[4].firstedge->next->next->next = pn43; //关于5点的 EdgeNode* pn50 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn50->adjvex = 1; p[5].firstedge = pn50; EdgeNode* pn51 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn51->adjvex = 4; p[5].firstedge->next = pn51; EdgeNode* pn52 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn52->adjvex = 6; p[5].firstedge->next->next = pn52; EdgeNode* pn53 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn53 = NULL; p[5].firstedge->next->next->next = pn53; //关于6点的 EdgeNode* pn60 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn60->adjvex = 2; p[6].firstedge = pn60; EdgeNode* pn61 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn61->adjvex = 5; p[6].firstedge->next = pn61; EdgeNode* pn62 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn62->adjvex = 7; p[6].firstedge->next->next = pn62; EdgeNode* pn63 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn63 = NULL; p[6].firstedge->next->next->next = pn63; //关于7点的 EdgeNode* pn70 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn70->adjvex = 3; p[7].firstedge = pn70; EdgeNode* pn71 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn71->adjvex = 4; p[7].firstedge->next = pn71; EdgeNode* pn72 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn72->adjvex = 6; p[7].firstedge->next->next = pn72; EdgeNode* pn73 = (EdgeNode*)malloc(sizeof(EdgeNode)); pn73 = NULL; p[7].firstedge->next->next->next = pn73; EdgeNode* pn = (EdgeNode*)malloc(sizeof(EdgeNode)); EdgeNode* s = (EdgeNode*)malloc(sizeof(EdgeNode)); glRotatef(45, 1, 1, 1); for (int i = 0; i < 8; i++) { pn = p[i].firstedge; do { glBegin(GL_LINES); {glVertex3fv(vertex_list[p[i].data]);//其中每条边由两点组成 glVertex3fv(vertex_list[pn->adjvex]); } glEnd(); s = pn; pn = pn->next; //free(s); } while (pn != NULL); } glFlush();}int main(int argc, char *argv[]){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("opengl1"); glutDisplayFunc(&myDisplay); glutMainLoop(); return 0;}
- 有理有条地绘制立体图(利用数据结构)
- matlab绘制立体图
- matlab绘制立体图
- 新手上路,matlab基础(4)绘制立体图
- 新手上路,matlab基础(4)绘制立体图
- MATLAB绘制矩阵权(Matrix weighted)有理Bezier曲线
- MATLAB 绘制有理Biezier曲线
- Matlab 绘制三维立体图(以地质异常体为例)
- Matlab 绘制三维立体图(以地质异常体为例)
- 立体图
- 立体图
- 非均匀有理样条NURBS
- noip2008 立体图 (字符串+模拟)
- 数据结构:请用一个数组实现两个堆栈,要求最大地利用数组空间,使 数组只要有空间入栈操作就可以成功
- Matlab slice方法和包络法绘制三维立体图
- DirectX学习笔记(四):利用D3DX网格数据结构绘制可旋转茶壶
- DirectX学习笔记(四):利用D3DX网格数据结构绘制可旋转茶壶
- 利用matlab中绘制多条y轴
- 类与对象
- 剑指offer之面试题29:数组中出现次数超过一半的数字
- More Effective C++----(11)禁止异常信息传递到析构函数外
- c++ 内存分区
- 百度地图API之覆盖物和事件
- 有理有条地绘制立体图(利用数据结构)
- 关于javascript的seal的扩展性一
- iPhone手机数据提取分析(一)
- oracle dba create view 失败 解决办法
- Postgresql 9 管理 手册(第二版)
- KairosDB 安装与入门
- C++编程笔记-特性
- 关于javascript的freeze的扩展性二
- 得到此时梦初醒