//----------------------------------------------------------------------------
Real Mgc::SqrDistance (const Line3& rkLine, const Circle3& rkCircle,
                       Vector3* pkLineClosest, Vector3* pkCircleClosest)
{
    Vector3 kDiff = rkLine.Origin() - rkCircle.Center();
    Real fDSqrLen = kDiff.SquaredLength();
    Real fMdM = rkLine.Direction().SquaredLength();
    Real fDdM = kDiff.Dot(rkLine.Direction());
    Real fNdM = rkCircle.N().Dot(rkLine.Direction());
    Real fDdN = kDiff.Dot(rkCircle.N());

    Real fA0 = fDdM;
    Real fA1 = fMdM;
    Real fB0 = fDdM - fNdM*fDdN;
    Real fB1 = fMdM - fNdM*fNdM;
    Real fC0 = fDSqrLen - fDdN*fDdN;
    Real fC1 = fB0;
    Real fC2 = fB1;
    Real fRSqr = rkCircle.Radius()*rkCircle.Radius();

    Real fA0Sqr = fA0*fA0;
    Real fA1Sqr = fA1*fA1;
    Real fTwoA0A1 = 2.0f*fA0*fA1;
    Real fB0Sqr = fB0*fB0;
    Real fB1Sqr = fB1*fB1;
    Real fTwoB0B1 = 2.0f*fB0*fB1;
    Real fTwoC1 = 2.0f*fC1;

    // The minimum point B+t*M occurs when t is a root of the quartic
    // equation whose coefficients are defined below.
    Polynomial kPoly(5);
    kPoly[0] = fA0Sqr*fC0 - fB0Sqr*fRSqr;
    kPoly[1] = fTwoA0A1*fC0 + fA0Sqr*fTwoC1 - fTwoB0B1*fRSqr;
    kPoly[2] = fA1Sqr*fC0 + fTwoA0A1*fTwoC1 + fA0Sqr*fC2 - fB1Sqr*fRSqr;
    kPoly[3] = fA1Sqr*fTwoC1 + fTwoA0A1*fC2;
    kPoly[4] = fA1Sqr*fC2;

    int iNumRoots;
    Real afRoot[4];
    kPoly.GetAllRoots(iNumRoots,afRoot);

    Real fMinSqrDist = Math::MAX_REAL;
    for (int i = 0; i < iNumRoots; i++)
    {
        // compute distance from P(t) to circle
        Vector3 kP = rkLine.Origin() + afRoot[i]*rkLine.Direction();
        Vector3 kCircleClosest;
        Real fSqrDist = SqrDistance(kP,rkCircle,&kCircleClosest);
        if ( fSqrDist < fMinSqrDist )
        {
            fMinSqrDist = fSqrDist;
            if ( pkLineClosest )
                *pkLineClosest = kP;
            if ( pkCircleClosest )
                *pkCircleClosest = kCircleClosest;
        }
    }

    return fMinSqrDist;
}
Real Mgc::SqrDistance (const Vector3& rkPoint, const Line3& rkLine,

    Real* pfParam)

{

    Vector3 kDiff = rkPoint - rkLine.Origin();

    Real fSqrLen = rkLine.Direction().SquaredLength();

    Real fT = kDiff.Dot(rkLine.Direction())/fSqrLen;

    kDiff -= fT*rkLine.Direction();



    if ( pfParam )

        *pfParam = fT;



    return kDiff.SquaredLength();

}
//----------------------------------------------------------------------------
bool Mgc::TestIntersection (const Line3& rkLine, const Box3& rkBox)
{
    Real fAWdU[3], fAWxDdU[3], fRhs;

    Vector3 kDiff = rkLine.Origin() - rkBox.Center();
    Vector3 kWxD = rkLine.Direction().Cross(kDiff);

    fAWdU[1] = Math::FAbs(rkLine.Direction().Dot(rkBox.Axis(1)));
    fAWdU[2] = Math::FAbs(rkLine.Direction().Dot(rkBox.Axis(2)));
    fAWxDdU[0] = Math::FAbs(kWxD.Dot(rkBox.Axis(0)));
    fRhs = rkBox.Extent(1)*fAWdU[2] + rkBox.Extent(2)*fAWdU[1];
    if ( fAWxDdU[0] > fRhs )
        return false;

    fAWdU[0] = Math::FAbs(rkLine.Direction().Dot(rkBox.Axis(0)));
    fAWxDdU[1] = Math::FAbs(kWxD.Dot(rkBox.Axis(1)));
    fRhs = rkBox.Extent(0)*fAWdU[2] + rkBox.Extent(2)*fAWdU[0];
    if ( fAWxDdU[1] > fRhs )
        return false;

    fAWxDdU[2] = Math::FAbs(kWxD.Dot(rkBox.Axis(2)));
    fRhs = rkBox.Extent(0)*fAWdU[1] + rkBox.Extent(1)*fAWdU[0];
    if ( fAWxDdU[2] > fRhs )
        return false;

    return true;
}
//----------------------------------------------------------------------------
Real Mgc::SqrDistance (const Segment3& rkSeg, const Box3& rkBox,
    Real* pfLParam, Real* pfBParam0, Real* pfBParam1, Real* pfBParam2)
{
#ifdef _DEBUG
    // The four parameters pointers are either all non-null or all null.
    if ( pfLParam )
    {
        assert( pfBParam0 && pfBParam1 && pfBParam2 );
    }
    else
    {
        assert( !pfBParam0 && !pfBParam1 && !pfBParam2 );
    }
#endif

    Line3 kLine;
    kLine.Origin() = rkSeg.Origin();
    kLine.Direction() = rkSeg.Direction();

    Real fLP, fBP0, fBP1, fBP2;
    Real fSqrDistance = SqrDistance(kLine,rkBox,&fLP,&fBP0,&fBP1,&fBP2);
    if ( fLP >= 0.0f )
    {
        if ( fLP <= 1.0f )
        {
            if ( pfLParam )
            {
                *pfLParam = fLP;
                *pfBParam0 = fBP0;
                *pfBParam1 = fBP1;
                *pfBParam2 = fBP2;
            }

            return fSqrDistance;
        }
        else
        {
            fSqrDistance = SqrDistance(rkSeg.Origin()+rkSeg.Direction(),
                rkBox,pfBParam0,pfBParam1,pfBParam2);

            if ( pfLParam )
                *pfLParam = 1.0f;

            return fSqrDistance;
        }
    }
    else
    {
        fSqrDistance = SqrDistance(rkSeg.Origin(),rkBox,pfBParam0,
            pfBParam1,pfBParam2);

        if ( pfLParam )
            *pfLParam = 0.0f;

        return fSqrDistance;
    }
}
//----------------------------------------------------------------------------
bool Mgc::FindIntersection (const Line3& rkLine, const Triangle3& rkTriangle,
    Vector3& rkPoint)
{
    Real fLinP;
    if ( SqrDistance(rkLine,rkTriangle,&fLinP) <= gs_fEpsilon )
    {
        rkPoint = rkLine.Origin() + fLinP*rkLine.Direction();
        return true;
    }
    return false;
}
//----------------------------------------------------------------------------
bool Mgc::FindIntersection (const Line3& rkLine, const Box3& rkBox,
    int& riQuantity, Vector3 akPoint[2])
{
    // convert line to box coordinates
    Vector3 kDiff = rkLine.Origin() - rkBox.Center();
    Vector3 kOrigin(
        kDiff.Dot(rkBox.Axis(0)),
        kDiff.Dot(rkBox.Axis(1)),
        kDiff.Dot(rkBox.Axis(2))
    );
    Vector3 kDirection(
        rkLine.Direction().Dot(rkBox.Axis(0)),
        rkLine.Direction().Dot(rkBox.Axis(1)),
        rkLine.Direction().Dot(rkBox.Axis(2))
    );

    Real fT0 = -Math::MAX_REAL, fT1 = Math::MAX_REAL;
    bool bIntersects = FindIntersection(kOrigin,kDirection,rkBox.Extents(),
        fT0,fT1);

    if ( bIntersects )
    {
        if ( fT0 != fT1 )
        {
            riQuantity = 2;
            akPoint[0] = rkLine.Origin() + fT0*rkLine.Direction();
            akPoint[1] = rkLine.Origin() + fT1*rkLine.Direction();
        }
        else
        {
            riQuantity = 1;
            akPoint[0] = rkLine.Origin() + fT0*rkLine.Direction();
        }
    }
    else
    {
        riQuantity = 0;
    }

    return bIntersects;
}
bool Wml::FindIntersection (const Line3<Real>& rkLine,
    const Cylinder3<Real>& rkCylinder, int& riQuantity,
    Vector3<Real> akPoint[2])
{
    Real afT[2];

    if ( rkCylinder.Capped() )
    {
        riQuantity = Find(rkLine.Origin(),rkLine.Direction(),rkCylinder,afT);
    }
    else
    {
        riQuantity = FindHollow(rkLine.Origin(),rkLine.Direction(),
            rkCylinder,afT);
    }

    for (int i = 0; i < riQuantity; i++)
        akPoint[i] = rkLine.Origin() + afT[i]*rkLine.Direction();

    return riQuantity > 0;
}
//----------------------------------------------------------------------------
bool Mgc::FindIntersection (const Plane& rkPlane0, const Plane& rkPlane1,
    Line3& rkLine)
{
    // If Cross(N0,N1) is zero, then either planes are parallel and separated
    // or the same plane.  In both cases, 'false' is returned.  Otherwise,
    // the intersection line is
    //
    //   L(t) = t*Cross(N0,N1) + c0*N0 + c1*N1
    //
    // for some coefficients c0 and c1 and for t any real number (the line
    // parameter).  Taking dot products with the normals,
    //
    //   d0 = Dot(N0,L) = c0*Dot(N0,N0) + c1*Dot(N0,N1)
    //   d1 = Dot(N1,L) = c0*Dot(N0,N1) + c1*Dot(N1,N1)
    //
    // which are two equations in two unknowns.  The solution is
    //
    //   c0 = (Dot(N1,N1)*d0 - Dot(N0,N1)*d1)/det
    //   c1 = (Dot(N0,N0)*d1 - Dot(N0,N1)*d0)/det
    //
    // where det = Dot(N0,N0)*Dot(N1,N1)-Dot(N0,N1)^2.

    Real fN00 = rkPlane0.Normal().SquaredLength();
    Real fN01 = rkPlane0.Normal().Dot(rkPlane1.Normal());
    Real fN11 = rkPlane1.Normal().SquaredLength();
    Real fDet = fN00*fN11 - fN01*fN01;

    if ( Math::FAbs(fDet) < gs_fEpsilon )
        return false;

    Real fInvDet = 1.0f/fDet;
    Real fC0 = (fN11*rkPlane0.Constant() - fN01*rkPlane1.Constant())*fInvDet;
    Real fC1 = (fN00*rkPlane1.Constant() - fN01*rkPlane0.Constant())*fInvDet;

    rkLine.Direction() = rkPlane0.Normal().Cross(rkPlane1.Normal());
    rkLine.Origin() = fC0*rkPlane0.Normal() + fC1*rkPlane1.Normal();
    return true;
}
bool Mgc::FindIntersection (const Line3& rkLine, const Sphere& rkSphere,

    int& riQuantity, Vector3 akPoint[2])

{

    // set up quadratic Q(t) = a*t^2 + 2*b*t + c

    Vector3 kDiff = rkLine.Origin() - rkSphere.Center();

    Real fA = rkLine.Direction().SquaredLength();

    Real fB = kDiff.Dot(rkLine.Direction());

    Real fC = kDiff.SquaredLength() -

        rkSphere.Radius()*rkSphere.Radius();



    Real afT[2];

    Real fDiscr = fB*fB - fA*fC;

    if ( fDiscr < 0.0f )

    {

        riQuantity = 0;

        return false;

    }

    else if ( fDiscr > 0.0f )

    {

        Real fRoot = Math::Sqrt(fDiscr);

        Real fInvA = 1.0f/fA;

        riQuantity = 2;

        afT[0] = (-fB - fRoot)*fInvA;

        afT[1] = (-fB + fRoot)*fInvA;

        akPoint[0] = rkLine.Origin() + afT[0]*rkLine.Direction();

        akPoint[1] = rkLine.Origin() + afT[1]*rkLine.Direction();

        return true;

    }

    else

    {

        riQuantity = 1;

        afT[0] = -fB/fA;

        akPoint[0] = rkLine.Origin() + afT[0]*rkLine.Direction();

        return true;

    }

}
//----------------------------------------------------------------------------
Real Mgc::SqrDistance (const Line3& rkLine, const Box3& rkBox,
    Real* pfLParam, Real* pfBParam0, Real* pfBParam1, Real* pfBParam2)
{
#ifdef _DEBUG
    // The four parameters pointers are either all non-null or all null.
    if ( pfLParam )
    {
        assert( pfBParam0 && pfBParam1 && pfBParam2 );
    }
    else
    {
        assert( !pfBParam0 && !pfBParam1 && !pfBParam2 );
    }
#endif

    // compute coordinates of line in box coordinate system
    Vector3 kDiff = rkLine.Origin() - rkBox.Center();
    Vector3 kPnt(kDiff.Dot(rkBox.Axis(0)),kDiff.Dot(rkBox.Axis(1)),
        kDiff.Dot(rkBox.Axis(2)));
    Vector3 kDir(rkLine.Direction().Dot(rkBox.Axis(0)),
        rkLine.Direction().Dot(rkBox.Axis(1)),
        rkLine.Direction().Dot(rkBox.Axis(2)));

    // Apply reflections so that direction vector has nonnegative components.
    bool bReflect[3];
    int i;
    for (i = 0; i < 3; i++)
    {
        if ( kDir[i] < 0.0f )
        {
            kPnt[i] = -kPnt[i];
            kDir[i] = -kDir[i];
            bReflect[i] = true;
        }
        else
        {
            bReflect[i] = false;
        }
    }

    Real fSqrDistance = 0.0f;

    if ( kDir.x > 0.0f )
    {
        if ( kDir.y > 0.0f )
        {
            if ( kDir.z > 0.0f )
            {
                // (+,+,+)
                CaseNoZeros(kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
            else
            {
                // (+,+,0)
                Case0(0,1,2,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
        }
        else
        {
            if ( kDir.z > 0.0f )
            {
                // (+,0,+)
                Case0(0,2,1,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
            else
            {
                // (+,0,0)
                Case00(0,1,2,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
        }
    }
    else
    {
        if ( kDir.y > 0.0f )
        {
            if ( kDir.z > 0.0f )
            {
                // (0,+,+)
                Case0(1,2,0,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
            else
            {
                // (0,+,0)
                Case00(1,0,2,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
        }
        else
        {
            if ( kDir.z > 0.0f )
            {
                // (0,0,+)
                Case00(2,0,1,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
            }
            else
            {
                // (0,0,0)
                Case000(kPnt,rkBox,fSqrDistance);
                if ( pfLParam )
                    *pfLParam = 0.0f;
            }
        }
    }

    if ( pfLParam )
    {
        // undo reflections
        for (i = 0; i < 3; i++)
        {
            if ( bReflect[i] )
                kPnt[i] = -kPnt[i];
        }

        *pfBParam0 = kPnt.x;
        *pfBParam1 = kPnt.y;
        *pfBParam2 = kPnt.z;
    }

    return fSqrDistance;
}