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、常用公式