计算几何的模板实在是太臭太长了....*2
包含有如下函数:
1.三角形面积(包括已知三边长,已知三点,已知两边长和夹角弧度值)
2.多边形面积(凹多边形和凸多边形皆可)
3.判断多边形是否为凸多边形
4.点是否在凸多边形内
5.点是否在多边形内(凹凸皆可)
6.凸包和旋转卡壳
double triangle_area(dot a,dot b,dot c){//三角形面积
//已知三点坐标,求面积
return fabs(0.5*((a.x-b.x)*(c.y-b.y)-(c.x-b.x)*(a.y-b.y)));
}
double triangle_area(double a,double b,double c,bool three_sides){//三角形面积
if(three_sides==true){
//已知三边边长,求面积
double p;
p=0.5*a+0.5*b+0.5*c;
return sqrt(p*(p-a)*(p-b)*(p-c));//海伦公式
}
//已知两边边长a和b,与其夹角弧度值c
return 0.5*a*b*sin(c);
}
double polygon_area(dot* data,int n)
{//多边形面积,考虑到了凸多边形和凹多边形
//这些点已经按顺时针或者逆时针排好了
//n表示有n个点
double res=0;
for(int i=1;i<n-1;i++)
res+=(data[i].x-data[0].x)*(data[i+1].y-data[0].y)-(data[i].y-data[0].y)*(data[i+1].x-data[0].x);
return fabs(res);//有可能是负的,但是不影响大小
}
bool is_convex(dot poly[],int n){//判断这个是不是凸多边形
//顺时针逆时针均可
bool s[3];
memset(s,0,sizeof(s));
for(int i=0;i<n;i++)
{
s[sign((poly[(i+1)%n]-poly[i])^(poly[(i+2)%n]-poly[i]))+1]=true;
if(s[0]&&s[2]) return false;
}
return true;
}
int dot_in_convexpoly(dot a,dot p[],int n){//判断点a在凸多边形内
//多边形的点形成一个凸包且排列为逆时针
for(int i=0;i<n;i++)//点从0到n-1计数
{//顺时针的话就把if条件里面的<0改为>0
if(sign((p[i]-a)^(p[(i+1)%n]))<0) return -1;//点在多边形外
else if(dot_on_segment(a,line(p[i],p[(i+1)%n]))) return 0;//点在多边形上
}
return 1;//点在多边形内
}
int dot_in_poly(dot a,dot p[],int n){//判断点是否在任意的多边形内(凹多边形亦可)
int cnt=0;
line ray(a,dot(-100000000000.0,a.y)),side;
for(int i=0;i<n;i++)
{
side=line(p[i],p[(i+1)%n]);
if(dot_on_segment(a,side)) return 0;//点在多边形上
if(sign(side.s.y-side.e.y)==0) continue;
if(dot_on_segment(side.s,ray)){
if(sign(side.s.y-side.e.y)>0) cnt++;
}
else if(dot_on_segment(side.e,ray)){
if(sign(side.e.y-side.s.y)>0) cnt++;
}
else if(segment_inter(ray,side)) cnt++;
}
if(cnt%2==1) return 1;//点在多边形内
return -1;//点在多边形外
}
凸包, 顾名思义, 就是一个凸出来的包裹住所有点的包, 当然了, 构成凸包的点的数量应该尽可能地少.
这里的模板是针对二维的凸包, 三维的某位学长讲过, 不会.......有机会再学啦
dot O;//原点
bool cmp(dot p1,dot p2)
{//极角排序函数,角度相同则距离原点近的的在前面
double tmp=(p1-O)^(p2-O);
if (tmp>0) return 1;
if (tmp==0 && dot(O-p1).length()<dot(O-p2).length()) return 1;
return 0;
}
int work_on_convex_hull(dot data[],int n,int result[])
{
//直接将凸包图形的序号写进result[],并返回有多少个凸包顶点,排列为顺时针
//原始的输入数据data[]
//result[]里面记录的是编号,这个编号是用于在data[]里面寻找点的.
//res记录的是寻找出来的凸包究竟有多少个点,并作为函数返回值返回
int i,origin,res;
origin=0;
for(i=1;i<n;i++)
if((data[origin].x>data[i].x)||((data[origin].x==data[i].x)&&(data[origin].y>data[i].y)))
origin=i;
O=data[origin];//可能碰上不能直接复制结构体的情况,更换语句就可以了
data[origin]=data[0];
data[0]=O;//交换data中第0点和真正的原点的位置
sort(data+1,data+n,cmp);
if(n==1){
res=1; result[0]=0;//改变这里可以改变result数组存的是编号还是结构体
}
else if(n==2){
res=2; result[0]=0; result[1]=1;//改变这里可以改变result数组存的是编号还是结构体
}
else if(n>2){
res=0;result[0]=0;//鬼畜*3
for (int i=1;i<n;i++){
while(res>0 &&((data[result[res-1]]-data[result[res]])^(data[i]-data[result[res]]))>=0) res--;
res++;result[res]=i;//鬼畜*4
}
res++;
}
else res=0;
return res;
}
然后就是旋转卡壳了。
先问你们一个问题, 旋转卡壳怎么念啊?
(逃
用于计算已经处理好的(按顺时针或者逆时针?应该都可以, 我这里是顺时针)凸包点之中, 任意两个点之间的最大距离是多少.
double rotating_calipers(dot data[],int n)
{//旋转卡壳求最远点距
//前提:已经使用过work_on_convex_hull
int i=1,j;
double res=0;
data[n]=data[0];//这里这样做是怕你跑到外面去
for(j=0;j<n;j++)
{
while(((data[i+1]-data[j+1])^(data[j]-data[j+1]))>((data[i]-data[j+1])^(data[j]-data[j+1])))
i=(i+1)%n;//取余是怕你跑到外面去
res=max(res,max(dot(data[j]-data[i]).length(),dot(data[j+1]-data[i+1]).length()));
}
return res;
}
关于具体的使用方法可以参见这个main函数
P.S 头文件不要忘了哦
int main()
{
dot data[1000],graph[1000];
int i,n,num,res[1000];
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
scanf("%lf%lf",&data[i].x,&data[i].y);
num=work_on_convex_hull(n,data,res);
printf("This graph has %d dots\n",num);
for(i=0;i<num;i++)
{
printf("%dth dot%d x:%lf y:%lf\n",i,res[i],data[res[i]].x,data[res[i]].y);//本模版使用方式可以看这一行
graph[i]=data[res[i]];
}
cout<<rotating_calipers(graph,num)<<endl;
}
return 0;
}