/*
**  Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
**
**  File:	objectmovingtowardscondition.cpp
**
**  Author:  
**
**  Description:
**      Implementation of the training library "objectmovingtowardscondition" interface.
**
**  History:
*/
#include    "pch.h"
#include    "ObjectMovingTowardsCondition.h"

namespace Training
{
    //------------------------------------------------------------------------------
    // class methods
    //------------------------------------------------------------------------------
    /* void */  ObjectMovingTowardsCondition::ObjectMovingTowardsCondition (const TRef<ImodelIGC>& object, const TRef<ImodelIGC>& target) :
    m_object (object),
    m_target (target)
    {
    }

    //------------------------------------------------------------------------------
    /* void */  ObjectMovingTowardsCondition::~ObjectMovingTowardsCondition (void)
    {
        m_object = 0;
        m_target = 0;
    }

    //------------------------------------------------------------------------------
    bool        ObjectMovingTowardsCondition::Evaluate (void)
    {
        // check that both objects in this condition still exist. This is mostly
        // to avoid unwanted crashes, not to provide any kind of desired behavior.
        // Note that if the objects don't exist, a constraint should have caught
        // the situation and appropriately handled it, so this shouldn't fail.
        assert (m_object->GetMission () and m_target->GetMission ());
        if (m_object->GetMission () and m_target->GetMission ())
        {
            // The algorithm here is to get the vector of the motion and the vector towards
            // the target (the look vector). If the object is moving towards the target, 
            // then the angle from its velocity vector to the look vector is less than 
            // the angle subtended by the target's radius around the look vector.
            Vector  forward = m_object->GetVelocity ();
            float   fSpeed = forward.Length ();
            if (fSpeed > 0.01f)
            {
                Vector  lookAtTarget = m_target->GetPosition () - m_object->GetPosition ();
                float   fDistanceToTarget = lookAtTarget.Length ();
                lookAtTarget /= fDistanceToTarget;
                forward /= fSpeed;
                float   fCosLookAngle = forward * lookAtTarget; // dot product
                if (fCosLookAngle > 0.0f)
                {
                    float   fLookAngle = acosf (fCosLookAngle);
                    float   fCoverageRadius = m_target->GetRadius () * 0.75f;
                    float   fCoverageAngle = asinf (fCoverageRadius / fDistanceToTarget);
                    return (fLookAngle < fCoverageAngle) ? true : false;
                }
            }
        }
        return false;
    }

    //------------------------------------------------------------------------------
}