题意:
给你一个实心球的球心+R 给出S、T两点在三维空间的坐标 问你S走到T的最短距离
思路
1.dis_st == 0.0
2.∠S或∠T >= pi/2 说明直线必定不与球相交
3.O到ST的距离H >= R 也不相交
4.常规相交:分别求出S、T与球相切这段的距离(勾股定理)、求出绕球(圆切面)的弧线距离 L = π R
这里求弧度需要用到余弦定理 求H:正弦定理面积= H*L
上代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
double R;
struct Point{
double x,y,z;
Point(double x = 0,double y = 0,double z = 0) : x(x),y(y),z(z) {}
}O,S,T;
double dis2(Point A,Point B){
return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z);
}
double calR(double a,double b,double c){//余弦定理求∠的弧度
return acos((a + b - c) / (2.0*sqrt(a*b)));
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%lf%lf%lf%lf",&O.x,&O.y,&O.z,&R);
scanf("%lf%lf%lf%lf%lf%lf",&S.x,&S.y,&S.z,&T.x,&T.y,&T.z);
double dis2_st = dis2(S,T);
double dis2_ot = dis2(O,T);
double dis2_os = dis2(S,O);
//ST == 0
if(dis2_st == 0.0){
printf("%.9f\n",0.0);
continue;
}
//如果存在∠OST||∠OTS >= pi/2 则ST一定与球不相交
double J_S = calR(dis2_st,dis2_os,dis2_ot);
double J_T = calR(dis2_st,dis2_ot,dis2_os);
if(J_S >= pi/2.0 || J_T >= pi/2.0){
printf("%.9f\n",sqrt(dis2_st));
continue;
}
//O到ST的距离>=R ans = ST
double H = sqrt(dis2_os) * sqrt(dis2_ot) * sin(pi - J_S - J_T) / sqrt(dis2_st);
if(H >= R){
printf("%.9f\n",sqrt(dis2_st));
continue;
}
double ss = sqrt(dis2_os - R * R);
double tt = sqrt(dis2_ot - R * R);
double sss = acos(R / sqrt(dis2_os));
double ttt = acos(R / sqrt(dis2_ot));
double Y = R * (pi - J_S - J_T - sss - ttt);//L = πR
printf("%.9f\n",ss + tt + Y);
}
return 0;
}