A VR-Link FOM Mapper for the entity attributes of the MATREX FOM for Time and Space Position Information. This is a working example which is integrated into the actual logger. This FOM Mapper demonstrates how to map the necessary TSPI attributes into the VR-Link state repository in order to support scaling and pause during playback when dead reckoning is used in the federation.
The MATREX FOM Mapper Initialization, Encoder, and Decoder:
matrexTspiFomMapper.h/cxx
matrexTspiPlatformObjEncoder.h/cxx
matrexTspiPlatformObjDecoder.h/cxx
matrexTspiFomMapper.h/cxx
#pragma once
#if DtHLA
#include <vl/emptyFomMap.h>
#include <vlutil/vlString.h>
{
public:
private:
public:
protected:
virtual void initObjClasses();
virtual void initObjChoosers();
protected:
static char* entityClassChooser(
const char* vrlinkClassName,
DtExerciseConn* exConn,
void *usr);
protected:
};
#endif
#pragma once
#if DtHLA
#include <vl/exerciseConn.h>
#include <vl/fom.h>
#include <vl/encFactory.h>
#include <vl/decFactory.h>
#include <vlpi/EntityTypes.h>
#include <vlutil/vlPrint.h>
using namespace M_TSPI_FM;
extern "C"
{
{
}
{
delete mapper;
}
}
bool getValue(
const char* args,
const char* label,
DtString& value)
{
const char* token = strstr(args, label);
bool foundLabel = token != NULL;
if (foundLabel)
{
token += strlen(label);
const char* delim = strstr( token, "::");
if ( delim == NULL )
{
value = token;
}
else
{
char valueBuffer[1024];
int length = delim-token;
memcpy(valueBuffer, token, length);
valueBuffer[length] = '\0';
value = valueBuffer;
}
}
return foundLabel;
}
{
double version = 7.1;
if ( args != NULL )
{
if (getValue(args, "tag=", value))
{
myTag = value;
}
if (getValue(args, "version=", value))
{
version = atof(value);
}
}
setVersion( version );
}
{
}
{
DtFom* fom = myExConn->fom();
DtObjClassDesc* baseEntDesc = fom->objClassByName("Platform");
if (baseEntDesc)
{
DtList entityClasses;
DtObjClassDesc* classDesc = NULL;
#if !DtHLA_1516
for (classDesc = fom->firstObjClass(); classDesc; classDesc = fom->nextObjClass(classDesc))
{
#else
std::list<DtObjClassDesc*>::const_iterator classIter = fom->objClassList().begin();
for ( ; classIter != fom->objClassList().end(); ++classIter)
{
classDesc = const_cast<DtObjClassDesc*>(*classIter);
#endif
if (classDesc != baseEntDesc && classDesc->isOfClass(baseEntDesc->handle()))
{
entityClasses.add((void *)classDesc->name());
}
}
setObjectClassNames("DtReflectedEntityList", entityClasses);
}
}
{
}
{
printf("************************************\n");
printf(" MATREX TSPI FOM MAPPER\n");
printf(" Built on Date: %s at time %s\n", __DATE__, __TIME__ );
printf(" Using Logger Version %.1f\n", version() );
printf("************************************\n");
DtObjClassDesc* objClass = exConn->fom()->objClassByName("Platform");
if (objClass)
{
stateEncoderFactory()->addEncoder( objClass->handle(),
stateDecoderFactory()->addDecoder( objClass->handle(),
}
{
}
}
const char* vrlinkClassName,
void *usr)
{
DtEntityType& type = *reinterpret_cast<DtEntityType*>(usr);
const char* name = "Platform";
if (type.kind() == DtMunition)
{
name = "Platform.Munition";
}
else if (type.kind() == DtLifeForm)
{
name = "Platform.IndividualCombatant";
}
else if (type.kind() == DtPlatform)
{
switch(type.domain())
{
case DtPlatformDomainLand:
name = "Platform.GroundPlatform";
break;
case DtPlatformDomainAir:
name = "Platform.Aircraft";
break;
}
}
else
{
DtInfo("MATREX TSPI FOM MAPPER: Copy not map entity type %s; using default class %s\n",
type.string(), name);
}
return const_cast<char*>(name);
}
{
exConn->setObjectTagModifier("ObjectRoot", objectTagModifier);
exConn->setInteractionTagModifier("InteractionRoot", interactionTagModifier);
}
#endif
matrexTspiPlatformObjEncoder.h/cxx
#pragma once
#if DtHLA
#include <vl/hStateEncoder.h>
namespace M_TSPI_FM
{
#define DtDECLARE_PlatformObjEncoder_ATTR_CHECKER(attrName) \
DtDECLARE_ATTR_CHECKER(DtEntityStateRepository, attrName)
#define DtDECLARE_PlatformObjEncoder_ATTR_ENCODER(attrName) \
DtDECLARE_ATTR_ENCODER(DtEntityStateRepository, attrName)
{
public:
PlatformObjEncoder(
DtExerciseConn* exConn, DtObjClassDesc* classDesc);
virtual ~PlatformObjEncoder();
protected:
static time_t systemTime();
};
#define DEFINE_SIMPLE_PlatformObjEncoder_ATTR_ENCODER( \
attrName, netType, inspector) \
DtDEFINE_SIMPLE_ATTR_ENCODER(PlatformObjEncoder, \
DtEntityStateRepository, \
attrName, netType, inspector)
#define DEFINE_SIMPLE_PlatformObjEncoder_ATTR_CHECKER( \
attrName, inspector) \
DtDEFINE_SIMPLE_ATTR_CHECKER(PlatformObjEncoder, \
DtEntityStateRepository, \
attrName, inspector)
}
#endif
#if DtHLA
#include <vl/entitySR.h>
#include <vlpi/NetStructs.h>
#include <vl/hExerciseConn.h>
#include <matrix/vlQuaternion.h>
#include <matrix/geodCoord.h>
#include <vlpi/EntityTypes.h>
#include <vlutil/vlPrint.h>
#include <assert.h>
#include <time.h>
namespace M_TSPI_FM
{
{
DtADD_ATTR_ENCODER(Timestamp);
DtADD_ATTR_CHECKER(Timestamp);
DtADD_ATTR_ENCODER(StateVector);
DtADD_ATTR_CHECKER(StateVector);
DtADD_ATTR_ENCODER(DRAlgorithm);
DtADD_ATTR_CHECKER(DRAlgorithm);
}
PlatformObjEncoder::~PlatformObjEncoder()
{
}
time_t PlatformObjEncoder::systemTime()
{
const time_t offset = ((long long)3600*24*365 * 70) + ((long long)3600*24 * 17);
return time(0) + offset;
}
void PlatformObjEncoder::encodeTimestamp(
RTI::AttributeHandleValuePairSet *attrs,
RTI::AttributeHandle attrHandle)
{
DtNetU64 netVal = systemTime();
attrs->add(attrHandle, (char*)&netVal, sizeof(DtNetU64));
}
DtBoolean PlatformObjEncoder::needTimestamp(
{
return needStateVector(stateRep,asSeenByRemote);
}
void PlatformObjEncoder::encodeStateVector(
RTI::AttributeHandleValuePairSet *attrs,
RTI::AttributeHandle attrHandle)
{
NetStateVectorCDT netVal;
DtGeodeticCoord geod;
geod.setGeocentric(rep.location());
netVal.location.latitude = geod.lat();
netVal.location.longitude = geod.lon();
netVal.location.altitude = geod.alt();
const DtVector topVel = rep.velocity();
netVal.velocity.x = topVel[0];
netVal.velocity.y = topVel[1];
netVal.velocity.z = topVel[2];
const DtVector accel = rep.acceleration();
netVal.acceleration.x = accel[0];
netVal.acceleration.y = accel[1];
netVal.acceleration.z = accel[2];
DtQuaternion quat(rep.orientation());
netVal.orientation.w = quat.w();
netVal.orientation.x = quat.x();
netVal.orientation.y = quat.y();
netVal.orientation.z = quat.z();
netVal.orientationRate.w = 0;
netVal.orientationRate.x = 0;
netVal.orientationRate.y = 0;
netVal.orientationRate.z = 0;
netVal.timeStamp = systemTime();
attrs->add(attrHandle, (char*)&netVal, sizeof(NetStateVectorCDT));
}
DtBoolean PlatformObjEncoder::needStateVector(
{
double distSqr = DtDistSqr(stateRep.location(), asSeenByRemote.location());
const double threshSqr = 9.0;
const double rotTrace = DtDcmDcmRotTrace(asSeenByRemote.bodyToGeoc(), stateRep.bodyToGeoc());
const double threshTrace = DtDeg2Rad(3.0);
if (distSqr > threshSqr)
{
return true;
}
else if (rotTrace < threshTrace)
{
return true;
}
return false;
}
void PlatformObjEncoder::encodeDRAlgorithm(
RTI::AttributeHandleValuePairSet *attrs,
RTI::AttributeHandle attrHandle)
{
switch( rep.algorithm() )
{
case DtDrOther:
break;
case DtDrStatic:
break;
case DtDrDrmFpw:
break;
case DtDrDrmRpw:
break;
case DtDrDrmRvw:
break;
case DtDrDrmFvw:
break;
case DtDrDrmFpb:
break;
case DtDrDrmRpb:
break;
case DtDrDrmRvb:
break;
case DtDrDrmFvb:
break;
default:
break;
}
attrs->add(attrHandle, (char*)&netVal, sizeof(DtNetU32));
}
DtBoolean PlatformObjEncoder::needDRAlgorithm(
{
return ( stateRep.algorithm() != asSeenByRemote.algorithm());
}
}
#endif
matrexTspiPlatformObjDecoder.h/cxx
#pragma once
#if DtHLA
#include <vl/hStateDecoder.h>
namespace M_TSPI_FM
{
#define DtDECLARE_PlatformObjDecoder_ATTR_DECODER(attrName) \
DtDECLARE_ATTR_DECODER(DtEntityStateRepository, attrName)
{
public:
PlatformObjDecoder(
DtExerciseConn* exConn, DtObjClassDesc* classDesc);
virtual ~PlatformObjDecoder();
protected:
};
#define DEFINE_SIMPLE_PlatformObjDecoder_ATTR_DECODER_WITH_CAST( \
attrName, netType, mutator, castExpr) \
DtDEFINE_SIMPLE_ATTR_DECODER_WITH_CAST( \
PlatformObjDecoder, DtEntityStateRepository, \
attrName, netType, mutator, castExpr)
#define DEFINE_SIMPLE_PlatformObjDecoder_ATTR_DECODER( \
attrName, netType, inspector) \
DEFINE_SIMPLE_PlatformObjDecoder_ATTR_DECODER_WITH_CAST( \
attrName, netType, inspector, (netType))
}
#endif
#if DtHLA
#include <vl/entitySR.h>
#include <vl/hExerciseConn.h>
#include <vl/topoView.h>
#include <vlutil/vlPrint.h>
#include <vl/hExerciseConn.h>
#include <vl/fom.h>
#include <vlpi/EntityTypes.h>
#include <vlpi/NetStructs.h>
#include <matrix/vlTaitBryan.h>
#include <matrix/vlQuaternion.h>
#include <matrix/geodCoord.h>
namespace M_TSPI_FM
{
#define PlatformObjDecoder_SIZE_WARNING(attributeName, type, length ) \
DtWarn("\nSize of value decoded from RTI update for attribute %s (%d)\n" \
" is %s than size of %s (%d)\n", \
attributeName, length, \
(length < sizeof(type) ? "smaller" : "larger"), #type, sizeof(type));
{
DtADD_ATTR_DECODER(StateVector);
DtADD_ATTR_DECODER(DRAlgorithm);
}
PlatformObjDecoder::~PlatformObjDecoder()
{
}
void PlatformObjDecoder::decodeStateVector(
const RTI::AttributeHandleValuePairSet& attrs,
int pairSetIndex)
{
RTI::ULong length = 0;
NetStateVectorCDT* netVal = reinterpret_cast<NetStateVectorCDT*>(attrs.getValuePointer(pairSetIndex, length));
if (length < sizeof(NetStateVectorCDT))
{
PlatformObjDecoder_SIZE_WARNING("StateVector",
NetStateVectorCDT,
length);
DtWarn("StateVector attribute was discarded!\n");
}
else
{
if (length > sizeof(NetStateVectorCDT))
{
PlatformObjDecoder_SIZE_WARNING("StateVector",
NetStateVectorCDT,
length);
}
DtGeodeticCoord geod(netVal->location.latitude,
netVal->location.longitude,
netVal->location.altitude);
DtVector loc = geod.geocentric();
stateRep->setLocation(loc);
DtVector vel( netVal->velocity.x,
netVal->velocity.y,
netVal->velocity.z);
stateRep->setVelocity(vel);
DtVector accel( netVal->acceleration.x,
netVal->acceleration.y,
netVal->acceleration.z);
stateRep->setAcceleration(accel);
DtQuaternion quat( netVal->orientation.w,
netVal->orientation.x,
netVal->orientation.y,
netVal->orientation.z);
DtTaitBryan tb(quat);
stateRep->setOrientation(tb);
}
}
void PlatformObjDecoder::decodeDRAlgorithm(
const RTI::AttributeHandleValuePairSet& attrs,
int pairSetIndex)
{
RTI::ULong length = attrs.getValueLength(pairSetIndex);
DtNetU32* netVal = reinterpret_cast<DtNetU32*>(attrs.getValuePointer(pairSetIndex, length));
if (length < sizeof(DtNetU32))
{
PlatformObjDecoder_SIZE_WARNING("DRAlgorithm", DtNetU32, length);
DtWarn("Attribute was discarded!\n");
}
else
{
if (length > sizeof(DtNetU32))
{
PlatformObjDecoder_SIZE_WARNING("DRAlgorithm", DtNetU32, length);
}
DtU32 matrexAlg = *netVal;
DtDeadReckonTypes rprAlg = DtDrOther;
switch ( matrexAlg )
{
rprAlg = DtDrOther;
break;
rprAlg = DtDrStatic;
break;
rprAlg = DtDrDrmFpw;
break;
rprAlg = DtDrDrmRpw;
break;
rprAlg = DtDrDrmRvw;
break;
rprAlg = DtDrDrmFvw;
break;
rprAlg = DtDrDrmFpb;
break;
rprAlg = DtDrDrmRpb;
break;
rprAlg = DtDrDrmRvb;
break;
rprAlg = DtDrDrmFvb;
break;
default:
DtWarn("Received unknown DR Algorithm value %d; using \"Other\"(%d)\n",
matrexAlg, DtDrOther);
break;
}
stateRep->setAlgorithm( rprAlg );
}
}
}
#endif