UVA 10674 Tangents 求两圆切线


给出两圆求切线。一顿套模板,结果完全按照大白来好像过不了...




#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<fstream>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define sqr(x) ((x)*(x))
#define zero(A) ((fabs(A.c.x)<eps)&&(fabs(A.c.y)<eps)&&(fabs(A.r)<eps))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const double eps=1e-10;
const double PI=4.0*atan(1.0);

int dcmp(double x)
{
    if(fabs(x)<eps)  return 0;
    else return x<0?-1:1;
}

struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {};
    bool operator < (const Point& e) const
   {
    return dcmp(x - e.x) < 0 || (dcmp(x - e.x) == 0 && dcmp(y - e.y) < 0);
   }
};




typedef Point Vector;
Vector operator +(Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y); }
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }
Vector operator *(Vector A,double p) {return Vector(A.x*p,A.y*p); }
Vector operator /(Vector A,double p) {return Vector(A.x/p,A.y/p); }
Vector operator -(Vector A)  {return  Vector(-A.x,-A.y);}

struct Circle
{
    Point c;
    double r;
    Circle(){}
    Circle(Point c,double r):c(c),r(r){}
    Point point(double a)
    {
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
};
struct Line
{
    Point p;
    Vector v;
    Line(Point p,Vector v):p(p),v(v){}
    Point point(double t)
    {
        return p+v*t;
    }
};
int getTangents(Circle A,Circle B,Point *a,Point *b)
{
    int cnt=0;
    if(dcmp(A.r - B.r) < 0){//不清楚这题为什么必须加这句话才能过?加了应该要换回来。
        swap(A, B);
        swap(a, b);
    }
    double d=sqrt((A.c.x-B.c.x)*(A.c.x-B.c.x)+(A.c.y-B.c.y)*(A.c.y-B.c.y));
    double rdiff=fabs(A.r-B.r);
    double rsum=A.r+B.r;
    if(dcmp(d - rdiff) < 0) return 0;
    double base=atan2(B.c.y-A.c.y,B.c.x-A.c.x);
    double base2=atan2(A.c.y-B.c.y )
    if(dcmp(d) == 0)  return -1;
    if(dcmp(d - rdiff) == 0)
    {
        a[cnt]=A.point(base);b[cnt]=B.point(base);cnt++;
        return 1;
    }
    double ang=acos( abs(A.r-B.r)/d );
    a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang);cnt++;
    a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang);cnt++;
    if(dcmp(d - rsum) == 0)
    {
        a[cnt]=A.point(base);
        b[cnt]=B.point(PI+base);
        cnt++;
    }
    else if(dcmp(d - rsum) > 0)
    {
        double ang=acos( (A.r+B.r)/d );
        a[cnt]=A.point(base+ang);b[cnt]=B.point(PI+base+ang);cnt++;
        a[cnt]=A.point(base-ang);b[cnt]=B.point(PI+base-ang);cnt++;
    }
    return cnt;

}


double dis(Point a,Point b)
{
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
int main()
{
   std::ios::sync_with_stdio(false);
   Circle A, B;

   while(cin>>A.c.x>>A.c.y>>A.r>>B.c.x>>B.c.y>>B.r)
   {
         if( zero(A)&&zero(B)  ) break;
         Point a[4],b[4];
         int ans=getTangents(A, B,a,b);
         if(ans==-1)
         {
             puts("-1");
             continue;
         }
         printf("%d\n",ans);
         for(int i=0;i<ans;i++)
         {
             for(int j=ans-1;j>i;j--)
             {
                 if(a[j]<a[j-1] )
                 {
                     swap(a[j-1],a[j]);
                     swap(b[j-1],b[j]);
                 }
             }
         }

         for0(i,ans)
         {
             printf("%.5f %.5f %.5f %.5f %.5f\n",a[i].x,a[i].y,b[i].x,b[i].y,dis(a[i],b[i])  );
         }

   }
   return 0;
}


下面是一个简单的 C++ 实现,可以解两个圆的外公切线和内公切线。其中,Circle 类表示圆,包含圆心坐标和半径信息,Line 类表示直线,包含直线上的两个点的坐标信息。 ``` #include <iostream> #include <cmath> using namespace std; const double eps = 1e-8; struct Point { double x, y; Point() {} Point(double x, double y) : x(x), y(y) {} }; struct Circle { Point c; double r; Circle() {} Circle(Point c, double r) : c(c), r(r) {} }; struct Line { Point p1, p2; Line() {} Line(Point p1, Point p2) : p1(p1), p2(p2) {} }; double dis(Point A, Point B) { return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)); } int dcmp(double x) { if (fabs(x) < eps) return 0; return x < 0 ? -1 : 1; } Point getIntersection(Line a, Line b) { double x1 = a.p1.x, y1 = a.p1.y; double x2 = a.p2.x, y2 = a.p2.y; double x3 = b.p1.x, y3 = b.p1.y; double x4 = b.p2.x, y4 = b.p2.y; double k1 = (y2 - y1) / (x2 - x1); double k2 = (y4 - y3) / (x4 - x3); double b1 = y1 - k1 * x1; double b2 = y3 - k2 * x3; double x = (b2 - b1) / (k1 - k2); double y = k1 * x + b1; return Point(x, y); } void getTangents(Circle A, Circle B, Line &l1, Line &l2, Line &l3, Line &l4) { double d = dis(A.c, B.c); double cosA = (A.r - B.r) / d; double sinA = sqrt(1 - cosA * cosA); Point v = (B.c - A.c) / d; Point p1 = A.c + v * (A.r / cosA); Point p2 = B.c - v * (B.r / cosA); Point p3 = A.c + v * (A.r / cosA * cosA * sinA); Point p4 = B.c - v * (B.r / cosA * cosA * sinA); l1 = Line(p1, p2); l2 = Line(p1, p3); l3 = Line(p2, p4); l4 = Line(p3, p4); } int main() { Circle A(Point(0, 0), 2); Circle B(Point(3, 0), 1); Line l1, l2, l3, l4; getTangents(A, B, l1, l2, l3, l4); cout << "Outer tangents: " << endl; cout << "(" << l1.p1.x << ", " << l1.p1.y << ") -> (" << l1.p2.x << ", " << l1.p2.y << ")" << endl; cout << "(" << l2.p1.x << ", " << l2.p1.y << ") -> (" << l2.p2.x << ", " << l2.p2.y << ")" << endl; cout << "Inner tangents: " << endl; cout << "(" << l3.p1.x << ", " << l3.p1.y << ") -> (" << l3.p2.x << ", " << l3.p2.y << ")" << endl; cout << "(" << l4.p1.x << ", " << l4.p1.y << ") -> (" << l4.p2.x << ", " << l4.p2.y << ")" << endl; return 0; } ``` 这个例子中,我们假设两个圆的圆心分别为 (0, 0) 和 (3, 0),半径分别为 2 和 1。程序输出了两个圆的外公切线和内公切线的坐标。在实际使用中,可以根据需要进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值