[置顶] 计算几何所用知识回收站

1.向量的叉积

向量a=(x1,y1),b=(x2,y2);
   
     向量的叉积|a×b|=x1*y2-x2*y1;
   
   (1)当|a×b|>0时,b在a的逆时针方向,当a×b=0时,b与a共线,当a×b<0时,b在a的顺时针方向。

(2)|a×b|=|a| |b|sin<a,b>,三角形ABC,边向量a=AB,b=AC,面积S=1/2*|a×b|=1/2*(x1*y2-x2*y1)

(1)向量积判断线段相交

struct node{
    double x1,y1,x2,y2;
}e[maxn],f[maxn];
double cross(double x1,double y1,double x2,double y2)
{
    return x1*y2-x2*y1;
}
int find(node a,node b) //判断是否相交
{
    double c[4];
    c[0]=cross(a.x2-a.x1,a.y2-a.y1,b.x1-a.x1,b.y1-a.y1);
    c[1]=cross(a.x2-a.x1,a.y2-a.y1,b.x2-a.x1,b.y2-a.y1);
    c[2]=cross(b.x2-b.x1,b.y2-b.y1,a.x1-b.x1,a.y1-b.y1);
    c[3]=cross(b.x2-b.x1,b.y2-b.y1,a.x2-b.x1,a.y2-b.y1);
    if(c[0]*c[1]<=0&&c[2]*c[3]<=0)return 1;
    return 0;
}





2.重心

(1)三角形重心:x=(x0+x1+x3)/3,y=(y0+y1+y2)/3;

(2)质量集中在顶点上。n个顶点坐标为(xi,yi),质量为mi,则重心

  X = ∑( xi×mi ) / ∑mi
  Y = ∑( yi×mi ) / ∑mi
  特殊地,若每个点的质量相同,则
  X = ∑xi / n
  Y = ∑yi / n

       (3)已知一多边形没有边相交,质量分布均匀。顺序给出多边形的顶点坐标,求其重心。

    将n+2多变形分成n个三角形,总面积为S,分重心为(xi,yi),分面积为si,则重心为X=(∑si*xi)/S,Y=(∑si*yi)/S;(凹多边形和凸多边形,均适用)

  这里的si=0.5*(a×b),有正负值,表示边是按顺时针还是逆时针,用于求凹多边形时加减多余部分。


3.平面几何预算模板

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;
//基础点和向量运算
struct Point{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);}
bool operator <(const Point& a, const Point& b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double eps=1e-10;
int dcmp(double x)//判断正负,或者等于0
{
    if(fabs(x)<eps)return 0;else return x<0?-1:1;
}
bool operator==(const Point& a,const Point &b)
{
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Dot(Vector A, Vector B){return A.x*B.x+A.y*B.y;}//点积
double Length(Vector A){return sqrt(Dot(A,A));}//OA长
double Angle(Vector A,Vector B){return acos(Dot(A,B)/Length(A)/Length(B));}//OA和OB的夹角
double Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//叉积
double Area2(Point A,Point B,Point C){return Cross(B-A,C-A);}//三角形面积
Vector Rotate(Vector A,double rad)//rad为弧度,旋转rad度
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A)//A的单位法向量,A不能为零向量
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}

//点和直线
//P+tv表示一条直线,P为点,tv为方向向量
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)//求直线交点,确保存在交点,即Cross(v,w)非0
{
    Vector u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}
double DistanceToLine(Point P,Point A,Point B)//P点到直线AB的距离
{
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1,v2)/Length(v1));
}
double DistanceToSegment(Point P,Point A,Point B)//点P到线段AB的距离
{
    if(A==B)return Length(P-A);
    Vector v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(Dot(v1,v2))<0)return Length(v2);
    else if(dcmp(Dot(v1,v3))>0)return Length(v3);
    else return fabs(Cross(v1,v2)/Length(v1));
}
Point GetLineProjection(Point P,Point A,Point B)//点在直线上的投影
{
    Vector v=B-A;
    return A+v*(Dot(v,P-A)/Dot(v,v));
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)//判断线段相交,不在端点相交
{
    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}
bool OnSegment(Point p,Point a1,Point a2)//判断点是否在线段上(不包括端点)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}

//多边型
double ConvexPolygonArea(Point* p,int n)//多边形面积,,点按顺序
{
    double area=0;
    for(int i=1;i<n-1;i++)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return area/2;
}



int main()
{

}

圆:

const double PI=atan(1.0)*4;
//圆
struct Circle{//定义圆
    Point c;
    double r;
    Circle(Point c,double r):c(c),r(r){}
    Point point(double a){//根据圆心角计算圆上的坐标
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
};
struct Line{//定义线
    Point p,v;
    Line(Point p,Point v):p(p),v(v){}
    Point point(double a){
        return p+(v-p)*a;
    }
};
int getLineCircleIntersection(Line L,Circle C,double &t1,double &t2,vector<Point> &sol)//圆与线相交
{
    double a=L.v.x,b=L.p.x-C.c.x,c=L.v.y,d=L.p.y-C.c.y;
    double e=a*a+c*c,f=2*(a*b+c*d),g=b*b+d*d-C.r*C.r;
    double delta=f*f-4*e*g;
    if(dcmp(delta)<0)return 0;
    if(dcmp(delta)==0)
    {
        t1=t2=-f/(2*e);
        sol.push_back(L.point(t1));
        return 1;
    }
    t1=(-f-sqrt(delta))/(2*e);sol.push_back(L.point(t1));
    t2=(-f+sqrt(delta))/(2*e);sol.push_back(L.point(t2));
    return 2;
}
double angle(Vector v){return atan2(v.y,v.x);}//计算向量极角
int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point> &sol)//圆与圆相交
{
    double d=Length(C1.c-C2.c);
    if(dcmp(d)==0)
    {
        if(dcmp(C1.r-C2.r)==0)return -1;//两圆重合
        return 0;
    }
    if(dcmp(C1.r+C2.r-d)<0)return 0;
    if(dcmp(fabs(C1.r-C2.r)-d)>0)return 0;

    double a=angle(C2.c-C1.c);  //向量C1C2的极角
    double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
    //C1C2到C1P1的角
    Point p1=C1.point(a-da),p2=C1.point(a+da);

    sol.push_back(p1);
    if(p1==p2)return 1;
    sol.push_back(p2);
    return 2;
}
int getTangents(Point p,Circle C,Vector *v)//过定点作圆的切线
{
    Vector u=C.c-p;
    double dist=Length(u);
    if(dist<C.r)return 0;
    else if(dcmp(dist-C.r)==0)
    {
        v[0]=Rotate(u,PI/2);
        return 1;
    }
    else
    {
        double ang=asin(C.r/dist);
        v[0]=Rotate(u,-ang);
        v[1]=Rotate(u,+ang);
        return 2;
    }
}
//求两圆的切线
//返回切线的条数,-1表示无穷条切线
//a[i]和b[i]分别是第i条切线在圆A和圆B上的切点
int getTangents(Circle A,Circle B,Point *a,Point *b)
{
    int cnt=0;
    if(A.r<B.r){swap(A,B);swap(a,b);}
    double d2=(A.c.x-B.c.x)*(A.c.x-B.c.x)+(A.c.y-B.c.y)*(A.c.y-B.c.y);
    double rdiff=A.r-B.r;
    double rsum=A.r+B.r;
    if(dcmp(d2-rdiff*rdiff)<0)return 0;//内含

    double base=atan2(B.c.y-A.c.y,B.c.x-A.c.x);
    if(d2==0&&A.r==B.r)return -1;//重合
    if(dcmp(d2-rdiff*rdiff)==0)         //内切
    {
        a[cnt]==A.point(base);b[cnt]=B.point(base);cnt++;
        return 1;
    }
    //外公切线
    double ang=acos((A.r-B.r)/sqrt(d2));
    a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang);cnt++;
    a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang);cnt++;
    if(dcmp(d2-rsum*rsum)==0)
    {
        a[cnt]=A.point(base);b[cnt]=B.point(PI+base);cnt++;
    }
    else if(dcmp(d2-rsum*rsum)>0)
    {
        double ang=acos(A.r+B.r)/sqrt(d2);
        a[cnt]=A.point(base+ang);b[cnt]=B.point(PI+base+ang);cnt++;
        a[cnt]=A.point(base-ang);b[cnt]=B.point(PI+base-ang);cnt++;
    }
    return cnt;
}
//三角形外接圆
Circle CircumscribedCircle(Point p1,Point p2,Point p3)
{
    double Bx=p2.x-p1.x,By=p2.y-p1.y;
    double Cx=p3.x-p1.x,Cy=p3.y-p1.y;
    double D=2*(Bx*Cy-By*Cx);
    double cx=(Cy*(Bx*Bx+By*By)-By*(Cx+Cx+Cy*Cy))/D+p1.x;
    double cy=(Bx*(Cx*Cx+Cy*Cy)-Cx*(Bx*Bx+By*By))/D+p1.y;
    Point p=Point(cx,cy);
    return Circle(p,Length(p1-p));
}
//三角形内切圆
Circle InscribedCircle(Point p1,Point p2,Point p3)
{
    double a=Length(p2-p3);
    double b=Length(p3-p1);
    double c=Length(p1-p2);
    Point p=(p1*a+p2*b+p3*c)/(a+b+c);
    return Circle(p,DistanceToLine(p,p1,p2));
}

int ConvexHull(Point *p,Point *ch,int n)//求凸包
{
    sort(p,p+n);
    int i,m=0,k;
    for(i=0;i<n;i++)
    {
        while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    k=m;
    for(i=n-2;i>=0;i--)
    {
        while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    if(n>1)m--;
    return m;
}

三维几何:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;

const double pi=atan(1.0)*4;
const double r=6371009;
const double eps=1e-10;

struct Point3{//定义三维点
    double x,y,z;
    Point3(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
};
typedef Point3 Vector3;

Vector3 operator +(Vector3 A,Vector3 B){return Vector3(A.x+B.x,A.y+B.y,A.z+B.z);}
Vector3 operator -(Vector3 A,Vector3 B){return Vector3(A.x-B.x,A.y-B.y,A.z-B.z);}
Vector3 operator *(Vector3 A,double p){return Vector3(A.x*p,A.y*p,A.z*p);}
Vector3 operator /(Vector3 A,double p){return Vector3(A.x/p,A.y/p,A.z/p);}

double Dot(Vector3 A,Vector3 B){return A.x*B.x+A.y*B.y+A.z*B.z;}//点积
double Length(Vector3 A){return sqrt(Dot(A,A));}
double Angle(Vector3 A,Vector3 B){return acos(Dot(A,B)/Length(A)/Length(B));}
int dcmp(double x)
{
    if(fabs(x)<eps)return 0;
    else return x<0?-1:1;
}
bool operator ==(Vector3 A,Vector3 B){return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0&&dcmp(A.z-B.z);}

//点p到平面p0-n的距离。n必须为单位向量
double DistanceToPlane(const Point3 &p,const Point3 &p0,const Vector3 &n)
{
    return fabs(Dot(p-p0,n));
}
//点在平面上的投影。n必须是单位向量
Point3 GetPlaneProjection(const Point3 &p,const Point3 &p0,const Vector3 &n)
{
    return p-n*Dot(p-p0,n);
}
//直线p1-p2和平面的交点。假定点唯一存在
Point3 LinePlaneIntersection(Point3 p1,Point3 p2,Point3 p0,Vector3 n)
{
    Vector3 v=p2-p1;
    double t=(Dot(n,p0-p1)/Dot(n,p2-p1));//判断分母是否为0
    return p1+v*t;//如果是线段,判断t是否在0和1之间。
}

//三维叉积
Vector3 Cross(Vector3 A,Vector3 B)
{
    return Vector3(A.y*B.z-A.z*B.y,A.z*B.x-A.x*B.z,A.x*B.y-A.y*B.x);
}
double Area2(Point3 A,Point3 B,Point3 C){return Length(Cross(B-A,C-A));}
//判断点P0是否在三角形△P0P1P2中
bool PointInTri(Point3 P,Point3 P0,Point3 P1,Point3 P2)
{
    double area1=Area2(P,P0,P1);
    double area2=Area2(P,P1,P2);
    double area3=Area2(P,P2,P0);
    return dcmp(area1+area2+area3-Area2(P0,P1,P2))==0;
}
//△P0P1P2是否和线段AB相交
bool TriSegIntersection(Point3 P0,Point3 P1,Point3 P2,Point3 A,Point3 B,Point3 &P)
{
    Vector3 n=Cross(P1-P0,P2-P0);
    if(dcmp(Dot(n,B-A))==0)return false;//线段AB和平面P0P1P2平行或者共面
    else
    {
        double t=Dot(n,P0-A)/Dot(n,B-A);
        if(dcmp(t)<0||dcmp(t-1)>0)return false;//交点不在线段AB上
        P=A+(B-A)*t;                    //计算交点
        return PointInTri(P,P0,P1,P2);//判断交点是否在三角形内
    }
}
//点P到直线AB的距离
double DistanceToLine(Point3 P,Point3 A,Point3 B)
{
    Vector3 v1=B-A,v2=P-A;
    return Length(Cross(v1,v2))/Length(v1);
}
//点P到线段AB的距离
double DistanceToSegment(Point3 P,Point3 A,Point3 B)
{
    if(A==B)return Length(P-A);
    Vector3 v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(Dot(v1,v2))<0)return Length(v2);
    else if(dcmp(Dot(v1,v3))>0)return Length(v3);
    else return Length(Cross(v1,v2))/Length(v1);
}
//返回AB,AC,AD的混合积。它也等于四面体ABCD的有向体积的6倍。
double Volume6(Point3 A,Point3 B,Point3 C,Point3 D)
{
    return Dot(D-A,Cross(B-A,C-A));
}



int main()
{

}







你可能感兴趣的:(计算几何)