计算几何模板——不断更新

基本的一些定义:

点:

[cpp]  view plain copy print ?
  1. struct point  
  2. {  
  3.     double x,y;  
  4. };  


线:

[cpp]  view plain copy print ?
  1. struct line  
  2. {  
  3.     point a,b;  
  4. };  
向量的长度

[cpp]  view plain copy print ?
  1. double distance(line l)  
  2. {  
  3.     return (l.b.x-l.a.x)*(l.b.x-l.a.x)-(l.b.y-l.a.y)*(l.b.y-l.a.y);  
  4. }  
  5. double distance(point p1,point p2)  
  6. {  
  7.     return (p2.x-p1.x)*(p2.x-p1.x)-(p2.y-p1.y)*(p2.y-p1.y);  
  8. }  
向量的点积

[cpp]  view plain copy print ?
  1. double dot(point p1,point p2)  
  2. {  
  3.     return p1.x*p2.x+p1.y*p2.y;  
  4. }  

向量的叉积

[cpp]  view plain copy print ?
  1. double cross(point p1,point p2)  
  2. {  
  3.     return p1.x*p2.y-p2.y*p1.x;  
  4. }  
[cpp]  view plain copy print ?
  1. // p0为起始点,求p1点在p0,p2所在直线的哪一侧  
  2. // 也可以说,p0p1构成的向量v在p0p2构成的向量w的哪一边  
  3. double cross(point p0,point p1,point p2)  
  4. {  
  5.     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);  
  6. }  

点的定位

[cpp]  view plain copy print ?
  1. /* 
  2. 判断点Q是否在线段P1P2上 
  3. ①(Q-P1)*(P2-P1)=0; 
  4. ② Q在以P1,P2为对角顶点的矩形内 
  5. */  
  6. bool onSegment(point Q,point p1,point p2)  
  7. {  
  8.     if( (Q.x-p1.x)*(p2.y-p1.y)==(p2.x-p1.x)*(Q.y-p1.y)  &&  
  9.         min(p1.x,p2,x)<=Q.x &&  
  10.         Q.x<=max(p1.x,p2.x) &&  
  11.         min(p1.y,p2.y)<=Q.y &&  
  12.         Q.y<=max(p1.y,p2.y) )  
  13.             return 1;  
  14.     else    return 0;  

两线段相交

const double EPS = 1e-10;
struct point
{
    double x,y;
};
struct line
{
    point a,b;
}l[100001];
double Max(double a,double b)   {return a>b?a:b;}
double Min(double a,double b)   {return a>b?b:a;}
// 判断两线段是否相交
bool inter(line l1,line l2)
{
    point p1,p2,p3,p4;
    p1=l1.a;p2=l1.b;
    p3=l2.a;p4=l2.b;

    if( Min(p1.x,p2.x)>Max(p3.x,p4.x) ||
       Min(p1.y,p2.y)>Max(p3.y,p4.y) ||
       Min(p3.x,p4.x)>Max(p1.x,p2.x) ||
       Min(p3.y,p4.y)>Max(p1.y,p2.y) )
        return 0;
    double k1,k2,k3,k4;
    k1 = (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x);
    k2 = (p2.x-p1.x)*(p4.y-p1.y) - (p2.y-p1.y)*(p4.x-p1.x);
    k3 = (p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x);
    k4 = (p4.x-p3.x)*(p2.y-p3.y) - (p4.y-p3.y)*(p2.x-p3.x);
    return (k1*k2<=EPS && k3*k4<=EPS);
}


点在多边形内:(这种题还是用实题练习一下才行)

①叉积法(适用于凸多边形)

http://blog.csdn.net/lttree/article/details/24172989

②射线法 (注意多种特殊情况)

http://blog.csdn.net/lttree/article/details/24301607

③二分法 (适用于耗时较少,判断许多点的情况)

http://blog.csdn.net/lttree/article/details/24291719


直线相交求交点

double x1,x2,x3,x4,y1,y2,y3,y4,x,y;
// 输入线段两个端点
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
scanf("%lf%lf%lf%lf",&x3,&y3,&x4,&y4);
// 判断是平行还是重合
if( (x2-x1)*(y4-y3) == (x4-x3)*(y2-y1) )
{
    // 重合
    if( (x3-x1)*(y4-y2) == (x4-x2)*(y3-y1) && (y4-y3)!=0 )
        printf("LINE\n");
    // 平行
    else    printf("NONE\n");
}
else    // 若相交则求交点,不难推出来
{
    x=( ((y1*(x2-x1))-x1*(y2-y1))*(x4-x3)-(y3*(x4-x3)-x3*(y4-y3))*(x2-x1) ) / ( (y4-y3)*(x2-x1)-(y2-y1)*(x4-x3) );
    y=( (y1*(x2-x1)-x1*(y2-y1))*(y4-y3)-(y3*(x4-x3)-x3*(y4-y3))*(y2-y1) ) / ( (y4-y3)*(x2-x1)-(y2-y1)*(x4-x3) );
    printf("POINT %.2lf %.2lf\n",x,y);
}

求凸包(Graham算法)

// pnt存输入的点,res存凸包内的点
struct point
{
    double x,y;
}pnt[10001],res[10001];
// 两向量叉积,此处用>=可以避免精度问题
double cross( point sp,point ep,point op)
{
    return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);
}
// sort数组排序,比较的<号重载
bool operator < (const point &l,const point &r)
{
    return l.y<r.y || (l.y==r.y && l.x<r.x) ;
}
int Graham( int n )
{
    int i,len,top=1;
    // 排序,纵坐标最小的排在前面,纵坐标相同,横坐标小的排在前面
    sort(pnt,pnt+n);
    // 判断点的个数是否大于2(所给的点能否构成凸包)
    if( n==0 )  return 0;res[0] = pnt[0];
    if( n==1 )  return 1;res[1] = pnt[1];
    if( n==2 )  return 2;res[2] = pnt[2];
    // 用叉积来判断后面的点是否为凸包中的点
    for( i=2;i<n;++i )
    {
        while( top && cross(pnt[i],res[top],res[top-1]) )   top--;
        res[++top] = pnt[i];
    }
    len = top; res[++top] = pnt[n-2];
    // 判断最后三个点
    for(i=n-3;i>=0;--i)
    {
        while( top!=len && cross(pnt[i],res[top],res[top-1]) )  top--;
        res[++top] = pnt[i];
    }
    // 返回凸包内点个数
    return top;
}

求多边形重心,详情可见→http://blog.csdn.net/lttree/article/details/24720007

struct point
{
    double x,y;
}pnt[1000001];
point bcenter( int n)
{
    point p,s;
    int i;
    double tp,area=0,tpx=0,tpy=0;
    p.x=pnt[0].x;p.y=pnt[0].y;
    for( i=1;i<=n;++i )
    {
        if( i==n )  s.x=pnt[0].x,s.y=pnt[0].y;
        else    s.x=pnt[i].x,s.y=pnt[i].y;
        tp = ( p.x*s.y - p.y*s.x );
        area+=tp/2.0;
        tpx+=(p.x+s.x)*tp;
        tpy+=(p.y+s.y)*tp;
        p.x=s.x;p.y=s.y;
    }
    s.x=tpx/( 6*area );
    s.y=tpy/( 6*area );
    return s;
}


求向量绕自己一点旋转后点的坐标

计算几何模板——不断更新_第1张图片

// 向量l,绕l.a点逆时针转a弧度,返回转到的点。
// OB=(x*cosα-y*sinα,x*sinα+y*cosα)
Point rotate_anticw(Line l,double a)
{
    Point p;
    p.x = ( l.b.x-l.a.x ) * cos(a) - ( l.b.y-l.a.y ) * sin(a);
    p.y = ( l.b.x-l.a.x ) * sin(a) + ( l.b.y-l.a.y ) * cos(a);
    p.x += l.a.x;
    p.y += l.a.y;
    return p;
}
// 向量l,绕l.a点顺时针转a弧度,返回转到的点。
// OA=(y*sinα - x*cosα,x*sinα+y*cosα)
Point rotate_cw(Line l,double a)
{
    Point p;
    p.x = ( l.b.y-l.a.y ) * sin(a) - ( l.b.x-l.a.x ) * cos(a);
    p.y = ( l.b.x-l.a.x ) * sin(a) + ( l.b.y-l.a.y ) * cos(a);
    p.x += l.a.x;
    p.y += l.a.y;
    return p;
}


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