计算几何(二)——点与向量

二维平面下的点保存横纵坐标即可

struct Point{
	double x,y;
	Point(double a=0,double b=0):x(a),y(b){}
    //运算符重载
};
向量

向量在数学意义上是矢量,即有方向的量,但是计算机并不能存储方向,因此还是要用坐标表示,但是因为一些函数是基于向量计算的,与点没有关系,为了区别开我们重定义向量名 V e c t o r Vector Vector

#define Point Vector    //typedef Point Vector 
常用运算符

加法运算符

加法一般用于向量

Vector operator + (Vector A,Vector B){
    return Vector(A.x+B.x,A.y+B.y);
}

减法运算符

两个点作差将得到一个向量。向量之间的减法则是高中那句话“共起点,指被减”,这里的起点在二维坐标系中指原点。向量 A − B A-B AB得到向量 B A BA BA

Vector operator - (Point A,Point B){
    return Vector(A.x-B.x,A.y-B.y);
}

乘法运算符

1.如果是数乘,向量与实数相乘得到等比例缩放的向量

Vector operator * (Vector A,double d){
    return Vector(A.x*d,A.y*d);
}

2.如果是向量之间的乘法,那就是向量的数量积

a = ( x 1 , y 1 ) , b = ( x 2 , y 2 ) a=(x_1,y_1),b=(x_2,y_2) a=(x1,y1),b=(x2,y2),则 a ⋅ b = x 1 ∗ x 2 + y 1 ∗ y 2 a·b=x_1*x_2 + y_1*y_2 ab=x1x2+y1y2

几何意义:数量积 a × b a×b a×b等于 ∣ a ∣ |a| a b b b a a a的方向上的投影 ∣ b ∣ c o s θ |b|cosθ bcosθ 的乘积,即 a × b = ∣ a ∣ ∣ b ∣ c o s θ a \times b=∣a∣∣b∣cosθ a×b=abcosθ

那么我们还可以用向量数量积求向量之间的夹角及判断锐角直角钝角,在后面有很大的用处

double operator * (Vector A,Vector B){
    return A.x*B.x+A.y*B.y;
}

除法运算符

向量与实数相除得到等比例缩放的向量

Vector operator / (Vector A,double d){
    return Vector(A.x/d,A.y/d);
}

^ 运算符——向量积(叉积)

向量积 c = a × b = ∣ a ∣ ∣ b ∣ s i n < a , b > c = a×b = |a||b|sin<a,b> c=a×b=absin<a,b>,若 a = ( x 1 , y 1 ) , b = ( x 2 , y 2 ) a=(x_1,y_1),b=(x_2,y_2) a=(x1,y1),b=(x2,y2),则 a × b = x 1 ∗ y 2 − x 2 ∗ y 1 a×b=x_1*y_2 - x_2*y_1 a×b=x1y2x2y1

a a a向量与 b ∗ 向 量 的 向 量 积 ∗ c ∗ 的 方 向 与 这 两 个 向 量 所 在 平 面 垂 直 , 且 遵 守 右 手 定 则 ( 当 右 手 的 四 指 从 ∗ a ∗ 以 不 超 过 180 度 的 转 角 转 向 b*向量的向量积*c*的方向与这两个向量所在平面垂直,且遵守右手定则(当右手的四指从*a*以不超过180度的转角转向 bc(a180b 时 , 竖 起 的 大 拇 指 指 向 是 时,竖起的大拇指指向是 c 的 方 向 , 默 认 的方向,默认 c$的方向向上为正)
在这里插入图片描述
几何意义:向量积的几何意义是两向量的围成平行四边形的面积

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

< 运算符

用于对点集排序

bool operator < (const Point& a,const Point &b) const {
    if(dcmp(a.x-b.x)==0) return a.y<b.y;
    return a.x<b.x;
}

== 运算符

bool operator == (const Point& a, const Point& b) const {
    if(dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0)
        return true;
    return false;
}
常用函数

求模长

double dis(Vector A){
    return sqrt(A*A);
}

求模长的平方

double sqrDis(Vector A){
    return A*A;
}

计算两向量夹角

a × b = ∣ a ∣ ∣ b ∣ c o s θ a \times b=∣a∣∣b∣cosθ a×b=abcosθ,那么 c o s θ = a × b / ( ∣ a ∣ ⋅ ∣ b ∣ ) cosθ=a \times b/(∣a|·∣b∣) cosθ=a×b/(ab),再由反余弦函数即可得到 θ θ θ,注意是弧度制下的夹角

double angle(Vector A,Vector B){
	return acos(A*B/dis(A)/dis(B));
}

计算向量逆时针旋转后的向量
在这里插入图片描述
x ′ = x c o s α − y s i n α x′ = xcosα−ysinα x=xcosαysinα
y ′ = x s i n α + y c o s α y′ = xsinα+ycosα y=xsinα+ycosα

Vector rotate(Vector A,double rad){
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}

计算向量逆时针旋转九十度的单位法向量

Vector normal(Vector A){
    double L=dis(A);
    return Vector(-A.y/L, A.x/L);
}

ToLeftTest

借用向量积的定义,如果向量 b c bc bc b a ba ba 左边,那么 a b × b c > 0 ab × bc > 0 ab×bc>0(右手定则)
在这里插入图片描述
判断向量 b c bc bc 是不是向量 b a ba ba 的逆时针方向(左边)转向。凸包构造时将会频繁用到此公式

bool ToLeftTest(Point c, Point b, Point a){
        return (a-b)^(c-b) > 0;
}
简单模板
#define Point Vector
const double PI=acos(-1.0);
const double eps=1e-8;

inline int dcmp(double d){   //浮点数和0比较
	if(fabs(d)<eps) return 0;
	return d>0?1:-1;
}

inline int cmp(double x,double y){ //x>y返回1,x=y返回0,x<y返回-1
	return dcmp(x-y);
}

struct Point{
    double x,y;
    Point(double a=0,double b=0):x(a),y(b){}

    Vector operator + (Vector B){
        return Vector(x+B.x,y+B.y);
    }

    Vector operator - (Point B){
        return Vector(x-B.x,y-B.y);
    }

    Vector operator * (double d){  //数乘
        return Vector(x*d,y*d);
    }

    double operator * (Vector B){  //数量积
        return x*B.x+y*B.y;
    }

    Vector operator / (double d){
        return Vector(x/d,y/d);
    }

    double operator ^ (Vector B){  //叉乘
        return x*B.y-y*B.x;
    }

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

    bool operator == (const Point& b) const {
        if(dcmp(x-b.x)==0 && dcmp(y-b.y)==0)
            return true;
        return false;
    }
};

double dis(Vector A){   //模长
    return sqrt(A*A);
}

double sqrDis(Vector A){  //模长平方
    return A*A;
}

double angle(Vector A,Vector B){  //向量夹角
    return acos(A*B/dis(A)/dis(B));
}

Vector rotate(Vector A,double rad){  //逆时针旋转
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}

Vector normal(Vector A){  //逆时针90°的法向量
    double L=dis(A);
    return Vector(-A.y/L, A.x/L);
}

bool ToLeftTest(Point c, Point b, Point a){ //判断折线bc是不是向ab的逆时针方向(左边)转向
    return ((a-b)^(c-b)) > 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值