MapLink Pro 11.1.1.0.
Envitia MapLink Pro: The Ultimate Mapping Application Toolkit
Loading...
Searching...
No Matches
Using the Track Display Manager

Introduction

The TrackDisplayManager provides an easy way to create and display dynamic objects representing real-world entities that frequently change position. Tracks can be styled using application-defined symbols, or the APP6A and 2525B military symbology standards.

Each real-world entity is represented in the application by an instance of the Track class, which contains information about the entity such as it's position, altitude, heading and velocity. Each track uses one or more symbol derived classes to define the appearance of the track at various zoom levels, the appearance of the track's selection indicator (to visually identify when a track will be used for application-defined operations) and the appearance of the track's history trail.

Tracks are associated with a drawing surface using the TrackDisplayManager class. The TrackDisplayManager acts as a container for a group of tracks within the application, and provides methods for efficiently updating common properties on large numbers of tracks at once. It also provides the capability to record and replay the status of tracks over time, allowing the viewing of the history of the tracks in the TrackDisplayManager

Track Display Manager Basics

When using the Track Display Manager all applications need to perform the following steps:

  1. Create a TrackDisplayManager.
  2. Associate the TrackDisplayManager with one or more drawing surfaces.
  3. Create a Track object for each real-world entity.
  4. Define the visualisation settings for each Track.
  5. Add the Track objects to the TrackDisplayManager.
  6. Set and update the position of the Tracks in the TrackDisplayManager.

Creating a TrackDisplayManager

A track display manager is created through the TSLTrackDisplayManager::create method. An application can create multiple TrackDisplayManagers if desired. A newly created TrackDisplayManager contains no tracks and is not associated with any drawing surfaces This would be configured as follows:

std::unique_ptr<TSLTrackDisplayManager, TSLDestroyPointer> manager(TSLTrackDisplayManager::create());
static TSLTrackDisplayManager * create()
Create a TSLTrackDisplayManager.

Associating a TrackDisplayManager with a drawing surface

In order for tracks in a TrackDisplayManager to be drawn, the TrackDisplayManager must be associated with a drawing surface . This is performed through the TrackDisplayManager::addDrawingSurface() method. This creates a data layer on the drawing surface that represents the tracks within the manager and provides access to all of the normal data layer functionality.

A TrackDisplayManager can be associated with more than one drawing surface allowing for different views to be shown of the same set of tracks. When a TrackDisplayManager is associated with multiple drawing surfaces , each drawing surface must use a compatible coordinate system.

This would be configured as follows:

int surfaceId = manager->addDrawingSurface(m_surface, "TDM1MC1");

Creating Tracks

Each real-world entity the application wishes to display requires a Track object. These are created through the TSLTrack::create method. When creating a track, a TrackPointSymbol must be provided which defines the base rendering for visualisation of the track.

At a minimum, a track must have its position set via the Track.move() , TrackDisplayManager::moveTrack() or TrackDisplayManager::moveTracks() methods prior to the track being displayed for the first time.

Track Visualisation

Each track uses one or more symbol objects to define how that track should be drawn. Each symbol represents a level of detail which allows for the visual complexity of a symbol to be altered based on the drawing surface 's zoom level. In a simple situation a track may be configured with two levels of detail:

  • A complex symbol for display when the view is zoomed in.
  • A simple symbol for display when the view is zoomed out.

This would be configured as follows:

TSLSymbol* createPointSymbol(int symbolIDVal, int symbolSize, TSLRGBA colour)
{
attribs.m_symbolStyle = symbolIDVal;
attribs.m_symbolColour = colour.composeRGB();
attribs.m_symbolSizeFactor = symbolSize;
TSLSymbol * symbol = TSLSymbol::create(0, 0, 0);
symbol->setRendering(attribs);
return symbol;
}
std::unique_ptr<TSLTrackPointSymbol, TSLReleasePointer> lowDetail(TSLTrackPointSymbol::create());
std::unique_ptr<TSLSymbol, TSLDestroyPointer> greenDot(createPointSymbol(1, 25.0, TSLRGBA(0x00, 0xff, 0x00, 0xff))); // Display as a green dot
lowDetail->addSymbolEntity(greenDot);
// By default maximumResolution is set such that there is no upper limit to when the symbol will be shown so this
// does not need to be set for the low detail symbol
std::unique_ptr<TSLTrackPointSymbol, TSLReleasePointer> highDetail(TSLTrackPointSymbol::create());
std::unique_ptr<TSLSymbol, TSLDestroyPointer> redAeroplane(createPointSymbol(6002, 35.0, TSLRGBA(0xff, 0x00, 0x00, 0xff))); // Display as a red aeroplane
highDetail->addSymbolEntity(redAeroplane);
// Only show this symbol up to 10,000 MU per pixel, otherwise show the other symbol
highDetail->maximumResolution( 10000.0 );
std::unique_ptr<TSLTrack, TSLReleasePointer> track(TSLTrack::create(highDetail));
track->addSymbol( lowDetail );
bool setRendering(TSLRenderingAttributeInt attribute, int value)
Definition tslrenderingattributes.h:28
double m_symbolSizeFactor
Definition tslrenderingattributes.h:433
int m_symbolStyle
Definition tslrenderingattributes.h:453
TSLDimensionUnits m_symbolSizeFactorUnits
Definition tslrenderingattributes.h:443
int m_symbolColour
Definition tslrenderingattributes.h:359
Definition tslsymbol.h:36
static TSLSymbol * create(TSLFeatureID featureID, TSLTMC x, TSLTMC y, TSLTMC height=100, double rotation=0)
static TSLTrack * create()
static TSLTrackPointSymbol * create()
Create a TSLTrackPointSymbol.
@ TSLDimensionUnitsPixels
Pixels.
Definition tsldimensionunits.h:32
Definition tslcolourhelper.h:122
int composeRGB()
Definition tslcolourhelper.h:278

At runtime the symbol displayed for each track will then automatically change based on the viewing resolution of the associated drawing surface

Track level of detail switching

A track can have as many levels of detail as required, and each level of detail can use a different type of symbol. A single symbol instance can be shared by multiple Tracks when the tracks require identical rendering at a given level of detail.

Point Symbols

Point symbols are the basic type of symbol. Each TSLNTrackPointSymbol consists of one or more MapLink entities, all of which will be drawn in the order specified. This allows for complex symbols to be built up from a set of component parts. MapLink comes with hundreds of pre-configured symbols for a wide variety of scenarios. Applicaton-specific symbols can be created by:

  • Using Symbol Studio to create a tmf symbol and adding it to config/symbols/tslsymbolsuser.dat
  • Adding custom raster symbols to config/symbols/tslsymbolsuser.dat
  • Providing application-defined entities to a point symbol at runtime
Examples of Point Symbols

Selection Symbols

Selection symbols represent an additional symbol which will be drawn when a track has been marked as 'selected'. These symbols may be drawn as a replacement for the track symbol or as an additional symbol on top.

This functionality is usually used to indicate that a track has been 'clicked' by the user, or to otherwise highlight it out of a larger set of tracks.

Any track symbol may be used as a selection symbol but typically a point symbol is used.

Selection symbols are set on point symbols . This means that each level of detail in a track can use a different selection symbol. This allows the selection symbol to be resized/changed relative to the track symbol in situations where a track has multiple levels of detail.

A track using a white box as a selection symbol

This would be configured as follows:

std::unique_ptr< TSLTrackSelectionSymbol, TSLReleasePointer> selectionSymbol(TSLTrackSelectionSymbol::create());
selectionSymbol->symbolID(3);
selectionSymbol->size(80);
selectionSymbol->sizeUnits(TSLDimensionUnitsPixels);
selectionSymbol->colour(0x000000ff);
trackSymbol->selectionSymbol(selectionSymbol, TSLTrackSymbol::SelectionBehaviourAdditional);
@ SelectionBehaviourAdditional
Definition tsltracksymbol.h:66

The second argument to TSLTrackSymbol.selectionSymbol() specifies whether the selection symbol should replace or display in addition to the default symbol.

History Symbols

History symbols are used to show the path a track has taken over time. In order for them to be drawn they must be enabled on the TrackDisplayManager containing the track using the TrackDisplayManager::historyPointsVisible() and TrackDisplayManager::historyPointDistance() methods. The number of history points to remember for each track and the visualisation type must also be set using the TrackDisplayManager::numHistoryPoints() and TrackDisplayManager::historyPointType() methods.

There are two types of history symbols, defined by the TrackDisplayManager::HistoryPointType enumeration. Square history points are extremely efficient to draw but only allow control over the colour of the point, set on the Track.historyPointColour() . Symbol history points are defined by a single identifier from the symbol configuration file in the same way as selection symbols and point symbols, allowing more control over their appearance at the cost of drawing performance.

Square history points showing a track's path over time

This would be configured as follows:

// Keep 20 seconds of history
manager->historicDataExpiry(20);
manager->historyPointDistance(50000);
manager->numHistoryPoints(4);
std::unique_ptr<TSLTrackHistorySymbol, TSLReleasePointer> historySymbol(TSLTrackHistorySymbol::create());
historySymbol->colour(0xff00ffff);
historySymbol->size(35);
historySymbol->sizeUnits(TSLDimensionUnitsPixels);
historySymbol->symbolID(1);
manager->historyPointSymbol(historySymbol);
track->historyPointsVisible(TrackTests::surfaceID, true);
@ HistoryPointTypeSquare
History points will be displayed as a 3x3 pixel square.
Definition tsltrackdisplaymanager.h:68
static TSLTrackHistorySymbol * create()
Create a TSLTrackHistorySymbol.

Heading Indicators

Tracks may optionally be shown with a heading indicator. For point symbols this is a simple line that shows the heading of the track as set through the Track.heading() method. The visibility, colour and length of the heading indicators can be set on a per-track basis.

This would be configured as follows:

track1->headingIndicatorVisible();
track1->headingIndicatorLength(100, TSLDimensionUnitsPixels);
track1->heading(50);
track2->headingIndicatorVisible(false);

Adding Tracks to a TrackDisplayManager

Once a track has been created it must be added to a TrackDisplayManager through the TrackDisplayManager::addTrack() method in order for the track to be displayed. A unique identifier for the track must be provided which is used to identify the track to other methods on the TrackDisplayManager . This identifier also controls the order that tracks in the manager will be drawn in. Tracks with a lower identifier will be drawn after those with a higher identifier.

The same track should not be added to more than one TrackDisplayManager This would be configured as follows:

manager->addTrack(trackNumber, track);

Setting Track Positions

As Tracks usually represent dynamic objects, it is usually necessary to frequently update their positions. As a minimum, for a track to appear in the correct position, it must have its position set using one of the following methods:

Example for TrackDisplayManager::moveTracks()

TSLTrack::TrackID trackNumbers[] = new TSLTrack::TrackID[updatedTracksInformation.Count];
double latitudes[] = new double[updatedTracksInformation.Count];
double longitudes[] = new double[updatedTracksInformation.Count];
int index = 0;
for (auto it: updatedTracksInformation)
{
trackNumbers[index] = it->id;
latitudes[index] = it->lat;
longitudes[index] = it->lon;
++index;
}
trackManager.moveTracks(updatedTracksInformation.Count, trackNumbers, latitudes, longitudes);
uint32_t TrackID
Definition tsltrackbase.h:37

Example for TrackDisplayManager::moveTrack()

trackManager->moveTracks(trackNumber, latitude, longitude);

Example for TrackDisplayManager::move()

track->move(latitude, longitude);

Decluttering Tracks

Tracks can be decluttered using the standard decluttering mechanism from the drawing surface using the setDeclutterStatus() method. Unlike other types of layers, it is up to the application to define the types of features that exist for the track's data layer using the addFeatureRendering() method. Tracks can then be assigned one of the created feature types using either the Track.featureName() or Track.featureID() methods. Note that in order to set a track's feature type by name the track must first have been added to the TrackDisplayManager which has that feature defined in its associated data layer.

Once tracks have been assigned a feature type, decluttering that feature will inhibit the display any tracks of that feature type. Alternatively tracks can be hidden on an individual basis through the Track.visible() method. The track layer can be turned on and off entirely via the DataLayerProperties object through the layer properties.

Picking Tracks

Identifying tracks at a specific screen location is performed using the drawing surface 's standard picking mechanism. Picking on the data layer associated with a TrackDisplayManager will return the Tracks at the requested position. These can then be used in subsequent operations, such as marking the tracks as selected.

Storing and Viewing Track History

The TrackDisplayManager can be asked to record changes to the state of its tracks (such as position and appearance) over time, and roll back the display of tracks to a previous point in time. To allow for this, the TrackDisplayManager has two distinct concepts of time:

  • Current time, which represents the most up to date information about the tracks. Modifications to tracks such as changing their position or heading, always change the track state at the current time and not at the time currently being displayed by the manager.
  • Display time, which represents the point in time currently being displayed by the TrackDisplayManager . This may either be the same as the current time, or some time in the past.

By default the TrackDisplayManager does not record the history of tracks. To enable history recording the manager must first be told how long history data should be kept for using the TrackDisplayManager::historicDataExpiry() method. Then, each time tracks are updated the manager should be informed of the time each track update should be stored for using the TrackDisplayManager::currentTime() method. Updating a track without also changing the current time in the TrackDisplayManager will overwrite the current value of the updated field(s), therefore a typical application's track update method should work as follows:

void TrackUpdater::updateTracks( TSLTrackDisplayManager *manager )
{
manager->currentTime( getUpdateTime() ); // getUpdateTime() is an application function that returns the time the track positions apply to
// All updates are recorded against the current time set on the manager
manager->moveTracks( numTracks, trackIDs, latitudes, longitudes );
manager->updateTrackLabels( numTracks, trackIDs, velocities, headings, altitudes );
}
Definition tsltrackdisplaymanager.h:59
void currentTime(uint64_t time)
bool updateTrackLabels(TSLTrack::TrackID trackNumber, double velocity, double heading, double altitude)
bool moveTracks(uint32_t numberOfTracks, const TSLTrack::TrackID *trackNumbers, const double *latitudes, const double *longitudes)

In order to make the TrackDisplayManager display the state of tracks in the past the TrackDisplayManager::displayTime() method should be used. This will cause the tracks within the manager to revert to the position and appearance that they had at that time. When viewing historical track information many query functions such as latitude, longitude, heading and velocity on the Track class will return the values for the track at the active display time rather than the current time.

The Track also provides methods to access information about the track at the current time regardless of the active display time. These methods are prefixed with 'current'. Therefore it is not necessary to reset the display time in the TrackDisplayManager in order to access information about tracks at the current time.

The visualisation settings of a track are not tracked across time, thus the values set on a track will apply regardless of the active display time. This includes visibility, selection status, heading indicator, history point, and the track symbol itself. Only the track's attribute such as position, altitude, and speed are tracked as part of the history data.

The memory usage when recording track history is minimised, by only storing the individual position/appearance values which have changed. However if data is stored for a long time, and very frequent updates are made to a lot of objects, the application may use a significant amount of memory.

Creating Custom Symbols

If the set of symbols provided with the drawing surface are not sufficient, new symbols can be created and used as point or history symbols. New symbols can either be a raster (such as a PNG) or a vector symbol created in Symbol Studio (a Windows application that is installed with MapLink Studio). New symbols need to be added to the symbol resource file, at which point they can be referenced by their identifier in the same way as the provided symbols.

The colour specified on the point symbol, selection symbol and history symbols will replace the overrideable colour defined in Symbol Studio.

Special Text Fields in Custom Symbols

When creating custom symbols, there are a number of special text strings that can be used which will automatically be replaced at runtime by the value of a property from the track(s) using the symbol. This is referred to as text replacement or text substitution in the Symbol Studio documentation.

The following special text strings are defined for custom symbols when used as a point symbol.

Text String Corresponding Track Property
__TN Name
__TH Heading
__TA Altitude
__TV Velocity

This text replacement functionality is also available for any text entity contained within a point symbol. The application may add any required attributes through the track class, which can then be displayed as part of the track's visualisation.