计算几何学习笔记
向量表示
当然是用点对((a,b))表示一个向量啊。
点积
(a_xcenterdot b_x+a_ycenterdot b_y)
这个东西可以判正交:
考虑他的向量形式是:
(vec{a}·vec{b}=|vec{a}||vec{b}|cos<vec{a},vec b>)
显然(cos(90°))=0,然后就可以如果点积为0,就垂直。
叉积
(a.x*b.y-a.y*b.x)
这是三角形有向面积的一半。
证明如下:
当然这个上面的推断是无向面积,有向面积换一下点就好了。
当然叉积可以判平行啊,写成向量的形式就是:
(vec{a}centerdot vec{b}=|vec{a}||vec{b}|sin<vec{a},vec{b}>)
看到sin不就直接和上面一样的判就好了。
如果向量1在逆时针(就是在左边),叉积为负,否则叉积为正。
判交
可以用点积+叉积判交。
考虑下面两种情况:
- 不平行,显然考虑点积和叉积判断点q在不在两条线段上就好了。
- 平行,这个直接搞(注意平行可能也有交)
转角
考虑一下如果一个向量在单位圆上,与x轴的夹角是(eta(etaleq 180°))显然他就是((R*sineta,R*coseta)),那么现在R就是他的模长(其实就是长度)。
然后如果增加的是(alpha)的话,直接和差角公式搞一下就好了。
极角
考虑怎么算上面那一个(eta),直接(acos(a.y,a.x))
凸包
这个东西的定义很简单不是吗?
求解:一般性用Graham扫描
吧...
void Graham()
{
//p数组先极角排序(p[1]是边界点,先算p[1])
s[top=1]=p[1];
for(int i=2;i<=n;i++)
p[i].ang=atan2(p[i].y-p[1].y,p[i].x-p[1].x);
sort(p+2,p+n+1,cmpang);s[++top]=p[2];
for(int i=2;i<=n;i++)
{
while(top>1 && cross(p[i]-s[top],p[i]-s[top-1])>=0)top--;
s[++top]=p[i];
}
}
凸包面积
直接按照边划分成三角形然后cross
算面积就好了.
最小圆覆盖
枚举第一个点,考虑当前圆是否包含了这个点,如果没有,则把圆变成以这个点为圆心,半径为0的圆。再枚举第二个点,考虑圆是否包含了这个点,如果没有,则把圆变成以这两个点的中点为圆心,半径为两点距离一半的圆。再枚举第三个点,节点是否在圆内,如果不在,则把圆直接变成这三个点的外接圆
这个算法看上去是(O(n^3))的,但是把点随机打乱之后是(O(n))的.
void GetCircle(point *p,int n){
random_shuffle(&p[1],&p[n+1]);
for(int i=1;i<=n;i++)
if(Dis(O.o,p[i])>O.r){
O.o=p[i];O.r=0;
for(int j=1;j<i;j++)
if(Dis(O.o,p[j])>O.r){
O.o=(p[i]+p[j])*0.5;O.r=Dis(p[i],p[j])*0.5;
for(int k=1;k<j;k++)
if(Dis(O.o,p[k])>O.r){
O.o=Intersecion(gethalfline((line){p[i],p[j]-p[i]}),gethalfline((line){p[i],p[k]-p[i]}));
O.r=Dis(O.o,p[i]);
}
}
}
printf("%.10lf
%.10lf %.10lf
",O.r,O.o.x,O.o.y);
}
自适应Simpson法
这个随便背一下模板就好了.