bool GetTangentsToCircles ( const Circle2<Real>& circle0,
                                const Circle2<Real>& circle1, Line2<Real> line[4] )
    {
        Vector2<Real> W = circle1.Center - circle0.Center;
        Real wLenSqr = W.SquaredLength();
        Real rSum = circle0.Radius + circle1.Radius;
        if ( wLenSqr <= rSum * rSum )
        {
            // Circles are either intersecting or nested.
            return false;
        }

        Real r0Sqr = circle0.Radius * circle0.Radius;
        Real tmp, a;

        Real rDiff = circle1.Radius - circle0.Radius;
        if ( Math<Real>::FAbs( rDiff ) >= Math<Real>::ZERO_TOLERANCE )
        {
            // Solve (R1^2-R0^2)*s^2 + 2*R0^2*s - R0^2 = 0..
            Real r1Sqr = circle1.Radius * circle1.Radius;
            Real c0 = -r0Sqr;
            Real c1 = ( ( Real )2 ) * r0Sqr;
            Real c2 = circle1.Radius * circle1.Radius - r0Sqr;
            Real minusHalfInvC2 = ( ( Real ) - 0.5 ) / c2;
            Real discr = Math<Real>::FAbs( c1 * c1 - ( ( Real )4 ) * c0 * c2 );
            Real root = Math<Real>::Sqrt( discr );
            Real s, oneMinusS;

            // Get the first root.
            s = ( c1 + root ) * minusHalfInvC2;
            line[0].Origin = circle0.Center + s * W;
            line[1].Origin = line[0].Origin;
            if ( s >= ( Real )0.5 )
            {
                tmp = Math<Real>::FAbs( wLenSqr - r0Sqr / ( s * s ) );
                a = Math<Real>::Sqrt( tmp );
            }
            else
            {
                oneMinusS = ( Real )1 - s;
                tmp = Math<Real>::FAbs( wLenSqr - r1Sqr / ( oneMinusS * oneMinusS ) );
                a = Math<Real>::Sqrt( tmp );
            }
            GetDirections( W, a, line[0].Direction, line[1].Direction );

            // Get the second root.
            s = ( c1 - root ) * minusHalfInvC2;
            line[2].Origin = circle0.Center + s * W;
            line[3].Origin = line[2].Origin;
            if ( s >= ( Real )0.5 )
            {
                tmp = Math<Real>::FAbs( wLenSqr - r0Sqr / ( s * s ) );
                a = Math<Real>::Sqrt( tmp );
            }
            else
            {
                oneMinusS = ( Real )1 - s;
                tmp = Math<Real>::FAbs( wLenSqr - r1Sqr / ( oneMinusS * oneMinusS ) );
                a = Math<Real>::Sqrt( tmp );
            }
            GetDirections( W, a, line[2].Direction, line[3].Direction );
        }
        else
        {
            // Circles effectively have same radius.

            // Midpoint of circle centers.
            Vector2<Real> mid = ( ( Real )0.5 ) * ( circle0.Center + circle1.Center );

            // Tangent lines passing through midpoint.
            tmp = Math<Real>::FAbs( wLenSqr - ( ( Real )4 ) * r0Sqr );
            a = Math<Real>::Sqrt( tmp );
            GetDirections( W, a, line[0].Direction, line[1].Direction );
            line[0].Origin = mid;
            line[1].Origin = mid;

            // Normalize W.
            W /= Math<Real>::Sqrt( wLenSqr );

            // Tangent lines parallel to normalized W:
            //   1.  D = W
            //   2.  a. P = mid+R0*perp(W), perp(a,b) = (b,-a)
            //       b. P = mid-R0*perp(W)
            line[2].Origin.X() = mid.X() + circle0.Radius * W.Y();
            line[2].Origin.Y() = mid.Y() - circle0.Radius * W.X();
            line[2].Direction = W;
            line[3].Origin.X() = mid.X() - circle0.Radius * W.Y();
            line[3].Origin.Y() = mid.Y() + circle0.Radius * W.X();
            line[3].Direction = W;
        }

        return true;
    }
bool GetTangentsToCircles (const Circle2<Real>& rkCircle0,
    const Circle2<Real>& rkCircle1, Line2<Real> akLine[4])
{
    Vector2<Real> kW = rkCircle1.Center - rkCircle0.Center;
    Real fWLenSqr = kW.SquaredLength();
    Real fRSum = rkCircle0.Radius + rkCircle1.Radius;
    if (fWLenSqr <= fRSum*fRSum)
    {
        // circles are either intersecting or nested
        return false;
    }

    Real fR0Sqr = rkCircle0.Radius*rkCircle0.Radius;
    Real fTmp, fA;

    Real fRDiff = rkCircle1.Radius - rkCircle0.Radius;
    if (Math<Real>::FAbs(fRDiff) >= Math<Real>::ZERO_TOLERANCE)
    {
        // solve (R1^2-R0^2)*s^2 + 2*R0^2*s - R0^2 = 0.
        Real fR1Sqr = rkCircle1.Radius*rkCircle1.Radius;
        Real fC0 = -fR0Sqr;
        Real fC1 = ((Real)2.0)*fR0Sqr;
        Real fC2 = rkCircle1.Radius*rkCircle1.Radius - fR0Sqr;
        Real fMHalfInvC2 = ((Real)-0.5)/fC2;
        Real fDiscr = Math<Real>::FAbs(fC1*fC1 - ((Real)4.0)*fC0*fC2);
        Real fRoot = Math<Real>::Sqrt(fDiscr);
        Real fS, fOmS;

        // first root
        fS = (fC1 + fRoot)*fMHalfInvC2;
        akLine[0].Origin = rkCircle0.Center + fS*kW;
        akLine[1].Origin = akLine[0].Origin;
        if (fS >= (Real)0.5)
        {
            fTmp = Math<Real>::FAbs(fWLenSqr - fR0Sqr/(fS*fS));
            fA = Math<Real>::Sqrt(fTmp);
        }
        else
        {
            fOmS = (Real)1.0 - fS;
            fTmp = Math<Real>::FAbs(fWLenSqr - fR1Sqr/(fOmS*fOmS));
            fA = Math<Real>::Sqrt(fTmp);
        }
        GetDirections(kW,fA,akLine[0].Direction,akLine[1].Direction);

        // second root
        fS = (fC1 - fRoot)*fMHalfInvC2;
        akLine[2].Origin = rkCircle0.Center + fS*kW;
        akLine[3].Origin = akLine[2].Origin;
        if (fS >= (Real)0.5)
        {
            fTmp = Math<Real>::FAbs(fWLenSqr - fR0Sqr/(fS*fS));
            fA = Math<Real>::Sqrt(fTmp);
        }
        else
        {
            fOmS = (Real)1.0 - fS;
            fTmp = Math<Real>::FAbs(fWLenSqr - fR1Sqr/(fOmS*fOmS));
            fA = Math<Real>::Sqrt(fTmp);
        }
        GetDirections(kW,fA,akLine[2].Direction,akLine[3].Direction);
    }
    else
    {
        // circles effectively have same radius

        // midpoint of circle centers
        Vector2<Real> kMid = ((Real)0.5)*(rkCircle0.Center+rkCircle1.Center);

        // tangent lines passing through midpoint
        fTmp = Math<Real>::FAbs(fWLenSqr - ((Real)4.0)*fR0Sqr);
        fA = Math<Real>::Sqrt(fTmp);
        GetDirections(kW,fA,akLine[0].Direction,akLine[1].Direction);
        akLine[0].Origin = kMid;
        akLine[1].Origin = kMid;

        // normalize W
        kW /= Math<Real>::Sqrt(fWLenSqr);

        // tangent lines parallel to normalized W
        //   1.  D = W
        //   2.  a. P = mid+R0*perp(W), perp(a,b) = (b,-a)
        //       b. P = mid-R0*perp(W)
        akLine[2].Origin.X() = kMid.X() + rkCircle0.Radius*kW.Y();
        akLine[2].Origin.Y() = kMid.Y() - rkCircle0.Radius*kW.X();
        akLine[2].Direction = kW;
        akLine[3].Origin.X() = kMid.X() - rkCircle0.Radius*kW.Y();
        akLine[3].Origin.Y() = kMid.Y() + rkCircle0.Radius*kW.X();
        akLine[3].Direction = kW;
    }

    return true;
}