define型计算几何模板
本想在寒假期间写点什么的…无奈域名出了点问题…
导致这一个半月里面网站一直处于无法访问的状态…
想起以前积累的计算几何模板…想差不多可以整理下发出来…
不过充斥着define…以及define的奇怪用法…可以说完全是C语言风格的代码…
总之这是一个基于数组和define而不是类和template的模板…会有人看吗…
如果每段代码都注解出一步步怎么得到的话…工程浩大…
结果心血来潮…给几乎每段代码画了个图片…
蓝色是已知,红色是所求…
画了几个才发现…有些还真难用图片表达啊…
那么就开始吧…
先是关于点,线,圆的形式的说明
说明: point,p,vector,v,点,向量: array[2] [0]:x,dx [1]:y,dy line,vl,直线: array[3] [0]:a [1]:b [2]:c 对应直线方程ax+by+c=0 circle,o,圆: array[3] [0]:x [1]:y [2]:r
#define PI 3.14159265358979 #define EPS 1e-10
#define IM(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]) #define IM2(ps1,pe1,ps2,pe2) ((pe1[0]-ps1[0])*(pe2[0]-ps2[0])+(pe1[1]-ps1[1])*(pe2[1]-ps2[1])) /* 外积大于0,则v2在v1左手方向 */ #define OM(v1,v2) (v1[0]*v2[1]-v1[1]*v2[0]) #define OM2(ps1,pe1,ps2,pe2) ((pe1[0]-ps1[0])*(pe2[1]-ps2[1])-(pe1[1]-ps1[1])*(pe2[0]-ps2[0])) #define SU(v1,v2,v3) v3[0]=v2[0]-v1[0];v3[1]=v2[1]-v1[1];
/*两点间距离平方*/
#define DIS2(p1,p2,ret) {double __v[2];SU(p1,p2,__v) ret=IM(__v,__v);}
/*两点间距离*/
double dis(long*p1,long*p2){
double v[2];
SU(p1,p2,v);
return sqrt(IM(v,v));
}
/* 三点求圆心 */ #define SQS(n,d) n=(d)*(d) #define ARCC(x1,y1,x2,y2,x3,y3,x0,y0) {\ double SQS(__y1,y1),SQS(__y2,y2),SQS(__y3,y3),SQS(__x1,x1),SQS(__x2,x2),SQS(__x3,x3); \ x0=((y3-y1)*(__y2-__y1+__x2-__x1)+(y2-y1)*(__y1-__y3+__x1-__x3))*0.5/ \ (double)((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)); \ y0=((x3-x1)*(__x2-__x1+__y2-__y1)+(x2-x1)*(__x1-__x3+__y1-__y3))*0.5/ \ (double)((y2-y1)*(x3-x1)-(y3-y1)*(x2-x1));} #define ARCCP(p1,p2,p3,pc) ARCC(p1[0],p1[1],p2[0],p2[1],p3[0],p3[1],pc[0],pc[1])
两点和直径求圆心:
/* 给定圆上两点和圆的直径求2个候选的圆心位置,不判断两点间距离是否超过直径 使用:math.h */ #define PDCC(x1,y1,x2,y2,d,rx1,ry1,rx2,ry2) {\ double SQS(_x,x2-x1),SQS(_y,y2-y1);\ double _u=sqrt(d*d/(_x+_y)-1);\ rx1=((x1+x2)+(y2-y1)*_u)/2;\ ry1=((y1+y2)-(x2-x1)*_u)/2;\ rx2=((x1+x2)-(y2-y1)*_u)/2;\ ry2=((y1+y2)+(x2-x1)*_u)/2;} #define PDCCP(p1,p2,d,r1,r2) PDCC(p1[0],p1[1],p2[0],p2[1],d,r1[0],r1[1],r2[0],r2[1])
圆外一点到圆的切点:
/* 求圆外一点到圆的2条切线的2个切点 po是圆心坐标,pp是圆外的一点,r是圆的半径,ret1和ret2存放2个切点坐标 不检测点是否在圆内 使用:向量运算,math.h */ #define TPC(p1,op,p2) (po[p1]+r*(r*d1[p1] op d1[p2]*sd)/s1) void tanpoint(double*po,double*pp,double r,double*ret1,double*ret2){ double d1[2],s1,sd; SU(po,pp,d1) s1=IM(d1,d1); sd=s1-r*r; if(sd<0)sd=-sd; sd=sqrt(sd); ret1[0]=TPC(0,+,1); ret1[1]=TPC(1,-,0); ret2[0]=TPC(0,-,1); ret2[1]=TPC(1,+,0); }
圆相交面积:
/* 圆相交面积 使用:向量运算,距离,常量,math.h */ double cosine(double b1, double b2, double b3){ double b = b2 * b2 + b3 * b3 - b1 * b1; return b / b2 / b3 / 2; } double circle_ins(double*o1,double*o2){ double dc=dis(o1,o2),r2=(o1[2]>o2[2]?o1[2]:o2[2]),r1=(o1[2]<o2[2]?o1[2]:o2[2]); if(r2-r1>=dc)return PI*r1*r1; else if(dc>=r2+r1)return 0; else{ double a1,a2,ang1,ang2,ret=0,s1=PI*r1*r1,s2=PI*r2*r2; a1=cosine(r2,r1,dc); a2=cosine(r1,r2,dc); ang1=acos(a1); ang2=acos(a2); if(a1>0)ret=(r1*r1*ang1-r1*r1*sin(ang1*2)/2); else ret=(r1*r1*ang1+r1*r1*sin((PI-ang1)*2)/2); if(a2>0)ret+=(r2*r2*ang2-r2*r2*sin(ang2*2)/2); else ret+=(r2*r2*ang2+r2*r2*sin((PI-ang2)*2)/2); return ret; } }
/* 给定两点,求其所在直线的解析式 ret[0]=a,ret[1]=b,ret[2]=c ax+by+c=0 使用:向量运算 */ #define PT_LINE(p1,p2,ret) {ret[1]=p2[0]-p1[0];ret[0]=p1[1]-p2[1];ret[2]=-IM(p1,ret);}
点关于直线的对称点:
/* 点关于直线的对称点 vl:直线解析式,pt:点,ret:返回对称点 使用:向量运算 */ #define PL_SYM(vl,pt,ret) {\ double __d=IM(vl,vl); \ ret[0]=((vl[1]*vl[1]-vl[0]*vl[0])*pt[0]-2*vl[0]*(vl[1]*pt[1]+vl[2]))/__d; \ ret[1]=((vl[0]*vl[0]-vl[1]*vl[1])*pt[1]-2*vl[1]*(vl[0]*pt[0]+vl[2]))/__d;}
直线交点:
/* 判断两条直线[ps1,pe1],[ps2,pe2]的交点情况: 0:平行 1:相交 2:重叠 如果有交点,返回值在ret中 使用:向量运算 */ long lineins(long*ps1,long*pe1,long*ps2,long*pe2,double*ret){ long v1[2],v2[2]; v1[0]=pe1[0]-ps1[0];v1[1]=pe1[1]-ps1[1]; v2[0]=pe2[0]-ps2[0];v2[1]=pe2[1]-ps2[1]; long mul=OM(v1,v2); if(mul==0){ v2[0]=pe2[0]-ps1[0]; v2[1]=pe2[1]-ps1[1]; return (OM(v1,v2)==0)?2:0; }else{ double t=((ps2[0]-ps1[0])*v2[1]+(ps1[1]-ps2[1])*v2[0])/(double)mul; ret[0]=ps1[0]+v1[0]*t; ret[1]=ps1[1]+v1[1]*t; return 1; } }
/* 点pt到直线[pl1,pl2]的距离平方 使用:向量运算 */ double dis2pl(double*pt,double*pl1,double*pl2){ double v1[2],v2[2]; SU(pt,pl1,v1)SU(pl1,pl2,v2) double om=OM(v1,v2); return om*om/IM(v2,v2); }
/* 直线[pl1,pl2]与圆[po,r]的交点,返回值为交点个数 ax+by+c=0; (x-ox)^2+(y-oy)^2=r^2 x=( b(b*ox-a*oy)-a*c土b*sqrt(r^2-dis2pl()^2) )/( a^2+b^2 ) y=( a(a*oy-b*ox)-b*c干a*sqrt(r^2-dis2pl()^2) )/( a^2+b^2 ) 使用:向量运算,常量,直线解析式,math.h */ long lcins(double*po,double r,double*pl1,double*pl2,double*ret1,double*ret2){ double vl[3],tmp1,tmp2; PT_LINE(pl1,pl2,vl) tmp1=IM(vl,po)+vl[2]; double ab=IM(vl,vl),mdis2=ab*r*r-tmp1*tmp1; if(mdis2<=-EPS)return 0; else{ tmp1=(vl[1]*OM(po,vl)-vl[0]*vl[2]); tmp2=(vl[0]*OM(vl,po)-vl[1]*vl[2]); if(mdis2<EPS){ ret1[0]=tmp1/ab;ret1[1]=tmp2/ab; return 1; }else{ double sq=sqrt(mdis2); ret1[0]=(tmp1+vl[1]*sq)/ab;ret1[1]=(tmp2-vl[0]*sq)/ab; ret2[0]=(tmp1-vl[1]*sq)/ab;ret2[1]=(tmp2+vl[0]*sq)/ab; return 2; } } }
直线和椭圆的交点:
/* 直线[pl1,pl2]与椭圆的交点,返回值为交点个数 ax+by+c=0 (x/d)^2+(y/e)^2=1 x=( -c*ad*d土be*d*sqrt(ad^2+be^2-c^2) )/( ad^2+be^2 ) y=( -c*be*e干ad*e*sqrt(ad^2+be^2-c^2) )/( ad^2+be^2 ) 使用:向量运算,常量,直线解析式,math.h */ long leins(double d,double e,double*pl1,double*pl2,double*ret1,double*ret2){ double vl[3]; PT_LINE(pl1,pl2,vl) double ab=vl[0]*vl[0]*d*d+vl[1]*vl[1]*e*e,delta=ab-vl[2]*vl[2]; if(delta<=-EPS)return 0; else if(delta<EPS){ ret1[0]=-vl[2]*vl[0]*d*d/ab; ret1[1]=-vl[2]*vl[1]*e*e/ab; return 1; }else{ double sq=sqrt(delta); ret1[0]=(-vl[2]*vl[0]*d*d+vl[1]*e*d*sq)/ab; ret1[1]=(-vl[2]*vl[1]*e*e-vl[0]*e*d*sq)/ab; ret2[0]=(-vl[2]*vl[0]*d*d-vl[1]*e*d*sq)/ab; ret2[1]=(-vl[2]*vl[1]*e*e+vl[0]*e*d*sq)/ab; return 2; } }
/* 整数点间连一条线,问穿过多少个单位正方形: =a+b-gcd(a,b) 扩展到三维: =a+b+c-gcd(a,b)-gcd(a,c)-gcd(b,c)+gcd(a,b,c) */
判断线段是否相交:
/* 判断两线段是否相交,跨立实验中用>则不包括端点,用>=则包括端点 使用:向量运算 */ #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) #define MN(a,b,t) (MAX(ps##a[t],pe##a[t])>=MIN(ps##b[t],pe##b[t])) long segins(long*ps1,long*pe1,long*ps2,long*pe2){ return MN(1,2,0)&&MN(2,1,0)&&MN(1,2,1)&&MN(2,1,1) && //快速排斥实验 (OM2(ps1,ps2,ps1,pe1)*OM2(ps1,pe1,ps1,pe2)>=0) && (OM2(ps2,ps1,ps2,pe2)*OM2(ps2,pe2,ps2,pe1)>=0); //跨立实验 }
点到线段的垂足:
/* 点pt到线段[ps,pe]所在直线的垂足,返回true表示垂足在线段上,垂足坐标存在ret中 使用:向量运算 */ long plfoot(double*pt,double*ps,double*pe,double*ret){ double vt[2],t,ret[2]; SU(ps,pe,vt) t=(-(ps[0]-pt[0])*(pe[0]-ps[0])-(ps[1]-pt[1])*(pe[1]-ps[1]))/IM(vt,vt); ret[0]=ps[0]+t*(pe[0]-ps[0]); ret[1]=ps[1]+t*(pe[1]-ps[1]); return !((ret[0]<ps[0]&&ret[0]<pe[0])||(ret[0]>ps[0]&&ret[0]>pe[0])|| (ret[1]<ps[1]&&ret[1]<pe[1])||(ret[1]>ps[1]&&ret[1]>pe[1])); }
点到线段的距离:
/* 点pt到线段[pl1,pl2]的距离的平方 使用:向量运算,常量,距离,点到直线距离 */ double dis2ps(double*pt,double*pl1,double*pl2){ double ret; if(IM2(pl1,pt,pl1,pl2)<-EPS)DIS2(pt,pl1,ret) else if(IM2(pl2,pt,pl2,pl1)<-EPS)DIS2(pt,pl2,ret) else ret=dis2pl(pt,pl1,pl2); return ret; }
角平分线上一点:
/* 求2个线段[pc,pl]和[pc,pr]组成的夹角的角平分线上的一个点 使用:向量运算,math.h */ void hangle(double*pl,double*pc,double*pr,double*ret){ double vl[2],vr[2]; SU(pc,pl,vl) SU(pc,pr,vr) double dl=sqrt(IM(vl,vl)),dr=sqrt(IM(vr,vr)); vl[0]/=dl;vl[1]/=dl; vr[0]/=dr;vr[1]/=dr; ret[0]=(vl[0]+vr[0])/2.0+pc[0]; ret[1]=(vl[1]+vr[1])/2.0+pc[1]; }
/* 三角形面积之海伦公式: p=(a+b+c)/2 s=sqrt((p-a)*(p-b)*(p-c)*p) */
三角形内切圆半径:
/* 三角形内切圆半径: 直角三角形:r=(a+b-c)/2,其中a,b是直角边长,c是斜边长 一般三角形:r=2S/(a+b+c),其中S是三角形面积 */
三角形内周长一定时的最大面积:
/* 三角形内周长一定的最大面积 triple=x+y+z; half=triple*0.5; area=sqrt(half*(half-x)*(half-y)*(half-z)); R=area*2.0/triple; if(x+y+z<=role) max=area; else if(2.0*PI*R>=role) max=role*role/(4.0*PI); else { r=(triple-role)/(triple/R-2.0*PI); max=area+PI*r*r-(r*r*area/(R*R)); } */
三角形重心:
/* 三角形重心 */
#define CGT(p1,p2,p3,pc) {pc[0]=(p1[0]+p2[0]+p3[0])/3;pc[1]=(p1[1]+p2[1]+p3[1])/3;}
判断点是否在三角形内:
/* 外积判断点是否在三角形内 在三角形内的返回2,边上的1,外面的0 使用:向量运算 */ long pint(long*p1,long*p2,long*p3,long*pm){ long v1[2],v2[2],t,l; SU(p1,p2,v1)SU(p1,pm,v2) if((t=OM(v1,v2))==0)return 1; t=t>0?1:-1; SU(p2,p3,v1)SU(p2,pm,v2) l=t*OM(v1,v2); if(l==0)return 1;else if(l<0)return 0; SU(p3,p1,v1)SU(p3,pm,v2) l=t*OM(v1,v2); if(l==0)return 1;else if(l<0)return 0; return 2; }
三角形内一点到3边的距离的平方和最小:(这个图片我实在想不出怎么画…)
/*
三角形内一点到3边的距离的平方和最小
void (double pts[3][2])
double x,y,vl[3][3],d2[3];
long i;
for(i=0;i<3;i++){
PT_LINE(pts[i],pts[(i+1)%3],vl[i]);
d2[i]=IM(vl[i],vl[i]);
}
double X=0,Y=0,C=0,U=0,B=0;
for(i=0;i<3;i++){
X+=vl[i][0]*vl[i][1]/d2[i];
Y+=vl[i][1]*vl[i][1]/d2[i];
C+=vl[i][1]*vl[i][2]/d2[i];
}
for(i=0;i<3;i++){
double t=vl[i][0]*Y-vl[i][1]*X;
U+=t*(vl[i][2]*Y-vl[i][1]*C)/d2[i];
B+=t*t/d2[i];
}
x=-U/B;
y=-(X*x+C)/Y;
*/
/* 判断矩形能否斜放在另一个矩形内 minh=(2xya+d*(x*x-y*y))/(x*x+y*y) (x>y) d=sqrt(x*x+y*y-a*a) return minh<=b 不判断面积大小和快速排斥 使用:math.h */ #define I __int64 long rcinrc(long w1,long h1,long w2,long h2){ if((w1<h1?w1:h1)<(w2<h2?w2:h2))return 0; I sq=(I)w2*(I)w2+(I)h2*(I)h2,l=2*(I)w2*(I)h2*(I)w1,a2=(I)w1*(I)w1; if(w2==h2||sq==a2)return l<=sq*h1; else{ if(w2<h2){long t=w2;w2=h2;h2=t;} if(sq<a2)return 0; I il=((I)w2*(I)w2-(I)h2*(I)h2); double dl=l+sqrt((double)(sq-a2))*il,dr=sq*h1; return dl<=dr; } }
三角形和圆的公共部分面积:
/* 点pt在线段[pl1,pl2]的位置 IM2(pl1,pt,pl1,pl2)<-EPS 点在线段外,pl1一侧 IM2(pl2,pt,pl2,pl1)<-EPS 点在线段外,pl2一侧 PTINSEG:点在线段所在直线的前提上,判断点是否在线段内,线段加长一段微小量 PTINSEGS:同上,线段缩小一段微小量 使用:向量运算,常量 */ #define PTINSEG(pt,pl1,pl2) ((IM2(pl1,pt,pl1,pl2)>=-EPS)&&(IM2(pl2,pt,pl2,pl1)>=-EPS)) #define PTINSEGS(pt,pl1,pl2) ((IM2(pl1,pt,pl1,pl2)>EPS)&&(IM2(pl2,pt,pl2,pl1)>EPS)) /* 2点和圆心组成的三角形与这个圆的公共部分面积 r是圆半径,原点是圆心 ps和pe是三角形另外两个点,逆时针为正 使用:向量运算,常量,直线和圆的交点,math.h */ #define VRAD(v,ret) {if(v[0]==0){if(v[1]>0)ret=PI/2;else ret=PI*3/2;}\ else{double _t=atan(v[1]/v[0]);if(v[0]<0)_t=PI+_t;ret=(_t<0?_t+PI*2:_t);}} #define MARC(rad) {if(rad>PI)rad-=PI*2;if(rad<-PI)rad+=PI*2;} double area_c2p(double r,double*ps,double*pe){ double d1=IM(ps,ps),d2=IM(pe,pe),r2=r*r; if(d1<=r2&&d2<=r2)return OM(ps,pe)/2; double rad1,rad2,po[2],ins1[2],ins2[2],drad; VRAD(ps,rad1)VRAD(pe,rad2) drad=rad2-rad1;MARC(drad) po[0]=po[1]=0; long nins=lcins(po,r,ps,pe,ins1,ins2); if(nins<=1)return drad/2*r*r; if((IM2(ps,ins1,ps,pe)<-EPS&&IM2(ps,ins2,ps,pe)<-EPS)||\ (IM2(pe,ins1,pe,ps)<-EPS&&IM2(pe,ins2,pe,ps)<-EPS))return drad/2*r*r; else if(PTINSEG(ins1,ps,pe)&&PTINSEG(ins2,ps,pe)){ double radi1,radi2,drad2,ret; if(PTINSEGS(ins1,ps,ins2)){VRAD(ins1,radi1)VRAD(ins2,radi2)ret=OM(ins1,ins2)/2;} else{VRAD(ins2,radi1)VRAD(ins1,radi2)ret=OM(ins2,ins1)/2;} drad=radi1-rad1;MARC(drad) drad2=rad2-radi2;MARC(drad2) return ret+(drad+drad2)/2*r*r; }else if(PTINSEG(ps,ins1,ins2)&&PTINSEG(pe,ins1,ins2))return OM(ps,pe)/2; else{ double*pins,*pout,radi; if(IM2(ps,ins1,ps,pe)<-EPS||IM2(pe,ins1,pe,ps)<-EPS){pins=ins2;pout=ins1;} else{pins=ins1;pout=ins2;} VRAD(pins,radi) if(IM2(pe,pout,pe,ps)<-EPS){ drad=radi-rad1;MARC(drad) return OM(pins,pe)/2+drad/2*r*r; }else{ drad=rad2-radi;MARC(drad) return OM(ps,pins)/2+drad/2*r*r; } } }
凸包:
/*排序用*/ #define POINT struct TPoint POINT{long xy[2];}pstart; long operator<(POINT a,POINT b){ long t=OM2(pstart.xy,a.xy,pstart.xy,b.xy); if(t==0){ long d1,d2; DIS2(pstart.xy,a.xy,d1) DIS2(pstart.xy,b.xy,d2) return d1<d2; }else return t>0; } /* O(nlogn)的凸包,返回值是凸多边形的顶点数,存在pts中,逆时针方向 使用:向量运算,距离,std::sort(algorithm) */ long convex(POINT*pts,long num,long*stack){ long i,minp,minx=0x7fffffff,miny; for(i=0;i<num;i++){ if(pts[i].xy[0]<minx){minx=pts[i].xy[0];miny=pts[i].xy[1];minp=i;} else if(pts[i].xy[0]==minx&&pts[i].xy[1]<miny)miny=pts[minp=i].xy[1]; } if(minx==0x7fffffff)return 0; POINT _t=pts[minp]; pts[minp]=pts[0]; pts[0]=_t; pstart=pts[0]; sort(pts+1,pts+num); long top=3; for(i=0;i<3;i++)stack[i+1]=i; for(i=3;i<num;i++){ while(OM2(pts[stack[top-1]].xy,pts[stack[top]].xy,pts[stack[top-1]].xy,pts[i].xy)<0)top--; stack[++top]=i; } for(i=1;i<=top;i++)pts[i-1]=pts[stack[i]]; return top; }
凸洞:见这里
6 条评论
Comments RSS
TrackBack Identifier URI
留下评论





















怎么说呢…这代码实在不是一般的难看…
图倒是挺可爱的.
评论 由 Answeror on 2011年02月23日 11:46 上午
ProjectEuler 331题是怎么解的?
是不是有什么文件可以参考?
评论 由 yang on 2011年04月4日 3:45 下午
不知…我是做了很多实验和假设才做出来的…这点大多数题目都一样…
在20人完成之前就问这种问题没关系吗?
评论 由 ben1222 on 2011年04月4日 4:14 下午
我只是想知道是否有文件
听到你这样说, 我就放心了
我很怕我做不出来是因为别人知道那份文件,而我不知道
评论 由 yang on 2011年04月4日 4:59 下午
Projecteuler 331想得快疯了
可以给个提示或方向吗?
我觉得331题比328题难好多
为什么328题第一天只有3个人答出,
331题第一天却有15个人?
难道是331题需要某些背景知识?
评论 由 Yang on 2011年04月8日 2:19 下午
我是按它的要求把这个游戏做出来手动玩了几盘,以期找出构造法
两个提示:
改变任意矩形四个顶点上的状态,也就是(x,y),(x,x),(y,x),(y,y)这四个点,看看效果
题目中的N=5对于奇数N来说是个特例
评论 由 ben1222 on 2011年04月8日 2:52 下午