Class TLcdGXYContinuousLabelingAlgorithm
- All Implemented Interfaces:
ILcdCloneable
,ILcdGXYLabelingAlgorithm
,Cloneable
ILcdGXYLabelingAlgorithm
that offers continuously decluttered
labels, ideally suited for labeling moving objects (e.g., tracks).
When the objects move, the labels move along and avoid overlap in a continuous fashion by moving the labels around gently. The locations of the labels are not limited to a fixed number of possible locations, instead a label can be put everywhere on the map. By default there is no hard constraint on the distance between the label and the object. The labels do tend to move to their desired label location though.
Using this class, the desired location of the labels can be specified for all labels at once or for every label individually.
Which labels are removed in the labeling process is defined by the
label coverage property. Which labels should
be dropped first is influenced by the order in which labels are retrieved from the label infos
object, see TLcdCollectedLabelInfoList.getLabels()
. The default
is to never drop any labels.
- Use
setPadding(double)
to add space between labels. - Use
setReuseLocationsScaleRatioInterval(com.luciad.util.ILcdInterval)
to keep the relative location after zooming in the view. - Use
setClampOnScreenEdges(boolean)
to specify if labels can be partially outside the view. - Use
setLabelMovementBehavior(com.luciad.realtime.gxy.labeling.TLcdGXYContinuousLabelingAlgorithm.LabelMovementBehavior)
to specify when labels should be moved. - Use
setMinDistance(float)
to ensure labels are never too close to their object. - Use
setMaxDistance(float)
to ensure labels are never too far from their object. - Use
setDisallowedAngle(float)
to specify where a label can be positioned around its object.
This algorithm uses the obstacles and placements from the given ILcdLabelConflictChecker
to avoid placing labels at these locations.
For smooth visual results, the layer/view using this painter should be refreshed regularly.
This can for example be done by using the TLcdSimulator
, or by
refreshing the map using a timer, e.g. for a gxy layer/view :
Timer timer = new Timer( 50, new ActionListener() {
public void actionPerformed( ActionEvent e ) {
ILcdGXYView view = ...;
ILcdGXYLayer track_layer = ...;
view.invalidateGXYLayer( track_layer, true, this, "Invalidating track layer" );
}
}
} );
timer.setRepeats( true );
timer.start();
Using such a timer, it might be important with respect to performance to set
the correct number of background layers (see ILcdGXYView.getNumberOfCachedBackgroundLayers()
).
The TLcdSimulator
does this automatically (see TLcdSimulator.isManageNumberOfCachedBackgroundLayers()
).
Notes:
- This labeling algorithm never drops labels. This means that in some cases, when many labels need to be displayed, labels can overlap.
- This algorithm assumes the
ILcdGXYLabelPainter
of the layer implementsILcdGXYLabelPainter2
as it can only declutter labels if they can be placed freely, not when placement is limited to a fixed number of locations. - The bounds returned by the
ILcdGXYLabelPainter2
need to be independent of the location of the label for this algorithm to work well. Therefore the optionsetConsiderPinForBounds
ofTLcdGXYStampLabelPainter
is not supported in combination with this algorithm, as the pin varies in size depending on the label location. - This class supports rotated labels and rotated obstacles. However for performance reasons the axis aligned bounds of these labels are used in most calculations. Because of this, labels might not be optimally placed.
- The implementation of this labeling algorithm is thread-safe if the set master-slave dependency provider is thread-safe, the label priority provider is thread-safe and all overridden methods are implemented in a thread-safe manner.
- Since:
- 10.1
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic enum
Indicates when labels should be moved. -
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptionclone()
MakesObject.clone()
public.collectLabelInfo
(List<TLcdLabelIdentifier> aLabelsToCollect, Graphics aGraphics, ILcdGXYView aGXYView) This method returns aTLcdCollectedLabelInfoList
object based on the given list ofTLcdLabelIdentifier
s.computeLabelPlacements
(TLcdCollectedLabelInfoList aLabelInfoList, ILcdLabelConflictChecker aLabelConflictChecker, ILcdGXYView aView) This method computes a list ofTLcdLabelPlacement
s using the givenTLcdCollectedLabelInfoList
.Returns the desired relative location.float
Returns the size of the disallowed range.Indicates when labels are moved.Returns the label placing priority provider.Returns the dependency provider that defines the master-slave dependency between labels.int
Returns the maximum declutter time.float
Returns the configured maximum allowed distance.double
Returns the maximum label coverage ratio.float
Returns the configured minimum allowed distance.protected double
getOrientation
(Object aDomainObject) Retrieves a domain object's orientation.double
Returns the padding around the labels.Returns the scale ratio interval in which label locations are reused.boolean
Indicates whether labels are clamped against screen edges.protected void
retrieveDesiredLabelLocation
(Graphics aGraphics, ILcdGXYContext aGXYContext, Object aObject, int aLabelIndex, int aSubLabelIndex, Point aRelativeLocationSFCT) Retrieves the desired label location for the given object, label and sub label index.void
setClampOnScreenEdges
(boolean aEnabled) Enable or disable clamping labels against screen edges.void
setDesiredRelativeLocation
(Point aDesiredRelativeLocation) Sets the desired relative label location: the location the labels tend to move to.void
setDisallowedAngle
(float aArcAngle) Set a range, relative to the object's heading, where labels cannot be placed.void
Indicate when labels should be moved.void
setLabelPriorityProvider
(ILcdGXYMultiLabelPriorityProvider aLabelPriorityProvider) Sets the label placing priority provider, specifying the priority for individual labels.void
setMasterSlaveDependencyProvider
(ILcdCollectedLabelInfoDependencyProvider aDependencyProvider) Sets the dependency provider that defines the master-slave dependency between labels.void
setMaxDeclutterTime
(int aMaxDeclutterTime) Sets the maximum time (in ms) that should be spend in decluttering the labels.void
setMaxDistance
(float aMaximumDistance) Set the maximum allowed distance of a label to its anchor point.void
setMaxLabelCoverage
(double aMaximumLabelCoverage) Sets the maximum label coverage ratio.void
setMinDistance
(float aMinimumDistance) Set the minimum allowed distance of a label to its anchor point.void
setPadding
(double aPadding) Sets the padding around the labels.void
setReuseLocationsScaleRatioInterval
(ILcdInterval aReuseLocationsScaleRatioInterval) Sets the scale ratio interval in which the label locations are reused.
-
Constructor Details
-
TLcdGXYContinuousLabelingAlgorithm
public TLcdGXYContinuousLabelingAlgorithm()
-
-
Method Details
-
setLabelMovementBehavior
public void setLabelMovementBehavior(TLcdGXYContinuousLabelingAlgorithm.LabelMovementBehavior aBehavior) Indicate when labels should be moved.- Use
MINIMAL_MOVEMENT
to avoid moving labels as much as possible - Use
REDUCED_MOVEMENT
to avoid moving labels when they are near other labels, but keep them close to their object - Use
OPTIMAL_SPREAD
to ensure an optimal spread of labels
The default is
OPTIMAL_SPREAD
.- Parameters:
aBehavior
- The desired behavior- Since:
- 2012.1
- Use
-
getLabelMovementBehavior
Indicates when labels are moved.- Returns:
- The current setting
- Since:
- 2012.1
- See Also:
-
setMinDistance
public void setMinDistance(float aMinimumDistance) Set the minimum allowed distance of a label to its anchor point.If set, a label cannot move closer to its anchor point than this distance. The distance is calculated from the point of the label closest to the anchor.
By default, the minimum distance is disabled (
0
).- Parameters:
aMinimumDistance
- the minimum distance, in pixels.
-
getMinDistance
public float getMinDistance()Returns the configured minimum allowed distance.- Returns:
- The configured minimum allowed distance.
- See Also:
-
setMaxDistance
public void setMaxDistance(float aMaximumDistance) Set the maximum allowed distance of a label to its anchor point.If set, a label cannot move further from its anchor point than this distance. The distance is calculated from the point of the label closest to the anchor.
By default, the maximum distance is disabled (
Float#POSITIVE_INFINITY
).- Parameters:
aMaximumDistance
- the maximum distance, in pixels.
-
getMaxDistance
public float getMaxDistance()Returns the configured maximum allowed distance.- Returns:
- The configured maximum allowed distance.
- See Also:
-
setDisallowedAngle
public void setDisallowedAngle(float aArcAngle) Set a range, relative to the object's heading, where labels cannot be placed.If set, a label cannot move inside the disallowed area. A label's arc is calculated between its center of the label, the anchor point and the orientation.
For example, to ensure a label is never "in front of" its object, use
setDisallowedAngle(120)
.Domain objects must implement
ILcdOriented
to use this feature, or you can overridegetOrientation(Object)
to use a custom implementation.By default, the disallowed range is disabled (0 degrees).
- Parameters:
aArcAngle
- The size of the range in which labels should not be positioned, in degrees, spread evenly around the object's orientation.
-
getDisallowedAngle
public float getDisallowedAngle()Returns the size of the disallowed range.- Returns:
- The size of the range in which labels should not be positioned, in degrees, spread evenly around the object's orientation.
- See Also:
-
setClampOnScreenEdges
public void setClampOnScreenEdges(boolean aEnabled) Enable or disable clamping labels against screen edges.If enabled, labels for visible objects are always fully visible. If disabled, labels can be partially outside the view.
By default, this is enabled.
- Parameters:
aEnabled
-true
if it should be enabled,false
otherwise.
-
isClampOnScreenEdges
public boolean isClampOnScreenEdges()Indicates whether labels are clamped against screen edges.- Returns:
true
if enabled,false
otherwise.- See Also:
-
getReuseLocationsScaleRatioInterval
Returns the scale ratio interval in which label locations are reused.- Returns:
- the scale ratio interval in which label locations are reused.
- See Also:
-
setReuseLocationsScaleRatioInterval
Sets the scale ratio interval in which the label locations are reused. To avoid labels suddenly jumping from one location to another, the previous label locations are reused (as stored inALcdLabelLocations
). If large changes inscale
occur (e.g., zooming in/out), trying to reuse those locations is no longer useful as visual contact with the labels is lost anyway. Using this interval, one can specify for which scale changes the label locations should be reused, using a lower and an upper ratio. For example setting this value tonew TLcdInterval(0.8, 1.2)
means that the label locations are reused if new scale (e.g., after zooming) divided by the old scale (e.g., before zooming) is within the interval [0.8, 1.2]. If this interval is set tonull
, label locations are never reused.- Parameters:
aReuseLocationsScaleRatioInterval
- The scale ratio interval.
-
getPadding
public double getPadding()Returns the padding around the labels.- Returns:
- the padding around the labels, in pixels.
- See Also:
-
setPadding
public void setPadding(double aPadding) Sets the padding around the labels. This padding is added to the bounds of the labels, enlarging it during placement.
In practice this means that the bigger the padding, the more space between the labels.
By default, this value is
0.0
.- Parameters:
aPadding
- the padding, in pixels.- Throws:
IllegalArgumentException
- when the given padding is smaller than0
.- See Also:
-
getDesiredRelativeLocation
Returns the desired relative location.- Returns:
- the desired relative location.
- See Also:
-
setDesiredRelativeLocation
Sets the desired relative label location: the location the labels tend to move to. The location of the label is relative to the anchor point of the object it belongs to. So if for example the relative location is set tonew Point( 10, 10 )
, all labels (that is, their anchors) tend to move to an offset of (10, 10) to the object they belong to. See alsoretrieveDesiredLabelLocation(java.awt.Graphics, com.luciad.view.gxy.ILcdGXYContext, java.lang.Object, int, int, java.awt.Point)
.- Parameters:
aDesiredRelativeLocation
- The desired location relative to the anchor point of the object.- See Also:
-
retrieveDesiredLabelLocation
protected void retrieveDesiredLabelLocation(Graphics aGraphics, ILcdGXYContext aGXYContext, Object aObject, int aLabelIndex, int aSubLabelIndex, Point aRelativeLocationSFCT) Retrieves the desired label location for the given object, label and sub label index. The desired location is specified relative to the anchor point of the object, and it is the label anchor point that tends to move there. By default, aRelativeLocationSFCT is modified to equal the result ofgetDesiredRelativeLocation
. Override this method to specify the desired location differently for every label. This for example can be used to avoid that labels would like to be at the location where a track is heading to.- Parameters:
aGraphics
- The graphics involved in the paint operation.aGXYContext
- The context containing the layer, the view and the transformations.aObject
- The object.aLabelIndex
- The label index, 0 if no ILcdGXYMultiLabelPainter is used.aSubLabelIndex
- The sub label index, 0 if no ILcdGXYMultiLabelPainter is used.aRelativeLocationSFCT
- The location this method adapts as a side effect, relative to the anchor point of the object.- See Also:
-
getMaxLabelCoverage
public double getMaxLabelCoverage()Returns the maximum label coverage ratio.- Returns:
- the maximum label coverage ratio.
- See Also:
-
setMaxLabelCoverage
public void setMaxLabelCoverage(double aMaximumLabelCoverage) Sets the maximum label coverage ratio. It controls when to start dropping labels if the view contains too many of them.It is defined as the surface used by the labels (approximated by their bounds) divided by the total surface of the view, so typical values are in the range of ]0,1]. To for example start dropping labels if more than 30% of the view would be covered by labels, set this property to 0.3. A value of for example 2 means the labels can use the available screen space twice (so possibly a lot of overlap). Set it to
Double.MAX_VALUE
to never drop any labels (the default value).- Parameters:
aMaximumLabelCoverage
- The maximum label coverage, must be larger than or equal to 0.
-
getMaxDeclutterTime
public int getMaxDeclutterTime()Returns the maximum declutter time.- Returns:
- the maximum declutter time.
- See Also:
-
setMaxDeclutterTime
public void setMaxDeclutterTime(int aMaxDeclutterTime) Sets the maximum time (in ms) that should be spend in decluttering the labels. Providing a smaller limit may cause label positioning to be less optimal. This time value is a hint, not a hard limit.- Parameters:
aMaxDeclutterTime
- The maximum time that can be spend in decluttering, in ms.
-
getMasterSlaveDependencyProvider
Returns the dependency provider that defines the master-slave dependency between labels.- Returns:
- the dependency provider that defines the master-slave dependency between labels.
- See Also:
-
setMasterSlaveDependencyProvider
public void setMasterSlaveDependencyProvider(ILcdCollectedLabelInfoDependencyProvider aDependencyProvider) Sets the dependency provider that defines the master-slave dependency between labels.The master-slave dependency is defined as follows. The slave always follows the master label. If the master label is translated, the slave label is translated by the same amount. If the master label is sticky, so is the slave label, and vice-versa.
- Parameters:
aDependencyProvider
- the dependency provider that defines the master-slave dependency between labels. Should never benull
.
-
getLabelPriorityProvider
Returns the label placing priority provider.- Returns:
- the label placing priority provider.
- See Also:
-
setLabelPriorityProvider
Sets the label placing priority provider, specifying the priority for individual labels. In case a max label coverage is set, the labels with the highest priority have the least chance of being omitted.When no label priority provider is set, a default label priority provider is used which returns
Integer.MAX_VALUE
for all labels.- Parameters:
aLabelPriorityProvider
- The priority provider to set.
-
clone
Description copied from interface:ILcdCloneable
Makes
When for example extending fromObject.clone()
public.java.lang.Object
, it can be implemented like this:public Object clone() { try { return super.clone(); } catch ( CloneNotSupportedException e ) { // Cannot happen: extends from Object and implements Cloneable (see also Object.clone) throw new RuntimeException( e ); } }
- Specified by:
clone
in interfaceILcdCloneable
- Overrides:
clone
in classObject
- See Also:
-
collectLabelInfo
public TLcdCollectedLabelInfoList collectLabelInfo(List<TLcdLabelIdentifier> aLabelsToCollect, Graphics aGraphics, ILcdGXYView aGXYView) Description copied from interface:ILcdGXYLabelingAlgorithm
This method returns aTLcdCollectedLabelInfoList
object based on the given list ofTLcdLabelIdentifier
s. The returnedTLcdCollectedLabelInfoList
should contain aTLcdCollectedLabelInfo
object for each label that should be placed.Each
TLcdCollectedLabelInfo
should also contain all information needed bycomputeLabelPlacements
to place the labels. In order to enable correct asynchronous label placing, all calls to the layer and the (label) painters should be done in this method. The results should then be stored in the info objects.It is possible that the returned
TLcdCollectedLabelInfoList
doesn't contain aTLcdCollectedLabelInfo
object for every givenTLcdLabelIdentifier
. In that case the missing labels are not placed.- Specified by:
collectLabelInfo
in interfaceILcdGXYLabelingAlgorithm
- Parameters:
aLabelsToCollect
- the labels for which aTLcdCollectedLabelInfoList
should be created.aGraphics
- the graphics.aGXYView
- the view.- Returns:
- a
TLcdCollectedLabelInfoList
which contains all the information needed to place the labels.
-
getOrientation
Retrieves a domain object's orientation. The orientation is used when a disallowed angle is specified (seesetDisallowedAngle(float)
).The result must be expressed as an azimuth, in degrees, clockwise starting from 12 o'clock.
Return
Double.NaN
if no orientation can be calculated or if it is not applicable.The default implementation returns an orientation if the object is
ILcdOriented
, orDouble.NaN
otherwise.- Parameters:
aDomainObject
- the domain object- Returns:
- the domain object's orientation, in degrees, clockwise starting from 12 o'clock.
- See Also:
-
computeLabelPlacements
public List<TLcdLabelPlacement> computeLabelPlacements(TLcdCollectedLabelInfoList aLabelInfoList, ILcdLabelConflictChecker aLabelConflictChecker, ILcdGXYView aView) Description copied from interface:ILcdGXYLabelingAlgorithm
This method computes a list ofTLcdLabelPlacement
s using the givenTLcdCollectedLabelInfoList
. The returned label placements should contain a validTLcdLabelLocation
and label bounds. They should also point to their correspondingTLcdCollectedLabelInfo
, which in turn should point to its correspondingTLcdCollectedLabeledObjectInfo
.The given
TLcdCollectedLabelInfoList
should always be an object created or returned bycollectLabelInfo
.The returned
List
ofTLcdLabelPlacement
s contains label placements that are either visible or invisible. When a placement is present in the list, it means that the location should be stored. When a placement in the list is marked as visible, it means that its location should be marked as to-be-painted.The labels should by preference be placed in the order in which the labels are returned by
TLcdCollectedLabelInfoList.getLabels()
.- Specified by:
computeLabelPlacements
in interfaceILcdGXYLabelingAlgorithm
- Parameters:
aLabelInfoList
- the info object that contains all information needed to place the labels.aLabelConflictChecker
- the bounds conflict checker that can be used to detect conflicts between labels.aView
- the view.- Returns:
- a list of labels to be rendered.
-