hdu 3712 计算几何

hdu 3712 计算几何
题目描述:

   给一个点光源(x0,y0),向(x1,y1)处发射射线。p0,p1,p2三个点是三棱镜,折射率为n。求最后光线与x轴的交点。

算法分析:
   
   此题非常爽... 各种几何...

   首先判断射线是否和p0,p1,p2构成的三条线段相交,如果相交,判断交点与(x0,y0)的距离,来确定第一个折射面。
   求交的过程不多说了,我用的是叉积求面积的方法。

   利用角度各种加减计算出入射光线与法线的夹角(可正可负)。从而计算出射光线line1。

   再用相同的方法计算出射光线2。这里需要判断全发射的情况。 然后计算与x轴的交点就可以了。

#include<cstdio>
#include<iostream>
#include<complex>
#include<cmath>
using  namespace std;
#define Y imag
#define X real
const  double eps = 1e-9;
const  char *err = "Error";
const  double pi = acos(-1.0);
typedef complex< double> pnt;
static  double dot( const pnt &a,  const pnt& b) { return X(conj(a)*b);}
static  double cross( const pnt &a,  const pnt &b) { return imag(conj(a)*b);}
//  final judge
void work( const pnt& s,  double argu) {
     while(argu<0) argu+=2*pi;
     while(argu >= 2*pi) argu -=2*pi;
     if(argu < pi+eps) {
        puts(err);
         return ;
    }
    argu = - argu;
//     cout<<argu<<endl;
    printf("%.3lf\n", X(s) +( abs(argu + 3*pi/2)<eps ? 0 :  Y(s)/tan(argu) ));
}
//  segment intersection
pnt jdg( const pnt& p0,  const pnt& p1, const pnt& p3,  const pnt& p2){
     if(cross(p3-p0,p1-p0) * cross(p2-p0,p1-p0) > -eps)  return p0;
     double s1 = cross(p2-p1,p0-p1), s2 = cross(p3-p1,p0-p1);
    s1 = abs(s1), s2 = abs(s2);
     double x = (X(p2) *s2 + X(p3)*s1) / (s1+ s2);
     double y = (Y(p2) *s2 + Y(p3)*s1) / (s1+ s2);
    pnt p(x,y);
     if(cross(p3-p2,p1-p2)*cross(p3-p2,p0-p2)>0 && abs(p-p0) < abs(p-p1))  return p0;
     return p;
}
//  cal reflex
double cal( double arg0,  double arg1,  double tmp) {
//     cout<<arg0<<" "<<arg1<<" "<<tmp<<endl;
     double t1 =arg1+pi/2-(arg0+pi);
     double s1 = sin(t1);
     double s2 = s1/tmp;
     // cout<<t1<<" "<<asin(s2)<<endl;    
     if(s2>=1.0 || s2 <=-1.0)  return 1e10;
     else  return arg1-pi/2-asin(s2);
}
//  main
int main(){
     int tst;
     double tmp;
    cin >> tst;
    pnt p[3];
     while(tst--) {
         double x1,y1,x2,y2;
         while(cin >> x1 >> y1 >> x2 >> y2){
            pnt p1(x1,y1), p2(x2,y2), p0;
             int s = -1;
             double mx = 1e10;
             for( int i=0;i<3;i++){
                cin >> x1 >> y1;
                p[i] = pnt(x1,y1);
            }
            cin >> tmp;
             //  comfirm p0
             for( int i=0;i<3;i++) {
                pnt P = jdg(p1,p2,p[i],p[(i+1)%3]);
                 if(P == p1)  continue;
                 double v = abs(p1-P);
                 if(v < mx) mx = v, s = i, p0 = P;
            }
             if(s == -1){
                work(p1, arg(p2-p1));
                 continue;
            }
            pnt p3;
             double t = 0;
             if(cross(p2-p1, p[(s+1)%3] - p[s])<0)t = pi;
             double arg0 = cal(arg(p2-p1),arg(p[(s+1)%3] - p[s])+t,tmp);
            pnt np = pnt(X(p0) + 200*cos(arg0), Y(p0) + 200*sin(arg0));
             //  use p0,arg0 to comfirm p3
//             cout<<"p0 :"<<X(p0)<<" "<<Y(p0)<<" "<<arg0<<endl;
//             cout<<"np :"<<X(np)<<" "<<Y(np)<<endl;
              int k = -1;
             for( int i=0;i<3;i++) {
                 if(i==s)  continue;
                pnt P = jdg(p0,np,p[i],p[(i+1)%3]);
                 if(P == p0)  continue;
                k = i;p3 = P;
            }
             //  p3 arg1 x-axis
            t = 0;
             if(cross(p3-p0, p[(k+1)%3] - p[k])<0)t = pi;
             double arg1 = cal(arg(p3 - p0), arg(p[(k+1)%3] - p[k])+t, 1.0/tmp);
//             cout<<"p3: "<<" "<<X(p3)<<" "<<Y(p3)<<" "<<arg1<<endl;
             if(arg1 == 1e10) {
                puts(err);
                 continue;
            }
            work(p3,arg1);
        }
    }
}

你可能感兴趣的:(hdu 3712 计算几何)