/* ** 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 (NA, NA, NA), m_fMinimumAngle (NA) { } //------------------------------------------------------------------------------ /* 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 (NA, NA, NA), m_fMinimumAngle (NA) { } //------------------------------------------------------------------------------ /* void */ ObjectPointingAtCondition::ObjectPointingAtCondition (ImodelIGC* pObject, AbstractTarget* pTarget) : m_pObject (new TypeIDTarget (pObject->GetObjectType (), pObject->GetObjectID ())), m_pTarget (pTarget), m_vectorMask (NA, NA, NA), m_fMinimumAngle (NA) { } //------------------------------------------------------------------------------ /* 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 (NA, NA, NA); } //------------------------------------------------------------------------------ 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; } //------------------------------------------------------------------------------ }