計算幾何模板之二維點線面模板

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
//================= 精度誤差 ==============
const double eps = 1e-8;
int dcmp( double x )
{
    if( fabs(x)<eps)
        return 0;
    return x < 0 ? -1: 1;
}

//================= 點結構 ===============
struct pnode
{
    double x,y;
    pnode( double a=0.0,double b=0.0):x(a),y(b){}

    // X乘重載
    double operator ^ (const pnode &b)const
    {
        return x*b.y - b.x*y;
    }

    pnode operator - ( const pnode &b)const
    {
        return pnode( x-b.x,    y-b.y);
    }

    pnode operator * (const double p)const
    {
        return pnode( x*p,   y*p );
    }

    pnode operator + (const pnode&b)const
    {
        return pnode( x+b.x, y+b.y );
    }

    bool operator == (const pnode&b)const
    {
        return dcmp( x-b.x )== 0 && dcmp( y-b.y )==0;
    }

    bool operator < (const pnode&b)const
    {
        return x < b.x || ( dcmp( x-b.x )==0 && y<b.y );
    }

    bool operator > (const pnode&b)const
    {
        return x > b.x || ( dcmp( x-b.x )==0 && y>b.y );
    }
};
//================ 線結構 ==============
typedef pnode myvec;
struct pline
{
    pnode st,ed;//st:起始點 ed:終點
    myvec vec;//向量
    pline(){}

    pline(pnode a,pnode b):st(a),ed(b)
    {
        vec = pnode(b-a);
    }
};

/*
    x乘:
        公共起始點p0, V向量p0p1,W向量p0p2
        cross(v,w) > 0 W向量在 V向量左邊
*/
double cross( pnode p0,pnode p1,pnode p2)
{
    return (p1-p0) ^ (p2-p0);
}
double cross(pline a,pline b)
{
    return (a.ed-a.st)^(b.ed-b.st);
}

/*
    點乘:
        dot(v,w) == 二者長度乘積再乘上他們夾角的餘弦
        夾角:從 v 到 w 逆時針旋轉的角
*/
double dot( myvec v,myvec w)
{
    return v.x*w.x + v.y*w.y;
}
double dot( pline a,pline b)
{
    return a.vec.x * b.vec.x + a.vec.y * b.vec.y;
}

//長度
double length( pline a)
{
    return sqrt(dot(a,a));
}
//返回夾角弧度值 逆時針爲正
double angle( pline a,pline b)
{
    return acos( dot(a,b)/length(a)/length(b) );
    /*
        double acos(double x),x範圍在 -1~1 之間
        返回的是一個數值的反餘弦弧度值,其範圍是 0~ pi 。
        例如: acos(1) 返回值是 0
    */
}
//a向量旋轉rad弧度 rad>0逆時針
myvec rotat(myvec a,double rad)
{
    return myvec( a.x*cos(rad)-a.y*sin(rad) , a.x*sin(rad)+a.y*cos(rad));
}
//矢量三角形面積*2
double area2(pnode p0,pnode p1,pnode p2)
{
    return cross(p0,p1,p2);
}


//============= 直線,線段 ============


//給定兩條直線,求角平分線
myvec angle_bisector(pnode p, pline v1, pline v2)
{
    double rad = angle(v1, v2);
    return rotat(v1.vec, dcmp(cross(v1, v2)) * 0.5 * rad);
}

//判斷3點共線
bool line_coincide(pnode p1, pnode p2, pnode p3)
{
    return dcmp(cross(p1,p2,p3)) == 0;
}
//判斷直線平行
bool line_parallel(pline v, pline w)
{
    return cross(v, w) == 0;
}
//判斷直線垂直
bool line_vertical(pline v, pline w)
{
    return dot(v, w) == 0;
}
//點在直線上的投影點
pnode get_line_projection(pnode p, pline line)
{
    return line.st + line.vec * (dot(line, pline(line.st,p)) / dot(line, line));
}

//判斷點在線段上, 不包含端點
//dcmp(dot())<=0包含端點
bool on_segment(pnode p, pline line)
{
    return dcmp(cross(p,line.st, line.ed)) == 0 && dcmp(dot(line.st - p, line.ed - p)) <0;
}
//直線求交點 線判斷非平行,非重合
//直線 p+tv ,q+tw 有唯一交點,當且僅當cross(v,w)!=0
pnode get_line_inter_point(pline v,pline w)
{
    pline u (w.st,v.st);
    double t = cross( w,u )/cross(v,w);
    return v.st + (v.ed-v.st) * t;
}

//點到直線的距離
//平行四邊形面積除以底
double dist_to_line( pnode p,pline line )
{

    pline v2 (line.st,p);
    return fabs( cross(line,v2)/length( line));
    //如果不區絕對值 得到的是有向距離
}

//點到線段的距離
double dist_to_seg( pnode p ,pline seg)
{
    if( seg.st == seg.ed )
        return  length( pline(seg.st,p) );

    pline v2 (seg.st,p);
    pline v3 (seg.ed,p);

    if( dcmp( dot(seg,v2) ) < 0)
        return length( v2 );
    else
        if( dcmp ( dot(seg,v2)) > 0)
        return length( v3 );
    else
        return fabs( cross(seg,v2) )/length( seg );
}
//判斷 線段 與 直線相交
bool seg_inter_line(pline line,pline seg)
{
    return ( dcmp( cross( seg.st,line.st,line.ed ) ) * dcmp( cross( seg.ed,line.st,line.ed) ) )<=0;
}
//判斷 線段 與 線段 相交(允許端點在另一條線段上或者重合
bool seg_inter_seg(pline a,pline b)
{

    return
        max( a.st.x, a.ed.x) >=  min( b.st.x, b.ed.x)
    &&
        max( b.st.x, b.ed.x) >=  min( a.st.x, a.ed.x)
    &&
        max( a.st.y, a.ed.y) >=  min( b.st.y, b.ed.y)
    &&
        max( b.st.y, b.ed.y) >=  min( a.st.y, a.ed.y)
    &&//以上端點判斷
        dcmp(cross( a.st, a.ed, b.st ))*dcmp(cross( a.st, a.ed, b.ed ))<=0
    &&  dcmp(cross( b.st, b.ed, a.st ))*dcmp(cross( b.st, b.ed, a.ed ))<=0;
}
//兩條線段有唯一一個不是端點的公共點
//線段規範相交(不允許端點在另一條線段上
bool seg_proper_inter_seg(pline a,pline b)
{
    double c1 = cross( a.st, a.ed, b.st );
    double c2 = cross( a.st, a.ed, b.ed );
    double c3 = cross( b.st, b.ed, a.st );
    double c4 = cross( b.st, b.ed, a.ed );

    return dcmp(c1)*dcmp(c2)<0
        && dcmp(c3)*dcmp(c4)<0;
}
//判斷線段是否在矩形內,允許線段端點再矩形四條邊上
//參數(線段,矩形左上角頂點,矩形右下角頂點)
bool seg_in_rec(pline seg,double xl,double xr,double yt,double yb)
{
    return
        seg.st.x >= min(xl,xr) && seg.st.x <= max(xl,xr)
    &&  seg.ed.x >= min(xl,xr) && seg.ed.x <= max(xl,xr)
    &&  seg.st.y >= min(yt,yb) && seg.st.y <= max(yt,yb)
    &&  seg.ed.y >= min(yt,yb) && seg.ed.y <= max(yt,yb);
}
//多邊形面積
double polygon_area(pnode*p,int n)
{
    double area = 0.0;
    for( int i = 1;i < n-1 ;++i )
        area += cross( p[0], p[i], p[i+1]);
    return area*0.5;
}
int main()
{
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章