c++求两点的距离利用友元_C++ 求解球内某点沿某向量到球面的距离

本文介绍了如何在C++中计算三维空间中球体内一点沿给定向量到球面的距离,并详细阐述了数学公式推导、代码实现以及处理特殊情况(如点位于球面上)的方法。内容包括直线参数方程、球面方程的结合,以及针对相切和不相切情况的解决方案。
摘要由CSDN通过智能技术生成

00 本文内容

  • 问题描述
    • 图像
    • 输入输出
  • 数学公式推导
    • 三维坐标下直线的参数方程
    • 直线与球面交点求解方法
    • 判断距离是否与方向向量相同
  • C++代码实现
    • 函数化封装
    • 可根据需要只修改函数参数
  • 特殊情况
    • 实际项目中遇到返回无效值
    • 当该点在球面上,讨论相切与不相切

01 问题描述

问题描述:在三维坐标内,已知一球体sphere内有一点focus,该点沿某方向向量n0延伸,与球面交于一点f。求解该点focus沿该方向向量到球面的距离,即focus和f两点间距离。

输入:该点focus的坐标、方向向量n0的坐标、sphere球心坐标与半径R

输入:距离ans

0dda0cd51177563ba6ab9537c1556a45.png
淡蓝色球体中有一点focus,其沿着黑色箭头方向与球面交于点f2,求出两点间距离

02 数学公式推导

刚开始遇到这个问题,大致觉得可以编程实现,但是很多高中几何知识都忘了。经查阅,将数学描述放置于下方。

已知focus点的坐标

和方向向量n0
,可以得到两者所在直线的参数方程

而已知球面方程

将参数方程组带入球面桌面,可以得到关于参数t的一元二次方程组

其中A、B、C可用

等参数表示

求解可得

带回直线的参数方程,可得两交点坐标,可分别与focus求两点间距离。

最后判断是否沿方向向量方向,可以通过两向量对应部分符号是否相同来判断。

03 C++代码实现

这是最初版本,可根据实际需要修改。

#include <math.h>
#include<iostream>
using namespace std;

typedef struct Points
{
    double x,y,z;
}Point;

double fun(Point focus,Point normalVector,Point sphere,double R)
{
    //直接到直线参数方程带入球面式子,得到了关于参数t的一元二次方程
    double A,B,C;//ABC为关于t的一元二次方程的参数
    A=pow(normalVector.x,2) + pow(normalVector.y,2) + pow(normalVector.z,2);
    B=2*( (focus.x-sphere.x)*normalVector.x + (focus.y-sphere.y)*normalVector.y + (focus.z-sphere.z)*normalVector.z );
    C=pow(focus.x-sphere.x,2) + pow(focus.y-sphere.y,2) + pow(focus.z-sphere.z,2) - pow(R,2);
    //cout<<"A B C t1 t2: "<<A<<" "<<B<<" "<<C<<" ";

    //现在可得 A*t*t+B*t+C=0,解一元二次方程
    double t1,t2;
    t1 = (-B+sqrt(pow(B,2)-4*A*C)) / (2*A);
    t2 = (-B-sqrt(pow(B,2)-4*A*C)) / (2*A);
    //cout<<t1<<" "<<t2<<endl;

    //将t带入带原直线参数方程中,可以得到交点坐标
    Point intersection1,intersection2;//交点
    intersection1.x=normalVector.x*t1+focus.x;
    intersection1.y=normalVector.y*t1+focus.y;
    intersection1.z=normalVector.z*t1+focus.z;

    intersection2.x=normalVector.x*t2+focus.x;
    intersection2.y=normalVector.y*t2+focus.y;
    intersection2.z=normalVector.z*t2+focus.z;

    //现在知道求内点focus,两交点intersection,求法向量方向的距离
    if((intersection1.x-focus.x)*normalVector.x>0||(intersection1.y-focus.y)*normalVector.y>0||(intersection1.z-focus.z)*normalVector.z>0)
    {
        //这时候说明 intersection1 是和法向量同向的点
        double ans=sqrt(pow(intersection1.x-focus.x,2)+pow(intersection1.y-focus.y,2)+pow(intersection1.z-focus.z,2));
        return ans;
    }
    else
    {
        //这时候说明 intersection2 是和法向量同向的点
        double ans=sqrt(pow(intersection2.x-focus.x,2)+pow(intersection2.y-focus.y,2)+pow(intersection2.z-focus.z,2));
        return ans;
    }
}
int main()
{
    Point focus;//圆内该点
    Point normalVector;//法向量
    Point sphere;//园的圆心
    double R;//圆的半径

    cin>>focus.x>>focus.y>>focus.z;
    cin>>normalVector.x>>normalVector.y>>normalVector.z;
    cin>>sphere.x>>sphere.y>>sphere.z>>R;
    double ans=fun(focus,normalVector,sphere,R);
    cout<<"ans="<<ans<<endl;

}

04 特殊情况

但是很多实际情况中(给老师用后有错),该点focus很可能会出现在球面上,此时使用上述代码会出错。

因此接下来将讨论focus在球面上的情况:

  1. 方向向量与球面相切
  2. 方向向量与球面不相切,且该方向向量指向球体外部
  3. 方向向量与球面不相切,且该方向向量指向球体内部

情况1:只有一个交点,也就是focus本身,这时直接返回0

情况2:指向外部,则此时方向向量方向是0,返回0

情况3:指向内部,返回值应该为两交点间距离

修改后的代码如下:

#include <math.h>
#include<iostream>
using namespace std;

typedef struct Points
{
    double x,y,z;
}Point;

double fun(Point focus,Point normalVector,Point sphere,double R)
{
    //直接到直线参数方程带入球面式子,得到了关于参数t的一元二次方程
    double A,B,C;//ABC为关于t的一元二次方程的参数
    A=pow(normalVector.x,2) + pow(normalVector.y,2) + pow(normalVector.z,2);
    B=2*( (focus.x-sphere.x)*normalVector.x + (focus.y-sphere.y)*normalVector.y + (focus.z-sphere.z)*normalVector.z );
    C=pow(focus.x-sphere.x,2) + pow(focus.y-sphere.y,2) + pow(focus.z-sphere.z,2) - pow(R,2);
    // cout<<"A B C t1 t2: "<<A<<" "<<B<<" "<<C<<" ";

    //现在可得 A*t*t+B*t+C=0,解一元二次方程
    double t1,t2;
    t1 = (-B+sqrt(pow(B,2)-4*A*C)) / (2*A);
    t2 = (-B-sqrt(pow(B,2)-4*A*C)) / (2*A);
    // cout<<t1<<" "<<t2<<endl;

    if(t1==0&&t2==0)//该点在球面上,且方向向量与球面相切 ,无论哪个方向都是0 
        return 0;
    
    //将t带入带原直线参数方程中,可以得到交点坐标
    Point intersection1,intersection2;//交点
    intersection1.x=normalVector.x*t1+focus.x;
    intersection1.y=normalVector.y*t1+focus.y;
    intersection1.z=normalVector.z*t1+focus.z;
    intersection2.x=normalVector.x*t2+focus.x;
    intersection2.y=normalVector.y*t2+focus.y;
    intersection2.z=normalVector.z*t2+focus.z;

    double f1=(intersection1.x-focus.x)*normalVector.x+(intersection1.y-focus.y)*normalVector.y+(intersection1.z-focus.z)*normalVector.z;
    double f2=(intersection2.x-focus.x)*normalVector.x+(intersection2.y-focus.y)*normalVector.y+(intersection2.z-focus.z)*normalVector.z;

    //现在知道求内点focus,两交点intersection,求法向量方向的距离
    if(f1>0||f2<0)
    {
        //这时候说明 intersection1 是和法向量同向的点
        double ans=sqrt(pow(intersection1.x-focus.x,2)+pow(intersection1.y-focus.y,2)+pow(intersection1.z-focus.z,2));
        return ans;
    }
    else if(f1<0||f2>0)
    {
        //这时候说明 intersection2 是和法向量同向的点
        double ans=sqrt(pow(intersection2.x-focus.x,2)+pow(intersection2.y-focus.y,2)+pow(intersection2.z-focus.z,2));
        return ans;
    }

    return -1;
}
int main()
{
    Point focus;//圆内该点
    Point normalVector;//法向量
    Point sphere;//园的圆心
    double R;//圆的半径

    cin>>focus.x>>focus.y>>focus.z;
    cin>>normalVector.x>>normalVector.y>>normalVector.z;
    cin>>sphere.x>>sphere.y>>sphere.z>>R;
    double ans=fun(focus,normalVector,sphere,R);
    cout<<"ans="<<ans<<endl;

}
好的,我来为您解答。 首先,我们需要定义一个 `Point` 类,表示一个的坐标。这个类可以有两个私有成员变量 `x` 和 `y`,分别表示横坐标和纵坐标。 然后,我们可以在 `Point` 类中定义一个公有成员函数 `distanceTo`,用于计算当前和另一个之间的距离。这个函数接受一个 `Point` 类型的参数,表示另一个。函数的实现可以使用勾股定理,计算两点之间的距离。 接下来,我们可以使用友元函数来计算两个之间的距离友元函数是在类外部定义的函数,但可以访问类的私有成员。我们可以在 `Point` 类中声明一个友元函数 `distanceBetween`,用于计算两个之间的距离。这个函数接受两个 `Point` 类型的参数,分别表示两个。函数的实现可以直接调用 `distanceTo` 函数,计算出两个之间的距离。 最后,在主函数中,我们可以创建两个 `Point` 对象,分别表示两个,并调用 `distanceTo` 函数和 `distanceBetween` 函数,计算出两个之间的距离。 下面是代码示例: ```cpp #include <iostream> #include <cmath> using namespace std; class Point { private: double x, y; // 的坐标 public: Point(double _x, double _y): x(_x), y(_y) {} double distanceTo(Point p) { return sqrt(pow(x - p.x, 2) + pow(y - p.y, 2)); } friend double distanceBetween(Point p1, Point p2); }; double distanceBetween(Point p1, Point p2) { return p1.distanceTo(p2); } int main() { Point p1(0, 0); Point p2(3, 4); cout << "The distance between (" << p1.distanceTo(p2) << ")" << endl; cout << "The distance between (" << distanceBetween(p1, p2) << ")" << endl; return 0; } ``` 运行结果: ``` The distance between (5) The distance between (5) ``` 另外,我们也可以将 `distanceBetween` 函数定义为 `Point` 类的静态成员函数,这样就不需要使用友元函数了。下面是代码示例: ```cpp #include <iostream> #include <cmath> using namespace std; class Point { private: double x, y; // 的坐标 public: Point(double _x, double _y): x(_x), y(_y) {} double distanceTo(Point p) { return sqrt(pow(x - p.x, 2) + pow(y - p.y, 2)); } static double distanceBetween(Point p1, Point p2) { return p1.distanceTo(p2); } }; int main() { Point p1(0, 0); Point p2(3, 4); cout << "The distance between (" << p1.distanceTo(p2) << ")" << endl; cout << "The distance between (" << Point::distanceBetween(p1, p2) << ")" << endl; return 0; } ``` 运行结果: ``` The distance between (5) The distance between (5) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值