计算几何--平面向量

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算几何--平面向量相关的知识,希望对你有一定的参考价值。

弧度

弧度π=角度180°

坐标表示法(a,b)的含义

大概就是:从(0,0)向(a,b)连一条有向线段,它表示的向量就与向量(a,b)相等。

或者:$(a,b)=ai+bj$,就是正交分解成两个分别与x、y轴同向的单位向量

点b与点a相减

直接两组坐标对应减即可,得到向量,得到一个方向为a到b的方向,长度为a与b的直线距离的向量

向量与数的乘/除

直接两个坐标乘/除该数字即可,得到向量,几何意义:方向不变,长度乘/除(本文中*号表示数乘)

点与向量的加/减

直接两组坐标对应加/减即可,得到点,几何意义:以该点为起点,沿着向量方向移动向量长度

向量与向量的加/减

直接两组坐标对应加/减即可,得到向量,几何意义:满足平行四边形法则/三角形法则

向量相同

长度相等且方向相同

向量共线(或称“平行”)

就是方向相同或相反,长度不管。判定:叉积为0

向量a与向量b的内积/点积/数量积(?)(返回一个数量)

a的长度*b的长度*cos夹角,$a{\\cdot}b=|a||b|cos\\theta$

这里的夹角指从a到b逆时针旋转的角,因此夹角绝对值大于90°时点积为负。

技术分享

($cos{\\theta}$图像)

几何意义:a的长度*b在a的方向上的投影

满足

交换律,分配律,结合律(可以几何证明)

垂直向量的内积为0。

a与b同向,那么内积等于长度的乘积。

a与b反向,那么内积等于长度乘积的相反数。

坐标计算:

设$a=x1*i+y1*j,b=x2*i+y2*j$,
那么$a{\\cdot}b=(x1*i+y1*j){\\cdot}(x2*i+y2*j)$
$=x1*x2*i^2+x1*y2*i*j+y1*x2*i*j+y1*y2*j^2$
由于i,j垂直且长度为1,那么$i^2=j^2=1$,$i{\\cdot}j=j{\\cdot}i=0$
所以$a{\\cdot}b=x1*x2+y1*y2$

向量夹角

用内积计算式变换一下即可。

${\\theta}=a{\\cdot}b/(|a||b|)$

向量长度(也叫“模”)

就是自身内积开平方根。

$|a|=\\sqrt{a{\\cdot}a}$

也可以理解为勾股定理。

向量a与向量b的叉积/外积(×)(返回一个向量)

(似乎一般只使用这个向量的长度也就是一个数量...)

$a{\\times}b=|a||b|sin{\\theta}$,就是三角形面积的某个公式乘2

$a{\\times}b=a.x*b.y-b.x*a.y$

满足

反交换律$a{\\times}b=-b{\\times}a$

分配律$a{\\times}(b+c)=a{\\times}b+a{\\times}c$

结合律$(r*a){\\times}b=a{\\times}(r*b)=r(a{\\times}b)$

几何意义:

把a和b的起点固定,a和b组成的三角形的“有向面积”的两倍,就是形成的一个平行四边形的面积。

所谓有向面积,如果从a到b旋转是逆时针,那么为正,如果是顺时针则为负(旋转取小于等于180°的角)。

或者说,沿着a的方向看,b在左侧,那么为正,如果在右侧则为负。

如果a、b共线,不管方向相同还是相反,叉积都为0。

向量旋转

设rad为逆时针旋转的角度(弧度制),那么新向量为$(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad))$

在2-D的迪卡尔坐标系中,一个位置向量的旋转公式可以由三角函数的几何意义推出。比如上图所示是位置向量R逆时针旋转角度B前后的情况。在左图中,我们有关系:

  x0 = |R| * cosA

  y0 = |R| * sinA

  =>

  cosA = x0 / |R|

  sinA = y0 / |R|

  在右图中,我们有关系:

  x1 = |R| * cos(A+B)

  y1 = |R| * sin(A+B)

  其中(x1, y1)就是(x0, y0)旋转角B后得到的点,也就是位置向量R最后指向的点。我们展开cos(A+B)和sin(A+B),得到

  x1 = |R| * (cosAcosB - sinAsinB)

  y1 = |R| * (sinAcosB + cosAsinB)

  现在把

  cosA = x0 / |R|

  sinA = y0 / |R|

  代入上面的式子,得到

  x1 = |R| * (x0 * cosB / |R| - y0 * sinB / |R|)

  y1 = |R| * (y0 * cosB / |R| + x0 * sinB / |R|)

  =>

  x1 = x0 * cosB - y0 * sinB

  y1 = x0 * sinB + y0 * cosB

  这样我们就得到了2-D迪卡尔坐标下向量围绕原点的逆时针旋转公式。

证明

直线的参数表示

$P+tv$,其中P为点,t为参数,v为向量(表示方向)

直线:t无限制;射线:t大于0;线段:t在0和1之间

直线交点

证明

设直线分别为$P+tv$和$Q+tw$。交点在第一条直线上参数为t1,第二条直线上参数为t2。

那么,$P+t1v=Q+t2w$

两边同时叉乘w,得到$(P+t1v){\\times}w=(Q+t2w){\\times}w$

分配律知,$P{\\times}w+t1v{\\times}w=Q{\\times}w+t2w{\\times}w$

结合律(?)知,$P{\\times}w+t1v{\\times}w=Q{\\times}w+t2(w{\\times}w)$

由$w×w=0$知,$P{\\times}w+t1v{\\times}w=Q{\\times}w$

则$t1v{\\times}w=Q{\\times}w-P{\\times}w=(Q-P){\\times}w=w{\\times}(P-Q)$

$t1=(w{\\times}(P-Q))/(v{\\times}w)=cross(w,P-Q)/cross(v,w)$

点到直线距离

简单,画图验证即可。基本就是直线上任取一点,叉积算出某个平行四边形的面积,再除以底。

直线上有点A、B,P到直线的距离是$(B-A){\\times}(P-a)/|(B-A)|$

如果不取绝对值,那么返回的是有向距离:

//(未验证)沿直线上两点形成有向线段方向看去,如果点在右侧那么为负,如果点在左侧则为正。

namespace X
{
    const double eps=1e-10;
    struct Point
    {
        double x,y;
        Point(double x=0,double y=0):x(x),y(y){}
    };
    typedef Point Vec;
    Vec operator+(const Vec& a,const Vec& b)
    {
        return Vec(a.x+b.x,a.y+b.y);
    }
    Vec operator-(const Vec& a,const Vec& b)
    {
        return Vec(a.x-b.x,a.y-b.y);
    }
    Vec operator*(const double& a,const Vec& b)
    {
        return Vec(a*b.x,a*b.y);
    }
    Vec operator*(const Vec& a,const double& b)
    {
        return Vec(b*a.x,b*a.y);
    }
    Vec operator/(const Vec& a,const double& b)
    {
        return Vec(a.x/b,a.y/b);
    }
    int dcmp(double x)
    {
        if(fabs(x)<eps)    return 0;
        return x<0?-1:1;
    }
    bool operator==(const Vec& a,const Vec& b)
    {
        return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
    }
    double dot(const Vec& a,const Vec& b)
    {
        return a.x*b.x+a.y*b.y;
    }
    double len(const Vec& x)
    {
        return sqrt(dot(x,x));
    }
    double angle(const Vec& a,const Vec& b)
    {
        return acos(dot(a,b)/len(a)/len(b));
    }
    double cross(const Vec& a,const Vec& b)
    {
        return a.x*b.y-a.y*b.x;
    }
    Vec Rotate(const Vec& a,const double& rad)
    {
        return Vec(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
    }
    Point get_line_intersection(const Point& p,const Vec& v,const Point& q,const Vec& w)
    {
        return p+v*cross(w,p-q)/cross(v,w);
    }
    double dis_to_line(const Point& p,const Point& a,const Point& b)
    {
        Vec v1=b-a,v2=p-a;
        return fabs(cross(v1,v2)/len(v1));
    }
    double dis_to_seg(const Point& p,const Point& a,const Point& b)
    {
        if(a==b)    return len(p-a);
        Vec v1=b-a,v2=p-a,v3=p-b;
        if(dcmp(dot(v1,v2))<0)    return len(v2);
        else if(dcmp(dot(v1,v3))>0)    return len(v3);
        else return fabs(cross(v1,v2)/len(v1));
    }
};

以上是关于计算几何--平面向量的主要内容,如果未能解决你的问题,请参考以下文章

计算几何/平面和空间

专题总结计算几何(未完)

平面解析几何初步--平面直角坐标系中的基本公式

向量乘积的几何意义

[模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和

计算几何学习5