Click or drag to resize

Entities

Since the information available in modern data sources can vary from source to source, Tracking Library does not define a single concrete class to contain that data. Instead, it defines many small interfaces that each contain properties commonly shared amongst data sources. Any class implementing one or more of these interfaces is referred to as an entity. Examples of typical entities are aircraft, ground vehicles, and satellites. To define an entity, the developer chooses which interfaces represent data available in their data source and then implements those interfaces in a new class. Any extra information not part of a built-in interface can be also added to the class as additional properties. For this reason, most Tracking Library types are generic types which take the entity type as their generic parameter and are constrained on the interfaces they require. This allows for a concrete entity implementation which closely matches the data being ingested, while the interfaces provide the means to connect those objects to the provided Tracking Library functionality which requires a specific piece of data.

Note Note

The functionality described in this topic requires a license for the Tracking Library.

Entity Interfaces

The reference documentation for these interfaces have more details about the required data they must provide. IEntityIdentifier should return a unique identifier for each entity in the data source and IEntityLastUpdate should always reflect the last time that the entity was modified. The example entity implementation in the code sample below contains seven properties, but only three of them: Callsign, Affiliation, and SymbolId are unique to this type of entity. The rest are defined using the entity interfaces.

C#
public enum Force
{
    Friendly,
    Hostile,
    Neutral,
    Unknown
}

public class ExampleEntity : IEntityIdentifier,
                             IEntityLastUpdate,
                             IEntityVelocity,
                             IEntityOrientation
{
    public static void RegisterEntityClass()
    {
        EntityDescriptor<ExampleEntity>.Default = new ExampleEntityDescriptor();
    }

    public ExampleEntity(TransactionContext context, string callSign)
    {
        if (context == null)
            throw new ArgumentNullException("context");
        if (callSign == null)
            throw new ArgumentNullException("callSign");

        m_callSign = callSign;
        m_lastUpdate = new TransactedProperty<JulianDate>(context, this);
        m_position = new TransactedProperty<Cartesian>(context, this);
        m_velocity = new TransactedProperty<Cartesian>(context, this);
        m_orientation = new TransactedProperty<UnitQuaternion>(context, this);
        m_force = new TransactedProperty<Force>(context, this, Force.Unknown);
        m_symbolID = new TransactedProperty<string>(context, this);
    }


    public object EntityIdentifier
    {
        get { return m_callSign; }
    }



    public TransactedProperty<JulianDate> LastUpdate
    {
        get { return m_lastUpdate; }
    }



    public TransactedProperty<Cartesian> Position
    {
        get { return m_position; }
    }

    public TransactedProperty<Cartesian> Velocity
    {
        get { return m_velocity; }
    }



    public TransactedProperty<UnitQuaternion> Orientation
    {
        get { return m_orientation; }
    }


    public TransactedProperty<string> SymbolId
    {
        get { return m_symbolID; }
    }

    public string CallSign
    {
        get { return m_callSign; }
    }

    public TransactedProperty<Force> Affiliation
    {
        get { return m_force; }
    }

    private string m_callSign;
    private TransactedProperty<Cartesian> m_position;
    private TransactedProperty<Cartesian> m_velocity;
    private TransactedProperty<Force> m_force;
    private TransactedProperty<JulianDate> m_lastUpdate;
    private TransactedProperty<string> m_symbolID;
    private TransactedProperty<UnitQuaternion> m_orientation;
}

IEntityPosition is not directly implemented here, since it inherits from IEntityVelocity, which is implemented. With this architecture, only code that needs to handle the Callsign, Affiliation or SymbolId properties (those that are not part of a built-in interface) needs to know about the specific ExampleEntity type. All other information can be accessed generically through the interfaces. Entities are designed for use with Transactions, so all settable properties should be TransactedProperty<T> instances. This allows for entities to be handled in a thread-safe manner using transactions, which allows use of all available processors for analysis and visualization.

Entity Descriptors

After defining the entity type itself, there are still more details to consider. While IEntityPosition specifies the actual position of the entity, it does not specify the ReferenceFrame in which the position is defined. Information such as this is shared across all instances of a specific entity type, rather than being defined on a per-entity basis like position. This information is defined using a EntityDescriptor<TEntity>. A descriptor for ExampleEntity is shown in the code sample below:

C#
public class ExampleEntityDescriptor : EntityDescriptor<ExampleEntity>,
                                       IEntityPositionDescriptor,
                                       IEntityOrientationDescriptor
{

    public ReferenceFrame PositionReferenceFrame
    {
        get { return CentralBodiesFacet.GetFromContext().Earth.FixedFrame; }
    }



    public Axes OrientationAxes
    {
        get { return PositionReferenceFrame.Axes; }
    }

}

Like entities, descriptors implement a set of standard interfaces:

IEntityArchiveDescriptor<TEntity> is discussed in detail in the Archiving topic. Once an EntityDescriptor<TEntity> is defined, an instance of it must be registered, as shown in the following code sample:

C#
EntityDescriptor<ExampleEntity>.Default = new ExampleEntityDescriptor();

Once registered, any class that needs access to any of the shared entity properties, such as the position's PositionReferenceFrame, can access it as shown in the following code sample:

C#
// get entity descriptor for ExampleEntity
EntityDescriptor<ExampleEntity> descriptor = EntityDescriptor<ExampleEntity>.Default;

// get the reference frame from the descriptor
ReferenceFrame frame = descriptor.Get<IEntityPositionDescriptor>().PositionReferenceFrame;
Entity Sets

Typically, data sources provide information about a number of different entities. EntitySet<TEntity> is a built-in collection type for entities, which is used throughout the library. EntitySet<TEntity> is transaction-aware, making it thread-safe when used properly with transactions. It also provides events that are raised when an entity is added, changed or removed. Entities stored in an EntitySet<TEntity> must implement the IEntityIdentifier interface, to ensure that each entity exists only once in the set.

Classes that parse a data source and store it into an entity set usually do so with a Lookup, Create, Modify approach, as shown in the below code sample:

C#
context.DoTransactionally(transaction =>
{
    ExampleEntity entity = entities.GetEntityById(transaction, entityID);
    if (entity == null)
    {
        entity = new ExampleEntity(context, entityID);
        entities.Add(transaction, entity);
    }
    entity.Position.SetValue(transaction, updatedPosition);
    entity.Orientation.SetValue(transaction, updatedOrientation);
});

An EntitySet<TEntity> can be used by filters, described in the Filtering topic, and with visualizers, described in the Visualization with Insight3D® topic, to perform analysis and visualization.