三维计算几何
声明:
由于本人较弱,并不能保证以下内容的100%正确
欢迎大佬来挑错
基本定义
1 struct Point3{ 2 double x,y,z; 3 Point3(){ 4 x=y=z=0.0; 5 } 6 Point3(double xx,double yy,double zz){ 7 x=xx;y=yy;z=zz; 8 } 9 }; 10 typedef Point3 Vec3; 11 12 Vec3 operator + (Vec3 v1,Vec3 v2){ 13 return Vec3(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z); 14 } 15 Vec3 operator - (Point3 p1,Point3 p2){ 16 return Vec3(p1.x-p2.x,p1.y-p2.y,p1.z-p2.z); 17 } 18 Vec3 operator * (Vec3 v,double p){ 19 return Vec3(v.x*p,v.y*p,v.z*p); 20 } 21 Vec3 operator / (Vec3 v,double p){ 22 return Vec3(v.x/p,v.y/p,v.z/p); 23 }
半平面的表示
Dot(n,p-p0)=0 Ax+By+Cz+D>=0
三维点积
1 double Dt(Vec3 v1,Vec3 v2){ 2 return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z; 3 } 4 double Getlen(Vec3 v){ 5 return sqrt(Dt(v,v)); 6 } 7 double Getang(Vec3 v1,Vec3 v2){ 8 return Dt(v1,v2)/Getlen(v1)/Getlen(v2); 9 }
应用:求夹角
求到平面的距离
求点在平面内的投影
1 double DistanceToPlane(Point3 p,Point3 p0,Vec3 n){ 2 return Myabs(Dt(p-p0,n)/Getlen(n)); 3 } 4 Point3 GetPlaneProjection(Point3 p,Point3 p0,Vec3 n){ 5 return p-n*Dt(p-p0,n)/Getlen(n); 6 }
直线和平面的交点
注意判断分母为0
Point3 LinePlaneIntersection(Point3 p1,Point3 p2,Point3 p0,Vec3 n){ Vec3 v=p2-p1; double t=Dt(n,p0-p1)/Dt(n,p2-p1); return p1+v*t; }
三维叉积
1 Vec3 Crs(Vec3 v1,Vec3 v2){ 2 return Vec3(v1.y*v2.z-v2.y*v1.z,v1.z*v2.x-v2.z*v1.x,v1.x*v2.y-v2.x*v1.y); 3 } 4 double GetS2(Point3 A,Point3 B,Point3 C){ 5 return Getlen(Crs(B-A,C-A)); 6 }
过不共线三点的平面的法向量
Crs(p2-p0,p1-p0)
三角形的有向面积????
求出叉积后取长度
判断点是否在三角形内
1 bool PointInTri(Poitn3 P,Point3 P0,Point3 P1,Point3 P2){ 2 double S1=GetS2(P,P0,P1); 3 double S2=GetS2(P,P1,P2); 4 double S3=GetS2(P,P2,P0); 5 return dcmp(S1+S2+S2-GetS2(P0,P1,P2))==0; 6 }
判断线段与三角形相交
1 bool TriSegIntersection(Point3 P0,Point3 P1,Point3 P2,Point3 A,Point3 B){ 2 Vec3 n=Crs(P1-P0,P2-P0); 3 if(dcmp(Dt(n,B-A))==0)return 0; 4 double t=Dt(n,P0-A)/Dt(n,B-A); 5 if(dcmp(t)<0||dcmp(t-1)>0)return 0; 6 Point3 P=A+(B-A)*t; 7 return PointInTri(P,P0,P1,P2); 8 }
点到直线线段的距离
1 double DistanceToLine(Point3 P,Point3 A,Point3 B){ 2 Vec3 v1=B-A,v2=P-A; 3 return Getlen(Crs(v1,v2))/Getlen(v1); 4 } 5 6 double DistanceToSegment(Point3 P,Point3 A,Point3 B){ 7 //(A!=B) 8 Vec3 v1=B-A,v2=P-A,v3=P-B; 9 if(dcmp(Dt(v1,v2))<0)return Getlen(v2); 10 else if(dcmp(Dt(v1,v3))>0)return Getlen(v3); 11 else return DistanceToLine(P,A,B); 12 }
四面体的体积
四面体的带符号体积
1 double Volume6(Point3 A,Point3 B,Point3 C,Point3 D){ 2 return Dt(D-A,Crs(B-A,C-A)); 3 }
计算有向面积时注意多边形的储存顺序
三维凸包
(我的模板是假的,注意四点共面的情况)
暴力法 O(n4)
枚举每三个点组成的有向三角形
判断是否所有点都在同侧
从而判断是否是凸包的一个面
判断在三角形的哪一侧需要一次叉积和一次点积(也可以理解为一次混合积)