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