这个blog解释的挺不错:http://blog.csdn.net/acdreamers/article/details/16966369
给定不相交的两个圆以及圆外一点,找一个经过给定点的圆与其他两个圆相切
首先来看反演变换,首先是给定一个圆圆心为O,半径为R
1、圆外一点P与圆内一点P‘会一一对应的反演OP*OP'=R*R
2、经过O的圆,反演后成为不经过O的一条直线
3、不经过O的圆,反演后成为另一个圆,且圆心并不对应
4、不经过O的直线反演后成为一个经过O的圆
5、过O的直线反演后不变
那么这道题就把两个圆反演之后求两圆的公切线,然后反演回去,就会成为一个过O的圆,且与另两圆相切(由反演的过程可看出)
求反演后的圆的圆心,可以将过O的直线所在的那条直径两端点反演,然后再求圆心
这道题貌似不需要求内公切线,且反演中心圆的半径要设大一点,否则会有精度问题
#include
#include
#include
#include
#include
#include
#define sqr(x) ((x)*(x))
using namespace std;
const double eps=1e-10;
struct Point{
double x,y,z;
Point operator +(const Point &b) const;
Point operator *(const double &b) const;
Point operator -() const;
double dist() const
{
return sqrt(x*x+y*y);
}
void print() const
{
printf("COR=(%.3lf,%.3lf)\n",x,y);
}
}P;
struct Circle{
Point o;
double r;
void print() const
{
o.print();
printf("R=%.3lf\n\n",r);
}
}C1,C2;
struct Line{
Point p1,p2;
void print() const
{
p1.print();
p2.print();
printf("\n");
}
}st[4];
int tot;
void cross(Point &p,Point e,Point r)
{
p.x=e.y*r.z-e.z*r.y;
p.y=e.z*r.x-e.x*r.z;
p.z=e.x*r.y-e.y*r.x;
}
double dot(Point l,Point P)
{
return l.x*P.x+l.y*P.y+l.z*P.z;
}
Point Point::operator +(const Point &b) const
{
Point c;
c.x=x+b.x,c.y=y+b.y;
return c;
}
Point Point::operator *(const double &b) const
{
Point c;
c.x=x*b,c.y=y*b;
return c;
}
Point Point::operator -() const
{
Point c;
c.x=-x,c.y=-y;
return c;
}
Point inverse_Point(Point P,Point A)
{
Point PA=A+(-P);
double len=1000000.0/PA.dist();
Point A1=P+PA*(len/PA.dist());
return A1;
}
Circle inverse_Circle(Point P,Circle C)
{
Point O=C.o,A,B,A1,B1;
Point PO=O+(-P);
A=P+PO*((PO.dist()-C.r)/PO.dist());
B=P+PO*((PO.dist()+C.r)/PO.dist());
A1=inverse_Point(P,A);
B1=inverse_Point(P,B);
Circle C1;
C1.o=(A1+B1)*0.5;
C1.r=((A1+(-B1)).dist())*0.5;
return C1;
}
int CircleCrossCircle( Point p1 , double r1 , Point p2 , double r2 , Point &cp1 , Point &cp2 ){
double mx = p2.x - p1.x , sx = p2.x+p1.x , mx2 = mx*mx;
double my = p2.y - p1.y , sy = p2.y+p1.y , my2 = my*my;
double sq = mx2 + my2 , d = -( sq - sqr ( r1-r2 ) ) * ( sq - sqr ( r1+r2 ) ) ;
if ( d+eps <0 ) return 0 ; if ( deps ) return 2 ; else return 1 ;
}
void Add_line(Point cp1,Circle C1,Circle C2,double e)
{
Point pp;
pp=(cp1+(-C2.o));
++tot;
st[tot].p1=C2.o+pp*(C2.r/pp.dist());
st[tot].p2=C1.o+pp*(C1.r/pp.dist())*e;
}
void Cut(Circle C1,Circle C2)
{
Circle CC,C3;
CC.o=(C1.o+C2.o)*0.5;
CC.r=((CC.o+(-C1.o)).dist());
if (C1.r-C2.r>-eps) {
Circle e;
e=C1,C1=C2,C2=e;
}
C3=C2,C3.r=C2.r-C1.r;
Point cp1,cp2;
int tmp;
if ((tmp=CircleCrossCircle(CC.o,CC.r,C3.o,C3.r,cp1,cp2)) || (fabs(C3.r)