SGU 110 三维计算几何 向量的灵活运用

来源:互联网 发布:智慧社区app源码下载 编辑:程序博客网 时间:2024/06/06 01:51

题意不解释.

思路:

我们用一个基点和一个方向向量来表示题目中的光线(射线) ,射线上的任何一点都可以用 base + t * dir 表示(t >= 0)

每次找到能射到的一个圆(与射线相交的圆,如果这种圆有多个就取距离最近的),找不到就停,然后反射,即维护一下base,dir。

向量活用:

1. 射线和圆求交点时把射线方程和圆方程联立,用向量的形式展开,再解个二元一次方程组即可。

2. 已知入射光线和法线,求反射光线


v1为入射光线,v2为法线。

把v1分解成v2方向和垂直v2方向,我们可以发现只要修改v1平行于v2的向量分量(把平行v2的那个向量分量大小不变,方向相反)。

以v2长度为基准,求出v1在v2方向的分量是v2长度的k倍。然后 反射光线v3 = v1 - v2*k*2;

k的求法可以先把v1投影到v2, 投影值为 v1*v2/|v2| (v1点乘v2, 除以v2的模), 然后 k =  投影值/|v2|;

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cmath>#include <vector>using namespace std;const double inf = 1e20;const double eps = 1e-10;struct point {double x, y, z;point(double x=0, double y=0, double z=0) : x(x), y(y), z(z) {}point operator +(point t) {return point(x+t.x, y+t.y, z+t.z);}point operator -(point t) {return point(x-t.x, y-t.y, z-t.z);}point operator *(double t) {return point(x*t, y*t, z*t);}point operator /(double t) {return point(x/t, y/t, z/t);}double operator *(point t) { // 向量点乘return x*t.x+y*t.y+z*t.z;}void in() {cin >> x >> y >> z;}};point cir[55], base, dir; // 圆心,基点,方向向量double R[55]; // 半径point Jiao; // 记录射线与圆的交点。vector <int> ans; // 记录路径int n;int cal() {double max_d = inf;double a, b, c;int i, ret = -1;    // 射线上的点可以用 base + t * dir 表示 (t >= 0) for(i = 0; i < n; i++) {  // (base + t*dir - cir[i]) == R[i]*R[i]; 解二元一次方程, 求出t。a = dir*dir;b = (base-cir[i])*dir*2;c = (base-cir[i])*(base-cir[i])-R[i]*R[i];double dlt = b*b-4*a*c;if(dlt < -eps) continue;dlt = sqrt(dlt);double t = (-b-dlt)/2/a; // 取小的那个,一定是碰到的if(t < eps) continue;point tp = base + dir * t;double d = (tp-base)*(tp-base);if(max_d > d + eps) {max_d = d; Jiao = tp; ret = i;}}return ret;}int main() {int i;cin >> n;for(i = 0; i < n; i++) {cir[i].in(); cin >> R[i];}base.in(); dir.in();ans.clear();int xx;dir = dir - base;for(xx = 1; xx <= 11; xx++) {int j = cal();if(j == -1) break;ans.push_back(j+1);point v = cir[j] - Jiao;dir = dir - v*(dir*v/(v*v))*2; // 向量的活用base = Jiao;}if(ans.size() >= 11) {for(i = 0; i < 10; i++)cout << ans[i] << " " ;cout << "etc." << endl;}else {for(i = 0; i < (int)ans.size(); i++) cout << ans[i] << " ";cout << endl;}return 0;}/*20 0 0 11 3 0 1-1 2 0 1 -1 020 0 0 15 0 0 1-99 1 0 999 0 01 21 2*/



原创粉丝点击