[模板]计算几何-二维Point

浮点精度

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
int sgn(double x) {
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}

s g n 三 态 函 数 用 于 减 少 浮 点 的 精 度 问 题 sgn三态函数用于减少浮点的精度问题 sgn


叉积

// 叉积
double operator ^ (const Point &b)const {
	return x*b.y - y*b.x;
}

定义
向量叉积 a × b = a b s i n ( θ ) a × b = absin(\theta) a×b=absin(θ)
模长 ∣ a × b ∣ = ∣ a ∣ ∣ b ∣ s i n ( θ ) |a × b| = |a||b|sin(\theta) a×b=absin(θ)
方向 θ 的 方 向 是 从 a → b 方 向 的 夹 角 。 \theta 的方向是从a \to b方向的夹角。 θab
叉 积 的 方 向 满 足 a → b 的 右 手 法 则 , 即 与 a , b 构 成 的 平 面 垂 直 。 叉积的方向满足a\to b的右手法则,即与a,b构成的平面垂直。 aba,b
这里写图片描述
性质
1. ∣ a × b ∣ = a 和 b 构 成 的 平 行 四 边 形 面 积 1.|a × b| = a和b构成的平行四边形面积 1.a×b=ab
如 上 图 因 为 ∣ a × b ∣ = ∣ a ∣ ∣ b ∣ s i n ( θ ) ; ∣ a ∣ s i n ( θ ) = h 如上图因为|a × b| = |a||b|sin(\theta) ;|a|sin(\theta) = h a×b=absin(θ);asin(θ)=h
∣ a × b ∣ = h ∣ b ∣ = S A B C D |a × b| = h|b| = S_{ABCD} a×b=hb=SABCD
2. 叉 积 判 断 线 段 拐 向 2.叉积判断线段拐向 2.线
a × b = = 0 : a 和 b 平 行 a × b ==0 : a和b平行 a×b==0:ab
a × b &gt; 0 : b 在 a 的 逆 时 针 方 向 ( 0 &lt; θ ≤ 10 8 。 ) a × b &gt; 0 : b在a的逆时针方向(0&lt; \theta \leq 108^。) a×b>0:ba(0<θ108)
a × b &lt; 0 : b 在 a 的 顺 时 针 方 向 ( 0 &lt; θ ≤ 10 8 。 ) a × b &lt; 0 : b在a的顺时针方向(0&lt; \theta \leq 108^。) a×b<0:ba(0<θ108)
3. 判 断 点 在 多 边 形 内 3.判断点在多边形内 3.
4. 判 断 两 直 线 相 交 ( 跨 立 实 验 ) 4.判断两直线相交(跨立实验) 4.线()
5. 极 角 排 序 5.极角排序 5.


点积

// 点积
double operator * (const Point &b)const {
	return x*b.x + y*b.y;
}

定义
a ∙ b = ∣ a ∣ ∣ b ∣ c o s ( θ ) a \bullet b = |a||b|cos(\theta) ab=abcos(θ)
这里写图片描述
a ∙ b = ∣ a ∣ ∣ b ∣ c o s ( θ ) = d ∣ a ∣ ; d 是 b 在 a 上 的 投 影 a \bullet b = |a||b|cos(\theta) = d|a|;d是b在a上的投影 ab=abcos(θ)=da;dba

计算 pa 和 pb 的夹角

// 测试LightOJ1203
double rad(Point a,Point b) {
	Point p = *this;
	return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));
}

x = p → a ; y = p → b x = p \to a;y = p \to b x=pa;y=pb
x × y = ∣ x ∣ ∣ y ∣ s i n ( θ ) x × y = |x||y|sin(\theta) x×y=xysin(θ)
x ∙ y = ∣ x ∣ ∣ y ∣ c o s ( θ ) x\bullet y = |x||y|cos(\theta) xy=xycos(θ)
t a n ( θ ) = x × y x ∙ y tan(\theta) = \frac{x × y}{x \bullet y} tan(θ)=xyx×y


化为长度为r的向量

Point trunc(double r) {
	double l = len();
	if(!sgn(l)) return *this;
	r /= l;
	return Point(x*r,y*r);
}

用途
已知直线向量。求出直线上任意一点
这里写图片描述
如 图 已 知 点 A ( x 1 , y 1 ) , C ( x 2 , y 2 ) 。 想 要 计 算 出 距 离 点 A 长 度 为 r 的 B 点 坐 标 如图已知点A(x1,y1),C(x2,y2)。想要计算出距离点A长度为r的B点坐标 A(x1,y1),C(x2,y2)ArB
B = A + ( C − A ) . t r u n c ( r ) B = A + (C-A).trunc(r) B=A+(CA).trunc(r)


向量绕点P旋转angle

公 式 已 知 点 A ( x , y ) , 绕 点 P ( a , b ) 逆 时 针 转 θ 得 到 B ( x 1 , y 1 ) 公式已知点A(x,y),绕点P(a,b)逆时针转\theta 得到B(x1,y1) A(x,y),P(a,b)θB(x1,y1)
x 1 = a + x ∗ c o s ( θ ) − y ∗ s i n ( θ ) x1 = a + x*cos(\theta)-y*sin(\theta) x1=a+xcos(θ)ysin(θ)
y 1 = b + x ∗ s i n ( θ ) + y ∗ c o s ( θ ) y1 = b + x*sin(\theta)+y*cos(\theta) y1=b+xsin(θ)+ycos(θ)

Point rotate(Point p,double angle) {
	Point v = (*this) - p;
	double c = cos(angle),s = sin(angle);
	return Point(p.x + v.x*c - v.y*s,p.y+v.x*s + v.y*c);
}

Code

#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
int sgn(double x) {
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}
inline double sqr(double x) {return x*x;}
struct Point {
    double x,y;
    Point() {}
    Point(double _x,double _y) {
        x = _x;
        y = _y;
    }
    void input() {
        scanf("%lf%lf",&x,&y);
    }
    void output() {
        printf("%.2f %.2f\n",x,y);
    }
    bool operator == (Point b)const {
        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
    }
    bool operator < (Point b)const {
        return sgn(x-b.x) == 0 ? sgn(y-b.y)<0 : sgn(x-b.x)<0;
    }
    Point operator - (const Point &b)const {
        return Point(x-b.x,y-b.y);
    }
    // 叉积
    double operator ^ (const Point &b)const {
        return x*b.y - y*b.x;
    }
    // 点积
    double operator * (const Point &b)const {
        return x*b.x + y*b.y;
    }
    // 返回长度
    double len() {
        return hypot(x,y); // 库函数
    }
    // 
    double len2() {
        return x*x + y*y;
    }
    double distance(Point p) {
        return hypot(x-p.x,y-p.y);
    }
    Point operator + (const Point &b)const {
        return Point(x+b.x,y+b.y);
    }
    Point operator * (const double &k)const {
        return Point(x*k,y*k);
    }
    Point operator / (const double &k)const {
        return Point(x/k,y/k);
    }
    // 计算 pa 和 pb 的夹角
    // 测试LightOJ1203
    double rad(Point a,Point b) {
        Point p = *this;
        return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));
    }
    // 化为长度为r的向量
    Point trunc(double r) {
        double l = len();
        if(!sgn(l)) return *this;
        r /= l;
        return Point(x*r,y*r);
    }
    // 逆时针旋转90度(绕原点)
    Point rotleft() {
        return Point(-y,x);
    }
    // 顺时针旋转90度(绕原点)
    Point rotright() {
        return Point(y,-x);
    }
    // 绕着p点逆时针旋转angle
    Point rotate(Point p,double angle) {
        Point v = (*this) - p;
        double c = cos(angle),s = sin(angle);
        return Point(p.x + v.x*c - v.y*s,p.y+v.x*s + v.y*c);
    }
};
int main()
{

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值