A recurring use case for LuciadLightspeed applications is the display of moving tracks with added heading vectors. The heading
vector needs to indicate the direction in which the track is moving. The tracks consist of dynamically updated ILcdPoint
objects. The length of this vector is commonly expressed in pixels rather than in a geographically defined unit of measure.
That way, the vector remains visible at all zoom levels.
Intuitively, a developer might attempt to tackle this problem as follows:
-
Given the lon/lat coordinates and the azimuth of the moving track, compute a second lon/lat point which lies at a pixel distance D from the track. To achieve this, the developer presumably uses the methods in
ILcdEllipsoid
and the view’s map scale to convert between a pixel distance and a distance in meters. -
Connect the track and the computed end point of the vector with a
TLcdLonLatLine
. -
Style the line with a
TLspLineStyle
.
This approach is cumbersome to implement and results in sub-optimal performance. Because the length of the lon/lat line depends
on the zoom level, it needs to be re-computed each time the map scale changes. You can neatly implement all that inside an
ALspStyler
, but this styler will have to fire a style change event every time the users zooms in or out.
How to do it?
A better approach to the problem is to encapsulate the heading vector into an ILcdIcon
. The icon could contain a simple line or a line with an arrowhead, for example:

You can implement this by using a custom ILcdIcon
that draws a line or arrow directly on the supplied Graphics
, or you can store the icon in a file and load it with TLcdImageIcon
. Once we have the ILcdIcon
, we will use the track itself (an ILcdPoint
) and style it with a TLspIconStyle
.
To apply the heading to the icon automatically, the track object must implement ILcdOriented
to advertise its current heading.
public class Track extends TLcdLonLatHeightPoint implements ILcdOriented {
private double fHeading;
public Track(double aLon, double aLat, double aZ, double aHeading) {
super(aLon, aLat, aZ);
fHeading = aHeading;
}
@Override
public double getOrientation() {
return fHeading;
}
}
If you use an ILcdIcon
, the icon style will position the icon so that its center is at the location of the track. The center point of the icon will
also be used as the rotation point. For heading vectors, you typically want the start point of the arrow at the location of
the track, and you also want to use this point to apply the rotation. To achieve that, make sure that your icon is an ILcdAnchoredIcon
. If you are using an existing icon, you can use TLcdAnchoredIcon
to wrap it and provide an anchor point.
When you are creating the TLspIconStyle
, enable useOrientation
so that the style will rotate the icon in the direction of the object as reported by ILcdOriented#getOrientation()
.
Note that an |
TLcdImageIcon arrowIcon = new TLcdImageIcon("arrow.png");
TLcdAnchoredIcon anchoredIcon = new TLcdAnchoredIcon(arrowIcon, new Point(arrowIcon.getIconWidth() / 2, arrowIcon.getIconHeight()));
TLspIconStyle iconStyle = TLspIconStyle.newBuilder()
.useOrientation(true)
.icon(anchoredIcon)
.build();
If the |