NanoApe's Blog

既是咸鱼又是辣鸡

【计算几何】基础几何

NanoApe posted @ 2016年2月17日 18:17 in 蒟蒻不撕烤智熵何来 , 1076 阅读

 

基础定义​

//圆周率
#define Pi acos(-1)

//结构体-点
struct Point{double x, y;};

//结构体-线
struct line{double a, b, c;};

//逆时针旋转向量(弧度)
Point Rotate(Point a, double rad)
{return (Point){a.x*cos(rad)-a.y*sin(rad), a.x*sin(rad)+a.y*cos(rad)};}

//叉积,a*b>0表示向量b在向量a的左边
double operator * (Point a, Point b){return a.x*b.y-a.y*b.x;}

//向量求极角
atan2(b.y-a.y, b.x-a.x)

半平面交

sort(l+1, l+m+1); //极角排序
cnt=0; 
rep(i, 1, m)
{
    if (l[i].ang!=a[cnt].ang) cnt++;
    a[cnt]=l[i];
} //极角排重
L=1, R=0; q[++R]=a[1]; q[++R]=a[2];
rep(i, 3, cnt)
{
    while (L<R && jud(q[R-1], q[R], a[i])) R--;
    while (L<R && jud(a[i], q[L], q[L+1])) L++;
    q[++R]=a[i];
}
while (L<R && jud(q[R-1], q[R], q[L])) R--;
while (L<R && jud(q[R], q[L], q[L+1])) L++;

凸包

int k=1;
rep(i, 2, n) if (p[i].y<p[k].y || (p[i].y==p[k].y && p[i].x<p[k].x)) k=i;
swap(p[1], p[k]); 
//先把横纵坐标最小的点移至第一
sort(p+2, p+n+1, cmp); 
//所有点顺时针排列,相同角度时按距离从小到大排
s[++top]=p[1]; s[++top]=p[2];
rep(i, 3, n)
{
    while (top>1 && (p[i]-s[top-1])*(s[top]-s[top-1])<=0) top--;
    s[++top]=p[i];
}

动态加点维护凸包

//点按照横纵坐标排序
set<P>::iterator r=q.lower_bound(p), l=r, t; l--;
if ((*r-*l)*(p-*l)<0) return;
now-=dis(*l, *r);
while (1)
{
    t=r++;
    if (r==q.end()) break;
    if ((*r-p)*(*t-p)>0) break;
    now-=dis(*t, *r);
    q.erase(t);
}
while (l!=q.begin())
{
    t=l--;
    if ((*t-p)*(*l-p)>0) break;
    now-=dis(*t, *l);
    q.erase(t);
}
q.insert(p); l=r=q.find(p); l--; r++;

圆心角$\theta$所对弓形面积:$S=\frac{1}{2}r^2(\theta - sin(\theta))$(部分圆减去三角形部分)

圆交

四种情况:相离相切、相交且两圆心分居公共弦两侧、相交且两圆心位于公共弦一侧、包含

半平面交

Step1:将所有半平面按极角排序,对于极角相同的,选择性的保留一个

Step2:使用一个双端队列,加入最开始2个半平面

Step3:每次考虑一个新的半平面:

a.假如队列顶端的两个半平面的交点在当前半平面外,删除deque顶端的半平面

b.假如队列底部的两个半平面的交点在当前半平面外,删除deque底部的半平面

c.将新半平面加入队列顶端

Step4:删除两端多余的半平面:

a.假如队列顶端的两个半平面的交点在底部半平面外,删除deque顶端的半平面

b.假如队列底部的两个半平面的交点在顶端半平面外,删除deque底部的半平面

Step5:计算出deque顶端和底部的交点即可

#define eps 1e-8

int n, x[maxn], y[maxn];
struct node{int x1,y1,x2,y2; ld a;} k[maxn], q[maxn], g[maxn]; int L, R, tot; bool fg;
struct P{ld x,y;} p[maxn];

inline bool Right(node a, P b){return (b.y-a.y1)*(a.x2-a.x1)-(b.x-a.x1)*(a.y2-a.y1)<0;}

inline P cross(node a, node b)
{
	ld a1=a.y2-a.y1, b1=a.x1-a.x2, c1=1LL*a.x2*a.y1-1LL*a.x1*a.y2;
	ld a2=b.y2-b.y1, b2=b.x1-b.x2, c2=1LL*b.x2*b.y1-1LL*b.x1*b.y2;
	if (fabs(fabs(a.a-b.a)-atan2(0,-1))<eps) fg=true; // fg为true时答案为空集
	return (P){(b1*c2-b2*c1)/(a1*b2-a2*b1),(a1*c2-a2*c1)/(b1*a2-b2*a1)};
}

bool cmp(node a, node b) {return a.a>b.a;}

int main()
{
	
	//........
	
	rep(i, 1, n) k[i]=(node){x[i],y[i],x[i+1],y[i+1],atan2(y[i+1]-y[i],x[i+1]-x[i])};
	sort(k+1, k+1+n, cmp);
	
	g[tot=1]=k[1]; rep(i, 2, n) 
		if (k[i-1].a-k[i].a>eps) g[++tot]=k[i];
		else if (Right(g[tot],(P){(ld)k[i].x1,(ld)k[i].y1})) g[tot]=k[i];
		
	L=1, R=0, q[++R]=g[1], q[++R]=g[2];
	rep(i, 3, tot)
	{
		while (L<R && !Right(g[i],cross(q[R],q[R-1]))) R--;
		while (L<R && !Right(g[i],cross(q[L],q[L+1]))) L++;
		q[++R]=g[i];
	}
	while (L<R && !Right(q[L],cross(q[R],q[R-1]))) R--;
	while (L<R && !Right(q[R],cross(q[L],q[L+1]))) L++;
	
	//........
	
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter