MAK Data Logger API Documentation for HLA
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
matrexTspiFomMapper Example

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

/*******************************************************************************
** Copyright (c) 1992-2025 MAK Technologies, Inc
** All rights reserved.
*******************************************************************************/
#pragma once
#if DtHLA
#include <vl/emptyFomMapper.h>
#include <vlutil/vlString.h>
{
public:
// Default constructor.
// Args is a null-terminated string. It should be in the form
// "label=value::label=value..."
// The accepted labels are version and tag.
// Either argument can be omitted and order doesn't matter.
// These are valid examples:
// "version=7.1"
// "tag=I-HITS"
// "tag=I-HITS::version=7.1"
// "version=7.1::tag=I-HITS"
//
DtMatrexTspiFomMapper( const char* args=NULL );
// Destructor
private:
// Copy CTOR not implemented -- do not copy
// Assignment operator not implemented -- do not copy
DtMatrexTspiFomMapper &operator=(const DtMatrexTspiFomMapper &other);
public:
virtual void init(DtExerciseConn* conn);
protected:
virtual void initObjClasses();
virtual void initObjChoosers();
virtual void registerUserTagModifiers(DtExerciseConn* exConn, const DtString& tag);
protected:
// Picks a FOM Class to Publish for DtEntityPublishers names
static char* entityClassChooser(const char* vrlinkClassName, DtExerciseConn* exConn,
void *usr);
protected:
DtString myTag;
};
#endif
/*******************************************************************************
** Copyright (c) 1992-2025 MAK Technologies, Inc
** All rights reserved.
*******************************************************************************/
#if DtHLA
#include <vl/exerciseConn.h>
#include <vl/fom.h>
#include <vl/stateEncoderFactory.h>
#include <vl/stateDecoderFactory.h>
#include <vlpi/entityTypes.h>
#include <vlutil/vlPrint.h>
using namespace M_TSPI_FM;
// Function to create an instance of the FOM Mapper
extern "C"
{
DT_DLL_MATREX_TSPI_FOM_MAP DtFomMapper* DtCreateFomMapper(void* usr)
{
return new DtMatrexTspiFomMapper( (const char*)usr );
}
DT_DLL_MATREX_TSPI_FOM_MAP void DtDeleteFomMapper(DtFomMapper* mapper)
{
delete mapper;
}
}
// parse the args string to find the version and tag.
// Args is a null-terminated string. It should be in the form
// "label=value::label=value"
// The accepted labels are version and tag.
// Either argument can be omitted, and order doesn't matter.
// So all these are valid:
// "version=7.1"
// "tag=I-HITS"
// "tag=I-HITS::version=7.1"
// "version=7.1::tag=I-HITS"
//
bool getValue(const char* args, const char* label, DtString& value)
{
const char* token = strstr(args, label);
bool foundLabel = token != NULL;
if (foundLabel)
{
// Get the value from the arguments.
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 )
{
DtString value;
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)
{
// Add mapping for entities
std::vector<DtString> 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.push_back(classDesc->name());
}
}
setObjectClassNames("DtReflectedEntityList", entityClasses);
}
}
{
setObjectClassChooser("DtEntityPublisher", entityClassChooser);
}
{
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");
// Call base class init. This sets myExConn, and initializes all factories
// to default or empty factories (no encoders or decoders registered, no
// mappings between FOM interaction classes and VR-Link interaction
// classes.
DtEmptyFomMapper::init(exConn);
DtObjClassDesc* objClass = exConn->fom()->objClassByName("Platform");
if (objClass)
{
stateEncoderFactory()->addEncoder( objClass->handle(),
new PlatformObjEncoder(exConn, objClass));
stateDecoderFactory()->addDecoder( objClass->handle(),
new PlatformObjDecoder(exConn, objClass));
}
if(myTag != "")
{
}
}
const char* vrlinkClassName,
DtExerciseConn* exConn,
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);
}
{
DtObjectTagModifierSP objectTagModifier(new MatrexObjectTagModifier(exConn, tag));
DtInteractionTagModifierSP interactionTagModifier(new MatrexInteractionTagModifier(exConn, tag));
// Register this tag modifier with all object classes.
exConn->setObjectTagModifier("ObjectRoot", objectTagModifier);
exConn->setInteractionTagModifier("InteractionRoot", interactionTagModifier);
}
#endif

matrexTspiPlatformObjEncoder.h/cxx

/*******************************************************************************
** Copyright (c) 1992-2025 MAK Technologies, Inc
** All rights reserved.
*******************************************************************************/
#pragma once
#if DtHLA
#include <vl/hlaStateEncoder.h>
// Forward declaration of DtEntityStateRepository class.
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)
class DT_DLL_MATREX_TSPI_FOM_MAP PlatformObjEncoder : public DtHlaStateEncoder
{
public:
// Constructor
PlatformObjEncoder(DtExerciseConn* exConn, DtObjClassDesc* classDesc);
// Destructor
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
/*******************************************************************************
** Copyright (c) 1992-2025 MAK Technologies, Inc
** All rights reserved.
*******************************************************************************/
#if DtHLA
#include <vl/entityStateRepository.h>
#include <vlpi/netStructs.h>
#include <vl/exerciseConnHLA.h>
#include <matrix/vlQuaternion.h>
#include <matrix/geodeticCoord.h>
#include <vlpi/entityTypes.h>
#include <vlutil/vlPrint.h>
#include <assert.h>
#include <time.h>
namespace M_TSPI_FM
{
PlatformObjEncoder::PlatformObjEncoder(DtExerciseConn* exConn, DtObjClassDesc* classDesc)
: DtHlaStateEncoder(exConn, classDesc)
{
// Register the individual attribute encoding and checking functions.
// The encoding functions have names like encodeStateVector,
// while checking functions have names like needStateVector.
// The macros expands to look like this:
// addEncoder("StateVector", (DtAttributeEncoder) encodeStateVector);
// addChecker("StateVector", (DtAttributeChecker) needStateVector);
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()
{
// The MATREX time is based from 1900 not 1970 so need to offset the difference (years and leap days)
const time_t offset = ((long long)3600*24*365 * 70) + ((long long)3600*24 * 17);
// Since this function is static, there is no access to the exercise connection
// and it is not possible to get the absolute real time.
// However, the MATREX FOM FAD specifies that time is based on the system time
// that is supposed to be in sync with other federates.
return time(0) + offset;
}
void PlatformObjEncoder::encodeTimestamp(
RTI::AttributeHandleValuePairSet *attrs,
RTI::AttributeHandle attrHandle)
{
// Timestamp is the current system time.
DtNetU64 netVal = systemTime();
attrs->add(attrHandle, (char*)&netVal, sizeof(DtNetU64));
}
DtBoolean PlatformObjEncoder::needTimestamp(
const DtEntityStateRepository& stateRep,
const DtEntityStateRepository& asSeenByRemote)
{
// Add timestamp when state vector is updated.
return needStateVector(stateRep,asSeenByRemote);
}
void PlatformObjEncoder::encodeStateVector(
RTI::AttributeHandleValuePairSet *attrs,
RTI::AttributeHandle attrHandle)
{
NetStateVectorCDT netVal;
// Compute Location. SR uses Geocentric Location, MATREX FOM uses
// geodetic Coordinates with a World Reference of WGS-84 ellipsoid,
// this is the same ellipsoid which VR-Link defaults to.
DtGeodeticCoord geod;
geod.setGeocentric(rep.location());
netVal.location.latitude = geod.lat();
netVal.location.longitude = geod.lon();
netVal.location.altitude = geod.alt();
// Velocity, acceleration, and orientation are the same format as repository.
// Set Velocity
const DtVector32 topVel = rep.velocity();
netVal.velocity.x = topVel[0];
netVal.velocity.y = topVel[1];
netVal.velocity.z = topVel[2];
// Set Acceleration
const DtVector32 accel = rep.acceleration();
netVal.acceleration.x = accel[0];
netVal.acceleration.y = accel[1];
netVal.acceleration.z = accel[2];
// Set Orientation
DtQuaternion quat(rep.orientation());
netVal.orientation.w = quat.w();
netVal.orientation.x = quat.x();
netVal.orientation.y = quat.y();
netVal.orientation.z = quat.z();
// Set Rotational Velocity
// FIX: There is no rotational velocity stored in the state rep and no way to calculate it.
// An extension of the state repository to store this value is needed.
netVal.orientationRate.w = 0;
netVal.orientationRate.x = 0;
netVal.orientationRate.y = 0;
netVal.orientationRate.z = 0;
// Set timestamp
netVal.timeStamp = systemTime();
attrs->add(attrHandle, (char*)&netVal, sizeof(NetStateVectorCDT));
}
DtBoolean PlatformObjEncoder::needStateVector(
const DtEntityStateRepository& stateRep,
const DtEntityStateRepository& asSeenByRemote)
{
// Position Threshold for Matrex FOM is 3 Meters
// Rotational Threshold for Matrex FOM is 3 degrees
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)
{
DtNetU32 netVal = DeadReckoningOther;
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(
const DtEntityStateRepository& stateRep,
const DtEntityStateRepository& asSeenByRemote)
{
return ( stateRep.algorithm() != asSeenByRemote.algorithm());
}
}
#endif

matrexTspiPlatformObjDecoder.h/cxx

/*******************************************************************************
** Copyright (c) 1992-2025 MAK Technologies, Inc
** All rights reserved.
*******************************************************************************/
#pragma once
#if DtHLA
#include <vl/hlaStateDecoder.h>
// Forward declaration of DtEntityStateRepository class
namespace M_TSPI_FM
{
#define DtDECLARE_PlatformObjDecoder_ATTR_DECODER(attrName) \
DtDECLARE_ATTR_DECODER(DtEntityStateRepository, attrName)
class DT_DLL_MATREX_TSPI_FOM_MAP PlatformObjDecoder : public DtHlaStateDecoder
{
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
/*******************************************************************************
** Copyright (c) 1992-2025 MAK Technologies, Inc
** All rights reserved.
*******************************************************************************/
#if DtHLA
#include <vl/entityStateRepository.h>
#include <vl/exerciseConnHLA.h>
#include <vl/topoView.h>
#include <vlutil/vlPrint.h>
#include <vl/fom.h>
#include <vlpi/entityTypes.h>
#include <vlpi/netStructs.h>
#include <matrix/vlTaitBryan.h>
#include <matrix/vlQuaternion.h>
#include <matrix/geodeticCoord.h>
namespace M_TSPI_FM
{
// Macro used to check for unexpected attribute size
#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));
PlatformObjDecoder::PlatformObjDecoder(DtExerciseConn* exConn, DtObjClassDesc* classDesc)
: DtHlaStateDecoder(exConn, classDesc)
{
// Register the individual attribute decoding functions.
// The decoding functions have names like decodeStateVector.
// The macro expands to look like this:
// addDecoder("StateVector", (DtAttributeDecoder) decodeStateVector);
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);
}
// Compute location. SR uses Geocentric Coordinates, and MATREX
// FOM uses geodetic Coordinates with a world Reference of WSG84
//
DtGeodeticCoord geod(netVal->location.latitude,
netVal->location.longitude,
netVal->location.altitude);
DtVector loc = geod.geocentric();
stateRep->setLocation(loc);
// Velocity, acceleration, and orientation are the same format as repository.
DtVector32 vel( netVal->velocity.x,
netVal->velocity.y,
netVal->velocity.z);
stateRep->setVelocity(vel);
DtVector32 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

Document ID: Generated on Thu Dec 18 15:35:09 EST 2025 from SVN revision 282494
Copyright © 2024 MAK Technologies. All Rights Reserved (www.mak.com)