扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
lambda表达式
创新互联-成都网站建设公司,专注网站设计、网站建设、网站营销推广,域名注册,虚拟主机,网站托管有关企业网站制作方案、改版、费用等问题,请联系创新互联。
C++ 语言中的lambda表达式在很多情况下提供了函数对象的另一种实现机制。Lambda表达式并不是STL所特有的,但它广泛应用于这一环境中。Lambda是表达式是定义一个没有名称、也不需要显示类定义的函数对象。Lambda表达式一般作为一种手段,用来将函数作为实参传递到另一个函数。相比于定义和创建一个常规的函数对象而言,lambda表达式非常容易使用和理解,而且需要的代码也较少。当然,一般而言,lambda表达式并不会取代函数对象。
举个例子,假设有个包含数值的矢量,我们计算此矢量的立方值。可以用transform()函数操作,简单的用lambda表达式完成。
double values[] = {1,2,3,4,5,6};
vectordouble data(values,values+6);
vectordouble cubes(data.size());
transform(values.begin(),values.end(),cubes.begin(),[](double x){ return x*x*x;});
最后这条语句用来计算data中的立方值,并存储在cubes。这里简单提一下transform()函数。它是algorithm头文件中的函数,它有两个版本。
第一个版本是将一个一元函数对象指定的操作应用到由一对迭代器指定的一个元素集合上,格式如下:
transform(InputIterator begin, InputIterator end, OutputIterator result,UnaryFuncton f);
transform()的这个版本将一元函数f应用到迭代器begin 和end指定的范围中的所有元素,并从迭代器result指定的位置开始存储结果。Result迭代器可以与begin迭代器相同,只是在这种情况下将会替换原有的内容。这个函数返回一个迭代器,指向存储的最后一个结果的下一个位置。
举例如下:
double values[] = {1,2,3,4,5,6};
vectordouble data(values,values+6);
transform(values.begin(),values.end(),values.begin(),negatedouble);
transform()函数调用negatedouble函数对象应用到矢量data中的所有元素,结果存储在data中,并重写了原始值,执行完后data将包含 -1,-2,-3,-4,-5,-6。函数返回迭代器data.end()。
transform()第二个版本通过来自迭代器指定的两个范围内的操作数应用一个二元函数。格式为:
transform(InputIterator1 begin1, InputIterator 1end1, InputIterator2 begin2, OutputIterator result,BinaryFunction f);
由begin1和end1指定的范围表示最后一个实参指定的二元函数f的左操作数集合。表示右操作的范围从begin2迭代器指定的位置开始,这个范围不需要提供end迭代器,因为这个范围的元素数量必须与begin1和end1指定的范围元素个数相同,结果从result迭代器位置开始存储在这个范围内。如果希望存回原范围中,result迭代器可以与begin1相同。
举例如下:
复制代码
double values[]={2.5,-3.5,4.5,-5.5,6.5,-7.5};
vectordouble data(values, values + sizeof values / sizeof values[0]);
vectordouble squares(data.size());
transform(data.begin(),data.end(),data.begin(),squares.begin(),multipliesdouble());
ostream_iteratordouble out(cout,” “);
copy(squares.begin(),squares.end(),out);
复制代码
Transform()函数通过multipliesdouble函数对象将自身相乘,结果存储到squares中。最后两句用一个输出迭代器输出内容。
现在回到上文:
transform(values.begin(),values.end(),cubes.begin(),[](double x){ return x*x*x;});
开始的方括号称为lambda引导,它标志着lambda表达式的开始。后面的圆括号中的是lambda的参数列表,这与普通函数相同。此例中只有一个形参x。注意,lambda的参数列表不允许指定形参的默认值,并且参数列表的长度是不可变的。大括号中的是lambda的主体,此例只有一条return语句,当然可以包含多条语句。大家可能注意到这里没有返回类型说明。当lambda表达式的主体是一条单一返回语句,而该语句在lambda表达式主体中返回一个值时,返回类型默认为返回值的类型。否则,返回void。当然可以指定返回类型,如下:
[](double x) -double{ return x*x*x;} //指定返回double
Capture子句
lambda表达式引导可以包含一个捕获子句,用来确定lambda主体如何访问封闭作用域中的变量。前面lambda表达式方括号之间没有内容,表面封闭作用域没有可以再lambda表达式中访问的变量。若要访问,第一种是方括号之间是 = ,则lambda主体可以按值访问封闭作用域的所有自动变量,但不会修改原始变量。另一中是方括号之间是 ,则封闭作用域的所有自动变量按应用访问,因此lambda表达式可以修改变量值。例如:
复制代码
double index = 3.0;
double values[] = {1,2,3,4,5,6};
vectordouble data(values,values+6);
vectordouble cubes(data.size());
transform(values.begin(),values.end(),cubes.begin(),
[=](double x){ return index*x*x*x;});
复制代码
需要主要的是,这与按值传递实参根本不同,变量index的值可用在lambda中,但不能更新index的副本。如:
transform(values.begin(),values.end(),cubes.begin(),
[=](double x) -double{
index += 10; // error
return index*x*x*x;});
以上是错误的,若要修改变量的临时副本,则通过添加mutable关键字实现。如:
transform(values.begin(),values.end(),cubes.begin(),
[=](double x)mutable -double{
index += 10; // ok
return index*x*x*x;});
现在可以修改作用域中的任意变量副本,而不会修改原始值。
transform(values.begin(),values.end(),cubes.begin(),
[](double x)mutable -double{
index += 10; // change original value
return index*x*x*x;});
现在采用按引用使用,则会改变index的原始值。
若要捕获一个特定的变量,则:
transform(values.begin(),values.end(),cubes.begin(),
[index](double x)mutable -double{
index += 10; // change original value
return index*x*x*x;});
这样,只捕获index,如要捕获多个变量,中间用逗号隔开即可。
Lambda也可以包含throw()异常说明,如:
transform(values.begin(),values.end(),cubes.begin(),
[index](double x)mutable throw()-double{
index += 10; // change original value
return index*x*x*x;});
如果想要包含mutable说明和throw()说明,则中间必须用一个或多个空格隔开。
现在综合看个实例,用以前说过的函数模板实现。
Marching Cubes算法(医学图像三维绘制中的面绘制)2007-08-16 00:50建议要看的资料
[1] Lorensen W E, Cline H E .Marching cubes: a high-resoulution 3D suface construction algorithm [J], Computer Graphics,1987, 21(4):163~169
[2]集成化医学影像算法平台理论与实践田捷,赵明昌,何晖光 清华大学出版社2004年10月
[3]Polygonising a scalar field Also known as: "3D Contouring", "Marching Cubes", "Surface Reconstruction"
Cubes;
[4]
Marching Cubes算法工作原理
Marching Cubes算法是三维数据场等值面生成的经典算法,是体素单元内等值面抽取技术的代表。
等值面是空间中所有具有某个相同值的点的集合。它可以表示为, ,c是常数。则称F(f)为体数据f中的等值面。
在MC算法中,假定原始数据是离散的三维空间规则数据场。用于医疗诊断的断层扫描(CT)及核磁共振成像(MRI) 等产生的图像均属于这一类型。MC算法的基本思想是逐个处理数据场中的体素,分类出与等值面相交的体素,采用插值计算出等值面与体素棱边的交点。根据体素中每一顶点与等值面的相对位置,将等值面与立方体边的交点按一定方式连接生成等值面,作为等值面在该立方体内的一个逼近表示。在计算出关于体数据场内等值面的有关参数后山常用的图形软件包或硬件提供的面绘制功能绘制出等值面。
图2.1 离散的三维空间规则数据场中的一个体素
2.1.1 MC算法的主要步骤
1. 确定包含等值面的体素
离散的三维空间规则数据场中的一个体素可以用图2.1表示。8个数据点分别位于该体素的8个角点上。MC算法的基本假设是:沿着体素的边其数据场呈局部连续线性变化,根据这个假设,可认为,如果两个相邻采样点一个为正点,一个为负点,则它们连成的边上一定存在且仅有一个等值点 (设等值面值为c)。如果得到了体素各条边上的等值点,就可以以这些点为顶点,用一系列的三角形拟合出该体素中的等值面。因此确定立方体体素中等值面的分布是该算法的基础。
首先对体素的8个顶点进行分类,以判断其顶点是位于等值面之外,还是位于等值面之内。再根据8个顶点的状态,确定等值面的剖分模式。顶点分类规则为:
1. 如体素顶点的数据值大于或等于等值面的值,则定义该顶点位于等值面之外, 记为正点,即“1“
2. 如体素顶点的数据值小于等值面的值,则定义该顶点位于等值面之内,记为负点, 即“0"
由于每个体素共有8个顶点,且每个顶点有正负两种状态,所以等值面可能以 =256种方式与一个体素相交。通过列举出这256种情况,就能创建一张表格,利用它可以查出任意体素中的等值面的三角面片表示。如果考虑互补对称性,将等值面的值和8个角点的函数值的大小关系颠倒过来,即将体素的顶点标记置反(0变为1, 1变为0),这样做不会影响该体素的8个角点和等值面之间的拓扑结构,可将256种方式简化成128种。其次,再利用旋转对称性,可将这128种构型进一步简化成15种。图3.2给出了这15种基本构型[131其中黑点标记为“1”的角点。
图2.2 分布状态表
图2.3 体素角点分布不同情况
基于上面的分析,MC算法中用一个字节的空间构造了一个体素状态表,如图2.2所示,该状态表中的每一位可表示出该体元中的一个角点的0或1的状态。根据这一状态表,就可知道当前体素属于图2.3中哪一种情况,以及等值面将与哪一条边相交。
2.求等值面与体元边界的交点
在确定体素内三角剖分模式后,就要计算三角片顶点位置。当三维离散数据场的密度较高时,即当体素很小时,可以假定函数值沿体素边界呈线性变化,这就是MC算法的基本假设。因此,根据这一基本假设,可以直接用线性插值计算等值面与体素边的交点。
对于当前被处理体素的某一条边,如果其两顶点 , 的标记值不同,那么等值面一定与此边相交,且仅有一个交点。交点为 其中P代表等值点坐标, , 代表两个端点的坐标, , 代表两个端点的灰度值,v代表域值。求出等值面与体素棱边的交点以后,就可以将这些交点连接成三角形或多边形,形成等值面的一部分。
3.等值面的法向量计算
为了利用图形硬件显示等值面图象,必须给出形成等值面的各三角面片的法向分量,选择适当的局部面光照模型进行光照计算,以生成真实感图形。
对于等值面上的每一点,其沿面的切线方向的梯度分量应该是零,因此,该点的梯度矢量的方向也就代表了等值面在该点的法向量,当梯度值非零。所幸的是等值面往往是由两种具有不同密度的物质的分解面,因此其上的每点的梯度矢量均不为零,即
Mc算法采用中心差分方法求采样点p〔m ,n, k ) 处的梯度矢量,公式如下:
Gx=〔g(i+1,j,k)-g(i-1,j,k)〕/2dx
Gy=〔g(i,j+1,k)-g(i,j-1,k)〕/2dy
Gz=〔g(i,j,k+1)-g(i,j,k-1)〕/2dz
其中D(i,j ,k)是切片k在像素(i,j)的密度, , , 是立方体边的长度。对g进行归一化,得到(gx/|g|,gy/|g|,gz/|g|)作为(i,j,k)上的单位法向量。然后,对体素八个顶点上法向量进行线性插值就可得到位于体素棱边上的三角片的各个顶点上的法向量。设计算得到的某个三角片的三个顶点上的单位法向量分别为( , 和 ),这个三角片的几何重心为 ,则该三角片的法向量起始于 ,终止于 。代入Gourand光照模型公式,就可计算出小三角片表面的光强(灰度)。将其投影在某个特定的二维平面上进行显示,从而显示出物体富有光感的整个表面形态。其中我们在内存中保留四个切片来计算立方体中所有顶点梯度。
2.1.2 MC算法流程
1、将三维离散规则数据场分层读入内存;
2、扫描两层数据,逐个构造体素,每个体素中的8个角点取自相邻的两层;
3、将体素每个角点的函数值与给定的等值面值c做比较,根据比较结果,构造
该体素的状态表;
4、根据状态表,得出将与等值面有交点的边界体素;
5、通过线性插值方法计算出体素棱边与等值面的交点;
6、利用中心差分方法,求出体素各角点处的法向量,再通过线性插值方法,求出三角面片各顶点处的法向;
7,根据各三角面片上各顶点的坐标及法向量绘制等值面图像。
========================================================
MC代码
MarchingCubes(float lowThreshold,float highThreshold,float XSpace,float YSpace,float ZSpace)
{
//记录生成的顶点数和面数初始时应该为0
m_vNumber=0;
m_fNumber=0;
//当前Cube中生成的顶点和面数
int vertPos,facePos;
//包围盒的尺寸 用于绘制程序计算整个场景的包围盒,用于调整观察位置,以使整个场景尽可能占满整个窗口。
float min[3],max[3];
min[0]=min[1]=min[2]=max[0]=max[1]=max[2]=0;//初始化
//当前扫描层的切片数据和一个临时的切片数据
short *pSliceA,*pSliceB,*pSliceC,*pSliceD,*tempSlice;
pSliceA=pSliceB=pSliceC=tempSlice=NULL;
int imageWidth,imageHeight,imageSize,sliceNumber;
imageWidth=imageHeight=512;//我们是512×512的数据
imageSize=imageWidth*imageHeight;
sliceNumber=m_FileCount-1;
if((highThreshold*lowThreshold)==0)
{
return 0;
}
pSliceD =new short [imageSize];
//因为等值面是每相邻两层切片为单位进行提取的,所以在处理后两层切片时难免生成前两层切片已经生成的顶点,这时候就用下面的数组记录哪些边上的顶点已经生成了,如果遇到已经生成的顶点就不再重复计算而是直接使用记录的索引,否则就生成新的顶点。
long *bottomXEdge=new long[imageSize];
long *bottomYEdge=new long[imageSize];
long *topXEdge=new long[imageSize];
long *topYEdge=new long[imageSize];
long *zEdge=new long[imageSize];
tempSlice=new short [imageSize];
if(bottomXEdge==NULL||bottomYEdge==NULL||
topXEdge==NULL||topYEdge==NULL||
zEdge==NULL||tempSlice==NULL)
{
return 0;//错误
}
//初始化数据
memset(bottomXEdge,-1,sizeof(long)*imageSize);
memset(bottomYEdge,-1,sizeof(long)*imageSize);
memset(topXEdge,-1,sizeof(long)*imageSize);
memset(topYEdge,-1,sizeof(long)*imageSize);
memset(zEdge,-1,sizeof(long)*imageSize);
memset(tempSlice,0,sizeof(short)*imageSize);
//计算某一层顶点和三角时所需要的一些变量
//一些循环变量
int i,j,k,w,r;
//cube类型
unsigned char cubeType(0);
//计算法向量
float dx[8],dy[8],dz[8],squaroot;
//记录某个Cube生成
float vertPoint[12][6];
int cellVerts[12]; //what use
int triIndex[5][3]; //每个cube最多生成5条边
//用于记录已生成顶点索引的临时变量
int offset;
//当前cube8个顶点的灰度值
short cubegrid[8];
long *edgeGroup;
//得到数据
pSliceD=m_volumeData;
pSliceB=tempSlice;
pSliceA=tempSlice;
int tt,tt1;
//扫描4层切片的顺序
/*
-----------------------D |
-----------------------B |
-----------------------C |
-----------------------A |
V
*/
//marching cubes 算法开始实行 ?第一次循环时,只读入一个切片?
for(i=0;i=(sliceNumber);i++)
{
pSliceC=pSliceA;
pSliceA=pSliceB;
pSliceB=pSliceD;
if(i=sliceNumber-2)
{
pSliceD=tempSlice;
}
else
{
pSliceD+=imageSize;
}
for(j=0;jimageHeight-1;++j)
for(k=0;kimageWidth-1;++k)
/* for(j=10;jimageHeight-5;j++)//调试用
for(k=10;kimageWidth-5;k++)*/
{
//得到八个顶点的灰度值step0
cubegrid[0]=pSliceA[j*imageWidth+k];
cubegrid[1]=pSliceA[j*imageWidth+k+1];
cubegrid[2]=pSliceA[(j+1)*imageWidth+k+1];
cubegrid[3]=pSliceA[(j+1)*imageWidth+k];
cubegrid[4]=pSliceB[j*imageWidth+k];
cubegrid[5]=pSliceB[j*imageWidth+k+1];
cubegrid[6]=pSliceB[(j+1)*imageWidth+k+1];
cubegrid[7]=pSliceB[(j+1)*imageWidth+k];
//计算cube的类型
cubeType=0;
for(w=0;w8;w++)
{
if((cubegrid[w]lowThreshold)(cubegrid[w]highThreshold))//需要画的点
{
cubeType|=(1w);
}
}//end for计算cube的类型
if(cubeType==0||cubeType==255)
{
continue;
}
for(w=0;w12;w++) //初始化cellVerts表到零
{
cellVerts[w]=-1;
}
//计算6个方向相邻点的象素差值(用于计算法向量)
if(k==0)
{
dx[0]=pSliceA[j*imageWidth+1];
dx[3]=pSliceA[(j+1)*imageWidth+1];
dx[4]=pSliceB[j*imageWidth+1];
dx[7]=pSliceB[(j+1)*imageWidth+1];
}
else
{
dx[0]=pSliceA[j*imageWidth+k+1]
-pSliceA[j*imageWidth+k-1];
dx[3]=pSliceA[(j+1)*imageWidth+k+1]
-pSliceA[(j+1)*imageWidth+k-1];
dx[4]=pSliceB[j*imageWidth+k+1]
-pSliceB[j*imageWidth+k-1];
dx[7]=pSliceB[(j+1)*imageWidth+k+1]
-pSliceB[(j+1)*imageWidth+k-1];
}
if(k==imageWidth-2)
{
dx[1]=-pSliceA[j*imageWidth+imageWidth-2];
dx[2]=-pSliceA[(j+1)*imageWidth+imageWidth-2];
dx[5]=-pSliceB[j*imageWidth+imageWidth-2];
dx[6]=-pSliceB[(j+1)*imageWidth+imageWidth-2];
}
else
{
dx[1]=pSliceA[j*imageWidth+k+2]
-pSliceA[j*imageWidth+k];
dx[2]=pSliceA[(j+1)*imageWidth+k+2]
-pSliceA[(j+1)*imageWidth+k];
dx[5]=pSliceB[j*imageWidth+k+2]
-pSliceB[j*imageWidth+k];
dx[6]=pSliceB[(j+1)*imageWidth+k+2]
-pSliceB[(j+1)*imageWidth+k];
}
if(j==0)
{
dy[0]=pSliceA[imageWidth+k];
dy[1]=pSliceA[imageWidth+k+1];
dy[4]=pSliceB[imageWidth+k];
dy[5]=pSliceB[imageWidth+k+1];
}
else
{
dy[0]=pSliceA[(j+1)*imageWidth+k]
-pSliceA[(j-1)*imageWidth+k];
dy[1]=pSliceA[(j+1)*imageWidth+k+1]
-pSliceA[(j-1)*imageWidth+k+1];
dy[4]=pSliceB[(j+1)*imageWidth+k]
-pSliceB[(j-1)*imageWidth+k];
dy[5]=pSliceB[(j+1)*imageWidth+k+1]
-pSliceB[(j-1)*imageWidth+k+1];
}
if(j==imageHeight-2)
{
dy[2]=-pSliceA[(imageHeight-2)*imageWidth+k+1];
dy[3]=-pSliceA[(imageHeight-2)*imageWidth+k];
dy[6]=-pSliceB[(imageHeight-2)*imageWidth+k+1];
dy[7]=-pSliceB[(imageHeight-2)*imageWidth+k];
}
else
{
dy[2]=pSliceA[(j+2)*imageWidth+k+1]-pSliceA[j*imageWidth+k+1];
dy[3]=pSliceA[(j+2)*imageWidth+k]-pSliceA[j*imageWidth+k];
dy[6]=pSliceB[(j+2)*imageWidth+k+1]-pSliceB[j*imageWidth+k+1];
dy[7]=pSliceB[(j+2)*imageWidth+k]-pSliceB[j*imageWidth+k];
}
dz[0]=pSliceB[j*imageWidth+k]
-pSliceC[j*imageWidth+k];
dz[1]=pSliceB[j*imageWidth+k+1]
-pSliceC[j*imageWidth+k+1];
dz[2]=pSliceB[(j+1)*imageWidth+k+1]
-pSliceC[(j+1)*imageWidth+k+1];
dz[3]=pSliceB[(j+1)*imageWidth+k]
-pSliceC[(j+1)*imageWidth+k];
dz[4]=pSliceD[j*imageWidth+k]
-pSliceA[j*imageWidth+k];
dz[5]=pSliceD[j*imageWidth+k+1]
-pSliceA[j*imageWidth+k+1];
dz[6]=pSliceD[(j+1)*imageWidth+k+1]
-pSliceA[(j+1)*imageWidth+k+1];
dz[7]=pSliceD[(j+1)*imageWidth+k]
-pSliceA[(j+1)*imageWidth+k];
//计算三角形顶点的坐标和梯度
vertPos=0;
facePos=0;
for(w=0;w12;w++)
{
if(g_EdgeTable[cubeType](1w)) //what …..
{
//根据g_edgeTable[256]对应值判断cube的那一条边与等值面有交点
switch(w)
{
case 0:
offset=j*imageWidth+k;
edgeGroup=bottomXEdge;
break;
case 1:
offset=j*imageWidth+k+1;
edgeGroup=bottomYEdge;
break;
case 2:
offset=(j+1)*imageWidth+k;
edgeGroup=bottomXEdge;
break;
case 3:
offset=j*imageWidth+k;
edgeGroup=bottomYEdge;
break;
case 4:
offset=j*imageWidth+k;
edgeGroup=topXEdge;
break;
case 5:
offset=j*imageWidth+k+1;
edgeGroup=topYEdge;
break;
case 6:
offset=(j+1)*imageWidth+k;
edgeGroup=topXEdge;
break;
case 7:
offset=j*imageWidth+k;
edgeGroup=topYEdge;
break;
case 8:
offset=j*imageWidth+k;
edgeGroup=zEdge;
break;
case 9:
offset=j*imageWidth+k+1;
edgeGroup=zEdge;
break;
case 10:
offset=(j+1)*imageWidth+k+1;
edgeGroup=zEdge;
break;
case 11:
offset=(j+1)*imageWidth+k;
edgeGroup=zEdge;
break;
}//对应switch的{。。。end for//根据g_EdgeTable对应值判断cube的那一条边与等值面有交点
//该边上的顶点是否已经在上一层中生成
if(edgeGroup[offset]==-1)
{
int index1,index2;
short s1,s2,s;
float x1,y1,z1,nx1,ny1,nz1;
float x2,y2,z2,nx2,ny2,nz2;
//得到该边两端点的索引进而得到两点的灰度值
index1=g_CoordTable[w][3];
index2=g_CoordTable[w][4];
s1=cubegrid[index1];
s2=cubegrid[index2];
if(s1highThresholds1lowThreshold)
{
if(s2=highThreshold)
{
s=highThreshold;
}
else if(s2=lowThreshold)
{
s=lowThreshold;
}
}
else if(s2highThresholds2lowThreshold)
{
if(s1=highThreshold)
{
s=highThreshold;
}
else if(s1=lowThreshold)
{
s=lowThreshold;
}
}
//计算两端点实际坐标
x1=(k+g_CoordVertex[index1][0])*XSpace;
y1=(j+g_CoordVertex[index1][1])*YSpace;
z1=(i+g_CoordVertex[index1][2])*ZSpace;
x2=(k+g_CoordVertex[index2][0])*XSpace;
y2=(j+g_CoordVertex[index2][1])*YSpace;
z2=(i+g_CoordVertex[index2][2])*ZSpace;
//计算两端点的法向量
nx1=dx[index1]/XSpace;
ny1=dy[index1]/YSpace;
nz1=dz[index1]/ZSpace;
nx2=dx[index2]/XSpace;
ny2=dy[index2]/YSpace;
nz2=dz[index2]/ZSpace;
float factor=((float)(s-s1))/((float)(s2-s1));
//插值计算交点坐标
vertPoint[vertPos][0]=factor*(x2-x1)+x1;
vertPoint[vertPos][1]=factor*(y2-y1)+y1;
vertPoint[vertPos][2]=factor*(z2-z1)+z1;
//计算法向量
vertPoint[vertPos][3]=factor*(nx1-nx2)-nx1;
vertPoint[vertPos][4]=factor*(ny1-ny2)-ny1;
vertPoint[vertPos][5]=factor*(nz1-nz2)-nz1;
//法向量归一化
squaroot=sqrt(vertPoint[vertPos][3]*vertPoint[vertPos][3]+vertPoint[vertPos][4]*vertPoint[vertPos][4]
+vertPoint[vertPos][5]*vertPoint[vertPos][5]);
if(squaroot=0)squaroot=1.0;
vertPoint[vertPos][3]/=squaroot;
vertPoint[vertPos][4]/=squaroot;
vertPoint[vertPos][5]/=squaroot;
//更新包围盒数据
if(min[0]vertPoint[vertPos][0])
{
min[0]=vertPoint[vertPos][0];
}
if(min[1]vertPoint[vertPos][1])
{
min[1]=vertPoint[vertPos][1];
}
if(min[2]vertPoint[vertPos][2])
{
min[2]=vertPoint[vertPos][2];
}
if(max[0]vertPoint[vertPos][0])
{
max[0]=vertPoint[vertPos][0];
}
if(max[1]vertPoint[vertPos][1])
{
max[1]=vertPoint[vertPos][1];
}
if(max[2]vertPoint[vertPos][2])
{
max[2]=vertPoint[vertPos][2];
}
//记录新生成的顶点索引
cellVerts[w]=m_vNumber;
edgeGroup[offset]=cellVerts[w];
m_vNumber++;
vertPos++;
} //end if(edgeGroup[offset]==-1) ////
else
{
//若该点已经在上一层生成,则直接得到其索引
cellVerts[w]=edgeGroup[offset];
}
} // end对应if(g_EdgeTable[cubeType](1w)) //
} //对应for(w=0;w12;w++)
//保存当前cubes 顶点和法向量
tt1=m_vNumber-vertPos;
for(tt=0;ttvertPos;tt++)
{
vPointNomal[tt1+tt][0]=vertPoint[tt][0];
vPointNomal[tt1+tt][1]=vertPoint[tt][1];
vPointNomal[tt1+tt][2]=vertPoint[tt][2];
vPointNomal[tt1+tt][3]=vertPoint[tt][3];
vPointNomal[tt1+tt][4]=vertPoint[tt][4];
vPointNomal[tt1+tt][5]=vertPoint[tt][5];
}
// memcpy(vPointNomal+6*(m_vNumber-vertPos) ,vertPoint,sizeof(float)*6*vertPos);
//记录新生成的三角面片数据
w=0;
while (g_TriTable[cubeType][w]!=-1)
{
for(r=0;r3;r++)
{
triIndex[facePos][r]=cellVerts[g_TriTable[cubeType][w++]];
if(triIndex[facePos][r]0)
{
AfxMessageBox("有问题",MB_OK,0);
}
}
facePos++;
m_fNumber++;
} //end 对应while (g_TriTable[cubeType][w]!=-1)
//保存面数据
tt1=m_fNumber-facePos;
for(tt=0;ttfacePos;tt++)
{
pFace[tt1+tt][0]=triIndex[tt][0];
pFace[tt1+tt][1]=triIndex[tt][1];
pFace[tt1+tt][2]=triIndex[tt][2];
}
// memcpy(pFace+3*(m_fNumber-facePos)*sizeof(long),triIndex,sizeof(int)*3*facePos);
} memcpy(bottomXEdge,topXEdge,sizeof(short)*imageSize);
memcpy(bottomYEdge,topYEdge,sizeof(short)*imageSize);
memset(topXEdge,-1,sizeof(short)*imageSize);
memset(topYEdge,-1,sizeof(short)*imageSize);
memset(zEdge,-1,sizeof(short)*imageSize);
}
delete []tempSlice;
delete []bottomXEdge;
delete []bottomYEdge;
delete []topXEdge;
delete []topYEdge;
delete []zEdge;
return 1;
}
在OnDraw
glBegin(GL_TRIANGLES);
for(i=0;ipDoc-m_fNumber;i++)
{
glNormal3fv((pDoc-vPointNomal[pDoc-pFace[ i][0]][3]));
glVertex3fv((pDoc-vPointNomal[pDoc-pFace[ i][0]][0]));
glNormal3fv((pDoc-vPointNomal[pDoc-pFace[ i ][1]][3]));
glVertex3fv((pDoc-vPointNomal[pDoc-pFace[ i ][1]][0]));
glNormal3fv((pDoc-vPointNomal[pDoc-pFace[ i ][2]][3]));
glVertex3fv((pDoc-vPointNomal[pDoc-pFace[ i ][2]][0]));
}
glEnd();
以上代码只用于理解,未测试
本原代码是基于C语言的原程序。是经典中的小游戏。-primitive code is based on the C language of the original procedure. Classic is a small game.
一个小游戏,用C语言编写的:俄罗斯方块.C原码及应用程序都在里面哦 -a small game using the C language : Russian cubes. The original C code and application procedures inside oh
十全十美游戏原程序,c语言-perfect game program, language c
上数据结构时,自己用C语言做的小游戏,做得不好,请大家原谅。-structure on the data they used C language to the small games, done well, please forgive me.
大家都耍过文曲星中的猜数字的游戏吧 !! 最近我在学习C语言。写了个菜鸟的C语言的猜数字的游戏程序的原代码-rings off the viewing of the game! ! I recently learning C language. Wrote a birdie C language viewing of the games original code procedures
这是我在大学二年级学习C语言课程时,作为“练笔”而编写的一个小程序(当时在我眼里可却是一个大程序!)其主要特点有:1、正真做到了全中文界面(不需要UCDOS操作系支持) 2、大量的图形特技(如图像的显隐技术、图像穿插技术、多任务仿真技术等) 3、纯C语言打造(不含任何C++知识) 4、实现了街机“俄罗斯方块”绝大部分功能(如动画、声音、速度变化) 5、用户可根据自据的习惯自由地调整“游戏操作键” 6、方法独特,全部语句和技术都是我本人原创,没有参考过任何相关代码 7、防“跟踪调试”技术,防“版权篡改”技术 8、……-
这个程序是模仿Windows中的扫雷小游戏制作的,该程序只是实现了扫雷游戏的主体部分,诸如计分、升级部分都没有做。这个程序可以作为初学者学习C语言绘图和游戏的实例。 该程序在Turbo C2.0 下编译通过 由于扫雷游戏是用鼠标操作的,而Turbo C中提供的鼠标驱动程序在Windows xp下不可用,所以我随源程序提供了一个鼠标驱动的头文件,须将将该头文件复制到Turbo C2.0 的安装目录下的“include”文件夹中方可编译或运行,也可自行修改原文件使之包含该投文件。 注:该鼠标驱动程序是我在网上找到的,其出处我已无法考证,如果侵犯了作者的权利还请作者与我联系。 由于在我的电脑上Turbo C图形环境下显示数字会有问题(估计是系统问题),所以程序中雷周围的数字1-8我用a-h代替,看不顺眼的可以自己修改原程序。-
c语言 猜拳游戏的原代码就是这个 已经测试成功了呀-language of the original game is the code has been tested successfully ah
俄罗斯方块对战版c语言原代码。希望大家能喜欢。是比较简单的一个代码,游戏开发高手请指教。-Tetris screen version of the original C language code. Hope you will like. It is a relatively simple code, game development experts please advise.
用linuX 下的C语言 运用CURSES编写的俄罗斯方块游戏,很好,这个是本人原创,值得参考-linuX use the C language CURSES prepared by the Russian box game, well, this is the original, worthy of reference
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流