计算几何
Posted st-lovaer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算几何相关的知识,希望对你有一定的参考价值。
1 const double eps=1e-10; 2 const double PI=acos(-1.0); 3 using namespace std; 4 struct Point 5 double x; 6 double y; 7 Point(double x=0,double y=0):x(x),y(y) 8 void operator<<(Point &A) cout<<A.x<<‘ ‘<<A.y<<endl; 9 ; 10 11 int dcmp(double x) return (x>eps)-(x<-eps); 12 int sgn(double x) return (x>eps)-(x<-eps); 13 typedef Point Vector; 14 15 Vector operator +(Vector A,Vector B) return Vector(A.x+B.x,A.y+B.y); 16 Vector operator -(Vector A,Vector B) return Vector(A.x-B.x,A.y-B.y); 17 Vector operator *(Vector A,double p) return Vector(A.x*p,A.y*p); 18 Vector operator /(Vector A,double p) return Vector(A.x/p,A.y/p); 19 ostream &operator<<(ostream & out,Point & P) out<<P.x<<‘ ‘<<P.y<<endl; return out; 20 bool operator< (const Point &A,const Point &B) return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0); 21 bool operator== ( const Point &A,const Point &B) return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0; 22 23 double Dot(Vector A,Vector B) return A.x*B.x+A.y*B.y; 24 double Cross(Vector A,Vector B) return A.x*B.y-B.x*A.y; 25 double Length(Vector A) return sqrt(Dot(A, A)); 26 double Angle(Vector A,Vector B) return acos(Dot(A,B)/Length(A)/Length(B)); 27 double Area2(Point A,Point B,Point C ) return Cross(B-A, C-A); 28 29 Vector Rotate(Vector A,double rad) return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); 30 Vector Normal(Vector A) double L=Length(A);return Vector(-A.y/L,A.x/L); 31 32 Point GetLineIntersection(Point P,Vector v,Point Q,Vector w) 33 Vector u=P-Q; 34 double t=Cross(w, u)/Cross(v,w); 35 return P+v*t; 36 //输入两个点斜式方程输出交点 37 38 double DistanceToLine(Point P,Point A,Point B) 39 Vector v1=P-A; Vector v2=B-A; 40 return fabs(Cross(v1,v2))/Length(v2); 41 //输入三个点,输出P到直线AB的距离 42 43 double DistanceToSegment(Point P,Point A,Point B) 44 if(A==B) return Length(P-A); 45 Vector v1=B-A; 46 Vector v2=P-A; 47 Vector v3=P-B; 48 if(dcmp(Dot(v1,v2))==-1) return Length(v2); 49 else if(Dot(v1,v3)>0) return Length(v3); 50 else return DistanceToLine(P, A, B); 51 //输入三个点,输出P到线段AB的距离 52 53 Point GetLineProjection(Point P,Point A,Point B) 54 Vector v=B-A; 55 Vector v1=P-A; 56 double t=Dot(v,v1)/Dot(v,v); 57 return A+v*t; 58 //输入三个点,输出P在直线AB上的投影点 59 60 bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2) 61 double c1=Cross(b1-a1, a2-a1); 62 double c2=Cross(b2-a1, a2-a1); 63 double c3=Cross(a1-b1, b2-b1); 64 double c4=Cross(a2-b1, b2-b1); 65 return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0; 66 //输入四个点,判断两条线段是否有交点 67 68 bool OnSegment(Point P,Point A,Point B) 69 return dcmp(Cross(P-A, P-B))==0&&dcmp(Dot(P-A,P-B))<=0; 70 //输入三个点,判断P是否在线段AB上 71 72 double PolygonArea(Point *p,int n) 73 double area=0; 74 for(int i=1;i<n-1;i++) 75 area+=Cross(p[i]-p[0], p[i+1]-p[0]); 76 77 return area/2; 78 //输入p[i]首地址和p[]的数量,(p[0]到p[n-1]),输出多边形面 79 80 Point read_point() 81 Point P; 82 scanf("%lf%lf",&P.x,&P.y); 83 return P; 84 //输入一个点 85 86 // ---------------与圆有关的-------- 87 88 struct Circle 89 Point c; 90 double r; 91 Circle(Point c=Point(0,0),double r=0):c(c),r(r) 92 Point point(double a) 93 return Point(c.x+r*cos(a),c.y+r*sin(a)); 94 95 ; 96 97 struct Line 98 Point p; 99 Vector v; 100 Line(Point p=Point(0,0),Vector v=Vector(0,1)):p(p),v(v) 101 Point point(double t) 102 return Point(p+v*t); 103 104 ; 105 106 int getLineCircleIntersection(Line L,Circle C,double &t1,double &t2,vector<Point> &sol) 107 double a=L.v.x; 108 double b=L.p.x-C.c.x; 109 double c=L.v.y; 110 double d=L.p.y-C.c.y; 111 double e=a*a+c*c; 112 double f=2*(a*b+c*d); 113 double g=b*b+d*d-C.r*C.r; 114 double delta=f*f-4*e*g; 115 116 if(dcmp(delta)<0) return 0; 117 if(dcmp(delta)==0) 118 t1=t2=-f/(2*e); 119 sol.push_back(L.point(t1)); 120 return 1; 121 122 123 else 124 t1=(-f-sqrt(delta))/(2*e); 125 t2=(-f+sqrt(delta))/(2*e); 126 127 sol.push_back(L.point(t1)); 128 sol.push_back(L.point(t2)); 129 130 return 2; 131 132 133 134 // 向量极角公式 135 136 double angle(Vector v) return atan2(v.y,v.x); 137 138 int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point> &sol) 139 140 double d=Length(C1.c-C2.c); 141 142 if(dcmp(d)==0) 143 144 if(dcmp(C1.r-C2.r)==0) return -1; // 重合 145 else return 0; // 内含 0 个公共点 146 147 148 if(dcmp(C1.r+C2.r-d)<0) return 0; // 外离 149 if(dcmp(fabs(C1.r-C2.r)-d)>0) return 0; // 内含 150 151 double a=angle(C2.c-C1.c); 152 double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d)); 153 154 Point p1=C1.point(a-da); 155 Point p2=C1.point(a+da); 156 157 sol.push_back(p1); 158 159 if(p1==p2) return 1; // 相切 160 else 161 sol.push_back(p2); 162 return 2; 163 164 165 166 167 // 求点到圆的切线 168 169 int getTangents(Point p,Circle C,Vector *v) 170 Vector u=C.c-p; 171 172 double dist=Length(u); 173 174 if(dcmp(dist-C.r)<0) return 0; 175 176 else if(dcmp(dist-C.r)==0) 177 v[0]=Rotate(u,PI/2); 178 return 1; 179 180 181 else 182 double ang=asin(C.r/dist); 183 v[0]=Rotate(u,-ang); 184 v[1]=Rotate(u,+ang); 185 return 2; 186 187 188 189 // 求两圆公切线 190 int getTangents(Circle A,Circle B,Point *a,Point *b) 191 int cnt=0; 192 193 if(A.r<B.r) 194 swap(A,B); swap(a, b); // 有时需标记 195 196 197 double d=Length(A.c-B.c); 198 double rdiff=A.r-B.r; 199 double rsum=A.r+B.r; 200 201 if(dcmp(d-rdiff)<0) return 0; // 内含 202 203 double base=angle(B.c-A.c); 204 if(dcmp(d)==0&&dcmp(rdiff)==0) return -1 ; // 重合 无穷多条切线 205 206 if(dcmp(d-rdiff)==0) // 内切 外公切线 207 208 a[cnt]=A.point(base); 209 b[cnt]=B.point(base); 210 cnt++; 211 return 1; 212 213 214 // 有外公切线的情形 215 216 double ang=acos(rdiff/d); 217 a[cnt]=A.point(base+ang); 218 b[cnt]=B.point(base+ang); 219 cnt++; 220 a[cnt]=A.point(base-ang); 221 b[cnt]=B.point(base-ang); 222 cnt++; 223 224 if(dcmp(d-rsum)==0) // 外切 有内公切线 225 226 a[cnt]=A.point(base); 227 b[cnt]=B.point(base+PI); 228 cnt++; 229 230 231 else if(dcmp(d-rsum)>0) // 外离 又有两条外公切线 232 233 double ang_in=acos(rsum/d); 234 a[cnt]=A.point(base+ang_in); 235 b[cnt]=B.point(base+ang_in+PI); 236 cnt++; 237 a[cnt]=A.point(base-ang_in); 238 b[cnt]=B.point(base-ang_in+PI); 239 cnt++; 240 241 242 return cnt; 243 244 245 Point Zero=Point(0,0); 246 247 double TriAngleCircleInsection(Circle C, Point A, Point B) 248 Vector OA = A-C.c, OB = B-C.c; 249 Vector BA = A-B, BC = C.c-B; 250 Vector AB = B-A, AC = C.c-A; 251 double DOA = Length(OA), DOB = Length(OB),DAB = Length(AB), r = C.r; 252 if(dcmp(Cross(OA,OB)) == 0) return 0; 253 if(dcmp(DOA-C.r) < 0 && dcmp(DOB-C.r) < 0) return Cross(OA,OB)*0.5; 254 else if(DOB < r && DOA >= r) 255 double x = (Dot(BA,BC) + sqrt(r*r*DAB*DAB-Cross(BA,BC)*Cross(BA,BC)))/DAB; 256 double TS = Cross(OA,OB)*0.5; 257 return asin(TS*(1-x/DAB)*2/r/DOA)*r*r*0.5+TS*x/DAB; 258 259 else if(DOB >= r && DOA < r) 260 double y = (Dot(AB,AC)+sqrt(r*r*DAB*DAB-Cross(AB,AC)*Cross(AB,AC)))/DAB; 261 double TS = Cross(OA,OB)*0.5; 262 return asin(TS*(1-y/DAB)*2/r/DOB)*r*r*0.5+TS*y/DAB; 263 264 else if(fabs(Cross(OA,OB)) >= r*DAB || Dot(AB,AC) <= 0 || Dot(BA,BC) <= 0) 265 if(Dot(OA,OB) < 0) 266 if(Cross(OA,OB) < 0) return (-acos(-1.0)-asin(Cross(OA,OB)/DOA/DOB))*r*r*0.5; 267 else return ( acos(-1.0)-asin(Cross(OA,OB)/DOA/DOB))*r*r*0.5; 268 269 else return asin(Cross(OA,OB)/DOA/DOB)*r*r*0.5; 270 271 else 272 double x = (Dot(BA,BC)+sqrt(r*r*DAB*DAB-Cross(BA,BC)*Cross(BA,BC)))/DAB; 273 double y = (Dot(AB,AC)+sqrt(r*r*DAB*DAB-Cross(AB,AC)*Cross(AB,AC)))/DAB; 274 double TS = Cross(OA,OB)*0.5; 275 return 276 (asin(TS*(1-x/DAB)*2/r/DOA)+asin(TS*(1-y/DAB)*2/r/DOB))*r*r*0.5 + TS*((x+y)/DAB-1); 277 278
以上是关于计算几何的主要内容,如果未能解决你的问题,请参考以下文章