计算几何

计算几何

凸包

极点法

n4

通过在不在三角形内部来判断是否为极点,如果为极点那么就是构成凸包的点,如果是在三角形内部的,那就不是构成凸包的点

由于n4会炸,那么in_triangle_test可以分解为三个to_left_test,三个to_left_test如果都为true那么in_triangle_test也为true 通过面积判断是否为true,计算三点形成的面积,若面积为正,则位于直线的左侧,否则位于直线的右侧

bool to_left(Point p,Ponit q,Point s)
{
int area=p.x*q.y-p.y*q.x+q.x*s.y-q.y*s.x+s.x*p.y-s.y*p.x;
return area>0;
}

极边法

n3

通过所有点是否都是在一条线的一遍来判断是否是极边,凸包是有所有极边和极边所连接的点组成的

相当于对每一条边判断是否是剩余的每个点都和极边的两点to_left都是一个值,即LEmpty都是false,REmpty都是true 或者说 LEmpty都是true,REmpty都是false

struct Point{
int x,y;
int extreme;
}point;
void check_edge(Point S[],int n,int p,int q)
{
bool LEmpty=true,REmpty=true;
for(int k=0;k<n&&(LEmpty||REmpty);k++){
if(k!=p&&k!=p)
if(to_left(S[p],S[q],S[k])) LEmpty=false;
else REmpty=false;
}
if(LEmpty||REmpty) S[p].extreme=S[q].extreme=true;
}
void markEE(Point S[],int n)
{
for(int k=0;k<n;k++){
S[k].extreme=false;
}
for(int p=0;p<n;p++){
for(int q=p+1;q<n;q++){
check_edge(S,n,p,q);
}
}
}

多边形判定法

并不是判断哪些点构成凸包,而是每次加入一个新的点,看他是否会构成新的凸包,构成新的凸包的条件是该点会有两个点与它的关系是LL和RR,则应该把该点插入,否则就不需要

n2 增量法

void in_convex_polygon test
{


}

Jarvis March

nh

关于第一个点的选择,遵循LTL原则,即lowest_then_leftmost_point,选择出的必定为极点。从极点出发找到一条极边,然后用另一个端点为起始点再找极边。找极边的过程为On两两比较,to_left为true的交换,否则留下。

struct Point{
int x,y;
int succ;//后继
int extreme;//极点标记
}point;
int ltl(Point S[],int n)
{
int LTL=0;
for(int k=1;k<n;k++){
if(S[k].y<S[LTL].y||(S[k].y==S[LTL].y&&S[k].x<S[LTL].x)) LTL=k;
}
return LTL;
}
void Jarvis(Point S[],int n)
{
for(int k=0;k<n;k++) S[k].extreme=false;
int LTL=ltl(s,n);
int k=LTL;
do{
S[k].extreme=true;
int s=-1;
for(int t=0;t<n;t++){
if(t!=k&&t!=s&&(s==-1||!to_left(P[k],P[s],P[t]))) s=t;
}
S[k].succ=s;
k=s;
}while(LTL!=k)
}

Graham Scan 算法

upper hull && lower hull

# include <bits/stdc++.h>
using namespace std;

typedef long double LD;
const int eps=1e-8;
int dcmp(LD x)
{
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
LD sqr(LD x) {
return x*x;
}
struct Point{
LD x,y;
Point(LD x=0,LD y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator -(Vector A,Vector B) { return Point(A.x-B.x,A.y-B.y);}
Vector operator +(Vector A,Vector B) { return Point(A.x+B.x,A.y+B.y);}
Vector operator *(Vector A,LD p) { return Point(A.x*p,A.y*p);}
Vector operator /(Vector A,LD p) { return Point(A.x/p,A.y/p);}
bool operator == (Point A,Point B) { return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;}
bool operator <(Point A,Point B) { return A.x<B.x||(A.x==B.x&&A.y<B.y);}

LD Dot(Vector A,Vector B) { return A.x*B.x+A.y*B.y;} //点积
LD Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x;} //叉积
LD dis(Point a,Point b) { return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
LD Length(const Point& A) { return sqrt(Dot(A,A)); }
LD angle(Vector A,Vector B) { return acos(Dot(A,B)/Length(A)/Length(B)); } //返回的是弧度值
Vector Rotate(Vector A,LD rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); }//旋转rad:弧度
Vector Normal(Vector A) { LD L=Length(A);return Vector(-A.y/L,A.x/L); } //求向量A的法向量
Point GetlineIntersection(Point P,Vector v,Point Q,Vector w){//求两线交点
Vector u=P-Q;
LD t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
LD DistanceToline(Point P,Point A,Point B){
Vector v1=B-A,v2=P-A;
return fabs(Cross(v1,v2)/Length(v1));//不取绝对值,得到有向距离
}
LD DistanceToSegment(Point P,Point A,Point B){//求点到线段的距离
if(A==B) return Length(P-A);
Vector v1=B-A,v2=P-A,v3=P-B;
if(dcmp(Dot(v1,v2))<0) return Length(v2);
else if(dcmp(Dot(v1,v3))>0) return Length(v3);
else return fabs(Cross(v1,v2))/Length(v1);  
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2){//两线段有一个公共点,且不在端点上
LD c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}
bool OnSegment(Point P,Point a1,Point a2){//点在线段上
return dcmp(Cross(a1-P,a2-P))==0&&dcmp(Dot(a1-P,a2-P))<0;
}  
//圆
struct Circle{
Point c;
LD r,v;
Circle() {}
Circle(Point c,LD r):c(c),r(r) {}
inline Point point(LD a){
return Point(c.x+cos(a)*r,c.y+sin(a)*r);
}
};
int getCircleCircleIntersection(Circle C1,Circle C2,Point &t1,Point &t2){
LD d=Length(C1.c-C2.c);
if(dcmp(d)==0){//圆心重合
if(dcmp(C1.r-C2.r)==0) return -1; //半径相同->重合
return 0;
}
if(dcmp(C1.r+C2.r-d)<0) return 0; //相离
if(dcmp(fabs(C1.r-C2.r)-d)>0) return 0; //包含
LD a=angle(C2.c,C1.c); //向量C1C2的极角
LD da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));//C1C2到C1P1的角
Point p1=C1.point(a-da),p2=C1.point(a+da);
t1=p1;
if(p1==p2) return 1;//相切
t2=p2;
return 2;
}
//凸包
//计算凸包,输入点数组p,个数为p,输出点数组为ch。函数返回凸包顶点数
//输入不能有重复节点
//如果精度要求搞需要用dcmp判断
//如果不希望在边上右点,需要将 <= 改为 <
int ConvexHull(Point *p,int n,Point *ch)//求出凸包
{
sort(p,p+n);
int m=0;
for(int i=0;i<n;i++){
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-2;i>=0;i--){
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
if(n>1) m--;
return m;
}
bool IsPointInPolygon(const Point& p,Point* poly,int n){//判断点是否在凸包内
int wn=0;
for(int i=0;i<n;i++){
const Point& p1=poly[i];
const Point& p2=poly[(i+1)%n];
if(p1==p||p2==p||OnSegment(p,p1,p2)) return -1;//在边界上
int k=dcmp(Cross(p2-p1,p-p1));
int d1=dcmp(p1.y-p.y);
int d2=dcmp(p2.y-p.y);
if(k>0&&d1<=0&&d2>0) wn++;
if(k<0&&d2<=0&&d1>0) wn--;
}
if(wn!=0) return 1;
return 0;
}
bool ConvexPolygonDisjoint(Point* ch1,int c1,Point* ch2,int c2){//两个凸包是否相交
for(int i=0;i<c1;i++){
if(IsPointInPolygon(ch1[i],ch2,c2)!=0) return false;
}
for(int i=0;i<c2;i++){
if(IsPointInPolygon(ch2[i],ch1,c1)!=0) return false;
}
for(int i=0;i<c1;i++){
for(int j=0;j<c2;j++){
if(SegmentProperIntersection(ch1[i],ch1[(i+1)%c1],ch2[j],ch2[(j+1)%c2])) return false;
}
}
return true;
}
int main()
{

return 0;
}



posted @ 2022-02-26 23:25  fengzlj  阅读(31)  评论(0)    收藏  举报