/*
** Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
**
** File: objectpointingatcondition.cpp
**
** Author:
**
** Description:
** Implementation of the training library "objectpointingatcondition" interface.
**
** History:
*/
#include "pch.h"
#include "ObjectPointingAtCondition.h"
#include "TypeIDTarget.h"
namespace Training
{
//------------------------------------------------------------------------------
// class methods
//------------------------------------------------------------------------------
/* void */ ObjectPointingAtCondition::ObjectPointingAtCondition (ImodelIGC* pObject, ImodelIGC* pTarget) :
m_pObject (new TypeIDTarget (pObject->GetObjectType (), pObject->GetObjectID ())),
m_pTarget (new TypeIDTarget (pTarget->GetObjectType (), pTarget->GetObjectID ())),
m_vectorMask (fNA, fNA, fNA),
m_fMinimumAngle (fNA)
{
}
//------------------------------------------------------------------------------
/* void */ ObjectPointingAtCondition::ObjectPointingAtCondition (ImodelIGC* pObject, ObjectType targetType, ObjectID targetID) :
m_pObject (new TypeIDTarget (pObject->GetObjectType (), pObject->GetObjectID ())),
m_pTarget (new TypeIDTarget (targetType, targetID)),
m_vectorMask (fNA, fNA, fNA),
m_fMinimumAngle (fNA)
{
}
//------------------------------------------------------------------------------
/* void */ ObjectPointingAtCondition::ObjectPointingAtCondition (ImodelIGC* pObject, AbstractTarget* pTarget) :
m_pObject (new TypeIDTarget (pObject->GetObjectType (), pObject->GetObjectID ())),
m_pTarget (pTarget),
m_vectorMask (fNA, fNA, fNA),
m_fMinimumAngle (fNA)
{
}
//------------------------------------------------------------------------------
/* void */ ObjectPointingAtCondition::~ObjectPointingAtCondition (void)
{
delete m_pObject;
delete m_pTarget;
}
//------------------------------------------------------------------------------
bool ObjectPointingAtCondition::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_pObject and *m_pTarget);
if (*m_pObject and *m_pTarget)
{
// The algorithm here is to get the vector of the forward orientation and
// the vector towards the target (the look vector).
// If the object is looking towards the target, then the angle from its
// forward vector to the look vector has some characteristic we can measure.
Vector targetPosition = MaskedVector ((*m_pTarget)->GetPosition ());
Vector objectPosition = MaskedVector ((*m_pObject)->GetPosition ());
Vector forward = MaskedVector ((*m_pObject)->GetOrientation ().GetForward ()).Normalize ();
Vector lookAtTarget = targetPosition - objectPosition;
float fDistanceToTarget = lookAtTarget.Length ();
lookAtTarget /= fDistanceToTarget;
float fCosLookAngle = forward * lookAtTarget; // dot product
if (fCosLookAngle > 0.0f)
{
// here is where we do the comparison against some measurable criteria
float fLookAngle = acosf (fCosLookAngle); // dot product
if (m_fMinimumAngle >= 0.0f)
{
// in this case, I care about a specific angle that I set, so we just
// compare against that
float fTargetLookAngle = RadiansFromDegrees (m_fMinimumAngle);
return (fLookAngle < fTargetLookAngle) ? true : false;
}
else
{
// here, we check to see if the look angle is less than the angle
// subtended by the target's radius around the look vector.
// this can be confused by long, skinny ships, such as the builder.
float fCoverageRadius = (*m_pTarget)->GetRadius () * 0.75f;
float fCoverageAngle = asinf (fCoverageRadius / fDistanceToTarget);
float fMinimumCoverageAngle = RadiansFromDegrees (3.0f); // settled on 3 degrees
return (fLookAngle < ((fCoverageAngle < fMinimumCoverageAngle) ? fMinimumCoverageAngle : fCoverageAngle)) ? true : false;
}
}
}
return false;
}
//------------------------------------------------------------------------------
void ObjectPointingAtCondition::SetVectorMask (const Vector& vectorMask)
{
assert ((vectorMask.X () == 0.0f) or (vectorMask.X () == NA));
assert ((vectorMask.Y () == 0.0f) or (vectorMask.Y () == NA));
assert ((vectorMask.Z () == 0.0f) or (vectorMask.Z () == NA));
m_vectorMask = vectorMask;
}
//------------------------------------------------------------------------------
void ObjectPointingAtCondition::ClearVectorMask (void)
{
m_vectorMask = Vector (fNA, fNA, fNA);
}
//------------------------------------------------------------------------------
Vector ObjectPointingAtCondition::MaskedVector (const Vector& vector)
{
// this masking of the vectors allows me to use this condition along any
// pair of axes, so that I could examine how much to the right or left any
// target is, not just relationship to the center of the screen
float x = (m_vectorMask.X () == NA) ? vector.X () : m_vectorMask.X ();
float y = (m_vectorMask.Y () == NA) ? vector.Y () : m_vectorMask.Y ();
float z = (m_vectorMask.Z () == NA) ? vector.Z () : m_vectorMask.Z ();
return Vector (x, y, z);
}
//------------------------------------------------------------------------------
void ObjectPointingAtCondition::SetMinimumAngle (float fMinimumAngle)
{
m_fMinimumAngle = fMinimumAngle;
}
//------------------------------------------------------------------------------
}