【模板】 计几有关圆的模板

  1 Vector Rotate(Vector A, double rad) {
  2     return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
  3 }
  4 double angle(Vector v) {return atan2(v.y, v.x);}
  5 struct Circle {
  6     Point c;
  7     double r;
  8     Circle(Point c, double r) {
  9         this->c = c;
 10         this->r = r;
 11     }
 12     Point point(double a) {
 13         return Point(c.x + cos(a) * r, c.y + sin(a) * r);
 14     }
 15 };
 16 
 17 Vector AngleBisector(Point p, Vector v1, Vector v2){//给定两个向量,求角平分线
 18     double rad = Angle(v1, v2);
 19     return Rotate(v1, dcmp(Cross(v1, v2)) * 0.5 * rad);
 20 }
 21 
 22 //求直线与圆的交点
 23 int getLineCircleIntersection(Point p, Vector v, Circle c, vector<point> &sol) {
 24     double a1 = v.x, b1 = p.x - c.c.x, c1 = v.y, d1 = p.y - c.c.y;
 25     double e1 = a1 * a1 +  c1 * c1, f1 = 2 * (a1 * b1 + c1 * d1), g1 = b1 * b1 + d1 * d1 - c.r * c.r;
 26     double delta = f1 * f1 - 4 * e1 * g1, t;
 27     if(dcmp(delta) < 0) return 0;
 28     else if(dcmp(delta) == 0){
 29         t = (-f1) / (2 * e1);
 30         sol.push_back(p + v * t);
 31         return 1;
 32     } else{
 33         t = (-f1 + sqrt(delta)) / (2 * e1); sol.push_back(p + v * t);
 34         t = (-f1 - sqrt(delta)) / (2 * e1); sol.push_back(p + v * t);
 35         return 2;
 36     }
 37 }
 38 
 39 //点到圆的切线
 40 int getTangents(Point p, Circle C, Vector *v) {
 41     Vector u = C.c - p;
 42     double dist = Length(u);
 43     if (dist < C.r) return 0;
 44     else if (dcmp(dist - C.r) == 0) {
 45         v[0] = Rotate(u, PI / 2);
 46         return 1;
 47     } else {
 48         double ang = asin(C.r / dist);
 49         v[0] = Rotate(u, -ang);
 50         v[1] = Rotate(u, +ang);
 51         return 2;
 52     }
 53 }
 54  
 55 //两圆公切线
 56 //a[i], b[i]分别是第i条切线在圆A和圆B上的切点
 57 int getCircleTangents(Circle A, Circle B, Point *a, Point *b) {
 58     int cnt = 0;
 59     if (A.r < B.r) { swap(A, B); swap(a, b); }
 60     //圆心距的平方
 61     double d2 = (A.c.x - B.c.x) * (A.c.x - B.c.x) + (A.c.y - B.c.y) * (A.c.y - B.c.y);
 62     double rdiff = A.r - B.r;
 63     double rsum = A.r + B.r;
 64     double base = angle(B.c - A.c);
 65     //重合有无限多条
 66     if (d2 == 0 && dcmp(A.r - B.r) == 0) return -1;
 67     //内切
 68     if (dcmp(d2 - rdiff * rdiff) == 0) {
 69         a[cnt] = A.point(base);
 70         b[cnt] = B.point(base);
 71         cnt++;
 72         return 1;
 73     }
 74     //有外公切线
 75     double ang = acos((A.r - B.r) / sqrt(d2));
 76     a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); cnt++;
 77     a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); cnt++;
 78  
 79     //一条内切线,两条内切线
 80     if (dcmp(d2 - rsum*rsum) == 0) {
 81         a[cnt] = A.point(base); b[cnt] = B.point(PI + base); cnt++;
 82     } else if (dcmp(d2 - rsum*rsum) > 0) {
 83         double ang = acos((A.r + B.r) / sqrt(d2));
 84         a[cnt] = A.point(base + ang); b[cnt] = B.point(pi+base + ang); cnt++;
 85         a[cnt] = A.point(base - ang); b[cnt] = B.point(pi+base - ang); cnt++;
 86     }
 87     return cnt;
 88 }
 89 
 90 //求经过点p1,与直线(p2, w)相切,半径为r的一组圆
 91 int CircleThroughAPointAndTangentToALineWithRadius(Point p1, Point p2, Vector w, double r, vector<point> &sol) {
 92     Circle c1 = Circle(p1, r);
 93     double t = r / Length(w);
 94     Vector u = Vector(-w.y, w.x);
 95     Point p4 = p2 + u * t;
 96     int tot = getLineCircleIntersection(p4, w, c1, sol);
 97     u = Vector(w.y, -w.x);
 98     p4 = p2 + u * t;
 99     tot += getLineCircleIntersection(p4, w, c1, sol);
100     return tot;
101 }
102 
103 //给定两个向量,求两向量方向内夹着的圆的圆心。圆与两线均相切,圆的半径已给定
104 Point Centre_CircleTangentTwoNonParallelLineWithRadius(Point p1, Vector v1, Point p2, Vector v2, double r){
105     Point p0 = GetLineIntersection(p1, v1, p2, v2);
106     Vector u = AngleBisector(p0, v1, v2);
107     double rad = 0.5 * Angle(v1, v2);
108     double l = r / sin(rad);
109     double t = l / Length(u);
110     return p0 + u * t;
111 }
112 
113 //求与两条不平行的直线都相切的4个圆,圆的半径已给定
114 int CircleThroughAPointAndTangentALineWithRadius(Point p1, Vector v1, Point p2, Vector v2, double r, Point *sol) {
115     int ans = 0;
116     sol[ans++] = Centre_CircleTangentTwoNonParallelLineWithRadius(p1, v1, p2, v2, r);
117     sol[ans++] = Centre_CircleTangentTwoNonParallelLineWithRadius(p1, v1 * -1, p2, v2, r);
118     sol[ans++] = Centre_CircleTangentTwoNonParallelLineWithRadius(p1, v1, p2, v2 * -1, r);
119     sol[ans++] = Centre_CircleTangentTwoNonParallelLineWithRadius(p1, v1 * -1, p2, v2 * -1, r);
120     return ans;
121 }
122 
123 //求与两个相离的圆均外切的一组圆,三种情况
124 int CircleTangentToTwoDisjointCirclesWithRadius(Circle c1, Circle c2, double r, Point *sol){
125     double dis1 = c1.r + r + r + c2.r;
126     double dis2= Length(c1.c - c2.c);
127     if(dcmp(dis1 - dis2) < 0) return 0;
128     Vector u = c2.c - c1.c;
129     double t = (r + c1.r) / Length(u);
130     if(dcmp(dis1 - dis2)==0){
131         Point p0 = c1.c + u * t;
132         sol[0] = p0;
133         return 1;
134     }
135     double aa = Length(c1.c - c2.c);
136     double bb = r + c1.r, cc = r + c2.r;
137     double rad = acos((aa * aa + bb * bb - cc * cc) / (2 * aa * bb));
138     Vector w = Rotate(u, rad);
139     Point p0 = c1.c + w * t;
140     sol[0] = p0;
141     w = Rotate(u, -rad);
142     p0 = c1.c + w * t;
143     sol[1] = p0;
144     return 2;
145 }
View Code 

 

常用的:

 1 // 点到线段最短距离
 2 double Point_to_Seg(Point p,Point a,Point b){
 3     if( sgn( dot(a,p,b) ) < 0 ) return dist(p,a);
 4     if( sgn( dot(b,p,a) ) < 0 ) return dist(p,b);
 5     return fabs( cross(p,a,b) ) / dist(a,b);
 6 }
 7 struct Circle{
 8     Point o;
 9     vector<int> v;
10     //圆心发出的射线
11     Point getPoint(double deta){
12         return (Point){o.x + cos(deta)*R , o.y + sin(deta)*R };
13     }
14     //判断线段是否和圆相交
15     bool is_insert(Point a,Point b){
16         double d;
17         if( dist(a,b) < eps ) d = dist(a,o);
18         else d = Point_to_Seg(o,a,b);
19         if( sgn(d  - R) < 0 ) return 1;
20         return 0;
21     }
22 }cir[10];
23 //点到圆切点
24 int getTangentPoints(Point p,Circle c,Point& r1,Point& r2){
25     double d = dist(p,c.o);
26     if( sgn(d-R) < 0 ) return 0;
27     else if( sgn(d-R) == 0 ){
28         r1 = p;        
29         return 1;
30     }
31     else{
32         double base = atan2(p.y - c.o.y,p.x - c.o.x);
33         double deta = acos( R/d );
34         r1 = c.getPoint(base - deta);
35         r2 = c.getPoint(base + deta);
36         return 2;
37     }
38 }
39 //两圆公切线
40 //a[i], b[i]分别是第i条切线在圆A和圆B上的切点
41 int getCircleTangents(Circle A, Circle B, Point *a, Point *b) {
42     int cnt = 0;
43     if (A.r < B.r) { swap(A, B); swap(a, b); }
44     //圆心距的平方
45     double d2 = (A.c.x - B.c.x) * (A.c.x - B.c.x) + (A.c.y - B.c.y) * (A.c.y - B.c.y);
46     double rdiff = A.r - B.r;
47     double rsum = A.r + B.r;
48     double base = angle(B.c - A.c);
49     //重合有无限多条
50     if (d2 == 0 && dcmp(A.r - B.r) == 0) return -1;
51     //内切
52     if (dcmp(d2 - rdiff * rdiff) == 0) {
53         a[cnt] = A.point(base);
54         b[cnt] = B.point(base);
55         cnt++;
56         return 1;
57     }
58     //有外公切线
59     double ang = acos((A.r - B.r) / sqrt(d2));
60     a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); cnt++;
61     a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); cnt++;
62  
63     //一条内切线,两条内切线
64     if (dcmp(d2 - rsum*rsum) == 0) {
65         a[cnt] = A.point(base); b[cnt] = B.point(PI + base); cnt++;
66     } else if (dcmp(d2 - rsum*rsum) > 0) {
67         double ang = acos((A.r + B.r) / sqrt(d2));
68         a[cnt] = A.point(base + ang); b[cnt] = B.point(pi+base + ang); cnt++;
69         a[cnt] = A.point(base - ang); b[cnt] = B.point(pi+base - ang); cnt++;
70     }
71     return cnt;
72 }
View Code

 

两圆相交模板:

 1 // p1,p2是交点
 2 inline bool operator<(const Point& lhs, const Point& rhs) {
 3     if (fabs(lhs.x - rhs.x) > 1e-8) {
 4         return lhs.x < rhs.x;
 5     } else if (fabs(lhs.y - rhs.y) > 1e-8) {
 6         return lhs.y < rhs.y;
 7     } else {
 8         return false;
 9     }
10 }
11 double dis(Point a,Point b){
12     return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
13 }
14 double sqr(double x){return x*x;}
15 bool intersection(Point o1, double r1,  Point o2, double r2, Point& p1, Point& p2) {
16     double d = dis(o1, o2);
17     if (d < fabs(r1 - r2) - eps || d > r1 + r2 + eps) {
18         return false;
19     }
20     double cosa = (sqr(r1) + sqr(d) - sqr(r2)) / (2 * r1 * d);
21     double sina = sqrt(max(0.0, 1.0 - sqr(cosa)));
22     p1 = p2 = o1;
23     p1.x += r1 / d * ((o2.x - o1.x) * cosa + (o2.y - o1.y) * -sina);
24     p1.y += r1 / d * ((o2.x - o1.x) * sina + (o2.y - o1.y) * cosa);
25     p2.x += r1 / d * ((o2.x - o1.x) * cosa + (o2.y - o1.y) * sina);
26     p2.y += r1 / d * ((o2.x - o1.x) * -sina + (o2.y - o1.y) * cosa);
27     return true;
28 }
View Code

 

三点求圆心:

1 Point core(Point a,Point b,Point c){
2     Point A=(Point){b.x-a.x,c.x-a.x}*2 , B = (Point){b.y-a.y,c.y-a.y}*2;
3     Point C = (Point){ len2(b)-len2(a),len2(c)-len2(a) };
4     return (Point){ cross(B,C)/cross(B,A),cross(A,C)/cross(A,B) };
5 }
View Code

 

posted @ 2019-11-12 18:23  小布鞋  阅读(202)  评论(0)    收藏  举报