计算几何总结

最近回顾了一下计算几何知识,反过来看感觉其中好像也没有很多知识点,无非就是点、线、面、体之间的关系。总结一下感觉知识清晰多了!


 使用下面7种常用的关系总结一下计算几何常用的知识点


  首先我们先定义代码表示点和线

struct Point {
	double x, y;
};
typedef Point Vec;

序号1表示关系,点 - 点

  • 点与点之间的距离

double Dist(Vec A, Vec B) {
	double dx = A.x - B.x;
	double dy = A.y - B.y;
	return sqrt(dx * dx + dy * dy);
}

  • 两点一条线

pair<double, double> getLine(Point a, Point b){
    double k, b;
    if(a.x == b.x) {
        k = inf; // 使用一个大质数浮点数表示
    }else {
        k = (a.y-b.y)/(a.x-b.x);
    }
    b = k * a.x - a.y;
    return {k,b}
}

序号2表示关系, 线-线

  • 两直线交点
// 两直线的交点
Point getJiaodian(Point p1, Point p2, Point p3, Point p4) {
	double a1 = p1.y - p2.y, b1 = p2.x - p1.x, c1 = p1.x * p2.y - p2.x * p1.y;
	double a2 = p3.y - p4.y, b2 = p4.x - p3.x, c2 = p3.x * p4.y - p4.x * p3.y;
	return Point{(c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2), (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1)};
}
  • 两直线夹角
double getJiajiao(Point a, Point b, Point c, Point d){
    Vec line_a = {a.x-b.x, a.y-b.y};
    Vec line_b = {c.x-d.x, c.y-d.y};
    return (line_a.x * line_b.y - line_b.x * line_a.y) / (Dist(a, b) * Dist(c, d)) 

}
  • 点乘
double Dot(Vec A, Vec B) {
	return A.x * B.x + A.y * B.y;
}
  • 叉乘
double Cross(Vec A, Vec B) {
	return A.x * B.y - A.y * B.x;
}
  • 线的长度
double Length(Vec A) {
	return sqrt(A.x * A.x + A.y * A.y);
}
  • 直线是否相交
// 两直线相交?
bool isXiangjiao(Point p1, Point p2, Point p3, Point p4) {
	if (max(p3.x, p4.x) < min(p1.x, p2.x) || max(p1.x, p2.x) < min(p3.x, p4.x)) return 0;
	if (max(p3.y, p4.y) < min(p1.y, p2.y) || max(p1.y, p2.y) < min(p3.y, p4.y)) return 0;
	if (Cross(p1 - p4, p3 - p4) * Cross(p2 - p4, p3 - p4) > 0) return 0;
	if (Cross(p4 - p2, p1 - p2) * Cross(p3 - p2, p1 - p2) > 0) return 0;
	return 1;
}
  • 极角排序
// 极角排序
bool mycmp(Point a, Point b) {
	if (atan2(a.y, a.x) != atan2(b.y, b.x))
		return atan2(a.y, a.x) < atan2(b.y, b.x);
	else
		return a.x < b.x;
}

序号4关系,面-面(考点,主要就是考投影)

  • 投影
  • 平行
  • 相交
  • 异面
  • 表面积
  • 体积

序号5关系,主要就是求体积


序号6关系,点-线(重点)

  • 点在直线上
// 点p是不是在直线上
bool OnSegment(Point p, Point p1, Point p2) {
	return sgn(Cross(p - p1, p2 - p1)) == 0 && sgn(Dot(p - p1, p - p2)) <= 0;
}
  • 点在线段上
//*判断点在线段上s->e
bool OnSeg(Point P, Point s, Point e) {
	return sgn(Cross((s - P), (e - P))) == 0 &&
	       sgn((P.x - s.x) * (P.x - e.x)) <= 0 &&
	       sgn((P.y - s.y) * (P.y - e.y)) <= 0;
}
  • 两点一条直线
pair<double, double> getLine(Point a, Point b){
    double k, b;
    if(a.x == b.x) {
        k = inf; // 使用一个大质数浮点数表示
    }else {
        k = (a.y-b.y)/(a.x-b.x);
    }
    b = k * a.x - a.y;
    return {k,b}
}
  • 点到直线的距离
double dist2(Point a, Point x, Point y){
    double dist = 0;
    pair<double, double> line = getline(x, y); // 上面有
    return abs(line.first * dist.x - dist.y + line.second) / sqrt(1 +         
               line.first*line.first)

}

序号7关系 , 点-面

  • 点在平面内
//判断点在凸多边形内
// 要求
// 点形成一个凸包,而且按逆时针排序
// 如果是顺时针把里面的<0改为>0
// 点的编号:0~n-1
// 返回值:
// -1:点在凸多边形外
// 0:点在凸多边形边界上
// 1:点在凸多边形内
int inConvexPoly(Point a, Point p[], int n) {
	for (int i = 0; i < n; i++) {
		if (sgn(Cross((p[i] - a), (p[(i + 1) % n] - a))) < 0)
			return -1;
		else if (OnSeg(a, p[i], p[(i + 1) % n]))
			return 0;
	}
	return 1;
}



//判断是不是在任意多边形里面
int inPoly(Point p, Point poly[], int n) {
 	int cnt;
 	Line ray, side;
 	cnt = 0;
 	ray.s = p;
 	ray.e.y = p.y;
 	ray.e.x = -100000000000.0; //-INF,注意取值防止越界

 	for (int i = 0; i < n; i++) {
 		side.s = poly[i];
 		side.e = poly[(i + 1) % n];

 		if (OnSeg(p, side))
 			return 0;

 		//如果平行轴则不考虑
 		if (sgn(side.s.y - side.e.y) == 0)
 			continue;

 		if (OnSeg(side.s, ray)) {
 			if (sgn(side.s.y - side.e.y) > 0)
 				cnt++;
		} else if (OnSeg(side.e, ray)) {
 			if (sgn(side.e.y - side.s.y) > 0)
				cnt++;
		} else if (inter(ray, side))
 			cnt++;
 	}
 	if (cnt % 2 == 1)
 		return 1;
	else
 		return -1;
 }
  • 点到平面的距离
  • 扫描面

序号8关系,线-面

  • 万能计算面积
// 计算多边形面积
double CalcArea(Point p[], int n) {
	double res = 0;
	for (int i = 0; i < n; i++)
		res += (Cross(p[i], p[(i + 1) % n])) / 2;
	return fabs(res);
}
  • 凸包
#include <bits/stdc++.h>
const int maxn = 10000 + 10;
using namespace std;
struct node {
    double x, y;
};
node p[maxn], z[maxn];
bool cmp(node u, node v) { return u.x < v.x; }
bool cmpxl(node a, node b, node c) { return (a.y - b.y) * (b.x - c.x) < (b.y - c.y) * (a.x - b.x); }
double dist(node a, node b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y;
    sort(p + 1, p + n + 1, cmp);
    z[1]    = p[1];
    z[2]    = p[2];
    int top = 2;
    for (int i = 3; i <= n; i++) {
        while (top > 1 && cmpxl(p[i], z[top], z[top - 1])) top--;
        z[++top] = p[i];
    }
    double ans = 0;
    for (int i = 1; i < top; i++) ans += dist(z[i], z[i + 1]);

    z[1] = p[n];
    z[2] = p[n - 1];
    top  = 2;
    for (int i = n - 2; i >= 1; i--) {
        while (top > 1 && cmpxl(p[i], z[top], z[top - 1])) top--;
        z[++top] = p[i];
    }
    for (int i = 1; i < top; i++) ans += dist(z[i], z[i + 1]);
    cout << ans << endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值