zoukankan      html  css  js  c++  java
  • 二维计算几何基础

    表示方法

    用两个变量((x,y))表示

    struct pt{
    	db x,y;
    	pt(db _x=0,db _y=0){x=_x,y=_y;}
    	inline void read(){scanf("%lf %lf",&x,&y);}
    	inline void print(){printf("%.3lf %.3lf
    ",x,y);}
    };
    

    用点也可以表示向量,即((0,0) o (x,y)​)的向量

    欧几里得距离

    (sqrt{x^2+y^2})

    inline db len2(pt a){return a.x*a.x+a.y*a.y;}
    inline db len(pt a){return sqrt(a.x*a.x+a.y*a.y);}//距离 
    

    向量的坐标表示

    (A(a,b),B(c,d)),那么(overrightarrow{AB}=(a-c,b-d))

    向量

    前置芝士:高中数学必修四 第二章 平面向量

    一个点在一个向量的左边指:该点在向量的逆时针方向

    向量运算

    加减与数乘

    inline pt operator +(pt a,pt b){return pt(a.x+b.x,a.y+b.y);}
    inline pt operator -(pt a,pt b){return pt(a.x-b.x,a.y-b.y);}
    inline pt operator *(pt a,db b){return pt(a.x*b,a.y*b);}//数乘 
    

    点积

    设向量 (a,b) 夹角为 ( heta)

    [acdot b=|a||b|cos heta ]

    几何意义:(a)的模与(b)(a)方向上的投影的乘积

    坐标运算

    (a=(m,n),b=(p,q)),则 (acdot b=mp+nq)

    inline db operator *(pt a,pt b){return a.x*b.x+a.y*b.y;}//点积
    

    应用

    • 根据正负号判断夹角:$>0 o (锐角,)=0 o (直角,)<0 o ​$钝角
    • 计算夹角:(cos heta = dfrac{|a||b|}{acdot b})

    叉积

    这部分是高中教材没有的

    叉积也叫向量积

    向量(a,b)的叉积(a imes b)是一个向量,其模长(|a imes b|=|a||b|sinlangle a,b angle),方向遵循右手定则(右手定则:右手除姆指外的四指合并,姆指与其他四指垂直,四指由(a)向量的方向握向(b)向量的方向,这时姆指的指向就是(a,b)叉积的方向)

    关于叉积的方向,在OI中应用较少,我们只需要记住

    [|a imes b|=|a||b|sinlangle a,b angle ]

    坐标运算

    (a=(m,n),b=(p,q)),则 (|a imes b|=mq-np)

    inline db operator ^(pt a,pt b){return a.x*b.y-a.y*b.x;}
    

    应用

    • 计算面积:三角形面积公式为(S=dfrac{1}{2}absin C)(|a imes b|)就是(a,b)为领边的平行四边形面积(有向面积),除以(2​)即可计算三角形面积
    inline db S_tri(pt a,pt b,pt c){return fabs((a-c)^(b-c))/2.0;
    
    • 判断方向:顺负逆正
    inline bool Left(Line a,pt b){return sgn((a.y-a.x)^(b-a.x))>=0;}//是否在左边(逆时针) 
    

    向量旋转

    (a=(x,y)),逆时针旋转( heta​)(角度制),旋转之后的向量为

    [a=(xcos heta-ysin heta,xsin heta+ycos heta) ]

    证明:

    (|a|=l),夹角为(alpha)(lcos alpha=x,lsinalpha=y),那么新的夹角为( heta+alpha)

    根据和角公式,横坐标:(lcos( heta+alpha)=l(cos hetacosalpha-sin hetasinalpha)=xcos heta-ysin heta)

    纵坐标同理

    三角恒等变形

    和差角公式

    [sin(alphapmeta)=sinalphacosetapmcosalphasineta\ cos(alphapmeta)=cosalphacosetampsinalphasineta\ an(alphapmeta)=dfrac{ analphapm aneta}{1mp analpha aneta} ]

    直线

    一般使用 两点 或者 一个点一个向量 的表示方法,我是用的是两点式,因为这样可以方便地表示线段和进行点与直线的转化

    点到直线距离

    平行四边形面积(叉积)除以底边长

    inline db dis(Line a,pt b){return (fabs((a.y-a.x)^(b-a.x))/2.0)/len(a.x-a.y);}//点到直线距离 
    

    垂足

    点击求出映射的长度,比上向量模长,得到变化的比例

    inline pt footpoint(Line a,pt b){//垂足 
    	pt x=b-a.x,y=a.y-a.x;
    	db s=x*y/len(y);
    	return a.x+(a.y-a.x)*(s/len(y));
    }
    

    对称点

    求出垂足之后中心对称即可

    inline pt symmetry(Line a,pt b){pt ft=footpoint(a,b);return ft+ft-b;}//对称点 
    

    点与线的位置关系

    点与直线

    叉积判

    点与射线

    在直线上+点积判角度

    点与线段

    同时在两条射线上

    inline bool on_line(Line a,pt b){return !sgn((b-a.x)^(a.y-a.x));}//在直线上 
    inline bool on_ray(Line a,pt b){return (!sgn((b-a.x)^(a.y-a.x)))&&(sgn((b-a.x)*(a.y-a.x))>=0);}//在射线上 
    inline bool on_segment(Line a,pt b){return (!sgn((b-a.x)^(a.y-a.x)))&&(sgn((b-a.x)*(b-a.y))<=0);}//在线段上 
    

    交点

    线段有无交点

    快速排斥实验

    一目了然

    跨立实验

    即一个线段的两个点在另一个线段的两侧,叉积判一判

    inline bool check_intersec(Line a,Line b){
    	if(max(a.x.x,a.y.x)+eps<min(b.x.x,b.y.x)||min(a.x.x,a.y.x)>max(b.x.x,b.y.x)+eps
    		|| max(a.x.y,a.y.y)+eps<min(b.x.y,b.y.y)||min(a.x.y,a.y.y)>max(b.x.y,b.y.y)+eps)return 0;//快速排斥实验 
    	return sgn((b.x-a.x)^(a.y-a.x))*sgn((b.y-a.x)^(a.y-a.x))<=0&&sgn((a.x-b.x)^(b.y-b.x))*sgn((a.y-b.x)^(b.y-b.x))<=0;//跨立实验 
    }
    

    求交点

    面积比得到长度比

    inline pt intersec(Line a,Line b){//两直线交点(需要保证不平行/重合) 
    	pt x=a.y-a.x,y=b.y-b.x,z=a.x-b.x;
    	return a.x+x*((y^z)/(x^y));
    }
    
  • 相关阅读:
    Beta 冲刺(1/7)
    福大软工 · 第十次作业
    11111111
    101
    7
    6
    5
    4
    p
    b2
  • 原文地址:https://www.cnblogs.com/harryzhr/p/14715839.html
Copyright © 2011-2022 走看看