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 }

 

posted @ 2014-03-23 21:53  辛力啤  阅读(281)  评论(0编辑  收藏  举报