hdu3712 Detector Placement
题意:给一束激光,一个三棱柱,三棱柱会折射光,问这束激光最终是否会和y = 0相交;
分析:模拟题,为了方便处理折射角,事先求出每条边的向内和向外的法向量;
findpoint : 找第一交点
step1: 判断激光是否和三角形有规范相交;
step2: 第一次折射;
step3:第二次折射,可能无法折射;
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int N = 100+10; 10 const double eps = 1e-8; 11 const double pi = acos(-1.0); 12 inline int dcmp(double x) { 13 return x < -eps ? -1 : x > eps; 14 } 15 inline double sqr(double x) { 16 return x * x; 17 } 18 19 struct Point{ 20 double x,y; 21 Point(){} 22 Point(double _x,double _y):x(_x),y(_y){} 23 bool operator == (const Point &p) const{ 24 return dcmp(x - p.x) == 0 && dcmp(y - p.y) == 0; 25 } 26 Point operator + (const Point &p) const{ 27 return Point(x + p.x, y + p.y); 28 } 29 Point operator - (const Point &p) const{ 30 return Point (x - p.x, y - p.y); 31 } 32 Point operator * (const double &k) const{ 33 return Point (x * k, y * k); 34 } 35 Point operator / (const double &k) const{ 36 return Point (x / k, y / k); 37 } 38 double operator * (const Point &p) const{ 39 return x * p.y - y * p.x; 40 } 41 double operator / (const Point &p) const{ 42 return x * p.x + y * p.y; 43 } 44 double len2() { 45 return x * x + y * y; 46 } 47 double len() { 48 return sqrt(len2()); 49 } 50 Point scale(const double &k) { 51 return dcmp( len() ) ? (*this) * (k / len()) : (*this); 52 } 53 Point turnLeft() { 54 return Point(-y,x); 55 } 56 Point turnRight(){ 57 return Point(y,-x); 58 } 59 double Distance(const Point &p) { 60 return sqrt(sqr(x - p.x) + sqr(y - p.y)); 61 } 62 Point rotate(const Point &p,double angle, double k = 1) { 63 Point vec = (*this) - p; 64 double c = cos(angle * k) , s =sin(angle * k) ; 65 return p + Point(vec.x * c - vec.y * s, vec.x * s + vec.y * c); 66 } 67 void input(){ 68 scanf("%lf%lf",&x,&y); 69 } 70 void ot() { 71 printf("%.3lf %.3lf\n",x,y); 72 } 73 }; 74 double Angle(Point a,Point b) { 75 return (a/b) / a.len() / b.len(); 76 } 77 struct Line{ 78 Point a,b; 79 Line(){} 80 Line(Point a,Point b):a(a),b(b){} 81 double operator * (const Point &p) const{ 82 return (b - a) * (p - a); 83 } 84 double operator / (const Point &p) const{ 85 return (p - a) / (p - b); 86 } 87 bool IsPointOnSeg(const Point &p) { 88 return dcmp( (a - p) * (b - p) ) == 0 && dcmp( (p - a) / (p - b) ) <= 0; 89 } 90 int LineCrossSeg(const Line &v) {//2jiao, 1 dian ,0 wu 91 int d1 = dcmp( (*this) * v.a), d2 = dcmp((*this) * v.b); 92 if ((d1 ^ d2) == -2) return 2; 93 return (d1 == 0 || d2 == 0); 94 } 95 Point CrossPoint(const Line &v) { 96 double s1 = v * a, s2 = v * b; 97 return ( a * s2 - b * s1 ) / (s2 - s1); 98 } 99 }; 100 Line li[3]; 101 int d[3]; 102 Point a[3],b[3],c[3]; 103 Point st,en; 104 105 double u; 106 int check(int i) { 107 if (dcmp( (li[i].b - li[i].a) * (a[d[i]] - li[i].a) ) > 0) { 108 return 1; 109 } 110 return 0; 111 } 112 void init(){ 113 for (int i = 0; i < 3; i++) { 114 if (check(i)) { 115 b[i] = (li[i].b - li[i].a).turnLeft(); 116 c[i] = (li[i].b - li[i].a).turnRight(); 117 }else { 118 b[i] = (li[i].b - li[i].a).turnRight(); 119 c[i] = (li[i].b - li[i].a).turnLeft(); 120 } 121 } 122 } 123 int ond(Point a,Point b,Point p) { 124 if (dcmp((p - a) / (b - a)) >= 0) return 1; 125 return 0; 126 } 127 int step1() { 128 int fg = 0; 129 Line line = Line(st,en); 130 for (int i = 0; i < 3; i++) { 131 if (line.LineCrossSeg(li[i]) == 2) { 132 Point p = line.CrossPoint(li[i]); 133 if (ond(st,en,p)) fg = 1; 134 } 135 } 136 if (fg == 0) { 137 138 Point p = line.CrossPoint(Line(Point(0,0),Point(1,0))); 139 if (ond(st,en,p)) printf("%.3lf\n",p.x+eps); 140 else printf("Error\n"); 141 return 0; 142 } 143 return 1; 144 145 } 146 void findPoint(Point &p,int &id) { 147 Line line = Line(st,en); 148 double dis = 1e50; 149 for (int i = 0; i < 3; i++) { 150 if (line.LineCrossSeg(li[i])) { 151 Point tp = line.CrossPoint(li[i]); 152 if (!ond(st,en,tp)) continue; 153 double tdis = tp.Distance(st); 154 if (tdis < dis && dcmp(tdis) != 0) { 155 dis = tdis; 156 p = tp; 157 id = i; 158 } 159 } 160 } 161 } 162 void step2() { 163 Point p; 164 int id = -1; 165 findPoint(p,id); 166 Point vec = en - st; 167 double cs = Angle(vec,b[id]); 168 double sn1 = sqrt(1 - cs * cs); 169 double sn2 = sn1 / u; 170 double ag = asin(sn1) - asin(sn2); 171 if (dcmp(vec * b[id]) <= 0) { 172 vec = (p + vec).rotate(p,-ag); 173 }else vec = (p + vec).rotate(p,ag); 174 st = p; en = vec; 175 } 176 void step3() { 177 Point p; 178 int id = -1; 179 findPoint(p,id); 180 Point vec = en - st; 181 double cs = Angle(vec,c[id]); 182 double sn1 = sqrt(1 - cs * cs); 183 double sn2 = sn1 * u; 184 if (sn2 > 1) { 185 if (dcmp(p.y) == 0) printf("%.3lf\n",p.x+eps); 186 else printf("Error\n"); 187 return; 188 } 189 double ag = asin(sn2) - asin(sn1); 190 if (dcmp(vec * c[id]) >= 0) { 191 vec = (p + vec).rotate(p,-ag); 192 }else vec = (p + vec).rotate(p,ag); 193 st = p; en = vec; 194 Point an = Line(st,en).CrossPoint(Line(Point(0,0),Point(1,0))); 195 if (ond(st,en,an)) { 196 printf("%.3lf\n",an.x+eps); 197 }else printf("Error\n"); 198 } 199 void solve(){ 200 init(); 201 if (!step1()) return; 202 step2(); 203 step3(); 204 } 205 int main(){ 206 // cout<<Line(Point(0,0),Point(1,0)).LineCrossSeg(Line(Point(0,0),Point(1,0)))<<endl; 207 int T; scanf("%d",&T); 208 while (T--) { 209 st.input(); en.input(); 210 for (int i = 0; i < 3; i++) a[i].input(); 211 li[0] = Line(a[0],a[1]); d[0] = 2; 212 li[1] = Line(a[1],a[2]); d[1] = 0; 213 li[2] = Line(a[2],a[0]); d[2] = 1; 214 scanf("%lf",&u); 215 solve(); 216 } 217 return 0; 218 } 219 /* 220 3 221 0 10 222 0 20 223 -1 3 1 2 -1 1 224 1.325 225 0 10 226 0 0 227 -1 3 1 2 -1 1 228 1.325 229 230 0 10 0 9 231 0 0 0 1 1 0 232 1.0 233 */