计算几何(学习)模板
点结构:
struct point
{
double x,y;
point(double a = 0,double b = 0): x(a),y(b){}
};
浮点误差处理:
int dblcmp(double x)
{
if(fabs(x) < eps)
return 0;
return x > 0 ? 1:-1;
}
或者
int dblcmp(double x)
{
if (x > eps) return 1;
else if (x < -eps) return -1;
else return 0;
}
判断线段是否相交并求交点(规范相交)
double det(double x1, double y1, double x2, double y2)
{ //求叉积
return x1*y2 - x2*y1;
}
double cross(Point a, Point b, Point c)
{ //向量ab,和向量ac
return det(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y);
}
double dotdet(double x1, double y1, double x2, double y2)
{ //点积
return x1*x2 + y1*y2;
}
double dot(Point a, Point b, Point c)
{
return dotdet(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y);
}
int betweenCmp(Point a, Point b, Point c)
{ //判断a是不是在bc范围内
return dbcmp(dot(a, b, c));
}
bool segcross(Point a, Point b, Point c, Point d)
{
double s1, s2;
int d1, d2, d3, d4;
d1 = dbcmp(s1 = cross(a, b, c));
d2 = dbcmp(s2 = cross(a, b, d));
d3 = dbcmp(cross(c, d, a));
d4 = dbcmp(cross(c, d, b));
if((d1^d2) == -2 && (d3^d4) == -2)
{ //规范相交
return true;
}
//非规范相交
if((d1 == 0 && betweenCmp(c, a, b) <= 0) ||
(d2 == 0 && betweenCmp(d, a, b) <= 0) ||
(d3 == 0 && betweenCmp(a, c, d) <= 0) ||
(d4 == 0 && betweenCmp(b, c, d) <= 0))
return true;
return false;
}
叉积求多边形面积
double area(point p[],int n)
{ //这里是相对于原点(0, 0),也可以在多边形上找一个点作为向量的起点
double s = 0;
int i;
p[n].x = p[0].x;
p[n].y = p[0].y;
for(i = 0; i < n; ++i)
s += det(p[i].x, p[i].y, p[i+1].x, p[i+1].y);
return fabs(s / 2.0);
}
三角形面积:
1. 海伦公式
p = (a+b+c)/2; S = sqrt(p*(p-a)*(p-b)*(p-c));
2:叉积求解:一直三点:
A(x1,y1),B(x2,y2),C(x3,y3); S = fabs(-x2 * y1 + x3*y1+x1*y2-x3*y2-x1*y3+x2*y3) / 2.0;
判断多边形是否为凸多边形
输入p[1],p[2] ...p[n]。 令p[0] = p[n] p[n + 1] = p[1];
bool isconvexpg()
{
int dir = 0;
for (int i = 0; i <= n - 1; ++i)
{
int temp = dblcmp(cross(p[i],p[i + 1],p[i + 2]));
if (!dir) dir = temp;
if (dir*temp < 0) return false;
}
return true;
}
判断一点是否在多边形内,环顾法:
double getdis(point a,point b)
{
double x = a.x - b.x;
double y = a.y - b.y;
return sqrt(x*x + y*y);
}
//利用点积求角度
double getangle(point a,point b,point c)
{
double dj = dotdet(b.x - a.x,b.y - a.y,c.x - a.x,c.y - a.y);
double dis = getdis(a,b)*getdis(a,c);
double tmp = dj/dis;
return acos(tmp);
}
//判断是否在多边形内
bool IsIn()
{
int i;
double angle = 0.0;
for (i = 1; i <= n; ++i)
{
if (dblcmp(cross(cir,p[i],p[i + 1])) >= 0)
angle += getangle(cir,p[i],p[i + 1]);
else
angle -= getangle(cir,p[i],p[i + 1]);
}
//printf("angle == %lf\n",angle);
if (dblcmp(angle) == 0) return false;//在外边
else if (dblcmp(angle - pi) == 0 || dblcmp(angle + pi) == 0)//在边上
{
if (dblcmp(r) == 0) return true;
}
else if (dblcmp(angle - 2.0*pi) == 0 || dblcmp(angle + 2.0*pi) == 0)//在里面
{
return true;
}
else //在多边行顶点
{
if (dblcmp(r) == 0) return true;
}
return false;
}
求凸包的graham_scan算法模板
//这里起点与终点肯定在凸包上,不知道怎么证明
int graham(point *p,int len)
{
top = 0; int i;
//先排序,lrj黑书上的排序方法
sort(p,p + len,cmp);
stack[top++] = p[0];
stack[top++] = p[1];
//求右链
for (i = 2; i < len; ++i)
{
while (top > 1 && dblcmp(cross(stack[top - 2],stack[top - 1],p[i])) <= 0) top--;
stack[top++] = p[i];
}
//求左链
int tmp = top;
for (i =len - 2; i >= 0; --i)
{
while (top > tmp && dblcmp(cross(stack[top - 2],stack[top - 1],p[i]))<= 0) top--;
stack[top++] = p[i];
}
return top - 1;//起点两次进栈 - 1
}
利用凸包求最远点距离——旋转卡壳法:
int rotaing(point *p,int len)
{
p[len] = p[0];
int ans = 0,q = 1;
for (int i = 0; i < len; ++i)
{
while (cross(p[i],p[i + 1],p[q + 1]) > cross(p[i],p[i + 1],p[q]))
q = (q + 1)%len;
ans = max(ans,max(dis2(p[i],p[q]),dis2(p[i + 1],p[q + 1])));
//这里之所以计算i+1与q+1的距离是考虑到在凸多边形中存在平行边的问题
}
return ans;
}


浙公网安备 33010602011771号