给出一个圆锥的半径,高,一个点的坐标和速度矢量,求最小的时间,使得点到达圆锥上
解析几何就需要取设点
圆心在原点的圆锥,半径为(r),高为(h)
[left{egin{array}{l}
frac{h-z}{h}=frac{R}{r} \
x^{2}+y^{2}=R^{2}
end{array}
ight.
]
再设点的坐标
[egin{array}{l}
x=x_{0}+v_{x} t \
y=y_{0}+v_{y} t \
z=z_{0}+v_{z} t
end{array}
]
然后联立化简得到
[left(v_{x}^{2}+v_{y}^{2}-frac{r^{2} v_{z}^{2}}{h^{2}}
ight) t^{2}+2left(v_{x} x_{0}+v_{y} y_{0}-frac{z_{0} v_{z} r^{2}}{h^{2}}+frac{v_{z} r^{2}}{h}
ight) t+x_{0}^{2}+y_{0}^{2}-frac{r^{2}}{h^{2}}left(h-z_{0}
ight)^{2}=0
]
求得
[egin{aligned}
t_{1} &=frac{-b+sqrt{b^{2}-4 a c}}{2 a} \
t_{2} &=frac{-b-sqrt{b^{2}-4 a c}}{2 a}
end{aligned}
]
最后check一下,这样求出来是两个值,可能直接穿过圆锥面到另一个面,所以得判断一下才行。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps = 1e-6;
double r, h, x0, y0, z0, vx, vy, vz;
bool check(double tt){
double x = x0 + vx * tt;
double y = y0 + vy * tt;
double z = z0 + vz * tt;
double R = (h - z) * r / h;
return (sqrt(x * x + y * y) - R) <= eps;
}
double min(double x, double y) {
return x > y ? y : x;
}
void solve(int kase) {
scanf("%lf%lf", &r, &h);
scanf("%lf%lf%lf", &x0, &y0, &z0);
scanf("%lf%lf%lf", &vx, &vy, &vz);
printf("Case %d: ", kase);
double a = vx * vx + vy * vy - r * r * vz * vz / h / h;
double b = 2 * (vx * x0 + vy * y0 - z0 * vz * r * r / h / h + vz * r * r / h);
double c = x0 * x0 + y0 * y0 - r * r / h / h * (h - z0) * (h - z0);
double t1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
double t2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
double ans = 1000000000.0;
if(check(t1)) {
ans = min(ans, t1);
}
if(check(t2)) {
ans = min(ans, t2);
}
printf("%.7f
", ans);
}
int main(){
// freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int t;
scanf("%d", &t);
for(int i = 1; i <= t; i++) solve(i);
return 0;
}