计算几何模板.docx
- 文档编号:4689767
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:12
- 大小:19.62KB
计算几何模板.docx
《计算几何模板.docx》由会员分享,可在线阅读,更多相关《计算几何模板.docx(12页珍藏版)》请在冰豆网上搜索。
计算几何模板
#include
#include
#include
#include
#include
usingnamespacestd;
constdoubleeps=1e-10;
constdoublepi=acos(-1.0);
constdoubleinf=1e100;
inlineintsig(doublex){
return(x>eps)-(x<-eps);
}
structpoint{//数据结构
doublex,y,dis,angle;
}
point(){}
point(constdouble&x_,constdouble&y_):
x(x_),y(y_){}
//逻辑运算
inlinebooloperator<(constpoint&t)const{
returnsig(y-t.y)<0||sig(y-t.y)==0&&sig(x-t.x)<0;
}
inlinebooloperator==(constpoint&t)const{
returnsig(x-t.x)==0&&sig(y-t.y)==0;
}
//算术运算
inlinepointoperator-(constpoint&b)const{
returnpoint(x-b.x,y-b.y);
}
inlinepointoperator+(constpoint&b)const{
returnpoint(x+b.x,y+b.y);
}
inlinepointoperator*(constdouble&t)const{
returnpoint(x*t,y*t);
}
inlinepointoperator/(constdouble&t)const{
returnpoint(x/t,y/t);
}
//求长度
inlinedoublelen(){
returnsqrt(x*x+y*y);
}
//长度的平方
inlinedoublelen2(){
returnx*x+y*y;
}
inlinedoubledist(pointt){
returnsqrt((x-t.x)*(x-t.x)+(y-t.y)*(y-t.y));
}
//输入输出
intread(){
returnscanf("%lf%lf",&x,&y);
}
voidout(){
printf("(%.2lf%.2lf)",x,y);
}
};
bool_cmp(constpoint&a,constpoint&b){
returnsig(a.angle-b.angle)<0||sig(a.angle-b.angle)==0&&sig(a.dis-b.dis)<0;
}
//点积
inlinedoubledot(pointp,pointa,pointb){//这种形式更常用
return(a.x-p.x)*(b.x-p.x)+(a.y-p.y)*(b.y-p.y);
}
//叉积,遵循左手定则(左旋为正)
inlinedoublecross(pointa,pointb){
returna.y*b.x-a.x*b.y;
}
inlinedoublecross(pointp,pointa,pointb){//这种形式更常用
return(a.y-p.y)*(b.x-p.x)-(a.x-p.x)*(b.y-p.y);
}
//angle>0表示逆时针旋转,angle<0为顺时针
//矢量pv以p为顶点逆时针旋转angle并放大scale倍
inlinepointrotate(pointv,pointp,doubleangle,doublescale){
pointret=p;
v.x-=p.x,v.y-=p.y;
p.x=scale*cos(angle); p.y=scale*sin(angle);
ret.x+=v.x*p.x-v.y*p.y;
ret.y+=v.x*p.y+v.y*p.x;
returnret;
}
//向量p的法向量,p逆时针旋转90度
inlinepointfaxiang(pointp){
returnpoint(-p.y,p.x);
}
//向量ab左移r长度
inlinepointleft(pointa,pointb,doubler){
pointta,tb,tt;
tt.x=b.y-a.y; tt.y=a.x-b.x;
doublek=r/sqrt(tt.x*tt.x+tt.y*tt.y);
tt.x=-tt.x*k; tt.y=-tt.y*k;
returntt;
}
//两向量之间的夹角[0,pi],乘以cross(a,b)后便成了有向夹角。
inlinedoublepoint_angle(pointa,pointb){
returnacos(dot(a,b)/sqrt(a.len2()*b.len2()));
returncross(a,b)*acos(dot(a,b)/sqrt(a.len2()*b.len2()));
}
//点到直线的距离
inlinedoublepoint_to_line(point&p,point&a,point&b){
returnfabs(cross(a,p,b)/(b-a).len());
}
//返回点p与线段ab的距离,
inlinedoublepoint_to_seg(point&p,point&a,point&b){
if(sig(dot(a,p,b))<0)//p在a端外
return(p-a).len();
if(sig(dot(b,p,a))<0)//p在b端外
return(p-b).len();
returnpoint_to_line(p,a,b);//p正对于ab
}
//返回线段ab与线段cd之间的距离,相交(有一个公共点)返回0,交点为p。
自己通过<,<=,来处理边界
inlinedoubleseg_to_seg(point&a,point&b,point&c,point&d,point&p){
if(!
((sig(max(a.x,b.x)-min(c.x,d.x))<0)||(sig(max(d.x,c.x)-min(a.x,b.x))<0)
||(sig(max(a.y,b.y)-min(c.y,d.y))<0)||(sig(max(d.y,c.y)-min(a.y,b.y))<0)))
{
if(sig(cross(a,b,c)*cross(a,b,d))<=0&&sig(cross(c,d,a)*cross(c,d,b))<=0){
p=a;
doublet=((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))
/((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x));
p.x+=(b.x-a.x)*t;
p.y+=(b.y-a.y)*t;
return0;
}
}
//不相交
returnmin(min(point_to_seg(a,c,d),point_to_seg(b,c,d)),min(point_to_seg(c,a,b),point_to_seg(d,a,b)));
}
//严格相交
inlineintseg_insert_line( point&a, point&b, point&c,point&d,point&p){
if(sig(cross(c,d,a)*cross(c,d,b))<0){
p=a;
doublet=((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))
/((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x));
p.x+=(b.x-a.x)*t;
p.y+=(b.y-a.y)*t;
return1;
}
return0;
}
//求向量a的极角,角度范围为[0,pi*2)
doubleangle(pointa){
doublet=atan2(a.y,a.x);
returnsig(t)>=0?
t:
t+pi*2;
}
//角度修正函数,根据不同的题目有不同写法和功能
voidfix_angle(double&rad){
if(sig(rad-pi)>0)rad-=pi*2;
if(sig(rad+pi)<0)rad+=pi*2;
}
//求直线和园相交。
0为相离,1为相切,2为相交,交点v1,v2,且v2到v1是逆时针指向
intline_insert_circle(pointc,doubler,pointa,pointb,point&v1,point&v2){
doubleh=fabs(cross(a,c,b)/(b-a).len());
if(sig(h-r)>0)
return0;
pointtmp=point(-(b-a).y,(b-a).x);
if(sig(cross(a,c,b))>0)
tmp.x=-tmp.x,tmp.y=-tmp.y;
tmp=tmp*(h/tmp.len());
pointmid=c+tmp;
if(sig(h-r)==0){
v1=mid;
return1;
}
doublel2=(r*r-h*h);
tmp=(b-a);
tmp=tmp*sqrt(l2/tmp.len2());
v1=tmp+mid;tmp.x=-tmp.x;
tmp.y=-tmp.y;v2=tmp+mid;
return2;
}
//判断点在线段上,条件:
pt,pl1,pl2共线
inlineboolpt_in_seg(pointpt,pointpl1,pointpl2){
return(sig(dot(pl1,pt,pl2))>=0&&sig(dot(pl2,pt,pl1))>=0);
}
//判断点在线段上(不含端点),条件:
pt,pl1,pl2共线
inlineboolpt_in_segs(pointpt,pointpl1,pointpl2){
return(sig(dot(pl1,pt,pl2))>0&&sig(dot(pl2,pt,pl1))>0);
}
inlineintpt_line(pointp1,pointp2,point&ret){
ret.y=p2.x -p1.x;ret.x=p1.y-p2.y;
ret.dis=-dot(p1,ret);
return0;
}
//求直线和园相交。
0为相离,1为相切,2为相交,交点v1,v2,且v2到v1是逆时针指向
intlcins(pointpo,doubler,pointpl1,pointpl2,point&ret1,point&ret2){
pointvl;
doubletmp1,tmp2;
pt_line(pl1,pl2,vl);
tmp1=dot(vl,po)+vl.dis;
doubleab=vl.len2(),mdis2=ab*r*r-tmp1*tmp1;
if(sig(mdis2)<0)
return0;
else{
tmp1=(vl.y*cross(vl,po)-vl.dis*vl.x);
tmp2=(vl.x*cross(po,vl)-vl.dis*vl.y);
if(sig(mdis2)<=0){
ret1.x=tmp1/ab;ret1.y=tmp2/ab;
return1;
}
else{
doublesq=sqrt(mdis2);
ret1.x=(tmp1+vl.y*sq)/ab;ret1.y=(tmp2-vl.x*sq)/ab;
ret2.x=(tmp1-vl.y*sq)/ab;ret2.y=(tmp2+vl.x*sq)/ab;
return2;
}
}
}
//半径为r,圆心在原点的圆,与三角形ps,pe,o的相交面积。
doublearea_c2p(doubler,pointps,pointpe){
doubled1=ps.len2(),d2=pe.len2(),r2=r*r;
doublerad1,rad2,drad;
if(d1<=r2&&d2<=r2)returncross(pe,ps)*.5;
pointpo(0,0),ins1,ins2;
rad1=angle(ps);rad2=angle(pe);
drad=rad2-rad1;fix_angle(drad);
intnins=line_insert_circle(po,r,ps,pe,ins1,ins2);
if(nins<=1)returndrad*.5*r*r;
if((sig(dot(ps,ins1,pe))<0&&sig(dot(ps,ins2,pe))<0)
||(sig(dot(pe,ins1,ps))<0&&sig(dot(pe,ins2,ps))<0))
returndrad*.5*r*r;
elseif(pt_in_seg(ins1,ps,pe)&&pt_in_seg(ins2,ps,pe)){
doubleradi1,radi2,drad2,ret;
if(pt_in_segs(ins1,ps,ins2)){
radi1=angle(ins1);radi2=angle(ins2);
ret=cross(ins2,ins1)*.5;
}
else{
radi1=angle(ins2);radi2=angle(ins1);
ret=cross(ins1,ins2)*.5;
}
drad=radi1-rad1;
fix_angle(drad);
drad2=rad2-radi2;
fix_angle(drad2);
returnret+(drad+drad2)*.5*r*r;
}
else{
pointpins,pout;
doubleradi;
if(sig(dot(ps,ins1,pe))<0||sig(dot(pe,ins1,ps))<0){
pins=ins2,pout=ins1;
}
else{
pins=ins1,pout=ins2;
}
radi=angle(pins);
if(sig(dot(pe,pout,ps)<0)){
drad=radi-rad1;fix_angle(drad);
returncross(pe,pins)*.5+drad*.5*r*r;
}
else{
drad=rad2-radi;fix_angle(drad);
returncross(pins,ps)*.5+drad*.5*r*r;
}
}
}
//半径为r圆,圆心在原点上的圆与多边形的相交面积
doublearea_cpoly(doubler,pointpts[],intnp){
inti;doubleret=0;
for(i=1;i ret+=area_c2p(r,pts[i-1],pts[i]); } returnret+area_c2p(r,pts[np-1],pts[0]); } //求圆和圆相交,返回交点个数,两圆重合返回-1 inlineintcir_insert_cir(pointc1,doubler1,pointc2,doubler2,point&p1,point&p2){ doubledist=c1.dist(c2),tmp; if(sig(dist-r1-r2)>0)//外离 return0; doubler_min=min(r1,r2),r_max=max(r1,r2); if(dist return0;//内离 if(sig(dist-r1-r2)==0){//外切 p1=c1+(c2-c1)*(r1)/(dist); return1; } if(dist if(sig(dist)==0) return-1;//两圆重合 p1=c1+(c2-c1)*(r_max)/(dist); return1; } pointu,v; doublet; t=(1+(r1*r1-r2*r2)/dist/dist)/2; u.x=c1.x+(c2.x-c1.x)*t; u.y=c1.y+(c2.y-c1.y)*t; v.x=u.x+c1.y-c2.y; v.y=u.y-c1.x+c2.x;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算 几何 模板