public class TLspContinuousLabelingAlgorithm extends Object implements ILspLabelingAlgorithm
ILspLabelingAlgorithm
that
offers continuously decluttered labels, ideally suited for moving objects (e.g., tracks).
When the objects move, the labels move along and avoid overlap in a continuous fashion by moving the representations around gently. The locations of the representations are not limited to a fixed number of possible locations, instead a representation can be put everywhere on the map. By default there is no hard constraint on the distance between the representation and the object. The representations do tend to move to their desired location though.
Using this class, the desired location of the representations can be specified for all representations at once or for every representation individually.
Which representations are
removed in the process is defined by the max coverage
property. Which representations should be dropped first is influenced by the priorities returned
by LabelContext.getPriority
. The default is to never drop any labels.
You can configure the positioning of the labels in various ways:
setPadding(double)
to add space between labels.setReuseLocationsScaleRatioInterval(com.luciad.util.ILcdInterval)
to keep the relative location after zooming in the view.setClampOnScreenEdges(boolean)
to specify if labels can be partially outside the view.setLabelMovementBehavior(com.luciad.realtime.lightspeed.labeling.TLspContinuousLabelingAlgorithm.LabelMovementBehavior)
to specify when labels should be moved.setMinDistance(float)
to ensure labels are never too close to their object.setMaxDistance(float)
to ensure labels are never too far from their object.setDisallowedAngle(float)
to specify where a label can be positioned around its object. This algorithm uses the
obstacles and placements from the given ILspLabelConflictChecker
to avoid placing representations at these locations.
For smooth
visual results, this algorithm should be triggered regularly. This can for example be done by
using the TLcdSimulator
, or by refreshing the label
location placement using a timer, e.g. :
Timer timer = new Timer( 50, new ActionListener() {
public void actionPerformed( ActionEvent e ) {
ILsp view = ...;
view.getLabelPlacer().invalidate( "refresh" );
view.getLabelPlacer().placeLabels( view );
}
});
timer.setRepeats( true );
timer.start();
Notes:
ILspLabelPainter
of the layer implements ILspStampLocationLabelPainter
as it can only declutter labels if they can be placed freely, not
when placement is limited to a fixed number of locations.ILspLabelPainter
need to be
independent of the location of the label for this algorithm to work well.Modifier and Type | Class and Description |
---|---|
static class |
TLspContinuousLabelingAlgorithm.LabelMovementBehavior
Indicates when labels should be moved.
|
ILspLabelingAlgorithm.LabelContext
Constructor and Description |
---|
TLspContinuousLabelingAlgorithm() |
Modifier and Type | Method and Description |
---|---|
TLspContinuousLabelingAlgorithm |
clone()
Makes
Object.clone() public. |
Point |
getDesiredRelativeLocation()
Returns the desired relative location.
|
float |
getDisallowedAngle()
Returns the size of the disallowed range.
|
TLspContinuousLabelingAlgorithm.LabelMovementBehavior |
getLabelMovementBehavior()
Indicates when labels are moved.
|
ILspLabelDependencyProvider |
getMasterSlaveDependencyProvider()
Returns the dependency provider that defines the master-slave dependency between view
representations.
|
double |
getMaxCoverage()
Returns the maximum coverage ratio.
|
int |
getMaxDeclutterTime()
Returns the maximum declutter time.
|
float |
getMaxDistance()
Returns the configured maximum allowed distance.
|
float |
getMinDistance()
Returns the configured minimum allowed distance.
|
protected double |
getOrientation(Object aDomainObject)
Retrieves a domain object's orientation.
|
double |
getPadding()
Returns the padding around the labels.
|
ILcdInterval |
getReuseLocationsScaleRatioInterval()
Returns the scale ratio interval in which label locations are reused.
|
boolean |
isClampOnScreenEdges()
Indicates whether labels are clamped against screen edges.
|
List<TLspLabelPlacement> |
placeLabels(List<TLspLabelID> aLabelIDs,
ILspLabelingAlgorithm.LabelContext aLabelContext,
ILspLabelConflictChecker aConflictChecker,
ILspView aView)
|
protected void |
retrieveDesiredLocation(TLspLabelID aLabel,
TLspPaintState aPaintState,
TLspContext aContext,
Point aRelativeLocationSFCT)
Retrieves the desired view location for the given label.
|
void |
setClampOnScreenEdges(boolean aEnabled)
Enable or disable clamping labels against screen edges.
|
void |
setDesiredRelativeLocation(Point aDesiredRelativeLocation)
Sets the desired relative view 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 |
setLabelMovementBehavior(TLspContinuousLabelingAlgorithm.LabelMovementBehavior aBehavior)
Indicate when labels should be moved.
|
void |
setMasterSlaveDependencyProvider(ILspLabelDependencyProvider aDependencyProvider)
Sets the dependency provider that defines the master-slave dependency between view
representations.
|
void |
setMaxCoverage(double aMaxCoverage)
Sets the maximum coverage ratio.
|
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 |
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.
|
public void setLabelMovementBehavior(TLspContinuousLabelingAlgorithm.LabelMovementBehavior aBehavior)
MINIMAL_MOVEMENT
to avoid moving labels as much as possibleREDUCED_MOVEMENT
to avoid moving labels when they are near other labels, but keep them close to their objectOPTIMAL_SPREAD
to ensure an optimal spread of labels
The default is OPTIMAL_SPREAD
.
aBehavior
- The desired behaviorpublic TLspContinuousLabelingAlgorithm.LabelMovementBehavior getLabelMovementBehavior()
setLabelMovementBehavior(com.luciad.realtime.lightspeed.labeling.TLspContinuousLabelingAlgorithm.LabelMovementBehavior)
public void setMinDistance(float aMinimumDistance)
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
).
aMinimumDistance
- the minimum distance, in pixels.public float getMinDistance()
setMinDistance(float)
public void setMaxDistance(float aMaximumDistance)
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
).
aMaximumDistance
- the maximum distance, in pixels.public float getMaxDistance()
setMaxDistance(float)
public void setDisallowedAngle(float aArcAngle)
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 override getOrientation(Object)
to use a custom implementation.
By default, the disallowed range is disabled (0 degrees).
aArcAngle
- The size of the range in which labels should not be positioned, in degrees, spread evenly around the object's orientation.public float getDisallowedAngle()
setDisallowedAngle(float)
public void setClampOnScreenEdges(boolean aEnabled)
If enabled, labels for visible objects are always fully visible. If disabled, labels can be partially outside the view.
By default, this is enabled.
aEnabled
- true
if it should be enabled, false
otherwise.public boolean isClampOnScreenEdges()
true
if enabled, false
otherwise.setClampOnScreenEdges(boolean)
public ILcdInterval getReuseLocationsScaleRatioInterval()
setReuseLocationsScaleRatioInterval(com.luciad.util.ILcdInterval)
public void setReuseLocationsScaleRatioInterval(ILcdInterval aReuseLocationsScaleRatioInterval)
ALspLabelLocations
). If large changes in scale 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 to new 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 to null
, label locations are
never reused.aReuseLocationsScaleRatioInterval
- The scale ratio interval.public Point getDesiredRelativeLocation()
setDesiredRelativeLocation(java.awt.Point)
public void setDesiredRelativeLocation(Point aDesiredRelativeLocation)
new Point( 10, 10 )
, all representations
(that is, their anchors) tend to move to an offset of (10, 10) to the object they belong to.
See also retrieveDesiredLocation(com.luciad.view.lightspeed.painter.label.TLspLabelID, com.luciad.view.lightspeed.layer.TLspPaintState, com.luciad.view.lightspeed.TLspContext, java.awt.Point)
.aDesiredRelativeLocation
- The desired location relative to the anchor point of the
object.ILspStampLocationLabelPainter
protected void retrieveDesiredLocation(TLspLabelID aLabel, TLspPaintState aPaintState, TLspContext aContext, Point aRelativeLocationSFCT)
By default, aRelativeLocationSFCT is modified to equal the result of
getDesiredRelativeLocation
.
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.
aLabel
- the label for which a desired location is returned.aPaintState
- the paint stateaContext
- the context.aRelativeLocationSFCT
- The location this method adapts as a side effect, relative to the
anchor point of the object.ILspStampLocationLabelPainter
public double getMaxCoverage()
setMaxCoverage(double)
public void setMaxCoverage(double aMaxCoverage)
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 representations if more than 30% of the view would be covered by
view representation, 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).
aMaxCoverage
- The maximum coverage, must be larger than or equal to 0.public int getMaxDeclutterTime()
setMaxDeclutterTime(int)
public void setMaxDeclutterTime(int aMaxDeclutterTime)
This time value is a hint, not a hard limit.
aMaxDeclutterTime
- The maximum time that can be spend in decluttering, in ms.public ILspLabelDependencyProvider getMasterSlaveDependencyProvider()
setMasterSlaveDependencyProvider(com.luciad.view.lightspeed.label.algorithm.ILspLabelDependencyProvider)
public void setMasterSlaveDependencyProvider(ILspLabelDependencyProvider aDependencyProvider)
The master-slave dependency is defined as follows. The slave always follows the master. If the master representation is translated, the slave representation is translated by the same amount. If the master representation is sticky, so is the slave representation, and vice-versa.
aDependencyProvider
- the dependency provider that defines the master-slave dependency
between labels. Can be null
.public double getPadding()
setPadding(double)
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
.
aPadding
- the padding, in pixels.IllegalArgumentException
- when the given padding is smaller than 0
.getPadding()
public TLspContinuousLabelingAlgorithm clone()
ILcdCloneable
Makes Object.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 );
}
}
clone
in interface ILcdCloneable
clone
in class Object
Object.clone()
public List<TLspLabelPlacement> placeLabels(List<TLspLabelID> aLabelIDs, ILspLabelingAlgorithm.LabelContext aLabelContext, ILspLabelConflictChecker aConflictChecker, ILspView aView)
ILspLabelingAlgorithm
This method computes a list of label placements for the given
List
of labels. The returned label placements
should contain a valid label location and label bounds. They
should also point to their corresponding TLspLabelID
The returned List
of TLspLabelPlacement
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 visible in the
label placer
placeLabels
in interface ILspLabelingAlgorithm
aLabelIDs
- the labels to be placed.aLabelContext
- provides context information, such as priorities, PaintState, ...aConflictChecker
- the conflict checker that can be used to detect conflicts between labels.aView
- the view.protected double getOrientation(Object aDomainObject)
setDisallowedAngle(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
, or Double.NaN
otherwise.
aDomainObject
- the domain objectILcdOriented
,
setDisallowedAngle(float)