Introduction
The package com.luciad.format.asdi
provides the ability to decode and display ASDI data.
It enables to decode ASDI data from a file or from a live stream.
It enables to replay ASDI data from a file as if it came from a live stream.
Finally it offers access to the parsed messages directly, offering fine-grained control.
The FAA provides airlines and other aviation-related organizations with access to near real-time air traffic data from the National Airspace System (NAS) through the ASDI feed of the Enhanced Traffic Management System (ETMS). More information on ASDI can be obtained from http://www.fly.faa.gov/ASDI/asdi.html.
About this guide
This book is a guide for developers who want to use ASDI data in a LuciadLightspeed application. It explains how data can be loaded and accessed.
The LuciadLightspeed ASDI functionality depends on the LuciadLightspeed Real-time Engine component. The documentation of the Real-time Engine component is considered prerequisite to reading this manual. Knowledge about air-traffic control is not required, but can be helpful.
Content overview
-
ASDI data modeling describes how ASDI data is modeled.
-
ASDI data decoding explains the different ways to decode ASDI data.
ASDI data modeling
Structure of ASDI data
The FAA provides members of the aviation industry with access to near real-time air traffic data from the National Airspace System (NAS) through the ASDI feed generated by the Enhanced Traffic Management System (ETMS).
An ASDI feed may contain two types of messages :
-
NAS messages : messages generated by the NAS and passed by the ETMS.
-
ETMS messages : messages generated by the ETMS.
Following NAS messages can occur in an ASDI feed :
-
TZ : Flow Control Track/Flight Data Block Information messages are used to provide a position update along with other information.
-
FZ : Flight Plan Information Messages contain flight plan data.
-
AF : Flow Control Amendment Information messages provide revised flight plan data whenever a flight plan is amended.
-
DZ : Departure messages are transmitted for all initially activated flight plans.
-
UZ : Flow Control Update Information messages are used to provide current flight plan information on active flights that enter an ARTCC.
-
AZ : Flow Control Arrival Information messages contain arrival data for all arriving flights.
-
RZ : Flow Control Cancellation messages are used to provide cancellation data for all flight plans.
Following ETMS messages can occur in an ASDI feed :
-
TO : TO messages are generated by the ETMS when Oceanic position reports are received via the ARINC network.
-
RT : The purpose of RT messages is to provide data from ETMS that is not otherwise available, for instance they contain predictions of the wheels-up and wheels-down times for a flight.
Each message is divided into fields. Fields can contain a simple value or can contain more complex data.
All messages in the ASDI feed are framed with a header containing some extra fields :
-
a sequence number : a number indicating the order in which messages were sent.
-
a time : the timestamp assigned to the message when it was received or generated by the ETMS.
-
a facility identifier : the facility that generated the message.
Not supported :
-
BZ : NAS Flow Control Beacon Code Information messages contain beacon code data for flight plans. They are however not included in the ASDI feed that goes to private industry and are therefore not supported in the
com.luciad.format.asdi
package. -
HB : The ASDI server at the ETMS generates heartbeat messages at regular times. These are ignored in the
com.luciad.format.asdi
package.
Concepts modeled by ASDI data
An ASDI feed contains air traffic data. The most important concepts modeled by the ASDI data are discussed in this section. They correspond to the types of data that are decoded by the LuciadLightspeed ASDI decoders.
Track
Conceptually a track is a point (i.e., a location) together with a timestamp. A track is, e.g., used to represent the position of an aircraft at a certain point in time. On a map, a track is typically represented as an icon with a label containing identification (e.g., flight id), and possibly other indications (e.g., history, speed).
Figure 1, “Map showing a track layer” shows a map with several tracks at a certain point in time. On the map tracks are represented by blue squares. The directions of the tracks are indicated by the yellow lines. The map shows the situation in the air at a particular point in time.
Trajectory
Conceptually a trajectory is a sequence of tracks of the same flight. It is ordered in ascending order of the tracks' timestamps. A trajectory is for instance used to represent an aircraft’s path to fly from point A to point B.
A non-empty trajectory has a begin time and an end time. The begin time is the timestamp of its first track; the end time is the timestamp of its last track.
On a map, a trajectory is typically represented as a polyline connecting the tracks.
Figure 2, “Map showing a trajectory (grey line) and track layer” shows a map with tracks and a trajectory layer showing in grey the trajectory of the selected track.
Flight plan
Conceptually a flight plan is the intended path of an aircraft, together with additional data as (estimated) departure time, (estimated) arrival time, status,…​ at a certain timestamp. On a map, a flight plan is typically represented as a polyline.
Figure 3, “Map showing a track, trajectory (grey line) and flight plan (black dashed line) layer” shows a map with a track and a flight plan layer showing the intended route of the selected track as a black dashed line, the trajectory layer shows in grey the trajectory of the selected track.
Flight plan history
As flight plans can change over time, the concept of a flight plan history was introduced. Conceptually a flight plan history is a sequence of flight plans, representing the flight plan of the same aircraft at different timestamps. The sequence of flight plans is ordered on ascending timestamps.
On a map, a flight plan history can for instance be represented by its last flight plan, so as a polyline.
LuciadLightspeed classes
This section describes the LuciadLightspeed classes used to model ASDI data, and their relationship with standard LuciadLightspeed
classes and interfaces.
Two types of classes can be distinguished. The classes TLcdASDITrajectory
and TLcdASDIFlightPlanHistory
are the main classes used to model ASDI data. The classes TLcdASDITrack
and TLcdASDIFlightPlan
are convenience classes derived from the main classes. This is explained below.
All ASDI classes are part of the package com.luciad.format.asdi
.
The samples samples.decoder.asdi.file.MainPanel
and samples.decoder.asdi.live.MainPanel
show examples of how to use the classes and their various methods.
Main classes
TLcdASDITrajectory
The class TLcdASDITrajectory
models a trajectory, i.e., it models a sequence of tracks, in ascending order of time.
For memory efficiency reasons the class TLcdASDITrajectory
has no methods to construct or retrieve individual track objects. All trajectory and individual track information can be
retrieved through the following interfaces and methods implemented by the class TLcdASDITrajectory
:
-
The class
TLcdASDITrajectory
implementscom.luciad.shape.ILcdPointList
, where the individual points are defined by the positions of the tracks. Points and corresponding tracks are ordered in ascending order of time. -
The class
TLcdASDITrajectory
implementscom.luciad.datamodel.ILcdDataObject
. The properties of trajectories are available through this interface. A trajectory has one property: its id. The value of this id links all the tracks of the trajectory. It corresponds with the aircraft id available in all ASDI messages. The ASDI format does not provide unique aircraft ids however : different trajectories can have the same id at the same time. -
The methods
getBeginTime
andgetEndTime
can be used to retrieve the valid time interval of the trajectory. -
The time associated with a particular track can be retrieved by using the
getTime( int aTrackIndex )
method. The argumentaTrackIndex
is the index of the track in the trajectory seen as an ILcdPointList. -
All ASDI data related to the trajectory is available through the properties of the tracks. They can be retrieved using the
getTrackValue(int aTrackIndex, TLcdDataProperty aProperty)
. The argumentaProperty
is property of which the value needs to be retrieved. These properties can be found in theTLcdDataType
instances of theTLcdASDITrackTODataTypes
andTLcdASDITrackTZDataTypes
classes, depending on the type of tracks represented by the trajectory. The data type of the tracks matching a trajectory can be found in the model descriptor of the trajectory, using theTLcdASDITrajectoryModelDescriptor.getTrackDataType()
method. The mapping of ASDI data to properties is explained in Message properties, track properties are discussed in more detail in ASDI Trajectory Messages. -
The method
getIndexForTimeStamp( long aTimeStamp )
can be used to get the index of the track in the trajectory that corresponds to the given timestamp : it returns the index of the track with the largest timestamp that is smaller than (or equal to)aTimeStamp
, provided thataTimeStamp
lies within thegetBeginTime()
andgetEndTime()
interval. When the timestamp could not be located -1 is returned. -
The method
getFlightPlanHistory
can be used to get the flight plan history that corresponds with the trajectory.
TLcdASDIFlightPlanHistory
The class TLcdASDIFlightPlanHistory
models a flight plan history, i.e., a flight plan that changes over time.
It is implemented as a sequence of flight plans, in ascending order of time. The flight plan at each timestamp
is represented by the points of its intended path and the additional information at that time stamp. For memory efficiency
reasons the class TLcdASDIFlightPlanHistory
has no methods to construct or retrieve individual flight plan objects. All history and individual flight plan information
can be retrieved through the following interfaces and methods implemented by the class TLcdASDIFlightPlanHistory
:
-
The class
TLcdASDIFlightPlanHistory
implementsILcdPointList
, where the points are defined by the intended path of the flight plan with the most recent timestamp. -
The class
TLcdASDIFlightPlanHistory
implementsILcdDataObject
. The proprerties of a flight plan history are available through this interface. A flight plan history one property: its id. This id links all the data in aTLcdASDIFlightPlanHistory
. It corresponds with the aircraft id available in all ASDI messages. The ASDI format does not provide unique aircraft ids however : different flight plan history objects can have the same id at the same time. -
The methods
getBeginTime
andgetEndTime
can be used to retrieve the time interval for which the flight plan history contains flight plan information. ThegetBeginTime
corresponds with the timestamp of the first flight plan in the history, thegetEndTime
with the last time the flight plans in the history are known to be active, which is at least the timestamp of the last flight plan in the history. -
The method
getFlightPlanCount
can be used to retrieve the number of flight plans in aTLcdASDIFlightPlanHistory
. It corresponds to the number of times the flight plan has changed + 1. -
The time associated with a particular flight plan can be retrieved by using the
getTime( int aFlightPlanIndex )
method. The argumentaFlightPlanIndex
is the index of the flight plan in the history. If the time for a particular flight plan is not known -1 is returned. -
The points of the intended path of a particular flight plan can be retrieved using the methods
getPointCount( int aFlightPlanIndex )
andgetPoint( int aFlightPlanIndex, int aPointIndex )
. -
The additional ASDI data related to flight plans is available through the properties of the flight plans. They can be retrieved using the
getFlightPlanValue(int aFlightPlanIndex, TLcdDataProperty aProperty)
method. TheaProperty
parameter must be a property declared by theTLcdDataType
found in theTLcdASDIFlightPlanDataTypes
class. The mapping of ASDI data to properties is explained in Message properties, flight plan properties are discussed in more detail in ASDI Flight Plan History Messages. -
The method
getIndexForTimeStamp( long aTimeStamp )
can be used to get the index of the flight plan in the history that corresponds to the given timestamp : it returns the index of the flight plan with the largest timestamp that is smaller than (or equal to)aTimeStamp
, provided thataTimeStamp
lies within thegetBeginTime()
andgetEndTime()
interval. When the timestamp could not be located -1 is returned. -
It is also possible to retrieve the messages on which a
TLcdASDIFlightPlanHistory
is based through the methodsgetMessageCount()
,getMessageDataType(int aMessageIndex)
andgetMessageValue( int aMessageIndex, TLcdDataProperty aProperty )
. The different data types for ASDI messages can be found in theTLcdASDIMessageDataTypes
class. These methods offer an alternative way to get the additional flight plan related ASDI data that would normally not be needed. The mapping of ASDI data to properties is explained in Message properties, flight plan message properties are discussed in more detail in ASDI Flight Plan History Messages.
Convenience classes
TLcdASDITrack
The class TLcdASDITrack
models a track by representing a TLcdASDITrajectory
at a specific point index.
A TLcdASDITrajectory
contains data for all its tracks. A TLcdASDITrack
is just a window on a TLcdASDITrajectory
, showing only the data of one track of the TLcdASDITrajectory
. A TLcdASDITrack
extracts its data from the TLcdASDITrajectory
on which it is a window.
All track and associated trajectory information can be retrieved through the following interfaces and methods implemented
by the class TLcdASDITrack
:
-
The class
TLcdASDITrack
has a constructor that needs theTLcdASDITrajectory
for which it represents a window as input parameter. The specifiedTLcdASDITrajectory
may not be null. The point index for which theTLcdASDITrack
represents theTLcdASDITrajectory
is -1 by default and must be set explicitly withupdateForIndex
orsetTrajectoryPointIndex
. -
The trajectory associated with the
TLcdASDITrack
can be retrieved by calling thegetTrajectory
method on theTLcdASDITrack
. -
The point index for which the
TLcdASDITrack
represents theTLcdASDITrajectory
can be retrieved using the methodgetTrajectoryPointIndex
. -
The class
TLcdASDITrack
extends the classcom.luciad.shape.shape3D.TLcdLonLatHeightPoint
. The point defines the position of the track. -
The class
TLcdASDITrack
implementsILcdDataObject
. All ASDI information associated with the track is available through the properties of theTLcdASDITrack
. The properties The mapping of ASDI data to properties is explained in Message properties, track properties are discussed in more detail in ASDI Track Messages. -
The method
isActive
allows to check if aTLcdASDITrack
is active. ATLcdASDITrack
is active if its timestamp lies within thegetTrajectory().getBeginTime
andgetTrajectory().getEndTime
, this is, if it represents the trajectory at a certain valid index. The data of an inactive track should not be used or interpreted in any way. -
Use the
updateForIndex( int aTrajectoryPointIndex )
method to update the state of the track so that it reflects the state of the trajectory at the given index, this is, the properties and the location of the track correspond to the given index. Specify an index -1 to mark a track as inactive. Note that the methodgetTrajectory().getIndexForTimeStamp(long aTimeStamp)
can be used to retrieve the index for a given time value. -
The
setTrajectoryPointIndex( int aTrajectoryPointIndex )
sets the index for which this track represents the trajectory. It is similar to theupdateForIndex
method except that it does not change the location of the track. This must be done separately when using this method. -
The
setTrajectoryPointIndex
andupdateForIndex
methods are typically used in the implementation of acom.luciad.realtime.ALcdTimeIndexedSimulatorModel
class forTLcdASDITrack
objects to update the state of theTLcdASDITrack
objects to a specific timestamp (see the methodALcdTimeIndexedSimulatorModel.updateTrackForDateSFCT
). The existence of the two methods enables to choose whether the location of the track should be updated automatically or not. In case interpolation should be done for instance one could use thesetTrajectoryPointIndex
method and move the tracks to the calculated interpolated positions afterward. This is demonstrated in thesamples.decoder.asdi.TrackSimulatorModel
class of the sample code.
TLcdASDIFlightPlan
The class TLcdASDIFlightPlan
models a flight plan by representing a TLcdASDIFlightPlanHistory
at a specific index. A TLcdASDIFlightPlanHistory
contains data for all its flight plans. A TLcdASDIFlightPlan
is just a window on a TLcdASDIFlightPlanHistory
, showing only the data of one flight plan. A TLcdASDIFlightPlan
extracts its data from the TLcdASDIFlightPlanHistory
on which it is a window.
All flight plan and associated history information can be retrieved through the following interfaces and methods implemented
by the class TLcdASDIFlightPlan
:
-
The class
TLcdASDIFlightPlan
has a constructor that needs theTLcdASDIFlightPlanHistory
for which it represents a window as input parameter. The specifiedTLcdASDIFlightPlanHistory
may not be null. The index for which theTLcdASDIFlightPlan
represents theTLcdASDIFlightPlanHistory
is -1 by default and must be set explicitly withsetFlightPlanHistoryIndex
. -
The flight plan history associated with the
TLcdASDIFlightPlan
can be retrieved by calling the methodgetFlightPlanHistory
on theTLcdASDIFlightPlan
. -
The index for which the
TLcdASDIFlightPlan
represents theTLcdASDIFlightPlanHistory
can be retrieved using the methodgetFlightPlanHistoryIndex
. -
The class
TLcdASDIFlightPlan
implementsILcdPointList
. The points define the intended path of the flight plan. These are the same points as returned fromgetFlightPlanHistory().getPoint(getFlightPlanHistoryIndex(), int aPointIndex)
. -
The class
TLcdASDIFlightPlan
implementsILcdDataObject
. All ASDI information associated with the flight plan is available through the properties of theTLcdASDIFlightPlan
. These are the same properties as returned fromgetFlightPlanHistory().getFlightPlanValue(getFlightPlanHistoryIndex(), TLcdDataProperty aProperty)
. The mapping of ASDI data to properties is explained in Message properties, flight plan properties are discussed in more detail in ASDI Flight Plan Messages. -
The method
isActive
allows to check if aTLcdASDIFlightPlan
is active. ATLcdASDIFlightPlan
is considered active if its timestamp lies within thegetFlightPlanHistory().getBeginTime
andgetFlightPlanHistory().getEndTime
, this is, it represents the flight plan history at a certain valid index. The data of an inactive flight plan should not be used or interpreted in any way. -
The
setFlightPlanHistoryIndex( int aFlightPlanHistoryIndex )
updates the state of the flight plan so that it reflects the state of the flight plan at the given index in the history. The properties and intended paths of the flight plans always correspond to this index. Specify an index -1 to mark a flight plan as inactive. This method is typically used in the implementation of acom.luciad.realtime.ALcdTimeIndexedSimulatorModel
class forTLcdASDIFlightPlan
objects to update the state of theTLcdASDIFlightPlan
objects to a specific timestamp (see the methodALcdTimeIndexedSimulatorModel.updateTrackForDateSFCT
). This is demonstrated in thesamples.decoder.asdi.FlightPlanSimulatorModel
class of the sample code. Note that the methodgetFlightPlanHistory().getIndexForTimeStamp(long aTimeStamp)
can be used to retrieve the index for a given time value. -
It is also possible to retrieve the properties corresponding with the messages on which a particular
TLcdASDIFlightPlan
is based through the methodsgetMessageCount()
,getMessageDataType(int aMessageIndex)
andgetMessageValue( int aMessageIndex, TLcdDataProperty aProperty )
. These are the same properties as returned fromgetFlightPlanHistory().getMessageValue(getFlightPlanHistoryIndex(), TLcdDataProperty aProperty)
. These methods offer an alternative way to get the additional flight plan related ASDI data that would normally not be needed. The mapping of ASDI data to properties is explained in Message properties, flight plan message properties are discussed in more detail in ASDI Flight Plan Messages.
ASDI data decoding
ASDI format
ASDI data can be decoded from file or from a live stream of data.
Data consists of a sequence of ASDI messages.
The file extension is assumed to be .asdi
.
A file can contain a first line specifying the start time of the ASDI message feed.
The format of this line must be '<set time> MM/dd/yyyy HH:mm:ss'
.
How to decode ASDI data
Decoders
In the com.luciad.format.asdi
package two decoders are available. Use a TLcdASDIModelDecoder
to decode ASDI data from a file and a TLcdASDILiveDecoder
to decode ASDI data from a live stream of data.
The class TLcdASDIModelDecoder
implements com.luciad.model.ILcdModelDecoder
. The decode
method produces a com.luciad.model.ILcdModel
which is in fact a com.luciad.model.TLcdModelList
containing ILcdModel
objects depending on the type of messages in the ASDI feed. The ILcdModel
objects contain either trajectories or flight plan history objects. All info of the file is available through the objects
of the different ILcdModel
objects in the TLcdModelList
.
The class TLcdASDILiveDecoder
does not implement ILcdModelDecoder
. Call the method decodeSFCT( InputStream aInputStream, int aFireEventMode, TLcdModelList aModelListSFCT )
to start reading data from a live stream. The decodeSFCT
method does not return a TLcdModelList
but in stead requires a TLcdModelList
argument. During the decode ILcdModel
objects are added to the TLcdModelList
depending on the type of messages in the ASDI feed. The decodeSFCT
creates ILcdModel
objects containing either tracks or flight plans and updates them with the latest info in the ASDI feed. History is available
through the tracks' trajectories and the flight plan’s history.
The input stream from which the data is to be read can be specified through the argument aInputStream
of the decodeSFCT
method. The argument aFireEventMode
of the decodeSFCT
allows to specify when and if any model events need to be fired when the ILcdModel
objects in the TLcdModelList
are changed by the decoder. The aFireEventMode
must be one of the values defined in com.luciad.util.ILcdFireEventMode
.
As a TLcdASDIModelDecoder
incorporates all info of a file in a TLcdModelList
it creates trajectories and flight plan history objects, the TLcdASDILiveDecoder
creates and updates tracks and flight plans. Following table gives an overview of the exact models and domain objects that
are created :
ASDI messages | Model | Domain Objects created by TLcdASDIModelDecoder | Domain Objects created by TLcdASDILiveDecoder |
---|---|---|---|
TZ |
TZ tracks |
TLcdASDITrajectory |
TLcdASDITrack |
TO |
TO tracks |
TLcdASDITrajectory |
TLcdASDITrack |
FZ, AF, DZ, UZ, AZ, RZ and RT |
Flight plan data |
TLcdASDIFlightPlanHistory |
TLcdASDIFlightPlan |
The model descriptors of the individual models depend on the type of domain object in the model. They can be used to check the type of domain object. They can also be used to check the type of model. Refer to Retrieving meta-data for more information on model descriptors.
The decoders can be configured in several ways:
-
The
TLcdASDIModelDecoder
class has a methodsetInputStreamFactory
to specify the input stream factory for creating input streams from source file names. By default thecom.luciad.io.TLcdInputStreamFactory
is used. -
ASDI messages contain time information that is not absolute. By default the decoders create absolute times from these relative times by assuming that the current time is the start time of the message feed. This behaviour can be overwritten. The method
setStartTime
allows to specify the start time of the message feed manually. If a file contains a<set time>
command at the first line theTLcdASDIModelDecoder
class uses the specified time as start time, ignoring the start time set withsetStartTime
. -
By default the decoders add all supported ASDI messages to the corresponding
ILcdModel
of theTLcdModelList
. ThesetMessageFilter
method can be used to filter out messages, so that they are not added to theILcdModel
. Refer to Filtering ASDI messages for more information on message filters. -
The
TLcdModelList
filled by theTLcdASDILiveDecoder
always represents the most recent situation. You can use thesetHistoryLength
method to specify the maximum history to keep in memory for the trajectories associated with theTLcdASDITrack
domain objects (obtained byTLcdASDITrack.getTrajectory
). Note that if more history is available than the specified maximum, the oldest information is purged. ForTLcdASDIFlightPlan
objects theTLcdASDILiveDecoder
always keeps all history.
Decoder samples
Decoding from file
The sample class samples.decoder.asdi.file.MainPanel
is a sample that allows to decode ASDI data from a file and to display that data on a map. It starts with creating a TLcdASDIModelDecoder
and registering it as one of the ILcdModelDecoder
objects that must be checked when a file is opened.
samples/decoder/asdi/file/MainPanel
)
private ILcdModelDecoder createASDIModelDecoder(
ILcdInputStreamFactory aInputStreamFactory
) {
TLcdASDIModelDecoder decoder = new TLcdASDIModelDecoder();
decoder.setMessageFilter(new FinalMessageFilter());
decoder.setInputStreamFactory(aInputStreamFactory);
return decoder;
}
private static class FinalMessageFilter implements ILcdASDIMessageFilter {
@Override
public boolean accept(
ILcdDataObject aMessageDataObject
) {
TLcdASDIFacility facility = (TLcdASDIFacility) aMessageDataObject.getValue("Facility");
return (!(facility != null && facility.getCode().equals("KGT*")));
}
}
Program: Creating an ASDI model decoder shows the implementation of the method createASDIModelDecoder
which is used to create the TLcdASDIModelDecoder
. The argument aInputStreamFactory
represents the com.luciad.io.ILcdInputStreamFactory
that the decoder must use for creating input streams from source file names. The method first creates a TLcdASDIModelDecoder
. Then it adds a message filter that filters out messages coming from certain facilities. Finally it attaches aInputStreamFactory
to it. Note that no start time is set : it is
assumed that the files loaded in the sample contain a <set time>
command at the first line or that the current time may be used.
samples/decoder/asdi/file/MainPanel
)
//create and initialize the ASDI model decoder.
fModelDecoder = createASDIModelDecoder(new TLcdInputStreamFactory());
//create an action to open an ASDI file.
OpenSupport openSupport = new OpenSupport(this, Collections.singletonList(fModelDecoder));
getView().setTransferHandler(openSupport.createDragAndDropTransferHandler());
openSupport.addStatusListener(getStatusBar());
openSupport.addModelProducerListener(new ASDIModelProducerListener());
OpenAction standaloneOpenAction = new OpenAction(openSupport);
Program: Using an open action to load ASDI files uses the method createASDIModelDecoder
to create fModelDecoder
. Since the created TLcdASDIModelDecoder
is an ILcdModelDecoder
it can be assigned to a samples.common.formatsupport.OpenAction
. An OpenAction
is a java.awt.event.ActionListener
that can be attached to a menu item for loading a file. To load a file the OpenAction
tries to find the correct ILcdModelDecoder
for the file by calling the canDecode
method on all registered ILcdModelDecoder
. If an ILcdModelDecoder
is found, its decode
method is called to load the file. Program: Using an open action to load ASDI files shows how an OpenAction
can be configured to load ASDI files. In the example only a TLcdASDIModelDecoder
is registered for the OpenAction
.
The complete sample code can be found in the packages samples.decoder.asdi.file
and samples.decoder.asdi
.
Decoding from a live stream
The sample class samples.decoder.asdi.live.MainPanel
is a sample that loads live ASDI data and displays it continuously on a map. The code for creating the TLcdASDILiveDecoder
and to start reading data from the live stream is explained below.
samples/decoder/asdi/live/MainPanel
)
private void startLiveDecoder(
long aStartTime,
int aHistoryLength,
final InputStream aInputStream,
final TLcdModelList aModelList,
final String aSuccessMessage,
final String aErrorMessage
) {
final TLcdASDILiveDecoder live_decoder = new TLcdASDILiveDecoder();
live_decoder.setStartTime(aStartTime);
live_decoder.setHistoryLength(aHistoryLength);
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
live_decoder.decodeSFCT(aInputStream, ILcdFireEventMode.FIRE_LATER, aModelList);
aInputStream.close();
showMessage(aSuccessMessage, JOptionPane.PLAIN_MESSAGE);
} catch (IOException e) {
sLogger.error("decodeSFCT:" + aErrorMessage, e);
showMessage(aErrorMessage, JOptionPane.ERROR_MESSAGE);
}
}
};
fUpdateThread = new Thread(runnable, "ASDI Update Thread");
fUpdateThread.setPriority(Thread.MIN_PRIORITY);
fUpdateThread.start();
}
Program: Starting an ASDI live decoder shows the implementation of the method startLiveDecoder
that is used to create and start a TLcdASDILiveDecoder
. The argument aInputStream
represents the input stream with live data. The argument aModelList
is the TLcdModelList
that must be filled by this live decoder. The method first creates a TLcdASDILiveDecoder
. Then it passes the aStartTime
and aHistoryLength
arguments to it. The decoder is now configured and can be started. The TLcdASDILiveDecoder
is not an ILcdModelDecoder
, hence there is no decode
method. Since the TLcdASDILiveDecoder
reads data continuously and the sample does not want to be blocked by that the TLcdASDILiveDecoder
is started from another thread. First a java.lang.Runnable
is created which calls the method decodeSFCT
with the specified input stream and model list in its run
method. Note that the decodeSFCT
method also has an argument ILcdFireEventMode.FIRE_LATER
: the reason for this is explained in the next paragraph. Next a java.lang.Thread
is created for the Runnable
. In the last line the thread is started. This starts the decoding from the live stream.
samples/decoder/asdi/live/MainPanel
)
fTimer = new Timer(DELAY, new TimerActionListener(model_list));
fTimer.setInitialDelay(INITIAL_DELAY);
fTimer.setRepeats(true);
fTimer.setDelay(DELAY);
fTimer.start();
private class TimerActionListener implements ActionListener {
private final TLcdModelList fModelList;
public TimerActionListener(TLcdModelList aModelList) {
fModelList = aModelList;
}
@Override
public void actionPerformed(ActionEvent e) {
fModelList.fireCollectedModelChanges();
// Firing the collected model changes automatically refreshes the map,
// but the label decluttering algorithm (TLcdContinuousDeclutteringLabelPainter,
// see SimulatorGXYLayerFactory) needs a refresh from time to time,
// to make the labels move away gently if overlap is about to occur.
getView().getLayers().stream()
.filter(layer -> fSimulatorLayerFactory.accept(layer.getModel()))
.filter(ILcdGXYLayer::isLabeled)
.forEach(layer -> getView().invalidateGXYLayer(layer, true, this, "Invalidating labels of track layers"));
}
}
In our sample we do not want the decoder to fire model changed events constantly, otherwise the map would be updating constantly.
That is why we pass a ILcdFireEventMode.FIRE_LATER
argument to the decodeSFCT
method: it indicates that the events related to changes in the TLcdModelList
during the decode must be collected but may not be fired immediately. We add a javax.swing.Timer
to effectively fire the model changed events (see Program: Using a timer to fire model changes). The Timer
regularly calls the fireCollectedModelChanges
method on the TLcdModelList
which results in an update of the map. The timer is also used to make the labels move fluently (e.g. if the user dragged
a label away, it gently moves back). To that end, the track and flight plan layers (layers accepted by the fSimulatorLayerFactory.accept
method) are refreshed, if they are labeled, using the method invalidateGXYLayer
.
The complete sample code can be found in the packages samples.decoder.asdi.live
and samples.decoder.asdi
.
Reading messages
Sometimes the standard decoders do not offer the exact functionality that is required and they need to be customized or a
custom decoder needs to be written. In these cases the class TLcdASDIMessageInputStream
of the com.luciad.format.asdi
package can come to help. A TLcdASDIMessageInputStream
is a java.io.FilterInputStream
dedicated to read ASDI messages from an underlying java.io.InputStream
.
It has a method readMessage
that reads an ASDI message and returns an ILcdDataObject
containing the properties of the message read. The data types for these messages can be found in the TLcdASDIMessageDataTypes
class. It throws a TLcdASDIParseException
if a supported message could not be parsed for any reason. Refer to Message properties for more information on message properties. Note that the TLcdASDIModelDecoder
and TLcdASDILiveDecoder
also use a TLcdASDIMessageInputStream
to read the ASDI messages.
A TLcdASDIMessageInputStream
can be configured in several ways:
-
ASDI messages contain time information that is not absolute. By default a
TLcdASDIMessageInputStream
creates absolute times from these relative times by assuming the current time is the start time of the message feed. This behaviour can be changed using the methodsetStartTime
which allows to specify the start time of the message feed manually. -
The
setMessageFilter
method can be used to skip messages. Refer to Filtering ASDI messages for more information on message filters.
Message properties
The information in the ASDI messages is exposed through data objects (represented by ILcdDataObject
) in LuciadLightspeed.
ASDI messages contain a number of fields grouping information that belongs together. Each message field is mapped to a property
of a message TLcdDataType
in LuciadLightspeed. The standard decoders TLcdASDIModelDecoder
and TLcdASDILiveDecoder
create domain objects offering the data objects and properties of the messages they are based on, the TLcdASDIMessageInputStream.readMessage
method returns the data objects of the message read. Classes exist that contain the various data types and data properties
used in ASDI. This is explained in following sections.
Mapping of ASDI message fields to properties
Each ASDI message consists of some common fields (sequence number, message time, facility) and fields specific for each message type. Refer to Structure of ASDI data for more information on the ASDI message types. Fields can contain one type of information or can group information that belongs together. Depending on its content a field can be mapped to a property in different ways:
-
A field that contains one type of information is mapped to a value of a simple type:
-
This can be any standard data type as
java.lang.String
,java.lang.Double
,java.lang.Integer
,…​ -
A numeric field that contains a measured value expressed in a certain unit is mapped to a property of the type
com.luciad.util.iso19103.TLcdISO19103Measure
. This class is an extension of the standardjava.lang.Number
class that has a methodILcdISO19103UnitOfMeasure getUnitOfMeasure()
to retrieve the unit associated with the value. The unit is anILcdISO19103UnitOfMeasure
which has various methods to retrieve the (short) name, type, conversion to a standard unit, …​ -
Sometimes a field contains an integer value that can be chosen from a list of possibilities each described by a
String
. Such values are mapped to properties of typeTLcdASDIMappedInteger
. TheTLcdASDIMappedInteger
class is an extension from the standardNumber
class. The methodintValue
returns the actual integer value. The methodsgetValueDescription
andtoString
return the descriptiveString
that corresponds with the integer value. In the cases where the integer values of aTLcdASDIMappedInteger
are not defined in the ASDI specification, the classTLcdASDIMappedInteger
contains constants for the allowed integer values. This allows to work with them without depending on the exact values. -
A field can also contain a code-like
String
value that can be chosen from a list of possibilities each described by a more descriptiveString
. Such values are mapped to properties of typeTLcdASDIMappedString
. The methodstringValue
returns the code-likeString
value. The methodsgetValueDescription
andtoString
return the corresponding descriptiveString
. -
Fields that contain facility information are translated to properties of type
TLcdASDIFacility
. The methodsgetShortCode
andgetCode
allow to retrieve the codes that correspond with the facility;getDescription
andtoString
return the description of the facility.
-
-
A field that groups information that belongs together is mapped to a property of type
ILcdDataObject
. All properties of this data object are of the type described above or can again beILcdDataObject
. For instance a field that represents a flight id is mapped to a property of typeILcdDataObject
, containing 2 properties, each of typeString
, one for the aircraft id and one for the computer id.Note that some complex fields are mapped to simple
String
properties containing theString
as extracted from the message. This is done in cases where it does not seem useful to split theString
in sub properties.
How to retrieve the message properties
Message properties of domain objects
All domain objects offer the message properties of the messages they are based on, literally or in a derived form :
- TLcdASDITrajectory
-
A
TLcdASDITrajectory
consists of a number of tracks, each track is based on one track message, hence aTLcdASDITrajectory
has a set of message properties corresponding to each track. All tracks of aTLcdASDITrajectory
are based on messages of the same type (either TZ or TO), hence all tracks of aTLcdASDITrajectory
have the same message data type. The methodsgetTrackDataType()
andgetTrackValue( int aTrackIndex, TLcdDataProperty aProperty )
must be used to retrieve the track message property values, whereaTrackIndex
indicates the track of interest andaProperty
the property of of which the value needs to be. Since there is a one-to-one relation between tracks and track messages, track properties and track message properties are the same.The
TLcdDataType
andTLcdDataProperty
instances can be found in theTLcdASDITrackTODataTypes
andTLcdASDITrackTZDataTypes
classes, depending on whether a trajectory represents a TZ or a TO data type. The data type can be retrieved through theTLcdASDITrajectoryModelDescriptor.getTrackDataType()
method.
- TLcdASDITrack
-
A
TLcdASDITrack
represents one track of aTLcdASDITrajectory
, hence it is also based on one track message (either TZ or TO). The properties of the track message are available through theILcdDataObject
interface of theTLcdASDITrack
class.
- TLcdASDIFlightPlanHistory
-
A
TLcdASDIFlightPlanHistory
contains a number of flight plans, representing the flight plan of a flight at different timestamps. ATLcdASDIFlightPlanHistory
is based on a group of flight plan messages (a mix of FZ, DZ, AZ, AF, RT, …​ messages) that relate to the same flight and that are ordered in ascending order of message time. A flight plan of aTLcdASDIFlightPlanHistory
is based on a subset of these flight plan messages : each time a flight plan message is added to aTLcdASDIFlightPlanHistory
a new flight plan is added too since each message adds extra flight plan information or updates the information set by the previous messages. Hence the fligth plan at indexi
in the history is based on the messages at indexes0..i
, so there’s a one-to-many relation between flight plans and flight plan messages. The flight plan messages of a flight plan are a mix of messages of different types that are ordered on message time. Each message type has its own set of message properties, different message data types can have properties in common. The data types are available in theTLcdASDIMessageDataTypes
class. This class has an abstract super-type for all messages, as well as a concrete representation of the different message types. For more information, refere to the API reference of the class.The most recent values of the union of all different message properties of a flight plan (which we call the flight plan properties) are available through the methods
getFlightPlanProperty()
andgetFlightPlanValue( int aFlightPlanIndex, TLcdDataProperty aProperty )
, whereaFlightPlanIndex
indicates the flight plan of interest andaProperty
the property of which the value should be retrieved. The properties for flight plan are available in theTLcdASDIFlightPlanDataTypes
class. Figure 4, “Flight plan properties and message properties” visualizes the relation between flight plan properties and message properties.Figure 4. Flight plan properties and message propertiesThe set of properties corresponding with the messages of the flight plans of a
TLcdASDIFlightPlanHistory
can be retrieved using the methodsgetMessageDataType(int aMessageIndex)
andgetMessageValue( int aMessageIndex, TLcdDataProperty aProperty )
. They allow to retrieve the properties that are otherwise hidden by the flight plan properties, for instanceProperty 2
ofMessage 0
in Figure 4, “Flight plan properties and message properties”.
- TLcdASDIFlightPlan
-
A
TLcdASDIFlightPlan
represents a flight plan of aTLcdASDIFlightPlanHistory
, hence it is also based on a group of flight plan messages (a mix of FZ, DZ, AZ, AF, RT, …​ messages). Here the flight plan properties are available through theILcdDataObject
interface of theTLcdASDIFlightPlan
class. The set of message properties corresponding to the messages of the flight plan can be retrieved using the methodsgetMessageCount()
,getMessageDataType(int aMessageIndex)
andgetMessageValue( int aMessageIndex, TLcdDataProperty aProperty )
, whereaMessageIndex
indicates the message of interest andaProperty
is the property of which the value should be retrieved. The various message data types can be found in theTLcdASDIMessageDataTypes
class.
All ILcdModel
in the TLcdModelList
filled by the ASDI decoders have model descriptors that implement ILcdDataModelDescriptor
, so they describe the data types of the model elements of the corresponding model. In ASDI all models have a single model
element data type. This model element data type can be retrieved using the ILcdDataModelDescriptor.getModelElementTypes()
method. You can use this data type to identify the type of tracks you are dealing with.
If extra methods are available to retrieve the property values of a helper class, there are also extra methods on the model
descriptors for retrieving the corresponding TLcdDataType
corresponding to that helper class. For instance the TLcdASDITrajectory
class has a method getTrackValue
to obtain the track properties, so a model containing TLcdASDITrajectory
objects has a model descriptor of type TLcdASDITrajectoryModelDescriptor
that has a method getTrackDataType()
to retrieve the TLcdDataType
for the track properties. If this TLcdDataType
matches TLcdASDITrackTODataTypes.getTrackTODataType()
then the tracks are of type TO, and the properties used to retrieve property values can be found in the TLcdASDITrackTODataTypes
class. Otherwise, if the TLcdDataType
matches TLcdASDITrackTZDataTypes.getTrackTZDataType()
then the tracks are of type TZ, and the properties used to retrieve property values can be found in the TLcdASDITrackTZDataTypes
class.
The sample package samples.decoder.asdi
delivered with the ASDI Industry Specific Component shows an example of how domain object properties can be retrieved in
order to show them in a tree view.
Message properties of read messages
When reading messages from a TLcdASDIMessageInputStream
the message properties of the read message are available through the ILcdDataObject
returned by the method TLcdASDIMessageInputStream.readMessage
.
Retrieving meta-data
The meta-data for the models in the model list can be obtained through the model descriptors of the models.
The model descriptor classes depend on the type of domain objects in the model.
All model descriptor classes extend the abstract class ALcdASDIModelDescriptor
. Following table gives an overview :
Domain Object | Model Descriptor |
---|---|
TLcdASDITrajectory |
TLcdASDITrajectoryModelDescriptor |
TLcdASDITrack |
TLcdASDITrackModelDescriptor |
TLcdASDIFlightPlanHistory |
TLcdASDIFlightPlanHistoryModelDescriptor |
TLcdASDIFlightPlan |
TLcdASDIFlightPlanModelDescriptor |
ALcdASDIModelDescriptor
Following information is always available through the interfaces and methods implemented by
the class ALcdASDIModelDescriptor
:
-
An
ALcdASDIModelDescriptor
is anILcdDataModelDescriptor
. This interface can be used to retrieve theTLcdDataType
of the model elements, using thegetModelElementTypes()
method. For ASDI, this will always return a set containing a single data type, that will be one of:TLcdASDIFlightPlanDataTypes.getFlightPlanDataType()
,TLcdASDITrackTODataTypes.getTrackTODataType()
,TLcdASDITrackTZDataTypes.getTrackTZDataType()
,TLcdASDIDataTypes.getTrajectoryDataType()
orTLcdASDIDataTypes.getFlightPlanHistoryDataType()
. -
The method
getDataType
can also be used to retrieve the type of the model data. It refers to the type of the messages the model data is originating from. Possible data types are described by constants in theALcdASDIModelDescriptor
class, for instanceALcdASDIModelDescriptor.DATA_TYPE_TZ_TRACK
refers to a model with track or trajectory data that originates from TZ messages. This can for instance be used in the implementation of acom.luciad.view.gxy.ILcdGXYLayerFactory
to distinguish between layers containing TO models and layers containing TZ models.
TLcdASDITrajectoryModelDescriptor
Models containing TLcdASDITrajectory
objects have a TLcdASDITrajectoryModelDescriptor
.
The method getTrackDataType
retrieves the TLcdDataType
for the track matching the trajectory model. The track property values themselves can be retrieved using the TLcdASDITrajectory.getTrackValue
method.
TLcdASDITrackModelDescriptor
Models containing TLcdASDITrack
objects have a TLcdASDITrackModelDescriptor
. The trajectory properties themselves can be retrieved using the methods of the ILcdDataObject
interface for the TLcdASDITrajectory
returned by TLcdASDITrack.getTrajectory()
.
TLcdASDIFlightPlanHistoryModelDescriptor
Models containing TLcdASDIFlightPlanHistory
objects have a TLcdASDIFlightPlanHistoryModelDescriptor
.
TLcdASDIFlightPlanModelDescriptor
Models containing TLcdASDIFlightPlan
objects have a TLcdASDIFlightPlanModelDescriptor
.
Filtering ASDI messages
Often a user will only be interested in a subset of the decoded messages, for instance a user is only interested in messages
that come from certain facilities. The classes TLcdASDIModelDecoder
, TLcdASDILiveDecoder
and TLcdASDIMessageInputStream
allow to filter messages by specifying an ILcdASDIMessageFilter
.
A filter must implement ILcdASDIMessageFilter
. This interface contains the accept(ILcdDataObject aMessage)
method. It returns only true
for the messages of interest. The aMessage
argument contains the data object representation of the message to concider. For more information on message properties refer
to Message properties.
To use the filter, attach it to the decoder or message input stream.
Program: Creating an ASDI model decoder shows an example of the use of an ILcdASDIMessageFilter
.
Replaying ASDI data from file
Replay input stream
It is also possible to replay the data from a file in ASDI format as if it came from a live stream of data.
For this purpose a class TLcdASDIFileReplayInputStream
is introduced. It reads an ASDI file
and uses the message time to replay the data: the data is only made available after the time between 2 messages has passed.
Using a TLcdASDILiveDecoder
with a TLcdASDIFileReplayInputStream
allows to replay data from an ASDI file.
The class TLcdASDIFileReplayInputStream
can be configured through the following classes and methods:
-
The class
TLcdASDIFileReplayInputStream
is an extension of the classjava.io.PipedInputStream
. -
The
setExceptionHandler
method allows to specify an exception handler that is called whenever a non recoverable exception occurs. It can for example be used to pop up a dialog to inform the user about it.
Sample
The sample class samples.decoder.asdi.live.MainPanel
implements a sample that creates a TLcdASDILiveDecoder
using a TLcdASDIFileReplayInputStream
.
samples/decoder/asdi/live/MainPanel
)
private InputStream createFileReplayInputStream(String aASDIFile) {
try {
TLcdInputStreamFactory input_stream_factory = new TLcdInputStreamFactory();
InputStream input_stream = input_stream_factory.createInputStream(aASDIFile);
return new TLcdASDIFileReplayInputStream(input_stream);
} catch (IOException e) {
sLogger.error(TLcdASDIFileReplayInputStream.class.getName() + "<init>", "The file [" + aASDIFile + "] could not be loaded.", e);
JOptionPane.showMessageDialog(MainPanel.this,
"The file [" + aASDIFile + "] could not be loaded.", "Could not load file", JOptionPane.ERROR_MESSAGE);
return null;
}
}
Program: Create a replay stream shows the implementation of the method createFileReplayInputStream(String aASDIFile)
that is used to create the TLcdASDIFileReplayInputStream
. It has an argument aASDIFile
that is the name of the file containing the ASDI data to replay. The method first creates an InputStream
on the specified file using the createInputStream
method of the TLcdInputStreamFactory
class. In the next step a TLcdASDIFileReplayInputStream
is created for this InputStream
, which is returned as result of the method.
The resulting InputStream
can be used in the startLiveDecoder
of Program: Starting an ASDI live decoder.
The complete sample code can be found in the packages samples.decoder.asdi.live
and samples.decoder.asdi
.