计算几何

double的比较大小(主要是判等)

const double eps=1e-9;
int dcmp(double x,double y){
	if(fabs(x-y)<eps)
		return 0;
	if(x>y)
		return 1;
	return -1;	
}
//判断正负
int sgn(double d){
    if(fabs(d) < eps)
        return 0;
    if(d > 0)
        return 1;
    return -1;
}

常用头文件&小数定义&取整方法

#include <cstdio>
#include <cmath>
const double eps=1e-9;
const double pi=acos(-1.0);
const double inf=1e100;

int fx=floor(x); //向下取整
int cx=ceil(x); //向上取整
int rx=round(x); //四舍五入取整

点的定义

struct Point{
	double x;
	double y;
	Point(double x = 0, double y = 0):x(x),y(y){} //此处定义可以直接Point a=Point(x,y)定义
};

向量的定义

既有大小又有方向的量叫做向量
在计算机中我们常用坐标表示
这样看来,向量这个结构体貌似与点没有任何区别,因此可以

#define Vector Point
struct Point{
	double x;
	double y;
	Point(double x = 0, double y = 0):x(x),y(y){}
};

内积运算(又称数量积点积)

α⋅β=|α||β|cosθ``

几何意义
向量α
在向量β的投影α′(带有方向性)与β的长度乘积
若α与β的夹角为锐角,则其内积为正
若α与β的夹角为钝角,则其内积为负
若α与β的夹角为直角,则其内积为0
计算方法
α=(x1,y1) β=(x2,y2)
α⋅β=x1* x2+y1* y2

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

外积运算(又称向量积,叉积)

α×β=|α||β|sinθ
θ表示向量α旋转到向量β所经过的夹角
几何意义
向量α与β所张成的平行四边形的有向面积
判断外积的符号
右手定则
α×β
若β在α的逆时针方向,则为正值
顺时针则为负值
两向量共线则为0

double Cross(Vector A, Vector B){
    return A.x*B.y-A.y*B.x;
}

重载向量运算符

//点与点之间的加法运算没有意义
//点与向量相加得到另一个点
//向量与向量相加得到另外一个向量
Vector operator + (Vector A, Vector B){
    return Vector(A.x+B.x, A.y+B.y);
}
//两个点之间作差将得到一个向量,A−B将得到由B指向A的向量BA
Vector operator - (Point A, Point B){
    return Vector(A.x-B.x, A.y-B.y);
}
//向量与实数相乘得到等比例缩放的向量
Vector operator * (Vector A, double p){
    return Vector(A.x*p, A.y*p);
}
//向量与实数相除得到等比例缩放的向量
Vector operator / (Vector A, double p){
    return Vector(A.x/p, A.y/p);
}

判断点是否在线段上

bool OnSegment(Point p, Point a1, Point a2){
    return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) <= 0;
}

判断两线段是否相交

不允许在端点相交

bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
    double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}

允许在端点处相交

bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
    double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    //if判断控制是否允许线段在端点处相交,根据需要添加
    if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
        bool f1 = OnSegment(b1, a1, a2);
        bool f2 = OnSegment(b2, a1, a2);
        bool f3 = OnSegment(a1, b1, b2);
        bool f4 = OnSegment(a2, b1, b2);
        bool f = (f1|f2|f3|f4);
        return f;
    }
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}

总结

struct Line{//直线定义
    Point v, p;
    Line(Point v, Point p):v(v), p(p) {}
    Point point(double t){//返回点P = v + (p - v)*t
        return v + (p - v)*t;
    }
};
//计算两直线交点
//调用前需保证 Cross(v, w) != 0
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w){
    Vector u = P-Q;
    double t = Cross(w, u)/Cross(v, w);
    return P+v*t;
}
//点P到直线AB距离公式
double DistanceToLine(Point P, Point A, Point B){
    Vector v1 = B-A, v2 = P-A;
    return fabs(Cross(v1, v2)/Length(v1));
}//不去绝对值,得到的是有向距离
//点P到线段AB距离公式
double DistanceToSegment(Point P, Point A, Point B){
    if(A == B)
        return Length(P-A);
    Vector v1 = B-A, v2 = P-A, v3 = P-B;
    if(dcmp(Dot(v1, v2)) < 0)
        return Length(v2);
    if(dcmp(Dot(v1, v3)) > 0)
        return Length(v3);
    return DistanceToLine(P, A, B);
}
//点P在直线AB上的投影点
Point GetLineProjection(Point P, Point A, Point B){
    Vector v = B-A;
    return A+v*(Dot(v, P-A)/Dot(v, v));
}
//判断p点是否在线段a1a2上
bool OnSegment(Point p, Point a1, Point a2){
    return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0;
}
//判断两线段是否相交
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
    double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    //if判断控制是否允许线段在端点处相交,根据需要添加
    if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
        bool f1 = OnSegment(b1, a1, a2);
        bool f2 = OnSegment(b2, a1, a2);
        bool f3 = OnSegment(a1, b1, b2);
        bool f4 = OnSegment(a2, b1, b2);
        bool f = (f1|f2|f3|f4);
        return f;
    }
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}

参考博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值