Support for displaying tracks of data based on visibility filtering has been added. This means that only the points which pass the visibility
filter will be displayed. A NeXtMidas visibility filter is made up of a Map of tests, of which all of the tests need to result in true
for the filter to pass.
Each test is saved in a NeXtMidas object called PredicateType, as not only the test (a Java Predicate) but also the required incoming
data type need to be known. Knowing the type facilitates NeXtMidas converting the data being tested into the right form (ex: String -> Integer or
Data object -> Double).
As mentioned above, the functional interfaces that NeXtMidas visibility filters use are Java Predicates. A Predicate is one of the predefined
functional interfaces in Java. A Predicate has generic type (T) and one abstract method that takes in a single parameter of type (T)
and returns a boolean value.
Behind the scenes, the Predicate functional interface looks like this:
interface Predicate<T> {
boolean test(T t);
}
/* This example defines a visibility filter where only the points whose NAME starts with "TRACK013" are displayed. */ // Make a Predicate whose test method checks that a given String parameter starts with "TRACK013" String predExpected = "TRACK013"; String expected = predExpected; PredicatestartsWith = s -> s.startsWith(expected); // Use the created Predicate to make a NeXtMidas PredicateType PredicateType startsWithPT = new PredicateType(startsWith, String.class, "Starts with \"TRACK013\""); // Create a Map for Strings to PredicateTypes Map<String,PredicateType> mapPT = new HashMap<>(); // Associate the LayerT5 component "NAME" to the created PredicateType String predKey = "NAME"; mapPT.put(predKey,startsWithPT); /* NOTE: This is an alternative way to add a PredicateType to a PredicateType Map: Map<String,PredicateType> mapPT = new HashMap<>(); PredicateType.addKeyFunction(mapPT,"NAME","STARTS TRACK013"); 1. NeXtMidas only supports this with specific comparisons for specific LayerT5 components. 2. NeXtMidas users will more commonly define their own Predicates, PredicateTypes, and PredicateType Maps as shown above. */ // The PredicateType Map defined above will be used as the visibility filter layerT5.setVisibilityFilter(mapPT); // Get the points matching the visibility filter List list = layerT5.getPointsMatchingFilter(); // Get the percentage of points matching the visibility filter list = layerT5.getPercentMatchingFilter(); // Sets the visibility filter to null layerT5.nullVisibilityFilter()
In a manner similar to the visibility filtering, NeXtMidas also supports highlighting points matching a given criteria. Multiple highlight filters can be active at one time, and each highlight filter can have its own highlight color.
Users can enable highlight total messages when the total number of highlighted points (or total number of visible highlighted points) changes. To do so:
Please refer to the macro at the bottom for an example.
Example where lt5 is the layer name and the T5000 file LAYER qualifier had FILTERDATAFIELDS=POS
Predicate lonGE = d -> d >= 50.0;
Predicate lonLE = d -> d <= 70.0;
Predicate latGE = d -> d >= 10.0;
Predicate latLE = d -> d <= 20.0;
Predicate lonRange = lonGE.and(lonLE);
Predicate latRange = latGE.and(latLE);
PredicateType lonRangePT = new PredicateType(lonRange, Double.class, "longitude range check");
PredicateType latRangePT = new PredicateType(latRange, Double.class, "latitude range check");
Map rangeMap = PredicateType.getNewPredicateTypeMap();
rangeMap.put("POS.LON",lonRangePT);
rangeMap.put("POS.LAT",latRangePT);
List t5points = lt5.getPointsAsList();
List pointsMatching = Point3D.getPointsMatchingFilter(t5points,rangeMap);
Users can enable color fading on tracks of data. This is when older track points gradually fade out towards the specified fade color, which defaults to dark grey if not provided. The following LayerT5 parameters can be added to adjust track fade settings:
Please refer to the macro at the bottom for an example.
Users now have the ability to tell NeXtMidas to register a MessageHandler which will send out LayerT5 SELECT and DESELECT messages to be received by the user. To do so:
Please refer to the macro at the bottom for an example.
Users can bring up a popup menu by doing a ctrl-left-click on any point. The selected point is the point closest to the click. LayerDrawable provides a way to point select across grouped LayerT5's (please see the LayerDrawable coordination section below).
LayerDrawable is used to group Layers and treat them as one layer. This is used a lot with grouping LayerT5's together. Newer capabilities associated with LayerDrawable/LayerT5 coordination include:
Users now have the option to display the number of points within certain regions (a.k.a. clusters). This can be applied across multiple LayerT5's grouped within a single LayerDrawable. Zooming in will make the size of each of these regions smaller. Clustering is not supported past a certain zoom level.
Please refer to test_plot_layert5_clusters_drawable.mm for an example on how to enable clustering for a LayerDrawable containing LayerT5's.
Users can now bring up a popup menu by doing a ctrl-left-click on any point. The selected point is the point closest to the click. (NOTE: with multiple LayerT5's grouped within a single LayerDrawable, the point selected will be across all LayerT5's. This is because each LayerDrawable treats its grouped LayerT5's as one single layer). The popup menu will display all info associated with the selected point (will only be for one point since using LayerDrawable).
Each LayerDrawable keeps track of the total number of points across all of its grouped LayerT5's.
Users can now plot XYZ data with a 3DGRAPH VIEW, which supports zooming, rotating, panning, and scaling. 3DGRAPH plots provide a grid
to be plotted with the XYZ data. VIEW 3DGRAPH are rotated about 0,0,0 (as opposed to VIEW XYZ which rotates about the center of the data.
To plot XYZ data for LayerT5, please do the following:
Please refer to the macro at the bottom for an example.
Users now have the option to display the number of points within certain regions (a.k.a. clusters).
This can be applied across a single LayerT5. Zooming in will make the size of each of these regions smaller.
Clustering is not supported past a certain zoom level.
Please refer to test_plot_layert5_clusters_fixed.mm for an example on how to enable clustering for a single LayerT5.
!Macro Example:
startmacro
pipe on
! CSV Plot with LayerDrawable
set ellipseColumnNames "D:ALT,D:LAT,D:LON,D:ELLIPSOIDMAJ,D:ELLIPSOIDMAJ,D:ELLIPSOIDMAJ,NAME,D:TIME,B:F1,B:F2,B:F3,B:F4,B:F5,B:F6,B:F7,B:F8,Z:NOTE"
set ellipseLayerCSV "LT=T5,TimeOrder=TRUE,Group=t5Group,NAME=CSV,SIZE=6,AutoselectEnable=CLICK,AutoSelectMode=PIXEL,SELECTCOLOR=PINK,X=LON,Y=LAT,Z=ALT,LABEL=NAME,TIMELF=TIME,METAPOS=METADATA"
set qualsEllipseCSV {HEADERROWS=L:1,COLUMNNAMES="^ellipseColumnNames",LAYER={^ellipseLayerCSV},TAG=CSVFILE}
plot/id=plotCSV/msgid=main world|{LT=Drawable,NAME=t5Group,listLayers=true}|nxm.sys.test.ellipsoid5000.csv^{qualsEllipseCSV} readoutExt=+SHOW|+FEATURE|+POINTS
! Table for the Type 5000 Blue file to be generated
set t:t5000 {}
set t:t5000.0 {POS=(0,0,0),NAME="String",ELLIPSOID=(1000,10000,100,0,0,0),COLOR="ORANGE",TIME=2.22447013119E9,SYMBOL=Arrow.png,METADATA="Just a String"}
set t:t5000.1 {POS=(0,20,20),NAME="Table",ELPSOID=(1000,10000,100,0,0,0),COLOR="PINK",TIME=2.22447013121E9,SYMBOL=Aero,METADATA={key="This is a Table"}}
! Generate the Type 5000 Blue file
table t5000 getsize tblSize
file open/n out ram:t5_tmp.tmp{COMPONENTS=(POS/VD,NAME/2A,ELLIPSOID/6D,COLOR/2A,TIME/SD,SYMBOL/2A,METADATA/9A),SIZE=tblSize}
foreach idx INTABLE t5000
invoke ,, out.setData(idx,t5000.^{idx})
endfor
file close out
set layTmp "LT=T5,NAME=t5Tmp,LABEL=NAME,AutoselectEnable=CLICK,AutoSelectMode=PIXEL,SELECTCOLOR=BLUE"
plot/id=plotTmp/msgid=main world|t5_tmp{Layer=^{layTmp}}
! Piped LayerT5 Plots with LayerDrawable
set layerPipe1 "LT=T5,Group=t5Group2,NAME=test1,ColorFade=TRUE,ColorFadeFactor=1,FadeColor=0x200000,AutoselectEnable=CLICK,AutoSelectMode=PIXEL,SELECTCOLOR=BLUE,SELECTMESSAGES=TRUE,METADATAFIELDS=NAME|NOTE,FILTERDATAFIELDS=ALL"
set layerPipe2 "LT=T5,Group=t5Group2,NAME=test2,ColorFade=TRUE,ColorFadeFactor=1,FadeColor=0x200000,AutoselectEnable=CLICK,AutoSelectMode=PIXEL,SELECTCOLOR=BLUE,SELECTMESSAGES=TRUE,METADATAFIELDS=NAME|NOTE,FILTERDATAFIELDS=ALL"
plot/id=plotPipe/msgid=main world|{LT=Drawable,NAME=t5Group2,listLayers=true}|_t5pipe1{Layer={^layerPipe1}}|_t5pipe2{Layer={^layerPipe2}}
! Plot LayerT5 with XYZ data
plot/id=3dgraph _t5Pipe{Layer={LT="T5",DATATYPE="XYZ",AutoselectEnable=CLICK,AutoSelectMode=PIXEL,SELECTCOLOR=BLUE,SELECTMESSAGES=TRUE}} view=3dgraph
! Plot LayerT5 with highlight filtering and with highlight total messages
! Plot LayerT5 with point selection color change turned off
plot/id=plotPipeHighlight _t5pipe3{Layer={LT="T5",AutoselectEnable=CLICK,AutoSelectMode=PIXEL,SELECTCOLOR=NONE,SELECTMESSAGES=TRUE,HIGHLIGHTTOTALMESSAGES=TRUE}}
pipe off
endmacro
procedure processMessage m:msg
if msg.name eqs "MAIN" then
assert/text="^reg.main.name: User indicated tests" msg.data eqss "PASS"
pipe stop
elseif msg.name EQS "SELECT" OR msg.name EQS "DESELECT" then
info "^msg.name MESSAGE"
say "^msg.name ^msg.data"
endif
return