计算几何模板——不断更新
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;
两线段相交
点在多边形内:(这种题还是用实题练习一下才行)
①叉积法(适用于凸多边形)
http://blog.csdn.net/lttree/article/details/24172989
②射线法 (注意多种特殊情况)
http://blog.csdn.net/lttree/article/details/24301607
③二分法 (适用于耗时较少,判断许多点的情况)
http://blog.csdn.net/lttree/article/details/24291719
直线相交求交点
求凸包(Graham算法)
求多边形重心,详情可见→http://blog.csdn.net/lttree/article/details/24720007
求向量绕自己一点旋转后点的坐标
// 向量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;
}
点:
[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;
}
相关文章推荐
- APS.NET CS0016: 未能写入输出文件“c:\WINDOWS\Microsoft.NET...”--“拒绝访问。
- Tomcat 配置 JNDI数据源出现Name jdbc is not bound in this Context
- bzoj 3522 tree-dp 暴力
- NYOJ--树的判定
- 想要成为Linux内核高手的四种有效途径
- JavaFX环境的搭建和一个简单的例子
- dns-prefetch
- 使用cv::findFundamentalMat要注意的几点
- jquery学习笔记
- hdu 1385 Minimum Transport Cost
- 隆安布泉乡推广种植栀子
- 星光之旅
- CRUX下实现进程隐藏(3)
- [leetcode]Jump Game I II
- file_operations结构
- 星光之旅
- 对数组的遍历及排序操作
- 带参数的可加载模块
- 设备驱动程序的分类
- W3C DOM 事件模型(简述)