您的位置:首页 > 其它

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

2014-04-18 21:38 423 查看
基本的一些定义:

点:

[cpp] view
plaincopyprint?





struct point  

{  

    double x,y;  

};  

线:

[cpp] view
plaincopyprint?





struct line  

{  

    point a,b;  

};  

向量的长度

[cpp] view
plaincopyprint?





double distance(line l)  

{  

    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);  

}  

double distance(point p1,point p2)  

{  

    return (p2.x-p1.x)*(p2.x-p1.x)-(p2.y-p1.y)*(p2.y-p1.y);  

}  

向量的点积

[cpp] view
plaincopyprint?





double dot(point p1,point p2)  

{  

    return p1.x*p2.x+p1.y*p2.y;  

}  

向量的叉积

[cpp] view
plaincopyprint?





double cross(point p1,point p2)  

{  

    return p1.x*p2.y-p2.y*p1.x;  

}  

[cpp] view
plaincopyprint?





// p0为起始点,求p1点在p0,p2所在直线的哪一侧  

// 也可以说,p0p1构成的向量v在p0p2构成的向量w的哪一边  

double cross(point p0,point p1,point p2)  

{  

    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);  

}  

点的定位

[cpp] view
plaincopyprint?





/* 

判断点Q是否在线段P1P2上 

①(Q-P1)*(P2-P1)=0; 

② Q在以P1,P2为对角顶点的矩形内 

*/  

bool onSegment(point Q,point p1,point p2)  

{  

    if( (Q.x-p1.x)*(p2.y-p1.y)==(p2.x-p1.x)*(Q.y-p1.y)  &&  

        min(p1.x,p2,x)<=Q.x &&  

        Q.x<=max(p1.x,p2.x) &&  

        min(p1.y,p2.y)<=Q.y &&  

        Q.y<=max(p1.y,p2.y) )  

            return 1;  

    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;
}


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



// 向量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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算几何模板