hdu 4617 计算几何 三维点线面关系
1 /* 2 题意:给出n个weapon,每个weapon都是一个镭射光束,相当于一个无限长的实心圆柱,当两个weapon相接触,就会产生爆炸; 3 问给出n个weapon的某一垂直切面(为圆形),求这n个weapon之间是否会相接触,会则输出Lucky,否则输出两两之间weapon的最 4 短距离; 5 6 题解:计算几何:两直线的距离+平面法向量+直线与平面交点+平行线段 7 首先分别求出两个平面的法向量,因为圆柱的中心轴平行于平面法向量,然后求该向量与平面交点to,通过原点o与点to以及 8 圆柱的中心点center,将线段o-to平移到center-aim(aim为要求的点),这样center,aim两点就能表示中心轴线,最后求两直 9 线间的距离,最终减去两个半径即可得出最终答案。 10 11 注意:当给出的平面的center为原点时,需要特判,否则会出错 12 */ 13 #include <cstdio> 14 #include <cmath> 15 #include <algorithm> 16 17 #define eps 1e-8 18 #define zero(x) (((x)>0?(x):-(x))<eps) 19 20 struct point3{double x,y,z;}; 21 struct line3{point3 a,b;}linea,lineb; 22 23 //计算cross product U x V 24 point3 xmult(point3 u,point3 v){ 25 point3 ret; 26 ret.x=u.y*v.z-v.y*u.z; 27 ret.y=u.z*v.x-u.x*v.z; 28 ret.z=u.x*v.y-u.y*v.x; 29 return ret; 30 } 31 32 //计算dot product U . V 33 double dmult(point3 u,point3 v){ 34 return u.x*v.x+u.y*v.y+u.z*v.z; 35 } 36 37 //矢量差 U - V 38 point3 subt(point3 u,point3 v){ 39 point3 ret; 40 ret.x=u.x-v.x; 41 ret.y=u.y-v.y; 42 ret.z=u.z-v.z; 43 return ret; 44 } 45 46 // 求平面法向量(原点到返回点即为所求向量) 47 point3 pvec(point3 s1,point3 s2,point3 s3) 48 { 49 return xmult(subt(s1,s2),subt(s2,s3)); 50 } 51 52 //向量大小 53 double vlen(point3 p){ 54 return sqrt(p.x*p.x+p.y*p.y+p.z*p.z); 55 } 56 57 // 两直线距离 58 double linetoline(point3 u1,point3 u2,point3 v1,point3 v2){ 59 point3 n=xmult(subt(u1,u2),subt(v1,v2)); 60 return fabs(dmult(subt(u1,v1),n))/vlen(n); 61 } 62 63 // 求直线与平面的交点 64 point3 intersection(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){ 65 point3 ret=pvec(s1,s2,s3); 66 double t=(ret.x*(s1.x-l1.x)+ret.y*(s1.y-l1.y)+ret.z*(s1.z-l1.z))/ 67 (ret.x*(l2.x-l1.x)+ret.y*(l2.y-l1.y)+ret.z*(l2.z-l1.z)); 68 ret.x=l1.x+(l2.x-l1.x)*t; 69 ret.y=l1.y+(l2.y-l1.y)*t; 70 ret.z=l1.z+(l2.z-l1.z)*t; 71 return ret; 72 } 73 74 75 struct location 76 { 77 point3 a,b,o; 78 }s[29]; 79 80 double getdistance(point3 a, point3 b) 81 { 82 return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z)); 83 } 84 85 86 int main(void) 87 { 88 int t,n; 89 scanf("%d",&t); 90 while (t--) 91 { 92 scanf("%d",&n); 93 for(int i=0; i<n; i++) 94 { 95 scanf("%lf%lf%lf",&s[i].o.x, &s[i].o.y, &s[i].o.z); 96 scanf("%lf%lf%lf",&s[i].a.x, &s[i].a.y, &s[i].a.z); 97 scanf("%lf%lf%lf",&s[i].b.x, &s[i].b.y, &s[i].b.z); 98 } 99 100 double ans = 1e10; 101 bool flag = true; 102 for(int i=0; i<n-1; i++) 103 { 104 for(int j=i+1; j<n; j++) 105 { 106 point3 to1,to2,origin,tmp; 107 origin.x = origin.y = origin.z = 0; 108 to1 = pvec(s[i].a,s[i].o,s[i].b); 109 tmp = intersection(to1,origin,s[i].o,s[i].a,s[i].b); 110 // 特判该平面的center是否原点 111 if (!(zero(tmp.x-origin.x) && zero(tmp.y-origin.y) && zero(tmp.z-origin.z))) 112 { 113 to1.x = s[i].o.x - to1.x; 114 to1.y = s[i].o.y - to1.y; 115 to1.z = s[i].o.z - to1.z; 116 } 117 118 to2 = pvec(s[j].a,s[j].o,s[j].b); 119 tmp = intersection(to2,origin,s[j].o,s[j].a,s[j].b); 120 // 特判该平面的center是否原点 121 if (!(zero(tmp.x-origin.x) && zero(tmp.y-origin.y) && zero(tmp.z-origin.z))) 122 { 123 to2.x = s[j].o.x - to2.x; 124 to2.y = s[j].o.y - to2.y; 125 to2.z = s[j].o.z - to2.z; 126 } 127 double radis1 = getdistance(s[i].o,s[i].a); 128 double radis2 = getdistance(s[j].o,s[j].a); 129 double linedis = linetoline(s[i].o,to1,s[j].o,to2); 130 linedis = linedis - radis1 - radis2; 131 if (linedis < eps) 132 { 133 flag = false; 134 break; 135 } 136 ans = std::min(ans,linedis); 137 } 138 if (!flag) 139 break; 140 } 141 if (flag) 142 printf("%.2lf\n",ans); 143 else 144 printf("Lucky\n"); 145 146 } 147 return 0; 148 }