基础几何学习笔记

1、向量

 

向量的定义为既有方向,又有长度,且可以自由平移的线段(注意不是有向线段,有向线段不可以自由平移,因为具有起点)。

PS:程序实现中,我们经常把向量的起点移到(0,0),然后用终点坐标(x,y)表示这个向量。

向量的定义:

 

struct Vector{

  double x,y;

  Vector(double x=0,double y=0):x(x),y(y){}//方便读入

};

typedef VectorPoint;   //定义点

struct Line   //直线的定义

{

    Pointp;

    Vector v;

    Line(Point P=Point(0,0),VectorV=Vector(0,0))

    {

        p=P,v=V;

    }

};

2、向量的基本运算

 

Vector operator +(const Vector a,const Vector b){return Vector(a.x+b.x,a.y+b.y);} //向量+向量 点+向量

Vector operator -(const Vector a,const Vector b){return Vector(a.x-b.x,a.y-b.y);} //点-点

Vector operator *(const Vector a,double b){return Vector(a.x*b,a.y*b);} //向量*点

Vector operator /(const Vector a,double b){return Vector(a.x/b,a.y/b);} //向量/点

 

bool operator <(const Vector a,const Vector b){     //小于号一般定义在结构体里,要调用STL排序(sort)时更加方便。

  returna.x<b.x||(a.x==b.x&&a.y<b.y);

}

 

const doubleeps=1e-10;     //这个是为了避免精度,eps的值随题目要求而定。

int dcmp(double x)

{

  if (fabs(x)<eps) return 0;

  return (x<0)?-1:1;

}

bool operator ==(const Vector a,const Vector b){    //dcmp是比较差值的函数,减少精度误差。

  returndcmp(a.x-b.x)==0&&dcmp(a.y-b.y==0);

}

 

3、向量的旋转

 

a=(x,y)可以看成是x*(1,0)+y*(0,1)

分别旋转两个单位向量 就变成了x*(cosα,sinα)+y*(-sinα,cosα)

合并后得(x*cosα-y*sinα,x*sinα+y*cosα)

 

VectorRotate(Vector A,double rad)

{

    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));

}

 

4、点积

 

(一)、求两个向量的点积

a·b的集合意义为a在b上的投影长度乘以b的模长

a⋅b=|a||b|cos<a,b>,其中<a,b>为ab间的夹角

坐标表示:a=(x1,y1),b=(x2,y2),a⋅b=(x1⋅x2,y1⋅y2)

 

double Dot(VectorA,Vector B)

{

    return A.x*B.x+A.y*B.y;

}

 

(二)、点积的性质

 

点积满足交换律

两个向量夹角是一个锐角时,点积为正数;为直角时点积为零(因此可用点积判垂直);为钝角时点积为负数

 

(三)、点积的应用

求向量的模长

 

double Len(VectorA)

{

    return sqrt(Dot(A,A));

}

 

求向量之间的夹角

 

doubleAngle(Vector A,Vector B)

{

    return acos(Dot(A,B)/Len(A)/Len(B));

}

 

5、单位向量与单位法向量

 

a/|a|为a的单位向量,与a同向,模为1

与a垂直的单位向量为a的单位法向量

求单位法向量

 

Vector Normal(Vector A)

{

    double L=Len(A);

    return Vector(-A.y/L,A.x/L);

}

 

6、叉积

(一)、求两个向量的叉积

 

两个二维向量的叉积是一个标量,a×b的几何意义为ab所形成的平行四边形的有向面积

坐标表示

a=(x1,y1),b=(x2,y2),a×b=x1∗y2−x2∗y1

 

doubleCross(Vector A,Vector B)

{

    return A.x*B.y-A.y*B.x;

}

 

(二)、叉积的性质

 

直观理解a×b,如果b在a的左边,叉积为正,右边为负,ab共线即为0

 

判断两条直线是否平行/相交/重合:

平行:两条直线各任选两个点组成两个向量平行(叉积为0)

相交:只需要判断是否平行即可(叉积为0)

重合:在平行的基础上,在两条直线上各选一个点组成一个向量在去与前两个判平行(叉积为0)

 

判断直线和线段是否相交:

在直线上任取两个点组成一个向量,再以其中的某一个点为起点到线段的两个端点分别组成两个向量,判断这两个向量和直线上向量的叉积是否同号,同号则不相交,异号则相交

 

double insLS(PointA,Point B,Point C,Point D)     //AB(直线)CD(线段)

{

    Vector v=B-A,w=C-A,u=D-A;

    return dcmp(Cross(v,w))!=dcmp(Cross(v,u));

}

 

判断两条线段是否相交:

和上一个的方法类似,只需要两个线段判断两次即可。同为真才为真。

 

7、点与线

 

(一)、点到直线的距离

 

用面积法

 

double DisTL(PointP,Point A,Point B)

{

    Vector v=B-A,w=P-A;

    return fabs(Cross(v,w)/Len(v));

}

 

(二)、点到线段的距离

 

分两种情况:一种是点到线段的垂线在线段上,这种情况同点到直线的距离,否则是点到点的距离

判断是哪种情况时用点积的正负判断很方便

 

double DisTS(PointP,Point A,Point B)

{

    if (A==B) return Len(P-A);

    Vector v=B-A,w=P-A,u=P-B;

    if (dcmp(Dot(v,w))<0) return Len(w);

    else if (dcmp(Dot(v,u))>0) returnLen(u);

    else return fabs(Cross(v,w)/Len(v));

}

 

(三)、求直线的交点

 

根据直线的分点(比值)来求

同样用面积法

 

Point GLI(PointP,Vector v,Point Q,Vector w)

{

    Vector u=P-Q;

    double t=Cross(w,u)/Cross(v,w);

    return P+v*t;

}

 

8、多边形

 

(一)、求三角形的外心

 

首先判断是否三点共线,共线的话即为线段的中点

否则任求两边的垂直平分线的交点即可

 

Point TC(PointA,Point B,Point C)

{

    Point P=(A+B)/2,Q=(A+C)/2;

    Vector v=Rotate(B-A,pi/2),w=Rotate(C-A,pi/2);

    if (dcmp(Cross(v,w))==0)

    {

        if(dcmp(Len(A-B)+Len(B-C)-Len(A-C))==0)

            return (A+C)/2;

        if(dcmp(Len(A-C)+Len(B-C)-Len(A-B))==0)

            return (A+B)/2;

        if (dcmp(Len(A-B)+Len(A-C)-Len(B-C))==0)

            return (B+C)/2;

    }

    return GLI(P,v,Q,w);

}

 

(二)、求三角形的重心

 

三角形的重心为三条中线的交点

经过推导可得G=(A+B+C)/3

 

Point TG(PointA,Point B,Point C)

{

    return (A+B+C)/3;

}

 

(三)、判断点是否在多边形内

 

射线法

注意判断点在多边形上的情况O(n)

 

bool PInP(Point P)

{

    int cnt=0,k,d1,d2;

    for (int i=1;i<=n;++i)

    {

        if(dcmp(DisTS(P,poly[i],poly[i%n+1]))==0) return false;

       k=dcmp(Cross(poly[i%n+1]-poly[i],P-poly[i]));

        d1=dcmp(poly[i].y-P.y);

        d2=dcmp(poly[i%n+1].y-P.y);

        if(k>0&&d1<=0&&d2>0) ++cnt;

        if(k<0&&d1>=0&&d2<0) --cnt;

    }

    if (cnt) return true;

    else return false;

}

 

(四)、求多边形面积

 

假如是凸多边形,可以在多边形内任取一点,进行三角剖分

因为叉积是有向面积,所以做法相同,基准点选在哪个点都可以

那么我们不妨选第一个点为基准点 O(n)

 

double Area()

{

    double area=0;

    for (int i=2;i<n;++i)

        area+=Cross(poly[i]-poly[1],poly[i+1]-poly[1]);

    return area/2;

}

 

(五)、Pick定理

 

一个计算点阵中顶点在格点上的多边形面积公式:S=a+b/2-1,其中a表示多边形内部的点数,b表示多边形边界上的点数,s表示多边形的面积。


(六)、四点共面

四个点构成的三个向量a,b,c共面的充要条件是存在不全为零的实数x,y,z满足x*a+y*b+z*c=0,转化为线性代数的3个向量线性相关的行列式为0


9、常用公式

。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值