基本的一些定义:
点:
向量的叉积
点的定位
两线段相交
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; }