基础计算几何

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础计算几何相关的知识,希望对你有一定的参考价值。

结构体的定义

struct point
{
    double x, y;
    point(double _x, double _y):x(_x), y(_y){}
    
    // 点-点=向量
    point operator-(const point &v){
        return point(x-v.x, y-v.y);
    }

};

int dcmp(double x){
    if (fabs(x)<eps) return 0;
    else return x<0?-1:1;
}
bool operator == (const point &a, const point &b){
    return (dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0); 
}

typedef point Vector; // Vector表示向量

//点积
double Dot(Vector a, Vector b){return a.x*b.x+a.y*b.y;}

//线段的长度
double Lenth(Vector a){return sqrt(Dot(a, a));}

//向量的夹角(弧度)
double Angle(Vector a, Vector b){return acos(Dot(a, b)/Lenth(a)/Lenth(b));}

//叉积
double Cross(Vector a, Vector b){return a.x*b.y-a.y*b.x;}

//三角形有向面积的2倍
double Area2(point a, point b, point c){return Cross(b-a, c-a);}

//向量旋转,a为逆时针旋转的角度
// rad是弧度
point Rotate(Vector a, double rad){
    return point(a.x*cos(rad)-a.y*sin(rad), a.x*sin(rad)+a.y*cos(rad));
}

//计算向量的单位法线
point Normal(Vector a){
    double L = Lenth(a);
    return point(-a.y/L, a.x/L);
}

 直线

// 两条直线的交点
// 两条直线为 p+tv, q+tw,其中p, q为两直线上的一点, v,w是直线所在方向的向量,
// 交点在第一条直线的参数为t1, 第二条直线的参数为t2
// t1 = (cross(w,u)/cross(v,w));  t2 = (cross(v,u)/cross(v,w));
// 调用前要确保两直线有唯一交点,当且仅当两直线不共线
point Getline(point p, Vector v, point q, Vector w){
    point u = p-q;
    double t = Cross(w, u)/Cross(v, w);
    return point(p.x+v.x*t, p.y+v.y*t);
}

//点到直线的距离
double Dis(point p, point a, point b){
    Vector v1 = b-a, v2 = p-a;
    return fabs(Cross(v1, v2)/Lenth(v1));
}

//点到线段的距离
//点p在直线的投影可能在直线上,也可能不在直线上
double Dis2(point p, point a, point b){
    if (a==b) return Lenth(p-a);
    Vector v1=b-a, v2 = p-a, v3=p-b;
    if (dcmp(Dot(v1, v2))<0) return Lenth(v2); // 注意大小于号
    if (dcmp(Dot(v1, v3))>0) return Lenth(v3);
    else return fabs(Cross(v1, v2)/Lenth(v1));
}

//点在线段上的投影
point Getline2(point p, point a, point b){
    Vector v = b-a;
    double f = Dot(v, p-a)/Dot(v, v);
    return point(a.x+v.x*f, a.y+v.y*f);
}

//线段相交判定(交点不在端点的位置,且两直线仅有唯一交点)
bool Inter(point a1, point a2, point b1, point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1),
           c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
//线段相交判定,交点可以在一条直线端点位置(交点不在两直线端点得位置)
bool OneInter(point p, point a1, point a2){
    return dcmp(Cross(a1-p, a2-p))==0 && dcmp(Dot(a1-p, a2-p))<0;
}
// 视题目要求是否特判两直线有端点重合的情况

 多边形

//多边形面积(有方向)
vector<point>ve;
double ConvexArea(int n){
    double area = 0;
    for(int i = 1; i < n-1; i++){
        area += Cross(ve[i]-ve[0], ve[i+1]-ve[0]);
    }
    return area/2;
}

 

整体一起

const double eps = 1e-10;
const double pi = acos(-1.0);

struct point
{
    double x, y;
    point(double _x, double _y):x(_x), y(_y){}
    
    // 点-点=向量
    point operator-(const point &v){
        return point(x-v.x, y-v.y);
    }

};

int dcmp(double x){
    if (fabs(x)<eps) return 0;
    else return x<0?-1:1;
}
bool operator == (const point &a, const point &b){
    return (dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0); 
}

typedef point Vector; // Vector表示向量

//点积
double Dot(Vector a, Vector b){return a.x*b.x+a.y*b.y;}

//线段的长度
double Lenth(Vector a){return sqrt(Dot(a, a));}

//向量的夹角(弧度)
double Angle(Vector a, Vector b){return acos(Dot(a, b)/Lenth(a)/Lenth(b));}

//叉积
double Cross(Vector a, Vector b){return a.x*b.y-a.y*b.x;}

//三角形有向面积的2倍
double Area2(point a, point b, point c){return Cross(b-a, c-a);}

//向量旋转,a为逆时针旋转的角度
// rad是弧度
point Rotate(Vector a, double rad){
    return point(a.x*cos(rad)-a.y*sin(rad), a.x*sin(rad)+a.y*cos(rad));
}

//计算向量的单位法线
point Normal(Vector a){
    double L = Lenth(a);
    return point(-a.y/L, a.x/L);
}

// 两条直线的交点
// 两条直线为 p+tv, q+tw,其中p, q为两直线上的一点, v,w是直线所在方向的向量,
// 交点在第一条直线的参数为t1, 第二条直线的参数为t2
// t1 = (cross(w,u)/cross(v,w));  t2 = (cross(v,u)/cross(v,w));
// 调用前要确保两直线有唯一交点,当且仅当两直线不共线
point Getline(point p, Vector v, point q, Vector w){
    point u = p-q;
    double t = Cross(w, u)/Cross(v, w);
    return point(p.x+v.x*t, p.y+v.y*t);
}

//点到直线的距离
double Dis(point p, point a, point b){
    Vector v1 = b-a, v2 = p-a;
    return fabs(Cross(v1, v2)/Lenth(v1));
}

//点到线段的距离
//点p在直线的投影可能在直线上,也可能不在直线上
double Dis2(point p, point a, point b){
    if (a==b) return Lenth(p-a);
    Vector v1=b-a, v2 = p-a, v3=p-b;
    if (dcmp(Dot(v1, v2))<0) return Lenth(v2); // 注意大小于号
    if (dcmp(Dot(v1, v3))>0) return Lenth(v3);
    else return fabs(Cross(v1, v2)/Lenth(v1));
}

//点在线段上的投影
point Getline2(point p, point a, point b){
    Vector v = b-a;
    double f = Dot(v, p-a)/Dot(v, v);
    return point(a.x+v.x*f, a.y+v.y*f);
}

//线段相交判定(交点不在端点的位置,且两直线仅有唯一交点)
bool Inter(point a1, point a2, point b1, point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1),
           c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
//线段相交判定,交点可以在一条直线端点位置(交点不在两直线端点得位置)
bool OneInter(point p, point a1, point a2){
    return dcmp(Cross(a1-p, a2-p))==0 && dcmp(Dot(a1-p, a2-p))<0;
}
// 视题目要求是否特判两直线有端点重合的情况

//多边形面积(有方向)
vector<point>ve;
double ConvexArea(int n){
    double area = 0;
    for(int i = 1; i < n-1; i++){
        area += Cross(ve[i]-ve[0], ve[i+1]-ve[0]);
    }
    return area/2;
}

 

以上是关于基础计算几何的主要内容,如果未能解决你的问题,请参考以下文章

计算几何基础知识--求两个线段的交点

计算几何基础知识--求两个线段的交点

计算几何基础知识--求两个线段的交点

计算几何基础知识--求两个线段的交点

计算几何及其应用——计算几何基础

kuangbin专题计算几何基础(极角相关)