叉乘(叉积)求两向量的交点?一张图就够了!——全网独家

先上数学证明

万物基于数学,算法也不例外
在这里插入图片描述
我得到的那个比值有什么用呢?
这也就引出了根本问题,为什么要去求AO/AB???为什么不能求CO/CD???
废话,这两个当然都嫩求,只不过在最后return的时候,对应的初始位置点不一样罢了,AO/AB,对应的就是A点,最后返回的时候A+AB*t,换成CO/CD也是一样,最后return C+CD*t

不要想着背模板,这无异于是自掘坟墓,弄懂弄透才是正道。

算法

通过上图,我们可以知道AO/AB=s▲ACD/s▲CB’D
因此我们只需要求出两个三角形的面积然后做比即可
求三角形的面积应该怎么求呢?
这里我们采用叉积的几何意义,向量a✖向量b=a的模长✖b的模长✖sin
而我们在高中的时候学过三角形的面积=1/2absinc,两者就可以对应起来,所以我们只需要知道两个向量即可。

叉积

首先这是一个二维平面,一个向量只有x,y两个方向的分量,这样难以写成行列式进行计算,我们可以手动添上K向量,代表Z轴的方向向量。这样就可以写成一个三阶行列式。

然后我们可以在纸上推演一下,能得到这个式子,因此我们就知道两个向量的叉积的计算公式,x1y2-x2y1.在这里插入图片描述

计算三角形面积

结合图片,我们要求的三角形面积为▲ACD和▲CB’D,那么有
S▲ACD=向量CA叉乘向量CD
S▲CB’D=向量CD叉乘向量CB’

我们能发现CD是反复使用的,而CB’的坐标就是AB的坐标,而向量CA可以通过C点的坐标和A的坐标求得,而最后得到的交点坐标也需要在C点坐标的基础上得到。因此我们在写自定义函数的时候需要传递2个向量和2个点。

为什么能保证叉乘的结果一定是正数?

这里需要说明一下啊,笔者从来没有说过这句话,谁说叉乘的结果一定是正的?我们也不需要保证叉乘的结果一定为正,各位读者细看,我们这里用到了两次叉乘,得到的是一个比值,也就是说我们只要保证两次叉乘得到的符号相同,那么就能够确保t的值一定为正!!!别看这里就写了这么点,笔者想了好久才想到,2333,还是太菜了。

在这里插入图片描述
废话不多说,直接上代码吧~

代码如下

#include<iostream>
#include<cmath>
using namespace std;

struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;

//自定义函数区
Point point_read();//读入点
Vector operator - (Point,Point);//点-点=向量
Vector operator + (Point,Vector);//向量+向量=向量    点+向量=向量
Vector operator * (double,Vector);//数*向量=向量    数*点=向量
double Cross(Vector,Vector);//计算向量叉积
Point point_inter(Point,Vector,Point,Vector);

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        //读入点的位置
        Point A,B,C,D;
        A=point_read();
        B=point_read();
        C=point_read();
        D=point_read();
        //计算向量    
        Vector AB=B-A;
        Vector CD=D-C;
        //判断两向量是否平行或共线
        if(Cross(AB,CD)==0){
            if(Cross(C-A,D-A)==0&&Cross(C-B,D-B)==0){//共线
                puts("LINE");
            }else{//平行
                puts("NONE");
            }
        }else{//相交
            Point ans=point_inter(A,AB,C,CD);
            printf("Point is:");
            printf("%.2lf  %.2lf\n",ans.x,ans.y);
        }
    }
    system("pause");
    return 0;
}


Point point_read()
{
    double x,y;
    scanf("%lf%lf",&x,&y);
    return Point(x,y);
}
Vector operator + (Point A,Vector AB)//向量+向量=向量    点+向量=向量
{
    return Vector(A.x+AB.x,A.y+AB.y);
}
Vector operator - (Point A,Point B)//点-点=向量
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (double k,Vector A)//数*向量=向量    数*点=向量
{
    return Vector(A.x*k,A.y*k);
}
double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
Point point_inter(Point A,Vector AB,Point C,Vector CD)
{
    Vector CA=A-C;
    double t=Cross(CD,CA)/Cross(AB,CD);
    return Point(A+t*AB);
}

附上测试样例吧

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值