碰撞检测中函数线与面,线与多边形,点到线的最近点) _ 转 - [叁]


转载地址:http://sakishum.blogbus.com/logs/53944554.html

1、线和平面碰撞。传入参数:线(起点,终点),平面(三个顶点)

调用:Intersectedplane(vTriangle,vLine);

bool Intersectedplane(CVector3 vTriangle[],CVector3 vLine[])
{
float distance1=0,distance2=0;
CVector3 vnormal = normal(vTriangle);//三角形法向量

// origindistance 为 Ax+By+Cz+D=0中的D (A,B,C为法向量)

float origindistance = Planedistance(vnormal,vTriangle[0]);

//求出线段两端点到平面的距离,若距离相乘为负,相交,否则不相交

distance1 = ((vnormal.x * vLine[0].x) +// Ax +
(vnormal.y * vLine[0].y) +// Bx +

(vnormal.z * vLine[0].z)) + origindistance;// Cz + D

distance2 = ((vnormal.x * vLine[1].x) +// Ax +
(vnormal.y * vLine[1].y) +// Bx +
(vnormal.z * vLine[1].z)) + origindistance;// Cz + D

if(distance1 * distance2 >= 0)

return false;
return true;

}

2.线段和多边形相交,参数:多边形顶点数组,线段,多边形顶点个数

Intersectedpolygon(vTriangle,vLine,3);

bool Intersectedpolygon(CVector3 vpoly[],CVector3 vLine[],int verticeCount)
{
CVector3 vnormal = {0};
float origindistance = 0;

//如果不和多边形所在平面相交,则不相交

if(!Intersectedplane(vpoly,vnormal,origindistance))
return false;

//求出线和平面的交点

CVector3 vIntersection = IntersectionPoint(vnormal,origindistance);

//如果交点在多边形内,就相交

if(Insidepolygon(vIntersection,vpoly,verticeCount))
return true;

return false;

辅助函数1:IntersectionPoint()返回线和平面的交点

思路:求出点与点和平面交点的距离1,用起始点+线段方向*距离1,求出交点

CVector3 IntersectionPoint(CVector3 vnormal,double distance)

{
CVector3 vPoint = {0},vLineDir = {0};

double Numerator = 0.0,Denominator = 0.0,dist = 0.0;

vLineDir = Vector(vLine[1],vLine[0]);//得到线向量

vLineDir = normalize(vLineDir); //标准化

//注意1:为什么要加负号,假设线段方向从平面正面指向背面。求线段到线段和平面间交点的距离(为正)

//1.点在平面正面,x1:Ax+By+Cz+D>0,线段方向和法向量的夹角x2:cos<0,dist=-x1/x2>0

//2.点在平面背面,x1:Ax+By+Cz+D<0,线段方向和法向量的夹角x2:cos<0,dist=-x1/x2<0

//在最终计算交点交点时,vPoint.x = vLine[0].x + vLineDir.x * dist;

//不管点在哪一面,交点始终指向平面

注意2:线段:起点 vLine[0],方向vLineDir,定义射线 vLine[0]+t*vLineDir

//Ax+By+Cz为原点到平面的距离,在之前定义了Ax+By+Cz+distance=0

//所以原点到已知平面的距离为 -distance

//若线段和射线相交( vLine[0]+t*vLineDir)*vnormal=-distance

//t=(-distance-vLine[0]*vnormal)/(vnormal*vLineDir)

Numerator = - (vnormal.x * vLine[0].x + vnormal.y * vLine[0].y +
vnormal.z * vLine[0].z + distance);//线段起点到平面的距离

Denominator = Dot(vnormal,vLineDir);//法线和线段夹角的cos值

if( Denominator == 0.0)//如何平面法向量和线段垂直,线段在平面上,返回线段上任意一点

return vLine[0];

dist = Numerator / Denominator;//线段起点到和平面交点的距离

vPoint.x = (float)(vLine[0].x + (vLineDir.x * dist));
vPoint.y = (float)(vLine[0].y + (vLineDir.y * dist));
vPoint.z = (float)(vLine[0].z + (vLineDir.z * dist));

return vPoint;

辅助函数2:Insidepolygon()判断点是否在多边形内

思路:当点在多边形内时,点和多边形任意两个角形成的角度之和等于360

bool Insidepolygon(CVector3 vIntersection,CVector3 poly[],long verticeCount)
{
const double MATCH_FACTOR = 0.9999;

double Angle = 0.0;

CVector3 vA,vB;

for (int i = 0; i < verticeCount; i++)

{
vA = Vector(poly[i],vIntersection);

vB = Vector(poly[(i + 1) % verticeCount],vIntersection);

Angle += AngleBetweenVectors(vA,vB);//返回(vA*vB)/(|vA|*|vB|)的arcos

if(Angle >= (MATCH_FACTOR * (2.0 * PI)) )

return TRUE;
return FALSE;

}

3.求一个球的球心到一条线段上的最近点,参数:线段点1,线段点2,小球球心

ClosestPointOnLine(g_vLine[0],g_vLine[1],g_vPosition);

思路:球心vPoint,线段起点vA,终点vB,求出线段起点到小球球心向量在线段上的投影长度,

线段起点+投影长度*线段方向即为所求

CVector3 ClosestPointOnLine(CVector3 vA,CVector3 vB,CVector3 vPoint)
{

CVector3 vVector1 = vPoint - vA;//线段起点到小球球心向量

CVector3 vVector2 = normalize(vB - vA);//线段方向
float d = distance(vA,51)">//d为线段长度
float t = Dot(vVector2,vVector1);//t为投影长度

if (t <= 0)//如果投影长度<0,为起点为最近点
return vA;
if (t >= d)//如果投影长度>线段长度,终点为最近点
return vB;
CVector3 vVector3 = vVector2 * t;

CVector3 vClosestPoint = vA + vVector3;

return vClosestPoint;
}

收藏到: Del.icio.us
http://www.blogbus.com/public/tb.PHP/4811502/53944554/7803cbb58abefd43d9c7275fd48

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...