今天主要学习力计算几何基础。
以下主要给出计算几何的一些算法的代码,而分析问题,知道所需算法也十分重要。
1.凸包
1)先上凸包需要的数据结构
完善点的数据结构:
struct Point {
double x, y;
Point(double x=0, double y=0): x(x), y(y) {} //构造函数
Point operator + (Point p) {return Point(x+p.x, y+p.y);} //两向量相加
Point operator - (Point p) {return Point(x-p.x, y-p.y);} //两向量相减
Point operator * (double k) {return Point(k*x, k*y);} //向量的数乘
Point operator / (double k) {return Point(x/k, y/k);} //向量的数乘(乘以一个分数)
bool operator < (const Point &p) const {return x!=p.x ? (x Polygon;
2)判断点与向量的位置关系
int ccw(Point p0, Point p1, Point p2) {
Vector v1 = p1-p0;
Vector v2 = p2-p0;
if(v1.cross(v2) > 0) return 1; //逆时针方向
if(v1.cross(v2) < 0) return -1; //顺时针方向
if(v1.dot(v2) < 0) return 2; //同一直线上的反方向
if(v1.norm() < v2.norm()) return -2; //同一直线上的正方向
return 0; //在向量上
}
3)安德鲁算法O(n*log(n))
Polygon convexHull(Polygon source) {
if(source.size() < 3) return source; //当点的个数少于三个,直接返回原点集
Polygon upper, lower; //凸包的上下部分
sort(source.begin(), source.end()); //原点集内点的排序
upper.push_back(source[0]);
upper.push_back(source[1]);
lower.push_back(source[source.size()-1]);
lower.push_back(source[source.size()-2]);
for(int i=2; i=1 && ccw(upper[n-1], upper[n], source[i])!=-1; --n)
upper.pop_back(); //当上部出现不合适的点时删除
upper.push_back(source[i]);
}
for(int i=source.size()-3; i>=0; --i) { //构建凸包下部
for(int n=lower.size()-1; n>=1 &&ccw(lower[n-1], lower[n], source[i])!=-1; --n)
lower.pop_back(); //当下部出现不合适的点时删除
lower.push_back(source[i]);
}
for(int i=1; i
2.其他数据结构
线段:
struct Segment {
Point p1, p2;
};
直线:
typedef Segment Line;
圆:
struct Circle {
Point o; //圆心
double radius; //半径
}
3.其他算法
1)直线的正交和平行判断
首先求出两条直线对应的向量
两向量的内积为0,则两直线正交(相互垂直)
两向量外积为0,则两直线平行
2)投影
Point project(Segment s, Point p) {
Vector base = s.p2 - s.p1;
double r = (p-s.p1).dot(base)/base.norm();
return s.p1 + base*r;
}
3)映像(关于直线的对称点)
Point reflect(Segment s, Point p) {
return p + (project(s, p) - p)*2.0;
}
4)距离
两点间距离:略
点与直线的距离:
double getDist(Line l, Point p) {
return abs((l.p2-l.p1).cross(p-l.p1) / (l.p2-l.p1).abs());
}
点与线段的距离:
double getDist(Segment s, Point p) {
if((s.p2-s.p1).dot(p-s.p1) < 0) return (p-s.p1).abs();
if((s.p1-s.p2).dot(p-s.p2) < 0) return (p-s.p2).abs();
return abs((s.p2-s.p1).cross(p-s.p1) / (s.p2-s.p1).abs());
}
线段之间的距离:
每条线段的两个端点到另一条线段的距离中的最小值
5)判断两线段是否相交
bool intersect(Point p1, Point p2, Point p3, Point p4) {
return ccw(p1, p2, p3)*ccw(p1, p2, p4)<=0 &&
ccw(p3, p4, p1)*ccw(p3, p4, p2)<=0;
}
6)求两线段的交点
Point getCrossPoint(Segment s1, Segment s2) {
Vector base = s2.p2 - s2.p1;
double d1 = abs(base.cross(s1.p1-s2.p1));
double d2 = abs(base.cross(s1.p2-s2.p1));
double t = d1/(d1+d2);
return s1.p1 + (s1.p2 - s1.p1)*t;
}
7)计算凸多边形的面积
double getArea(Polygon polygon) {
double res = 0;
for(int i=0; i
8)判断一个点是否在多边形内部
int contains(Polygon g, Point p) {
int n = g.size();
bool flag = false;
for(int i=0; i b.y) swap(a, b);
if(a.y<0 && b.y>0 && a.cross(b)>0) flag = !flag;
}
return flag ? 2 : 0; //2表示在“内”,0表示在“外”
}
9)