www.pudn.com > 林海血原源代码.zip > CMath.cpp
// CMath.cpp: implementation of the CMath class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CMath.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMath::CMath()
{}
CMath::~CMath()
{}
/////////////////////////////
bool CMath::IsLineSegmentCutByPolygon(VERTEX v1 ,VERTEX v2,VERTEX* pv,int num)
{
if(num<3)return false;
PLANE plane;
plane=GetPlaneEquation(pv,num);
///////////如果两点在同一侧
if((ClassifyPointPlane(v1,plane)*ClassifyPointPlane(v2,plane))>=0)
return false;
//////////////获得线段与平面的交点
VERTEX intersection;
intersection=GetIntersection(v1,v2,plane);
///////////包围盒粗略判断
float maxx,minx, maxy,miny, maxz,minz;
maxx=minx=pv[0].xpos;
maxy=miny=pv[0].ypos;
maxz=minz=pv[0].zpos;
for(int i=1;imaxx)maxx=pv[i].xpos;
if(pv[i].xposmaxy)maxy=pv[i].ypos;
if(pv[i].yposmaxz)maxz=pv[i].zpos;
if(pv[i].zposmaxx || intersection.xposmaxy || intersection.yposmaxz || intersection.zposabsC)
{ //////比较 Z 轴坐标
VERTEX sect[6];/////可能有重复的交点,如顶点
int index=0;
for( i=0;i<(num-1);i++)
{
if(ClassifyPointPlane(pv[i],p)!=ClassifyPointPlane(pv[i+1],p))
{
sect[index]=GetIntersection(pv[i],pv[i+1],p);
index++;
}
}
if(ClassifyPointPlane(pv[0],p)!=ClassifyPointPlane(pv[num-1],p))
{
sect[index]=GetIntersection(pv[0],pv[num-1],p);
index++;
}
/////////////////////////////
float maxzz,minzz;
maxzz=minzz=sect[0].zpos;
for(i=0;imaxzz)maxzz=sect[i].zpos;
if(sect[i].zposmaxzz || intersection.zposmaxyy)maxyy=sect[i].ypos;
if(sect[i].yposmaxyy || intersection.yposabsC)
{ //////比较 Z 轴坐标
VERTEX sect[6];/////可能有重复的交点,如顶点
int index=0;
for( i=0;i<(num-1);i++)
{
if(ClassifyPointPlane(pv[i],p)!=ClassifyPointPlane(pv[i+1],p))
{
sect[index]=GetIntersection(pv[i],pv[i+1],p);
index++;
}
}
if(ClassifyPointPlane(pv[0],p)!=ClassifyPointPlane(pv[num-1],p))
{
sect[index]=GetIntersection(pv[0],pv[num-1],p);
index++;
}
/////////////////////////////
float maxzz,minzz;
maxzz=minzz=sect[0].zpos;
for(i=0;imaxzz)maxzz=sect[i].zpos;
if(sect[i].zposmaxzz || intersection.zposmaxxx)maxxx=sect[i].xpos;
if(sect[i].xposmaxxx || intersection.xposabsB)
{ //////比较 Y 轴坐标
VERTEX sect[6];/////可能有重复的交点,如顶点
int index=0;
for( i=0;i<(num-1);i++)
{
if(ClassifyPointPlane(pv[i],p)!=ClassifyPointPlane(pv[i+1],p))
{
sect[index]=GetIntersection(pv[i],pv[i+1],p);
index++;
}
}
if(ClassifyPointPlane(pv[0],p)!=ClassifyPointPlane(pv[num-1],p))
{
sect[index]=GetIntersection(pv[0],pv[num-1],p);
index++;
}
/////////////////////////////
float maxyy,minyy;
maxyy=minyy=sect[0].ypos;
for(i=0;imaxyy)maxyy=sect[i].ypos;
if(sect[i].yposmaxyy || intersection.yposmaxxx)maxxx=sect[i].xpos;
if(sect[i].xposmaxxx || intersection.xposbd.maxx && v2.xpos>bd.maxx)return false;
if(v1.xposbd.maxy && v2.ypos>bd.maxy)return false;
if(v1.yposbd.maxz && v2.zpos>bd.maxz)return false;
if(v1.zpos=0)
return false;
//////////////获得线段与平面的交点
VERTEX intersection;
intersection=GetIntersection(v1,v2,plane);
///////////包围盒判断
float maxx,minx, maxy,miny, maxz,minz;
maxx=minx=va.xpos;
maxy=miny=va.ypos;
maxz=minz=va.zpos;
if(vb.xpos>maxx)maxx=vb.xpos;
if(vb.xposmaxy)maxy=vb.ypos;
if(vb.yposmaxz)maxz=vb.zpos;
if(vb.zposmaxx)maxx=vc.xpos;
if(vc.xposmaxy)maxy=vc.ypos;
if(vc.yposmaxz)maxz=vc.zpos;
if(vc.zposmaxx)maxx=vd.xpos;
if(vd.xposmaxy)maxy=vd.ypos;
if(vd.yposmaxz)maxz=vd.zpos;
if(vd.zposmaxx || intersection.xposmaxy || intersection.yposmaxz || intersection.zposxpos+plane.B*pVertices->ypos+plane.C*pVertices->zpos);
}
return plane;
}
PLANE CMath::GetPlaneEquation(VERTEX v1,VERTEX v2,VERTEX v3)
{
PLANE plane;
NORMAL N12,N13,N;
////////////calculate n12 n13
N12.nx=v2.xpos-v1.xpos;
N12.ny=v2.ypos-v1.ypos;
N12.nz=v2.zpos-v1.zpos;
N13.nx=v3.xpos-v1.xpos;
N13.ny=v3.ypos-v1.ypos;
N13.nz=v3.zpos-v1.zpos;
N=GetTwoNormalProduct(N12,N13);
plane.A=N.nx;
plane.B=N.ny;
plane.C=N.nz;
plane.D= -(plane.A*v1.xpos+plane.B*v1.ypos+plane.C*v1.zpos);
return plane;
}
PLANE CMath::GetPlaneEquation(VERTEX v,PLANE p1,PLANE p2)
{
PLANE plane;
NORMAL n1,n2,normal;
n1.nx=p1.A; n1.ny=p1.B; n1.nz=p1.C;
n2.nx=p2.A; n2.ny=p2.B; n2.nz=p2.C;
normal=GetTwoNormalProduct(n1,n2);
plane.A=normal.nx;
plane.B=normal.ny;
plane.C=normal.nz;
plane.D=-(plane.A*v.xpos+plane.B*v.ypos+plane.C*v.zpos);
return plane;
}
VERTEX CMath::GetIntersection(VERTEX v1,VERTEX v2,PLANE plane)
{
VERTEX point;
double temp1=(plane.A*(v2.xpos-v1.xpos)+plane.B*(v2.ypos-v1.ypos)+plane.C*(v2.zpos-v1.zpos));
double temp2=-plane.D-plane.A*v1.xpos-plane.B*v1.ypos-plane.C*v1.zpos;
///// Line param is temp2/temp1
point.xpos=v1.xpos+float((double(v2.xpos-v1.xpos)*temp2)/temp1);
point.ypos=v1.ypos+float((double(v2.ypos-v1.ypos)*temp2)/temp1);
point.zpos=v1.zpos+float((double(v2.zpos-v1.zpos)*temp2)/temp1);
return point;
}
TEXCOORD CMath::GetIntersectionTexCoord(VERTEX pointA,TEXCOORD texcoordA,
VERTEX pointB,TEXCOORD texcoordB, PLANE plane)
{
VERTEX intersect=GetIntersection(pointA,pointB,plane);
float distA=GetDistance(pointA,intersect);
float distAB=GetDistance(pointA,pointB);
if(distAB<0.0001)return texcoordA; ///////safe
TEXCOORD texcoord;
texcoord.u=(texcoordA.u*distAB + distA*(texcoordB.u-texcoordA.u))/distAB;
texcoord.v=(texcoordA.v*distAB + distA*(texcoordB.v-texcoordA.v))/distAB;
return texcoord;
}
VERTEX CMath::GetPositionOnGrid(VERTEX *pQuads,float u,float v)
{
/////////u,v 的范围为0-1
if(u<0)u=0; if(u>1)u=1;
if(v<0)v=0; if(v>1)v=1;
//////////////////////////////////////
VERTEX v1,v2; //与u相关的两条边上的点
v1=VERTEX(pQuads[0].xpos+(pQuads[1].xpos-pQuads[0].xpos)*u,
pQuads[0].ypos+(pQuads[1].ypos-pQuads[0].ypos)*u,
pQuads[0].zpos+(pQuads[1].zpos-pQuads[0].zpos)*u);
v2=VERTEX(pQuads[3].xpos+(pQuads[2].xpos-pQuads[3].xpos)*u,
pQuads[3].ypos+(pQuads[2].ypos-pQuads[3].ypos)*u,
pQuads[3].zpos+(pQuads[2].zpos-pQuads[3].zpos)*u);
///////////////////////////////////////
VERTEX vertex; ///所求的点
vertex.xpos=v1.xpos+(v2.xpos-v1.xpos)*v;
vertex.ypos=v1.ypos+(v2.ypos-v1.ypos)*v;
vertex.zpos=v1.zpos+(v2.zpos-v1.zpos)*v;
return vertex;
}
NORMAL CMath::GetTwoNormalProduct(NORMAL n1,NORMAL n2)
{
double n1x,n1y,n1z,n2x,n2y,n2z;
n1x=n1.nx; n1y=n1.ny; n1z=n1.nz;
n2x=n2.nx; n2y=n2.ny; n2z=n2.nz;
double nx,ny,nz;
nx= n1y*n2z-n2y*n1z;
ny=-(n1x*n2z-n2x*n1z);
nz= n1x*n2y-n2x*n1y;
// return NORMAL(float(nx),float(ny),float(nz));
return Normalization(nx,ny,nz);
}
NORMAL CMath::GetNormal(VERTEX v1,VERTEX v2,VERTEX v3)
{
NORMAL n1,n2;
n1.nx=v2.xpos-v1.xpos;
n1.ny=v2.ypos-v1.ypos;
n1.nz=v2.zpos-v1.zpos;
n2.nx=v3.xpos-v1.xpos;
n2.ny=v3.ypos-v1.ypos;
n2.nz=v3.zpos-v1.zpos;
return GetTwoNormalProduct(n1,n2);
}
NORMAL CMath::GetNormal(float *v1,float *v2,float *v3)
{
NORMAL n1,n2;
n1.nx=v2[0]-v1[0];
n1.ny=v2[1]-v1[1];
n1.nz=v2[2]-v1[2];
n2.nx=v3[0]-v1[0];
n2.ny=v3[1]-v1[1];
n2.nz=v3[2]-v1[2];
return GetTwoNormalProduct(n1,n2);
}
float CMath::GetTwoVectorAngleCosine(NORMAL na,NORMAL nb)
{
NORMAL n1,n2;
n1=Normalization(na);
n2=Normalization(nb);
double temp,length1,length2;
temp=n1.nx*n2.nx+n1.ny*n2.ny+n1.nz*n2.nz;
length1=pow( n1.nx*n1.nx +n1.ny*n1.ny +n1.nz*n1.nz,0.5);
length2=pow( n2.nx*n2.nx +n2.ny*n2.ny +n2.nz*n2.nz,0.5);
return float(temp/(length1*length2));
}
float CMath::GetDistance(VERTEX v1,VERTEX v2)
{
float dist;
dist=(float)pow((v2.xpos-v1.xpos)*(v2.xpos-v1.xpos)+
(v2.ypos-v1.ypos)*(v2.ypos-v1.ypos)+
(v2.zpos-v1.zpos)*(v2.zpos-v1.zpos),0.5);
return dist;
}
float CMath::GetDistance(VERTEX point,PLANE plane)
{
float abc=(float)sqrt(plane.A*plane.A+plane.B*plane.B+plane.C*plane.C);
float dist=(plane.A*point.xpos+plane.B*point.ypos+plane.C*point.zpos+plane.D)/abc;
if(dist<0)dist=-dist;
return dist;
}
float CMath::GetDistance(VERTEX point,PLANE plane,float powABC)
{
return (plane.A*point.xpos+plane.B*point.ypos+plane.C*point.zpos+plane.D)/powABC;
}
float CMath::GetTwoVectorAngleCosine(VERTEX v1,VERTEX vCenter,VERTEX v2)
{
double temp,length1,length2;
double n1nx,n1ny,n1nz,n2nx,n2ny,n2nz;
n1nx=v1.xpos-vCenter.xpos;
n1ny=v1.ypos-vCenter.ypos;
n1nz=v1.zpos-vCenter.zpos;
n2nx=v2.xpos-vCenter.xpos;
n2ny=v2.ypos-vCenter.ypos;
n2nz=v2.zpos-vCenter.zpos;
temp=n1nx*n2nx+n1ny*n2ny+n1nz*n2nz;
length1=pow( n1nx*n1nx +n1ny*n1ny +n1nz*n1nz,0.5);
length2=pow( n2nx*n2nx +n2ny*n2ny +n2nz*n2nz,0.5);
return float(temp/(length1*length2));
}
int CMath::ClassifyTwoNormal(NORMAL n1,NORMAL n2)
{
float temp;
temp=n1.nx*n2.nx+n1.ny*n2.ny+n1.nz*n2.nz;
if(temp==0)return PERPENDICULAR;
if(temp>0)return SHARP_ANGLE;
if(temp<0)return OBTUSE_ANGLE;
return UNKNOW;
}
int CMath::ClassifyTwoNormal(VERTEX v1,VERTEX vCenter,VERTEX v2)
{
float temp;
NORMAL n1,n2;
n1.nx=v1.xpos-vCenter.xpos;
n1.ny=v1.ypos-vCenter.ypos;
n1.nz=v1.zpos-vCenter.zpos;
n2.nx=v2.xpos-vCenter.xpos;
n2.ny=v2.ypos-vCenter.ypos;
n2.nz=v2.zpos-vCenter.zpos;
temp=n1.nx*n2.nx+n1.ny*n2.ny+n1.nz*n2.nz;
if(temp==0)return PERPENDICULAR;
if(temp>0)return SHARP_ANGLE;
if(temp<0)return OBTUSE_ANGLE;
return UNKNOW;
}
int CMath::ClassifyPointPlane(VERTEX point,PLANE plane)
{
float distance=plane.A*point.xpos+plane.B*point.ypos+plane.C*point.zpos+plane.D;
if(distance==0)return COINCIDENT;
if(distance>0)return IN_FRONT_OF;
return IN_BACK_OF;
}
int CMath::ClassifyPolygonPlane(PLANE plane,VERTEX *vertices,int num)
{
if(num<3)return UNKNOW;
int current=0;
int dist=ClassifyPointPlane(vertices[0],plane);
if(dist==IN_FRONT_OF)
{
current=1;
while(current