public interface ILcdMultiDimensionalModel extends ILcdMultiDimensional, ILcdModel
In the simple case of a single model, a filter will usually contain exactly one interval for every axis the model supports. This allows a filter to be applied atomically: you can define all intervals for all axes in a single filter and apply them at once.
If a filter contains more axes than the model supports, the unknown axes should be ignored by the model. For example, if a model only has time dimension but the filter has a level and time interval, then the model should filter only on time. This allows instances of global filters to be defined: you can define a filter for every possible dimension in your view, even if different models in view support a different subset of axes, and all the models will behave according to the filter.
If a filter contains fewer axes than the model supports, the model should still apply the filter as much as
it can for the axes the filter does contain.
For the axes that the filter does not define, the model should reset to default.
Resetting to default is slightly different for vector models compared to raster models.
This is explained in more detail in applyDimensionFilter(com.luciad.multidimensional.TLcdDimensionFilter, int)
.
For example, if a NetCDF raster model has axes defining time and vertical dimensions, but the filter only specifies
a time axis, the implementation will pick typically the first raster at the given time.
A special case is when a filter contains no axes: then the model resets its filter to the default.
The model implementations may decide what the filters should look like.
Most models only support single-valued intervals as filter values in practice.
Models should match filters according to TLcdDimensionInterval.overlaps(com.luciad.multidimensional.TLcdDimensionInterval<T>, com.luciad.multidimensional.TLcdDimensionInterval<T>)
:
applyDimensionFilter(com.luciad.multidimensional.TLcdDimensionFilter, int)
.
A typical implementation of a multi-dimensional model filters its elements when a dimensional filter is applied. Events will be fired for every element that was added to or removed from the model as a result of applying the filter. When no objects pass the filter, the model will be empty. Examples of such implementations are NVG and ASTERIX models.
Multi-dimensional raster models
Another typical implementation of a multi-dimensional model is a model that has a single ILcdDataObject
that
has an ALcdImage
as property.
When a filter is applied, the element remains the same, but the ALcdImage
it owns changes.
An event will be fired for the element.
When no ALcdImage
passes the filter, the ILcdDataObject
will remain the same (not null
), but
its ALcdImage
will be null
.
Examples of such implementations are NetCDF and LuciadFusion fused multi-dimensional raster models.
Implementations should not 'snap' to the intervals defined by the filter in case no elements match.
There shall be no snapping to nearest, previous or next.
Instead, the result must be 'empty' (or 'image is null
' in case of raster models).
If you need to snap a filter interval to an actual interval the model has to offer, you should use
TLcdDimensionFilter.createSnappingFilter(com.luciad.multidimensional.ILcdMultiDimensionalModel, com.luciad.multidimensional.TLcdDimensionFilter.SnapMode)
instead.
ILcdModel.Query
FIRE_LATER, FIRE_NOW, NO_EVENT
Modifier and Type | Method and Description |
---|---|
void |
applyDimensionFilter(TLcdDimensionFilter aFilter,
int aEventMode)
Applies a given dimensional filter and fires an event accordingly.
|
TLcdDimensionFilter |
getDimensionFilter()
Gets the current dimensional filter, possibly empty but never
null . |
getDimensions
addElement, addElements, addModelListener, all, canAddElement, canRemoveElement, dispose, elementChanged, elements, elementsChanged, filter, fireCollectedModelChanges, getModelDescriptor, getModelEncoder, getModelMetadata, getModelReference, query, removeAllElements, removeElement, removeElements, removeModelListener
close
void applyDimensionFilter(TLcdDimensionFilter aFilter, int aEventMode)
Filtering behavior
In practice, filtering behavior and the default filter depend on the type of the model:
ALcdImage
instances, every one of which is valid within a certain interval. An implementation of this
interface needs to make sure that
ALcdImage.fromDomainObject(java.lang.Object)
.
We advise to use the 'has-an-image' paradigm to expose this image, because it allows for faster updates
in a Lightspeed view.
Filter matching
Matching intervals happens based on TLcdDimensionInterval.overlaps(com.luciad.multidimensional.TLcdDimensionInterval<T>, com.luciad.multidimensional.TLcdDimensionInterval<T>)
.
The rationale for this is the following:
Locking
This method should typically be called from within a write lock:
try (TLcdLockUtil.Lock lock = TLcdLockUtil.writeLock(model) {
...
model.applyDimensionFilter(filter, ILcdModel.FIRE_LATER);
...
} finally {
model.fireCollectedModelChanges();
}
The most common exception to this rule is when you're creating a model initially and no-one has a reference to it
yet: in that case, it's safe to not lock at all and use ILcdModel.NO_EVENT
.
No snapping
Implementations should not 'snap' to the intervals defined by the filter in case no elements match.
There shall be no snapping to nearest, previous or next.
Instead, the result must be 'empty' (or 'image is null
' in case of raster models).
If you need to snap a filter interval to an actual interval the model has to offer, you should use
TLcdDimensionFilter.createSnappingFilter(com.luciad.multidimensional.ILcdMultiDimensionalModel, com.luciad.multidimensional.TLcdDimensionFilter.SnapMode)
to create a snapped filter.
Differences with createSnappingFilter
As its name suggests, the primary purpose of the utility method createSnappingFilter
is to create a
filter which 'snaps' to filter intervals so that there is always at least one match.
But the method does more than just that.
Here is a list of differences between using and not using createSnappingFilter
:
Behavior | applyDimensionFilter | createSnappingFilter->applyDimensionFilter |
---|---|---|
Snapping | Never, possibly resulting in no matches | Snaps to intervals defined by the model if needed, such that there is always at least one match |
Supported snap modes | None | Nearest, previous, next, or none (null ) |
Filter has less axes than supported by model | Reset to default for those axes | Keep the last current filter value for those axes, so that there are minimal model changes |
Empty filter | Reset to default filter | Keep current filter, so that there are no model changes |
ILcdModel which is not ILcdMultiDimensionalModel |
Not supported | Checks instance of ILcdMultiDimensionalModel , leaves others alone |
aFilter
- The dimensional filter, possibly empty but never null
.aEventMode
- The mode of the event that should be triggered when the value of the filter parameters changes.TLcdDimensionInterval.overlaps(com.luciad.multidimensional.TLcdDimensionInterval<T>, com.luciad.multidimensional.TLcdDimensionInterval<T>)
,
TLcdDimensionFilter.createSnappingFilter(com.luciad.multidimensional.ILcdMultiDimensionalModel, com.luciad.multidimensional.TLcdDimensionFilter.SnapMode)
TLcdDimensionFilter getDimensionFilter()
null
.
The current dimensional filter is the last one that was set on this model using
applyDimensionFilter(TLcdDimensionFilter, int)
.
It may contain more or less dimensions than this model supports, and it may be empty
(TLcdDimensionFilter.EMPTY_FILTER
), but it must never be null
.
The filter intervals may but does not have to be one of the intervals given by getDimensions().getValues()
.
When no dimensional filter has been set on this model yet, this method returns the default dimensional filter. The default dimensional filter depends on the implementation. Typical implementations:
The default filter is not necessarily constant. It may change as elements are added to or removed from the model, because the default filter is often computed from the dimensional information of the elements.
TLcdDimensionFilter.EMPTY_FILTER
but never null
.